Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use double-wide types for additions in scalar code #786

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 33 additions & 48 deletions src/scalar_4x64_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,70 +185,55 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {

/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */
#define muladd(a,b) { \
uint64_t tl, th; \
{ \
uint128_t t = (uint128_t)a * b; \
th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \
tl = t; \
} \
c0 += tl; /* overflow is handled on the next line */ \
th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \
c1 += th; /* overflow is handled on the next line */ \
c2 += (c1 < th); /* never overflows by contract (verified in the next line) */ \
VERIFY_CHECK((c1 >= th) || (c2 != 0)); \
uint128_t t = (uint128_t)a * b + c0; \
c0 = t; \
t >>= 64; \
t += c1; \
c1 = t; \
c2 += (t >> 64); \
VERIFY_CHECK(c2 >= (t >> 64)); /* c2 must never overflow. */ \
}

/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */
#define muladd_fast(a,b) { \
uint64_t tl, th; \
{ \
uint128_t t = (uint128_t)a * b; \
th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \
tl = t; \
} \
c0 += tl; /* overflow is handled on the next line */ \
th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \
c1 += th; /* never overflows by contract (verified in the next line) */ \
VERIFY_CHECK(c1 >= th); \
uint128_t t = (uint128_t)a * b + c0; \
c0 = t; \
c1 += (t >> 64); \
VERIFY_CHECK(c1 >= (t >> 64)); /* c1 must never overflow. */ \
}

/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */
#define muladd2(a,b) { \
uint64_t tl, th, th2, tl2; \
{ \
uint128_t t = (uint128_t)a * b; \
th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \
tl = t; \
} \
th2 = th + th; /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \
c2 += (th2 < th); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((th2 >= th) || (c2 != 0)); \
tl2 = tl + tl; /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \
th2 += (tl2 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \
c0 += tl2; /* overflow is handled on the next line */ \
th2 += (c0 < tl2); /* second overflow is handled on the next line */ \
c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \
c1 += th2; /* overflow is handled on the next line */ \
c2 += (c1 < th2); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \
uint128_t t1 = (uint128_t)a * b; \
uint64_t t1l = t1; \
uint64_t t1h = t1 >> 64; \
uint128_t t = (uint128_t)t1l + t1l + c0; \
c0 = t; \
t >>= 64; \
t = t + c1 + t1h + t1h; \
c1 = t; \
c2 += (t >> 64); \
VERIFY_CHECK(c2 >= (t >> 64)); /* c2 must never overflow. */ \
}

/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */
#define sumadd(a) { \
unsigned int over; \
c0 += (a); /* overflow is handled on the next line */ \
over = (c0 < (a)); \
c1 += over; /* overflow is handled on the next line */ \
c2 += (c1 < over); /* never overflows by contract */ \
uint128_t t = (uint128_t)a + c0; \
c0 = t; \
t >>= 64; \
t += c1; \
c1 = t; \
c2 += (t >> 64); \
VERIFY_CHECK(c2 >= (t >> 64)); /* c2 must never overflow. */ \
}

/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */
#define sumadd_fast(a) { \
c0 += (a); /* overflow is handled on the next line */ \
c1 += (c0 < (a)); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \
VERIFY_CHECK(c2 == 0); \
uint128_t t = (uint128_t)a + c0; \
c0 = t; \
c1 += (t >> 64); \
VERIFY_CHECK(c1 >= (t >> 64)); /* c1 must never overflow. */ \
VERIFY_CHECK(c2 == 0); /* c2 must be zero. */ \
}

/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. */
Expand Down
81 changes: 33 additions & 48 deletions src/scalar_8x32_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,70 +264,55 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {

/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */
#define muladd(a,b) { \
uint32_t tl, th; \
{ \
uint64_t t = (uint64_t)a * b; \
th = t >> 32; /* at most 0xFFFFFFFE */ \
tl = t; \
} \
c0 += tl; /* overflow is handled on the next line */ \
th += (c0 < tl); /* at most 0xFFFFFFFF */ \
c1 += th; /* overflow is handled on the next line */ \
c2 += (c1 < th); /* never overflows by contract (verified in the next line) */ \
VERIFY_CHECK((c1 >= th) || (c2 != 0)); \
uint64_t t = (uint64_t)a * b + c0; \
c0 = t; \
t >>= 32; \
t += c1; \
c1 = t; \
c2 += (t >> 32); \
VERIFY_CHECK(c2 >= (t >> 32)); /* c2 must never overflow. */ \
}

/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */
#define muladd_fast(a,b) { \
uint32_t tl, th; \
{ \
uint64_t t = (uint64_t)a * b; \
th = t >> 32; /* at most 0xFFFFFFFE */ \
tl = t; \
} \
c0 += tl; /* overflow is handled on the next line */ \
th += (c0 < tl); /* at most 0xFFFFFFFF */ \
c1 += th; /* never overflows by contract (verified in the next line) */ \
VERIFY_CHECK(c1 >= th); \
uint64_t t = (uint64_t)a * b + c0; \
c0 = t; \
c1 += (t >> 32); \
VERIFY_CHECK(c1 >= (t >> 32)); /* c1 must never overflow. */ \
}

/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */
#define muladd2(a,b) { \
uint32_t tl, th, th2, tl2; \
{ \
uint64_t t = (uint64_t)a * b; \
th = t >> 32; /* at most 0xFFFFFFFE */ \
tl = t; \
} \
th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \
c2 += (th2 < th); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((th2 >= th) || (c2 != 0)); \
tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \
th2 += (tl2 < tl); /* at most 0xFFFFFFFF */ \
c0 += tl2; /* overflow is handled on the next line */ \
th2 += (c0 < tl2); /* second overflow is handled on the next line */ \
c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \
c1 += th2; /* overflow is handled on the next line */ \
c2 += (c1 < th2); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \
uint64_t t1 = (uint64_t)a * b; \
uint32_t t1l = t1; \
uint32_t t1h = t1 >> 32; \
uint64_t t = (uint64_t)t1l + t1l + c0; \
c0 = t; \
t >>= 32; \
t = t + c1 + t1h + t1h; \
c1 = t; \
c2 += (t >> 32); \
VERIFY_CHECK(c2 >= (t >> 32)); /* c2 must never overflow. */ \
}

/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */
#define sumadd(a) { \
unsigned int over; \
c0 += (a); /* overflow is handled on the next line */ \
over = (c0 < (a)); \
c1 += over; /* overflow is handled on the next line */ \
c2 += (c1 < over); /* never overflows by contract */ \
uint64_t t = (uint64_t)a + c0; \
c0 = t; \
t >>= 32; \
t += c1; \
c1 = t; \
c2 += (t >> 32); \
VERIFY_CHECK(c2 >= (t >> 32)); /* c2 must never overflow. */ \
}

/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */
#define sumadd_fast(a) { \
c0 += (a); /* overflow is handled on the next line */ \
c1 += (c0 < (a)); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \
VERIFY_CHECK(c2 == 0); \
uint64_t t = (uint64_t)a + c0; \
c0 = t; \
c1 += (t >> 32); \
VERIFY_CHECK(c1 >= (t >> 32)); /* c1 must never overflow. */ \
VERIFY_CHECK(c2 == 0); /* c2 must be zero. */ \
}

/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. */
Expand Down