blob: 74c0d217c6cce0575fd15a3dde46695e208db239 [file] [log] [blame] [edit]
// Copyright 2025 The BoringSSL Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <openssl/rand.h>
#include "bedrock_unverified_platform.c.inc"
namespace ref {
#include "bedrock_unverified_bareminimum.c.inc" // currently unused but planned
#include "bedrock_polyfill_platform.c.inc"
}
namespace {
#define SECRET_EQ_W(a, b) EXPECT_EQ(br_declassify(a), br_declassify(b))
TEST(BedrockTest, ArithmeticAndBroadcast) {
std::vector<br_word_t> test_values = {
0,
1,
1024,
12345,
32000,
0xffffffff / 2 - 1,
0xffffffff / 2,
0xffffffff / 2 + 1,
0xffffffff - 1,
0xffffffff,
std::numeric_limits<br_word_t>::max() / 2 - 1,
std::numeric_limits<br_word_t>::max() / 2,
std::numeric_limits<br_word_t>::max() / 2 + 1,
std::numeric_limits<br_word_t>::max() - 1,
std::numeric_limits<br_word_t>::max(),
};
for (int i = 0; i < 100; i++) {
br_word_t word;
RAND_bytes(reinterpret_cast<uint8_t *>(&word), sizeof(word));
test_values.push_back(word);
}
auto broadcast = [](bool b) { return b ? 0u-(br_word_t)1 : (br_word_t)0; };
for (br_word_t a : test_values) {
SCOPED_TRACE(a);
EXPECT_EQ(a, br_value_barrier(a));
EXPECT_EQ(a, ref::br_value_barrier(a));
EXPECT_EQ(a, br_declassify(a));
EXPECT_EQ(a, ref::br_declassify(a));
EXPECT_EQ(broadcast(a != 0), br_broadcast_nonzero(a));
EXPECT_EQ(broadcast(a != 0), ref::br_broadcast_nonzero(a));
EXPECT_EQ(broadcast((br_signed_t)a < 0), br_broadcast_negative(a));
EXPECT_EQ(broadcast((br_signed_t)a < 0), ref::br_broadcast_negative(a));
CONSTTIME_SECRET(&a, sizeof(a));
br_word_t t = broadcast(true);
SECRET_EQ_W(br_broadcast_negative(a) | br_broadcast_negative(~a), t);
SECRET_EQ_W(br_broadcast_nonzero(a) | br_broadcast_nonzero(~a), t);
for (br_word_t b : test_values) {
SCOPED_TRACE(b);
CONSTTIME_SECRET(&b, sizeof(b));
SECRET_EQ_W(a, br_cmov(broadcast(true), a, b));
SECRET_EQ_W(b, br_cmov(broadcast(false), a, b));
br_word_t lo = 0, lr = 0;
SECRET_EQ_W(br_full_mul(a, b, &lo), ref::br_full_mul(a, b, &lr));
SECRET_EQ_W(lo, lr);
SECRET_EQ_W(lo, a * b);
for (br_word_t c : {0, 1}) {
SCOPED_TRACE(c);
CONSTTIME_SECRET(&c, sizeof(c));
SECRET_EQ_W(br_declassify(a) ? b : c, br_cmov(a, b, c));
SECRET_EQ_W(br_declassify(a) ? c : b, br_cmov(a, c, b));
SECRET_EQ_W(br_full_add(a, b, c, &lo), ref::br_full_add(a, b, c, &lr));
SECRET_EQ_W(lo, lr);
SECRET_EQ_W(lo, a + b + c);
SECRET_EQ_W(br_full_sub(a, b, c, &lo), ref::br_full_sub(a, b, c, &lr));
SECRET_EQ_W(lo, lr);
SECRET_EQ_W(lo, a - b - c);
}
}
}
}
#undef SECRET_EQ_W
} // namespace