From 60751536aa6099c726b92297ed228853e4528631 Mon Sep 17 00:00:00 2001 From: "John M. Schanck" Date: Fri, 18 Sep 2020 22:18:08 -0400 Subject: [PATCH] falcon: fix fpr_lt --- crypto_sign/falcon-1024/clean/fpr.h | 24 ++++++++++++++++++------ crypto_sign/falcon-512/clean/fpr.h | 24 ++++++++++++++++++------ 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/crypto_sign/falcon-1024/clean/fpr.h b/crypto_sign/falcon-1024/clean/fpr.h index 795a5b49..004bc0df 100644 --- a/crypto_sign/falcon-1024/clean/fpr.h +++ b/crypto_sign/falcon-1024/clean/fpr.h @@ -424,20 +424,32 @@ fpr fpr_sqrt(fpr x); static inline int fpr_lt(fpr x, fpr y) { /* - * If x >= 0 or y >= 0, a signed comparison yields the proper - * result: + * If both x and y are positive, then a signed comparison yields + * the proper result: * - For positive values, the order is preserved. * - The sign bit is at the same place as in integers, so * sign is preserved. + * Moreover, we can compute [x < y] as sgn(x-y) and the computation + * of x-y will not overflow. + * + * If the signs differ, then sgn(x) gives the proper result. * * If both x and y are negative, then the order is reversed. - * We cannot simply invert the comparison result in that case - * because it would not handle the edge case x = y properly. + * Hence [x < y] = sgn(y-x). We must compute this separately from + * sgn(x-y); simply inverting sgn(x-y) would not handle the edge + * case x = y properly. */ int cc0, cc1; + int64_t sx; + int64_t sy; + + sx = *(int64_t *)&x; + sy = *(int64_t *)&y; + sy &= ~((sx ^ sy) >> 63); /* set sy=0 if signs differ */ + + cc0 = (int)((sx - sy) >> 63) & 1; /* Neither subtraction overflows when */ + cc1 = (int)((sy - sx) >> 63) & 1; /* the signs are the same. */ - cc0 = (int)((*(int64_t *)&x - * (int64_t *)&y) >> 63) & 1; - cc1 = (int)((*(int64_t *)&y - * (int64_t *)&x) >> 63) & 1; return cc0 ^ ((cc0 ^ cc1) & (int)((x & y) >> 63)); } diff --git a/crypto_sign/falcon-512/clean/fpr.h b/crypto_sign/falcon-512/clean/fpr.h index 65ce5db4..b662a52b 100644 --- a/crypto_sign/falcon-512/clean/fpr.h +++ b/crypto_sign/falcon-512/clean/fpr.h @@ -424,20 +424,32 @@ fpr fpr_sqrt(fpr x); static inline int fpr_lt(fpr x, fpr y) { /* - * If x >= 0 or y >= 0, a signed comparison yields the proper - * result: + * If both x and y are positive, then a signed comparison yields + * the proper result: * - For positive values, the order is preserved. * - The sign bit is at the same place as in integers, so * sign is preserved. + * Moreover, we can compute [x < y] as sgn(x-y) and the computation + * of x-y will not overflow. + * + * If the signs differ, then sgn(x) gives the proper result. * * If both x and y are negative, then the order is reversed. - * We cannot simply invert the comparison result in that case - * because it would not handle the edge case x = y properly. + * Hence [x < y] = sgn(y-x). We must compute this separately from + * sgn(x-y); simply inverting sgn(x-y) would not handle the edge + * case x = y properly. */ int cc0, cc1; + int64_t sx; + int64_t sy; + + sx = *(int64_t *)&x; + sy = *(int64_t *)&y; + sy &= ~((sx ^ sy) >> 63); /* set sy=0 if signs differ */ + + cc0 = (int)((sx - sy) >> 63) & 1; /* Neither subtraction overflows when */ + cc1 = (int)((sy - sx) >> 63) & 1; /* the signs are the same. */ - cc0 = (int)((*(int64_t *)&x - * (int64_t *)&y) >> 63) & 1; - cc1 = (int)((*(int64_t *)&y - * (int64_t *)&x) >> 63) & 1; return cc0 ^ ((cc0 ^ cc1) & (int)((x & y) >> 63)); }