diff --git a/doc/crypto.dox b/doc/crypto.dox
index b793611d..88553484 100644
--- a/doc/crypto.dox
+++ b/doc/crypto.dox
@@ -30,6 +30,7 @@
\li Block cipher modes: CTR, CFB, CBC, OFB
\li Stream ciphers: ChaCha
\li Hash algorithms: SHA1, SHA256, SHA512, SHA3_256, SHA3_512, BLAKE2s, BLAKE2b (regular and HMAC modes)
+\li Message authenticators: Poly1305
\li Public key algorithms: Curve25519
\li Random number generation: \link RNGClass RNG\endlink, TransistorNoiseSource, RingOscillatorNoiseSource
@@ -74,6 +75,7 @@ Ardunino Mega 2560 running at 16 MHz are similar:
SHA3_512 | 229.12us | | | 403 |
BLAKE2s | 18.54us | | | 169 |
BLAKE2b | 50.58us | | | 337 |
+Poly1305 | 26.29us | | | 87 |
Where a cipher supports more than one key size (such as ChaCha), the values
diff --git a/doc/mainpage.dox b/doc/mainpage.dox
index fcd2647b..4b58ba47 100644
--- a/doc/mainpage.dox
+++ b/doc/mainpage.dox
@@ -95,6 +95,7 @@ realtime clock and the LCD library to implement an alarm clock.
\li Block cipher modes: CTR, CFB, CBC, OFB
\li Stream ciphers: ChaCha
\li Hash algorithms: SHA1, SHA256, SHA512, SHA3_256, SHA3_512, BLAKE2s, BLAKE2b (regular and HMAC modes)
+\li Message authenticators: Poly1305
\li Public key algorithms: Curve25519
\li Random number generation: \link RNGClass RNG\endlink, TransistorNoiseSource, RingOscillatorNoiseSource
diff --git a/libraries/Crypto/Poly1305.cpp b/libraries/Crypto/Poly1305.cpp
new file mode 100644
index 00000000..4b918751
--- /dev/null
+++ b/libraries/Crypto/Poly1305.cpp
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2015 Southern Storm Software, Pty Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "Poly1305.h"
+#include "Crypto.h"
+#include "utility/EndianUtil.h"
+#include
+
+/**
+ * \class Poly1305 Poly1305.h
+ * \brief Poly1305 message authenticator
+ *
+ * Poly1305 is a message authenticator designed by Daniel J. Bernstein.
+ * An arbitrary-length message is broken up into 16-byte chunks and fed
+ * into a polynomial mod 2130 - 5 based on the 16-byte
+ * authentication key. The final polynomial value is then combined with a
+ * 16-byte nonce to create the authentication token.
+ *
+ * The following example demonstrates how to compute an authentication token
+ * for a message made up of several blocks under a specific key and nonce:
+ *
+ * \code
+ * Poly1305 poly1305;
+ * uint8_t token[16];
+ * poly1305.reset(key);
+ * poly1305.update(block1, sizeof(block1));
+ * poly1305.update(block2, sizeof(block2));
+ * ...
+ * poly1305.update(blockN, sizeof(blockN));
+ * poly1305.finalize(nonce, token, sizeof(token));
+ * \endcode
+ *
+ * In the original Poly1305 specification, the nonce was encrypted with AES
+ * and a second 16-byte key. Since then, common practice has been for the
+ * caller to encrypt the nonce which gives the caller more flexibility as
+ * to how to derive and/or encrypt the nonce.
+ *
+ * References: http://en.wikipedia.org/wiki/Poly1305-AES,
+ * http://cr.yp.to/mac.html
+ */
+
+// Useful sizes for limb array and word manipulation.
+#define NUM_LIMBS_128BIT (16 / sizeof(limb_t))
+#define NUM_LIMBS_130BIT ((16 / sizeof(limb_t)) + 1)
+#define LIMB_BITS (sizeof(limb_t) * 8)
+
+// Endian helper macros. Need modification if the size of limb_t changes.
+#define lelimbtoh(x) (le16toh((x)))
+#define htolelimb(x) (htole16((x)))
+#if defined(CRYPTO_LITTLE_ENDIAN)
+#define littleToHost(r,size) do { ; } while (0)
+#else
+#define littleToHost(r,size) \
+ do { \
+ for (uint8_t i = 0; i < (size); ++i) \
+ (r)[i] = lelimbtoh((r)[i]); \
+ } while (0)
+#endif
+
+/**
+ * \brief Constructs a new Poly1305 message authenticator.
+ */
+Poly1305::Poly1305()
+{
+ state.chunkSize = 0;
+}
+
+/**
+ * \brief Destroys this Poly1305 message authenticator after clearing all
+ * sensitive information.
+ */
+Poly1305::~Poly1305()
+{
+ clean(state);
+}
+
+/**
+ * \brief Resets the Poly1305 message authenticator for a new session.
+ *
+ * \param key Points to the 16 byte authentication key.
+ *
+ * \sa update(), finalize()
+ */
+void Poly1305::reset(const void *key)
+{
+ // Copy the key into place and clear the bits we don't need.
+ uint8_t *r = (uint8_t *)state.r;
+ memcpy(r, key, 16);
+ r[3] &= 0x0F;
+ r[4] &= 0xFC;
+ r[7] &= 0x0F;
+ r[8] &= 0xFC;
+ r[11] &= 0x0F;
+ r[12] &= 0xFC;
+ r[15] &= 0x0F;
+
+ // Convert into little-endian if necessary.
+ littleToHost(state.r, NUM_LIMBS_128BIT);
+
+ // Reset the hashing process.
+ state.chunkSize = 0;
+ memset(state.h, 0, sizeof(state.h));
+}
+
+/**
+ * \brief Updates the message authenticator with more data.
+ *
+ * \param data Data to be hashed.
+ * \param len Number of bytes of data to be hashed.
+ *
+ * If finalize() has already been called, then the behavior of update() will
+ * be undefined. Call reset() first to start a new authentication process.
+ *
+ * \sa reset(), finalize()
+ */
+void Poly1305::update(const void *data, size_t len)
+{
+ // Break the input up into 128-bit chunks and process each in turn.
+ const uint8_t *d = (const uint8_t *)data;
+ while (len > 0) {
+ uint8_t size = 16 - state.chunkSize;
+ if (size > len)
+ size = len;
+ memcpy(((uint8_t *)state.c) + state.chunkSize, d, size);
+ state.chunkSize += size;
+ len -= size;
+ d += size;
+ if (state.chunkSize == 16) {
+ littleToHost(state.c, NUM_LIMBS_128BIT);
+ state.c[NUM_LIMBS_128BIT] = 1;
+ processChunk();
+ state.chunkSize = 0;
+ }
+ }
+}
+
+/**
+ * \brief Finalizes the authentication process and returns the token.
+ *
+ * \param nonce Points to the 16-bit nonce to combine with the token.
+ * \param token The buffer to return the token value in.
+ * \param len The length of the \a token buffer between 0 and 16.
+ *
+ * If \a len is less than 16, then the token value will be truncated to
+ * the first \a len bytes. If \a len is greater than 16, then the remaining
+ * bytes will left unchanged.
+ *
+ * If finalize() is called again, then the returned \a token value is
+ * undefined. Call reset() first to start a new authentication process.
+ *
+ * \sa reset(), update()
+ */
+void Poly1305::finalize(const void *nonce, void *token, size_t len)
+{
+ dlimb_t carry;
+ uint8_t i;
+
+ // Pad and flush the final chunk.
+ if (state.chunkSize > 0) {
+ uint8_t *c = (uint8_t *)state.c;
+ c[state.chunkSize] = 1;
+ memset(c + state.chunkSize + 1, 0, 16 - state.chunkSize - 1);
+ littleToHost(state.c, NUM_LIMBS_128BIT);
+ state.c[NUM_LIMBS_128BIT] = 0;
+ processChunk();
+ }
+
+ // At this point, processChunk() has left h as a partially reduced
+ // result that is less than (2^130 - 5) * 6. Perform one more
+ // reduction and a trial subtraction to produce the final result.
+
+ // Multiply the high bits of h by 5 and add them to the 130 low bits.
+ carry = (dlimb_t)((state.h[NUM_LIMBS_128BIT] >> 2) +
+ (state.h[NUM_LIMBS_128BIT] & ~((limb_t)3)));
+ state.h[NUM_LIMBS_128BIT] &= 0x0003;
+ for (i = 0; i < NUM_LIMBS_128BIT; ++i) {
+ carry += state.h[i];
+ state.h[i] = (limb_t)carry;
+ carry >>= LIMB_BITS;
+ }
+ state.h[i] += (limb_t)carry;
+
+ // Subtract (2^130 - 5) from h by computing t = h + 5 - 2^130.
+ // The "minus 2^130" step is implicit.
+ carry = 5;
+ for (i = 0; i < NUM_LIMBS_130BIT; ++i) {
+ carry += state.h[i];
+ state.t[i] = (limb_t)carry;
+ carry >>= LIMB_BITS;
+ }
+
+ // Borrow occurs if bit 2^130 of the previous t result is zero.
+ // Carefully turn this into a selection mask so we can select either
+ // h or t as the final result. We don't care about the highest word
+ // of the result because we are about to drop it in the next step.
+ // We have to do it this way to avoid giving away any information
+ // about the value of h in the instruction timing.
+ limb_t mask = (~((state.t[NUM_LIMBS_128BIT] >> 2) & 1)) + 1;
+ limb_t nmask = ~mask;
+ for (i = 0; i < NUM_LIMBS_128BIT; ++i) {
+ state.h[i] = (state.h[i] & nmask) | (state.t[i] & mask);
+ }
+
+ // Add the encrypted nonce and format the final hash.
+ memcpy(state.c, nonce, 16);
+ littleToHost(state.c, NUM_LIMBS_128BIT);
+ carry = 0;
+ for (i = 0; i < NUM_LIMBS_128BIT; ++i) {
+ carry += state.h[i];
+ carry += state.c[i];
+ state.h[i] = htolelimb((limb_t)carry);
+ carry >>= LIMB_BITS;
+ }
+ if (len > 16)
+ len = 16;
+ memcpy(token, state.h, len);
+}
+
+/**
+ * \brief Clears the authenticator's state, removing all sensitive data.
+ */
+void Poly1305::clear()
+{
+ clean(state);
+}
+
+/**
+ * \brief Processes a single 128-bit chunk of input data.
+ */
+void Poly1305::processChunk()
+{
+ // Compute h = ((h + c) * r) mod (2^130 - 5).
+
+ // Start with h += c. We assume that h is less than (2^130 - 5) * 6
+ // and that c is less than 2^129, so the result will be less than 2^133.
+ dlimb_t carry = 0;
+ uint8_t i, j;
+ for (i = 0; i < NUM_LIMBS_130BIT; ++i) {
+ carry += state.h[i];
+ carry += state.c[i];
+ state.h[i] = (limb_t)carry;
+ carry >>= LIMB_BITS;
+ }
+
+ // Multiply h by r. We know that r is less than 2^124 because the
+ // top 4 bits were AND-ed off by reset(). That makes h * r less
+ // than 2^257. Which is less than the (2^130 - 6)^2 we want for
+ // the modulo reduction step that follows.
+ carry = 0;
+ limb_t word = state.r[0];
+ for (i = 0; i < NUM_LIMBS_130BIT; ++i) {
+ carry += ((dlimb_t)(state.h[i])) * word;
+ state.t[i] = (limb_t)carry;
+ carry >>= LIMB_BITS;
+ }
+ state.t[NUM_LIMBS_130BIT] = (limb_t)carry;
+ for (i = 1; i < NUM_LIMBS_128BIT; ++i) {
+ word = state.r[i];
+ carry = 0;
+ for (j = 0; j < NUM_LIMBS_130BIT; ++j) {
+ carry += ((dlimb_t)(state.h[j])) * word;
+ carry += state.t[i + j];
+ state.t[i + j] = (limb_t)carry;
+ carry >>= LIMB_BITS;
+ }
+ state.t[i + NUM_LIMBS_130BIT] = (limb_t)carry;
+ }
+
+ // Reduce h * r modulo (2^130 - 5) by multiplying the high 130 bits by 5
+ // and adding them to the low 130 bits. See the explaination in the
+ // comments for Curve25519::reduce() for a description of how this works.
+ carry = ((dlimb_t)(state.t[NUM_LIMBS_128BIT] >> 2)) +
+ (state.t[NUM_LIMBS_128BIT] & ~((limb_t)3));
+ state.t[NUM_LIMBS_128BIT] &= 0x0003;
+ for (i = 0; i < NUM_LIMBS_128BIT; ++i) {
+ // Shift the next word of t up by (LIMB_BITS - 2) bits and then
+ // multiply it by 5. Breaking it down, we can add the results
+ // of shifting up by LIMB_BITS and shifting up by (LIMB_BITS - 2).
+ // The main wrinkle here is that this can result in an intermediate
+ // carry that is (LIMB_BITS * 2 + 1) bits in size which doesn't
+ // fit within a dlimb_t variable. However, we can defer adding
+ // (word << LIMB_BITS) until after the "carry >>= LIMB_BITS" step
+ // because it won't affect the low bits of the carry.
+ word = state.t[i + NUM_LIMBS_130BIT];
+ carry += ((dlimb_t)word) << (LIMB_BITS - 2);
+ carry += state.t[i];
+ state.h[i] = (limb_t)carry;
+ carry >>= LIMB_BITS;
+ carry += word;
+ }
+ state.h[i] = (limb_t)(carry + state.t[NUM_LIMBS_128BIT]);
+
+ // At this point, h is either the answer of reducing modulo (2^130 - 5)
+ // or it is at most 5 subtractions away from the answer we want.
+ // Leave it as-is for now with h less than (2^130 - 5) * 6. It is
+ // still within a range where the next h * r step will not overflow.
+}
diff --git a/libraries/Crypto/Poly1305.h b/libraries/Crypto/Poly1305.h
new file mode 100644
index 00000000..9dde521a
--- /dev/null
+++ b/libraries/Crypto/Poly1305.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 Southern Storm Software, Pty Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef CRYPTO_POLY1305_h
+#define CRYPTO_POLY1305_h
+
+#include
+#include
+
+class Poly1305
+{
+public:
+ Poly1305();
+ ~Poly1305();
+
+ void reset(const void *key);
+ void update(const void *data, size_t len);
+ void finalize(const void *nonce, void *token, size_t len);
+
+ void clear();
+
+private:
+ typedef uint16_t limb_t;
+ typedef int16_t slimb_t;
+ typedef uint32_t dlimb_t;
+ struct {
+ limb_t h[(16 / sizeof(limb_t)) + 1];
+ limb_t c[(16 / sizeof(limb_t)) + 1];
+ limb_t r[(16 / sizeof(limb_t))];
+ limb_t t[(32 / sizeof(limb_t)) + 1];
+ uint8_t chunkSize;
+ } state;
+
+ void processChunk();
+};
+
+#endif
diff --git a/libraries/Crypto/examples/TestPoly1305/TestPoly1305.ino b/libraries/Crypto/examples/TestPoly1305/TestPoly1305.ino
new file mode 100644
index 00000000..0c07cc3d
--- /dev/null
+++ b/libraries/Crypto/examples/TestPoly1305/TestPoly1305.ino
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2015 Southern Storm Software, Pty Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+This example runs tests on the Poly1305 implementation to verify correct behaviour.
+*/
+
+#include
+#include
+#include
+
+// Test vectors from the Poly1305 specification.
+
+struct TestPoly1305Vector
+{
+ const char *name;
+ uint8_t key[16];
+ uint8_t nonce[16];
+ uint8_t data[64];
+ size_t dataLen;
+ uint8_t hash[16];
+};
+
+static TestPoly1305Vector const testVectorPoly1305_1 = {
+ .name = "Poly1305 #1",
+ .key = {0x85, 0x1f, 0xc4, 0x0c, 0x34, 0x67, 0xac, 0x0b,
+ 0xe0, 0x5c, 0xc2, 0x04, 0x04, 0xf3, 0xf7, 0x00},
+ .nonce = {0x58, 0x0b, 0x3b, 0x0f, 0x94, 0x47, 0xbb, 0x1e,
+ 0x69, 0xd0, 0x95, 0xb5, 0x92, 0x8b, 0x6d, 0xbc},
+ .data = {0xf3, 0xf6},
+ .dataLen = 2,
+ .hash = {0xf4, 0xc6, 0x33, 0xc3, 0x04, 0x4f, 0xc1, 0x45,
+ 0xf8, 0x4f, 0x33, 0x5c, 0xb8, 0x19, 0x53, 0xde}
+
+};
+static TestPoly1305Vector const testVectorPoly1305_2 = {
+ .name = "Poly1305 #2",
+ .key = {0xa0, 0xf3, 0x08, 0x00, 0x00, 0xf4, 0x64, 0x00,
+ 0xd0, 0xc7, 0xe9, 0x07, 0x6c, 0x83, 0x44, 0x03},
+ .nonce = {0xdd, 0x3f, 0xab, 0x22, 0x51, 0xf1, 0x1a, 0xc7,
+ 0x59, 0xf0, 0x88, 0x71, 0x29, 0xcc, 0x2e, 0xe7},
+ .data = {0},
+ .dataLen = 0,
+ .hash = {0xdd, 0x3f, 0xab, 0x22, 0x51, 0xf1, 0x1a, 0xc7,
+ 0x59, 0xf0, 0x88, 0x71, 0x29, 0xcc, 0x2e, 0xe7}
+};
+static TestPoly1305Vector const testVectorPoly1305_3 = {
+ .name = "Poly1305 #3",
+ .key = {0x48, 0x44, 0x3d, 0x0b, 0xb0, 0xd2, 0x11, 0x09,
+ 0xc8, 0x9a, 0x10, 0x0b, 0x5c, 0xe2, 0xc2, 0x08},
+ .nonce = {0x83, 0x14, 0x9c, 0x69, 0xb5, 0x61, 0xdd, 0x88,
+ 0x29, 0x8a, 0x17, 0x98, 0xb1, 0x07, 0x16, 0xef},
+ .data = {0x66, 0x3c, 0xea, 0x19, 0x0f, 0xfb, 0x83, 0xd8,
+ 0x95, 0x93, 0xf3, 0xf4, 0x76, 0xb6, 0xbc, 0x24,
+ 0xd7, 0xe6, 0x79, 0x10, 0x7e, 0xa2, 0x6a, 0xdb,
+ 0x8c, 0xaf, 0x66, 0x52, 0xd0, 0x65, 0x61, 0x36},
+ .dataLen = 32,
+ .hash = {0x0e, 0xe1, 0xc1, 0x6b, 0xb7, 0x3f, 0x0f, 0x4f,
+ 0xd1, 0x98, 0x81, 0x75, 0x3c, 0x01, 0xcd, 0xbe}
+};
+static TestPoly1305Vector const testVectorPoly1305_4 = {
+ .name = "Poly1305 #4",
+ .key = {0x12, 0x97, 0x6a, 0x08, 0xc4, 0x42, 0x6d, 0x0c,
+ 0xe8, 0xa8, 0x24, 0x07, 0xc4, 0xf4, 0x82, 0x07},
+ .nonce = {0x80, 0xf8, 0xc2, 0x0a, 0xa7, 0x12, 0x02, 0xd1,
+ 0xe2, 0x91, 0x79, 0xcb, 0xcb, 0x55, 0x5a, 0x57},
+ .data = {0xab, 0x08, 0x12, 0x72, 0x4a, 0x7f, 0x1e, 0x34,
+ 0x27, 0x42, 0xcb, 0xed, 0x37, 0x4d, 0x94, 0xd1,
+ 0x36, 0xc6, 0xb8, 0x79, 0x5d, 0x45, 0xb3, 0x81,
+ 0x98, 0x30, 0xf2, 0xc0, 0x44, 0x91, 0xfa, 0xf0,
+ 0x99, 0x0c, 0x62, 0xe4, 0x8b, 0x80, 0x18, 0xb2,
+ 0xc3, 0xe4, 0xa0, 0xfa, 0x31, 0x34, 0xcb, 0x67,
+ 0xfa, 0x83, 0xe1, 0x58, 0xc9, 0x94, 0xd9, 0x61,
+ 0xc4, 0xcb, 0x21, 0x09, 0x5c, 0x1b, 0xf9},
+ .dataLen = 63,
+ .hash = {0x51, 0x54, 0xad, 0x0d, 0x2c, 0xb2, 0x6e, 0x01,
+ 0x27, 0x4f, 0xc5, 0x11, 0x48, 0x49, 0x1f, 0x1b}
+};
+
+Poly1305 poly1305;
+
+byte buffer[128];
+
+bool testPoly1305_N(Poly1305 *hash, const struct TestPoly1305Vector *test, size_t inc)
+{
+ size_t size = test->dataLen;
+ size_t posn, len;
+
+ hash->reset(test->key);
+
+ for (posn = 0; posn < size; posn += inc) {
+ len = size - posn;
+ if (len > inc)
+ len = inc;
+ hash->update(test->data + posn, len);
+ }
+
+ hash->finalize(test->nonce, buffer, 16);
+
+ return !memcmp(buffer, test->hash, 16);
+}
+
+void testPoly1305(Poly1305 *hash, const struct TestPoly1305Vector *test)
+{
+ bool ok;
+
+ Serial.print(test->name);
+ Serial.print(" ... ");
+
+ ok = testPoly1305_N(hash, test, test->dataLen);
+ ok &= testPoly1305_N(hash, test, 1);
+ ok &= testPoly1305_N(hash, test, 2);
+ ok &= testPoly1305_N(hash, test, 5);
+ ok &= testPoly1305_N(hash, test, 8);
+ ok &= testPoly1305_N(hash, test, 13);
+ ok &= testPoly1305_N(hash, test, 16);
+ ok &= testPoly1305_N(hash, test, 24);
+ ok &= testPoly1305_N(hash, test, 63);
+ ok &= testPoly1305_N(hash, test, 64);
+
+ if (ok)
+ Serial.println("Passed");
+ else
+ Serial.println("Failed");
+}
+
+void perfPoly1305(Poly1305 *hash)
+{
+ unsigned long start;
+ unsigned long elapsed;
+ int count;
+
+ Serial.print("Hashing ... ");
+
+ for (size_t posn = 0; posn < sizeof(buffer); ++posn)
+ buffer[posn] = (uint8_t)posn;
+
+ hash->reset(testVectorPoly1305_1.key);
+ start = micros();
+ for (count = 0; count < 1000; ++count) {
+ hash->update(buffer, sizeof(buffer));
+ }
+ elapsed = micros() - start;
+
+ Serial.print(elapsed / (sizeof(buffer) * 1000.0));
+ Serial.print("us per byte, ");
+ Serial.print((sizeof(buffer) * 1000.0 * 1000000.0) / elapsed);
+ Serial.println(" bytes per second");
+}
+
+void setup()
+{
+ Serial.begin(9600);
+
+ Serial.println();
+
+ Serial.println("Test Vectors:");
+ testPoly1305(&poly1305, &testVectorPoly1305_1);
+ testPoly1305(&poly1305, &testVectorPoly1305_2);
+ testPoly1305(&poly1305, &testVectorPoly1305_3);
+ testPoly1305(&poly1305, &testVectorPoly1305_4);
+
+ Serial.println();
+
+ Serial.println("Performance Tests:");
+ perfPoly1305(&poly1305);
+}
+
+void loop()
+{
+}
diff --git a/libraries/Crypto/utility/EndianUtil.h b/libraries/Crypto/utility/EndianUtil.h
index b64f9726..29c2c150 100644
--- a/libraries/Crypto/utility/EndianUtil.h
+++ b/libraries/Crypto/utility/EndianUtil.h
@@ -30,6 +30,16 @@
#define CRYPTO_LITTLE_ENDIAN 1
+#define htole16(x) (x)
+#define le16toh(x) (x)
+#define htobe16(x) \
+ (__extension__ ({ \
+ uint16_t _temp = (x); \
+ ((_temp >> 8) & 0x00FF) | \
+ ((_temp << 8) & 0xFF00); \
+ }))
+#define be16toh(x) (htobe16((x)))
+
#define htole32(x) (x)
#define le32toh(x) (x)
#define htobe32(x) \