From b2e96b3086cc3033ddc31cc981b601ff5b9b5f08 Mon Sep 17 00:00:00 2001
From: Vitaly Chikunov <vt@altlinux.org>
Date: Thu, 30 Jan 2020 04:05:10 +0300
Subject: [PATCH] gosthash2012: Simpler version of add512

Similar to my commit into adegtyarev/streebog@432d5de.
---
 gosthash2012.c | 46 +++++++++++++++++++++-------------------------
 1 file changed, 21 insertions(+), 25 deletions(-)

diff --git a/gosthash2012.c b/gosthash2012.c
index 201fe31..3dacc35 100644
--- a/gosthash2012.c
+++ b/gosthash2012.c
@@ -57,34 +57,30 @@ static INLINE void add512(const union uint512_u *x,
                           const union uint512_u *y, union uint512_u *r)
 {
 #ifndef __GOST3411_BIG_ENDIAN__
-    unsigned int CF, OF;
-    unsigned long long tmp;
+    unsigned int CF;
     unsigned int i;
 
     CF = 0;
-    for (i = 0; i < 8; i++)
-    {
-        /* Detecting integer overflow condition for three numbers
-         * in a portable way is tricky a little. */
-
-        /* Step 1: numbers cause overflow */
-        tmp = x->QWORD[i] + y->QWORD[i];
-
-        /* Compare with any of two summands, no need to check both */
-        if (tmp < x->QWORD[i])
-            OF = 1;
-        else
-            OF = 0;
-
-        /* Step 2: carry bit causes overflow */
-        tmp += CF;
-
-        if (CF > 0 && tmp == 0)
-            OF = 1;
-
-        CF = OF;
-
-        r->QWORD[i] = tmp;
+    for (i = 0; i < 8; i++) {
+	const unsigned long long left = x->QWORD[i];
+	unsigned long long sum;
+
+	sum = left + y->QWORD[i] + CF;
+	/*
+	 * (sum == left): is noop, because it's possible only
+	 * when `left' is added with `0 + 0' or with `ULLONG_MAX + 1',
+	 * in that case `CF' (carry) retain previous value, which is correct,
+	 * because when `left + 0 + 0' there was no overflow (thus no carry),
+	 * and when `left + ULLONG_MAX + 1' value is wrapped back to
+	 * itself with overflow, thus creating carry.
+	 *
+	 * (sum != left):
+	 * if `sum' is not wrapped (sum > left) there should not be carry,
+	 * if `sum' is wrapped (sum < left) there should be carry.
+	 */
+	if (sum != left)
+	    CF = (sum < left);
+	r->QWORD[i] = sum;
     }
 #else
     const unsigned char *xp, *yp;
-- 
2.39.5