+ currentInputBlock = (grasshopper_w128_t *) current_in;
+ currentOutputBlock = (grasshopper_w128_t *) current_out;
+ grasshopper_encrypt_block(&c->c.encrypt_round_keys, iv_buffer,
+ &c->partial_buffer, &c->c.buffer);
+ for (i = 0; i < lasted; i++) {
+ if (encrypting) {
+ currentOutputBlock->b[i] =
+ c->partial_buffer.b[i] ^ currentInputBlock->b[i];
+ c->partial_buffer.b[i] = currentOutputBlock->b[i];
+ } else {
+ unsigned char in = currentInputBlock->b[i];
+ currentOutputBlock->b[i] =
+ c->partial_buffer.b[i] ^ currentInputBlock->b[i];
+ c->partial_buffer.b[i] = in;
+ }
+ }
+ EVP_CIPHER_CTX_set_num(ctx, n + i);
+ ctr128_inc(iv_buffer->b);
+ }
+
+ /* Final step */
+ if (in == NULL && inl == 0) {
+ unsigned char len_buf[16];
+ uint64_t a_len = 0, p_len = 0;
+
+ if (rest_len != 0) {
+ memset(c->partial_buffer.b + rest_len, 0,
+ GRASSHOPPER_BLOCK_SIZE - rest_len);
+ grasshopper_encrypt_block(&c->c.encrypt_round_keys, c->mgm_iv, &h,
+ &c->c.buffer);
+ inc_counter(c->mgm_iv->b, 8);
+ hexdump(stderr, "Hnext", h.b, 16);
+ hexdump(stderr, "Padded ciphertext", c->partial_buffer.b, 16);
+ /* Galois multiply Hi * Ai */
+ gf128_mul_uint64(tmp.q, h.q, c->partial_buffer.q);
+
+ /* XOR to c->tag */
+ grasshopper_plus128(&h, (grasshopper_w128_t *) c->tag, &tmp);
+ grasshopper_copy128((grasshopper_w128_t *) c->tag, &h);
+ hexdump(stderr, "Tag", c->tag, 16);
+ }
+
+ a_len = c->ad_length << 3;
+ p_len = (c->mgm_state == mgm_associated_data) ? 0 : n << 3;
+
+#ifdef L_ENDIAN
+ a_len = bswap_64(a_len);
+ p_len = bswap_64(p_len);
+#endif
+ memset(len_buf, 0, 16);
+
+ memcpy(len_buf, &a_len, sizeof(a_len));
+ memcpy(len_buf + sizeof(a_len), &p_len, sizeof(p_len));
+ grasshopper_encrypt_block(&c->c.encrypt_round_keys, c->mgm_iv,
+ &h, &c->c.buffer);
+
+ hexdump(stderr, "Hlast", h.b, 16);
+ hexdump(stderr, "Lenbuf", len_buf, 16);
+ /* Galois multiply Hi * Ai */
+ gf128_mul_uint64(tmp.q, h.q, (uint64_t *)len_buf);
+
+ /* XOR to c->tag */
+ grasshopper_plus128(&h, (grasshopper_w128_t *) c->tag, &tmp);
+ grasshopper_copy128((grasshopper_w128_t *) c->tag, &h);
+ hexdump(stderr, "Tag", c->tag, 16);
+
+ /* Final tag calculation */
+ if (encrypting) {
+ grasshopper_encrypt_block(&c->c.encrypt_round_keys,
+ (grasshopper_w128_t *) c->tag,
+ (grasshopper_w128_t *) c->final_tag,
+ &c->c.buffer);
+ return 1;
+ } else {
+ grasshopper_w128_t decrypt_tag;
+ grasshopper_encrypt_block(&c->c.encrypt_round_keys,
+ (grasshopper_w128_t *) c->tag,
+ &decrypt_tag, &c->c.buffer);
+ if (memcmp(decrypt_tag.b, c->final_tag, 16)) {
+ hexdump(stderr, "Bad final tag", decrypt_tag.b, 16);
+ return 0;
+ } else
+ return 1;