Skip to content

Commit 48f8dc1

Browse files
authored
Check hamming weights of AES key shares (#252)
* Add hamming weight checks * Rework to deal with whole shares, not word-wise * Fix logging * Revert "Rework to deal with whole shares, not word-wise" This reverts commit 65245f8. * Switch to checking half-words, and add fixed number of attempts (100,000) before failing * Switch to checking numbers are within middle ranges, rather than checking deltas
1 parent 63cb67f commit 48f8dc1

File tree

1 file changed

+66
-6
lines changed

1 file changed

+66
-6
lines changed

main.cpp

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5189,18 +5189,78 @@ bool encrypt_command::execute(device_map &devices) {
51895189
}
51905190
}
51915191

5192+
int min_weight = 6;
5193+
int max_weight = 10;
5194+
int min_combined_weight = 28;
5195+
int max_combined_weight = 36;
5196+
51925197
if (!keyIsShare) {
5198+
std::vector<int> num_attempts;
51935199
// Generate a random key share from 256-bit key
51945200
std::random_device rand{};
51955201
assert(rand.max() - rand.min() >= 256);
51965202
for(int i=0; i < 8; i++) {
5197-
for (int j=0; j < 12; j++) {
5198-
aes_key_share.bytes[i*16 + j] = rand();
5203+
// Regenerate the share word until the hamming weights are close to each other
5204+
bool pass = false;
5205+
for (int attempt=0; attempt < 100000; attempt++) {
5206+
for (int j=0; j < 12; j++) {
5207+
aes_key_share.bytes[i*16 + j] = rand();
5208+
}
5209+
aes_key_share.words[i*4 + 3] = aes_key.words[i]
5210+
^ aes_key_share.words[i*4]
5211+
^ aes_key_share.words[i*4 + 1]
5212+
^ aes_key_share.words[i*4 + 2];
5213+
5214+
pass = true;
5215+
for (int half=0; half < 2; half++) {
5216+
uint8_t combined_weight = 0;
5217+
for (int j=0; j < 4; j++) {
5218+
uint16_t half_word = aes_key_share.words[i*4 + j] >> half*16;
5219+
uint8_t weight = __builtin_popcount(half_word);
5220+
if (weight < min_weight || weight > max_weight) {
5221+
DEBUG_LOG("Generated share %d word %d half %d has hamming weights out of range %d -> %d - regenerating attempt %d\n", j, i, half, min_weight, max_weight, attempt);
5222+
pass = false;
5223+
break;
5224+
}
5225+
combined_weight += weight;
5226+
}
5227+
if (!pass) break;
5228+
if (combined_weight < min_combined_weight || combined_weight > max_combined_weight) {
5229+
DEBUG_LOG("Generated share word %d half %d has hamming weights out of range %d -> %d - regenerating attempt %d\n", i, half, min_combined_weight, max_combined_weight, attempt);
5230+
pass = false;
5231+
break;
5232+
}
5233+
}
5234+
if (pass) {
5235+
num_attempts.push_back(attempt);
5236+
break;
5237+
}
5238+
}
5239+
if (!pass) {
5240+
fail(ERROR_INCOMPATIBLE, "Failed to generate a share word with hamming weights within %d -> %d", min_weight, max_weight);
5241+
}
5242+
}
5243+
5244+
DEBUG_LOG("Average number of attempts: %d\n", std::accumulate(num_attempts.begin(), num_attempts.end(), 0) / num_attempts.size());
5245+
DEBUG_LOG("Max number of attempts: %d\n", *std::max_element(num_attempts.begin(), num_attempts.end()));
5246+
DEBUG_LOG("Min number of attempts: %d\n", *std::min_element(num_attempts.begin(), num_attempts.end()));
5247+
} else {
5248+
// Check the share word hamming weights are close to each other
5249+
for(int i=0; i < 8; i++) {
5250+
for (int half=0; half < 2; half++) {
5251+
uint8_t combined_weight = 0;
5252+
for (int j=0; j < 4; j++) {
5253+
uint16_t half_word = aes_key_share.words[i*4 + j] >> half*16;
5254+
uint8_t weight = __builtin_popcount(half_word);
5255+
if (weight < min_weight || weight > max_weight) {
5256+
std::cout << "WARNING: Key Share " << j << " Word " << i << " half " << half << " has hamming weights out of range " << min_weight << " -> " << max_weight << " - this may leak information about the key\n";
5257+
}
5258+
combined_weight += weight;
5259+
}
5260+
if (combined_weight < min_combined_weight || combined_weight > max_combined_weight) {
5261+
std::cout << "WARNING: Key Share Word " << i << " half " << half << " has hamming weights out of range " << min_combined_weight << " -> " << max_combined_weight << " - this may leak information about the key\n";
5262+
}
51995263
}
5200-
aes_key_share.words[i*4 + 3] = aes_key.words[i]
5201-
^ aes_key_share.words[i*4]
5202-
^ aes_key_share.words[i*4 + 1]
5203-
^ aes_key_share.words[i*4 + 2];
52045264
}
52055265
}
52065266

0 commit comments

Comments
 (0)