- g4 = h4 + b - (1 << 26);
-
- b = (g4 >> 31) - 1;
- nb = ~b;
- h0 = (h0 & nb) | (g0 & b);
- h1 = (h1 & nb) | (g1 & b);
- h2 = (h2 & nb) | (g2 & b);
- h3 = (h3 & nb) | (g3 & b);
- h4 = (h4 & nb) | (g4 & b);
-
- f0 = ((h0) | (h1 << 26)) + (uint64_t) U8TO32_LE(&key[16]);
- f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t) U8TO32_LE(&key[20]);
- f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t) U8TO32_LE(&key[24]);
- f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t) U8TO32_LE(&key[28]);
-
- U32TO8_LE(&out[0], f0);
- f1 += (f0 >> 32);
- U32TO8_LE(&out[4], f1);
- f2 += (f1 >> 32);
- U32TO8_LE(&out[8], f2);
- f3 += (f2 >> 32);
- U32TO8_LE(&out[12], f3);
+ g4 = h4 + c - (1 << 26);
+
+ /* select h if h < p, or h + -p if h >= p */
+ mask = (g4 >> ((sizeof(uint32_t) * 8) - 1)) - 1;
+ g0 &= mask;
+ g1 &= mask;
+ g2 &= mask;
+ g3 &= mask;
+ g4 &= mask;
+ mask = ~mask;
+ h0 = (h0 & mask) | g0;
+ h1 = (h1 & mask) | g1;
+ h2 = (h2 & mask) | g2;
+ h3 = (h3 & mask) | g3;
+ h4 = (h4 & mask) | g4;
+
+ /* h = h % (2^128) */
+ h0 = ((h0) | (h1 << 26)) & 0xffffffff;
+ h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff;
+ h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
+ h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff;
+
+ /* mac = (h + pad) % (2^128) */
+ f = (uint64_t)h0 + st->pad[0] ;
+ h0 = (uint32_t)f;
+ f = (uint64_t)h1 + st->pad[1] + (f >> 32);
+ h1 = (uint32_t)f;
+ f = (uint64_t)h2 + st->pad[2] + (f >> 32);
+ h2 = (uint32_t)f;
+ f = (uint64_t)h3 + st->pad[3] + (f >> 32);
+ h3 = (uint32_t)f;
+
+ U32TO8(mac + 0, h0);
+ U32TO8(mac + 4, h1);
+ U32TO8(mac + 8, h2);
+ U32TO8(mac + 12, h3);
+
+ /* zero out the state */
+ st->h[0] = 0;
+ st->h[1] = 0;
+ st->h[2] = 0;
+ st->h[3] = 0;
+ st->h[4] = 0;
+ st->r[0] = 0;
+ st->r[1] = 0;
+ st->r[2] = 0;
+ st->r[3] = 0;
+ st->r[4] = 0;
+ st->pad[0] = 0;
+ st->pad[1] = 0;
+ st->pad[2] = 0;
+ st->pad[3] = 0;
+}
+
+
+void
+poly1305_update(struct poly1305_context *st, const unsigned char *m, size_t bytes) {
+ size_t i;
+
+ /* handle leftover */
+ if(st->leftover) {
+ size_t want = (POLY1305_BLOCK_SIZE - st->leftover);
+
+ if(want > bytes) {
+ want = bytes;
+ }
+
+ for(i = 0; i < want; i++) {
+ st->buffer[st->leftover + i] = m[i];
+ }
+
+ bytes -= want;
+ m += want;
+ st->leftover += want;
+
+ if(st->leftover < POLY1305_BLOCK_SIZE) {
+ return;
+ }
+
+ poly1305_blocks(st, st->buffer, POLY1305_BLOCK_SIZE);
+ st->leftover = 0;
+ }
+
+ /* process full blocks */
+ if(bytes >= POLY1305_BLOCK_SIZE) {
+ size_t want = (bytes & ~(POLY1305_BLOCK_SIZE - 1));
+ poly1305_blocks(st, m, want);
+ m += want;
+ bytes -= want;
+ }
+
+ /* store leftover */
+ if(bytes) {
+#if (USE_MEMCPY == 1)
+ memcpy(st->buffer + st->leftover, m, bytes);
+#else
+
+ for(i = 0; i < bytes; i++) {
+ st->buffer[st->leftover + i] = m[i];
+ }
+
+#endif
+ st->leftover += bytes;
+ }
+}
+
+void
+poly1305_auth(unsigned char mac[16], const unsigned char *m, size_t bytes, const unsigned char key[32]) {
+ struct poly1305_context ctx;
+ poly1305_init(&ctx, key);
+ poly1305_update(&ctx, m, bytes);
+ poly1305_finish(&ctx, mac);