Added constant time methods to FieldElem class.

This commit is contained in:
Eric Lombrozo 2013-03-19 10:21:46 -07:00
parent b358450114
commit 8803181c61
2 changed files with 65 additions and 4 deletions

View file

@ -33,8 +33,11 @@ FieldElem::FieldElem(const unsigned char *b32) {
} }
void FieldElem::Normalize() { void FieldElem::Normalize() {
#ifdef CONSTANT_TIME
NormalizeCT();
return;
#else
uint64_t c; uint64_t c;
#ifndef CONSTANT_TIME
if (n[0] > 0xFFFFFFFFFFFFFULL || n[1] > 0xFFFFFFFFFFFFFULL || n[2] > 0xFFFFFFFFFFFFFULL || n[3] > 0xFFFFFFFFFFFFFULL || n[4] > 0xFFFFFFFFFFFFULL) { if (n[0] > 0xFFFFFFFFFFFFFULL || n[1] > 0xFFFFFFFFFFFFFULL || n[2] > 0xFFFFFFFFFFFFFULL || n[3] > 0xFFFFFFFFFFFFFULL || n[4] > 0xFFFFFFFFFFFFULL) {
c = n[0]; c = n[0];
uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; uint64_t t0 = c & 0xFFFFFFFFFFFFFULL;
@ -69,7 +72,14 @@ void FieldElem::Normalize() {
n[1] = 0; n[1] = 0;
n[0] -= 0xFFFFEFFFFFC2FULL; n[0] -= 0xFFFFEFFFFFC2FULL;
} }
#else #ifdef VERIFY_MAGNITUDE
magnitude = 1;
#endif
#endif
}
void FieldElem::NormalizeCT() {
uint64_t c;
c = n[0]; c = n[0];
uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; uint64_t t0 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + n[1]; c = (c >> 52) + n[1];
@ -106,8 +116,7 @@ void FieldElem::Normalize() {
n[2] &= mask; n[2] &= mask;
n[1] &= mask; n[1] &= mask;
n[0] -= (~mask & 0xFFFFEFFFFFC2FULL); n[0] -= (~mask & 0xFFFFEFFFFFC2FULL);
#endif
#ifdef VERIFY_MAGNITUDE #ifdef VERIFY_MAGNITUDE
magnitude = 1; magnitude = 1;
#endif #endif
@ -118,12 +127,23 @@ bool inline FieldElem::IsZero() {
return (n[0] == 0 && n[1] == 0 && n[2] == 0 && n[3] == 0 && n[4] == 0); return (n[0] == 0 && n[1] == 0 && n[2] == 0 && n[3] == 0 && n[4] == 0);
} }
bool inline FieldElem::IsZeroCT() {
NormalizeCT();
return (n[0] == 0 && n[1] == 0 && n[2] == 0 && n[3] == 0 && n[4] == 0);
}
bool inline operator==(FieldElem &a, FieldElem &b) { bool inline operator==(FieldElem &a, FieldElem &b) {
a.Normalize(); a.Normalize();
b.Normalize(); b.Normalize();
return (a.n[0] == b.n[0] && a.n[1] == b.n[1] && a.n[2] == b.n[2] && a.n[3] == b.n[3] && a.n[4] == b.n[4]); return (a.n[0] == b.n[0] && a.n[1] == b.n[1] && a.n[2] == b.n[2] && a.n[3] == b.n[3] && a.n[4] == b.n[4]);
} }
bool inline EqualCT(FieldElem &a, FieldElem &b) {
a.NormalizeCT();
b.NormalizeCT();
return (a.n[0] == b.n[0] && a.n[1] == b.n[1] && a.n[2] == b.n[2] && a.n[3] == b.n[3] && a.n[4] == b.n[4]);
}
void FieldElem::GetBytes(unsigned char *o) { void FieldElem::GetBytes(unsigned char *o) {
Normalize(); Normalize();
for (int i=0; i<32; i++) { for (int i=0; i<32; i++) {
@ -137,6 +157,19 @@ void FieldElem::GetBytes(unsigned char *o) {
} }
} }
void FieldElem::GetBytesCT(unsigned char *o) {
NormalizeCT();
for (int i=0; i<32; i++) {
int c = 0;
for (int j=0; j<2; j++) {
int limb = (8*i+4*j)/52;
int shift = (8*i+4*j)%52;
c |= ((n[limb] >> shift) & 0xF) << (4 * j);
}
o[31-i] = c;
}
}
void FieldElem::SetBytes(const unsigned char *in) { void FieldElem::SetBytes(const unsigned char *in) {
n[0] = n[1] = n[2] = n[3] = n[4] = 0; n[0] = n[1] = n[2] = n[3] = n[4] = 0;
for (int i=0; i<32; i++) { for (int i=0; i<32; i++) {
@ -329,6 +362,11 @@ bool FieldElem::IsOdd() {
return n[0] & 1; return n[0] & 1;
} }
bool FieldElem::IsOddCT() {
NormalizeCT();
return n[0] & 1;
}
std::string FieldElem::ToString() { std::string FieldElem::ToString() {
unsigned char tmp[32]; unsigned char tmp[32];
GetBytes(tmp); GetBytes(tmp);
@ -341,6 +379,18 @@ std::string FieldElem::ToString() {
return ret; return ret;
} }
std::string FieldElem::ToStringCT() {
unsigned char tmp[32];
GetBytesCT(tmp);
std::string ret;
for (int i=0; i<32; i++) {
static const char *c = "0123456789ABCDEF";
ret += c[(tmp[i] >> 4) & 0xF];
ret += c[(tmp[i]) & 0xF];
}
return ret;
}
void FieldElem::SetHex(const std::string &str) { void FieldElem::SetHex(const std::string &str) {
unsigned char tmp[32] = {}; unsigned char tmp[32] = {};
static const int cvt[256] = {0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, static const int cvt[256] = {0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
@ -378,6 +428,7 @@ const FieldConstants &GetFieldConst() {
return field_const; return field_const;
} }
// Nonbuiltin Field Inverse is not constant time.
void FieldElem::SetInverse(FieldElem &a) { void FieldElem::SetInverse(FieldElem &a) {
#if defined(USE_FIELDINVERSE_BUILTIN) #if defined(USE_FIELDINVERSE_BUILTIN)
// calculate a^p, with p={45,63,1019,1023} // calculate a^p, with p={45,63,1019,1023}

10
field.h
View file

@ -18,6 +18,10 @@ namespace secp256k1 {
* is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations * is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations
* accept any input with magnitude at most M, and have different rules for propagating magnitude to their * accept any input with magnitude at most M, and have different rules for propagating magnitude to their
* output. * output.
*
* There are two implementations of the Normalize method, NormalizeCT executing in constant time.
* Similarly, a second version of all the other methods that call Normalize have been added which
* NormalizeCT instead to prevent sidechannel leaks.
*/ */
class FieldElem { class FieldElem {
private: private:
@ -36,13 +40,17 @@ public:
/** Normalizes the internal representation entries. Magnitude=1 */ /** Normalizes the internal representation entries. Magnitude=1 */
void Normalize(); void Normalize();
void NormalizeCT();
bool IsZero(); bool IsZero();
bool IsZeroCT();
bool friend operator==(FieldElem &a, FieldElem &b); bool friend operator==(FieldElem &a, FieldElem &b);
bool friend EqualCT(FieldElem &a, FieldElem &b);
/** extract as 32-byte big endian array */ /** extract as 32-byte big endian array */
void GetBytes(unsigned char *o); void GetBytes(unsigned char *o);
void GetBytesCT(unsigned char *o);
/** set value of 32-byte big endian array */ /** set value of 32-byte big endian array */
void SetBytes(const unsigned char *in); void SetBytes(const unsigned char *in);
@ -65,11 +73,13 @@ public:
void SetSquareRoot(const FieldElem &a); void SetSquareRoot(const FieldElem &a);
bool IsOdd(); bool IsOdd();
bool IsOddCT();
/** Set this to be the (modular) inverse of another FieldElem. Magnitude=1 */ /** Set this to be the (modular) inverse of another FieldElem. Magnitude=1 */
void SetInverse(FieldElem &a); void SetInverse(FieldElem &a);
std::string ToString(); std::string ToString();
std::string ToStringCT();
void SetHex(const std::string &str); void SetHex(const std::string &str);
}; };