Packages
hackney
3.0.0
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Retired package: Release invalid - Use 3.0.1 instead
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/boringssl/crypto/fipsmodule/ec/simple_mul.cc.inc
// Copyright 2018 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 <openssl/ec.h>
#include <assert.h>
#include <iterator>
#include <type_traits>
#include "internal.h"
#include "../bn/internal.h"
#include "../../internal.h"
void ec_GFp_mont_mul(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_JACOBIAN *p, const EC_SCALAR *scalar) {
// This is a generic implementation for uncommon curves that not do not
// warrant a tuned one. It uses unsigned digits so that the doubling case in
// |ec_GFp_mont_add| is always unreachable, erring on safety and simplicity.
// Compute a table of the first 32 multiples of |p| (including infinity).
EC_JACOBIAN precomp[32];
ec_GFp_simple_point_set_to_infinity(group, &precomp[0]);
ec_GFp_simple_point_copy(&precomp[1], p);
for (size_t j = 2; j < std::size(precomp); j++) {
if (j & 1) {
ec_GFp_mont_add(group, &precomp[j], &precomp[1], &precomp[j - 1]);
} else {
ec_GFp_mont_dbl(group, &precomp[j], &precomp[j / 2]);
}
}
// Divide bits in |scalar| into windows.
unsigned bits = EC_GROUP_order_bits(group);
int r_is_at_infinity = 1;
for (unsigned i = bits - 1; i < bits; i--) {
if (!r_is_at_infinity) {
ec_GFp_mont_dbl(group, r, r);
}
if (i % 5 == 0) {
// Compute the next window value.
const size_t width = group->order.N.width;
uint8_t window = bn_is_bit_set_words(scalar->words, width, i + 4) << 4;
window |= bn_is_bit_set_words(scalar->words, width, i + 3) << 3;
window |= bn_is_bit_set_words(scalar->words, width, i + 2) << 2;
window |= bn_is_bit_set_words(scalar->words, width, i + 1) << 1;
window |= bn_is_bit_set_words(scalar->words, width, i);
// Select the entry in constant-time.
EC_JACOBIAN tmp;
OPENSSL_memset(&tmp, 0, sizeof(EC_JACOBIAN));
for (size_t j = 0; j < std::size(precomp); j++) {
BN_ULONG mask = constant_time_eq_w(j, window);
ec_point_select(group, &tmp, mask, &precomp[j], &tmp);
}
if (r_is_at_infinity) {
ec_GFp_simple_point_copy(r, &tmp);
r_is_at_infinity = 0;
} else {
ec_GFp_mont_add(group, r, r, &tmp);
}
}
}
if (r_is_at_infinity) {
ec_GFp_simple_point_set_to_infinity(group, r);
}
}
void ec_GFp_mont_mul_base(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_SCALAR *scalar) {
ec_GFp_mont_mul(group, r, &group->generator.raw, scalar);
}
static void ec_GFp_mont_batch_precomp(const EC_GROUP *group, EC_JACOBIAN *out,
size_t num, const EC_JACOBIAN *p) {
assert(num > 1);
ec_GFp_simple_point_set_to_infinity(group, &out[0]);
ec_GFp_simple_point_copy(&out[1], p);
for (size_t j = 2; j < num; j++) {
if (j & 1) {
ec_GFp_mont_add(group, &out[j], &out[1], &out[j - 1]);
} else {
ec_GFp_mont_dbl(group, &out[j], &out[j / 2]);
}
}
}
static void ec_GFp_mont_batch_get_window(const EC_GROUP *group,
EC_JACOBIAN *out,
const EC_JACOBIAN precomp[17],
const EC_SCALAR *scalar, unsigned i) {
const size_t width = group->order.N.width;
uint8_t window = bn_is_bit_set_words(scalar->words, width, i + 4) << 5;
window |= bn_is_bit_set_words(scalar->words, width, i + 3) << 4;
window |= bn_is_bit_set_words(scalar->words, width, i + 2) << 3;
window |= bn_is_bit_set_words(scalar->words, width, i + 1) << 2;
window |= bn_is_bit_set_words(scalar->words, width, i) << 1;
if (i > 0) {
window |= bn_is_bit_set_words(scalar->words, width, i - 1);
}
crypto_word_t sign, digit;
ec_GFp_nistp_recode_scalar_bits(&sign, &digit, window);
// Select the entry in constant-time.
OPENSSL_memset(out, 0, sizeof(EC_JACOBIAN));
for (size_t j = 0; j < 17; j++) {
BN_ULONG mask = constant_time_eq_w(j, digit);
ec_point_select(group, out, mask, &precomp[j], out);
}
// Negate if necessary.
EC_FELEM neg_Y;
ec_felem_neg(group, &neg_Y, &out->Y);
crypto_word_t sign_mask = sign;
sign_mask = 0u - sign_mask;
ec_felem_select(group, &out->Y, sign_mask, &neg_Y, &out->Y);
}
void ec_GFp_mont_mul_batch(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_JACOBIAN *p0, const EC_SCALAR *scalar0,
const EC_JACOBIAN *p1, const EC_SCALAR *scalar1,
const EC_JACOBIAN *p2, const EC_SCALAR *scalar2) {
EC_JACOBIAN precomp[3][17];
ec_GFp_mont_batch_precomp(group, precomp[0], 17, p0);
ec_GFp_mont_batch_precomp(group, precomp[1], 17, p1);
if (p2 != nullptr) {
ec_GFp_mont_batch_precomp(group, precomp[2], 17, p2);
}
// Divide bits in |scalar| into windows.
unsigned bits = EC_GROUP_order_bits(group);
int r_is_at_infinity = 1;
for (unsigned i = bits; i <= bits; i--) {
if (!r_is_at_infinity) {
ec_GFp_mont_dbl(group, r, r);
}
if (i % 5 == 0) {
EC_JACOBIAN tmp;
ec_GFp_mont_batch_get_window(group, &tmp, precomp[0], scalar0, i);
if (r_is_at_infinity) {
ec_GFp_simple_point_copy(r, &tmp);
r_is_at_infinity = 0;
} else {
ec_GFp_mont_add(group, r, r, &tmp);
}
ec_GFp_mont_batch_get_window(group, &tmp, precomp[1], scalar1, i);
ec_GFp_mont_add(group, r, r, &tmp);
if (p2 != nullptr) {
ec_GFp_mont_batch_get_window(group, &tmp, precomp[2], scalar2, i);
ec_GFp_mont_add(group, r, r, &tmp);
}
}
}
if (r_is_at_infinity) {
ec_GFp_simple_point_set_to_infinity(group, r);
}
}
static unsigned ec_GFp_mont_comb_stride(const EC_GROUP *group) {
return (EC_GROUP_get_degree(group) + EC_MONT_PRECOMP_COMB_SIZE - 1) /
EC_MONT_PRECOMP_COMB_SIZE;
}
int ec_GFp_mont_init_precomp(const EC_GROUP *group, EC_PRECOMP *out,
const EC_JACOBIAN *p) {
// comb[i - 1] stores the ith element of the comb. That is, if i is
// b4 * 2^4 + b3 * 2^3 + ... + b0 * 2^0, it stores k * |p|, where k is
// b4 * 2^(4*stride) + b3 * 2^(3*stride) + ... + b0 * 2^(0*stride). stride
// here is |ec_GFp_mont_comb_stride|. We store at index i - 1 because the 0th
// comb entry is always infinity.
EC_JACOBIAN comb[(1 << EC_MONT_PRECOMP_COMB_SIZE) - 1];
unsigned stride = ec_GFp_mont_comb_stride(group);
// We compute the comb sequentially by the highest set bit. Initially, all
// entries up to 2^0 are filled.
comb[(1 << 0) - 1] = *p;
for (unsigned i = 1; i < EC_MONT_PRECOMP_COMB_SIZE; i++) {
// Compute entry 2^i by doubling the entry for 2^(i-1) |stride| times.
unsigned bit = 1 << i;
ec_GFp_mont_dbl(group, &comb[bit - 1], &comb[bit / 2 - 1]);
for (unsigned j = 1; j < stride; j++) {
ec_GFp_mont_dbl(group, &comb[bit - 1], &comb[bit - 1]);
}
// Compute entries from 2^i + 1 to 2^i + (2^i - 1) by adding entry 2^i to
// a previous entry.
for (unsigned j = 1; j < bit; j++) {
ec_GFp_mont_add(group, &comb[bit + j - 1], &comb[bit - 1], &comb[j - 1]);
}
}
// Store the comb in affine coordinates to shrink the table. (This reduces
// cache pressure and makes the constant-time selects faster.)
static_assert(
std::extent_v<decltype(comb)> == std::extent_v<decltype(out->comb)>,
"comb sizes did not match");
return ec_jacobian_to_affine_batch(group, out->comb, comb, std::size(comb));
}
static void ec_GFp_mont_get_comb_window(const EC_GROUP *group,
EC_JACOBIAN *out,
const EC_PRECOMP *precomp,
const EC_SCALAR *scalar, unsigned i) {
const size_t width = group->order.N.width;
unsigned stride = ec_GFp_mont_comb_stride(group);
// Select the bits corresponding to the comb shifted up by |i|.
unsigned window = 0;
for (unsigned j = 0; j < EC_MONT_PRECOMP_COMB_SIZE; j++) {
window |= bn_is_bit_set_words(scalar->words, width, j * stride + i)
<< j;
}
// Select precomp->comb[window - 1]. If |window| is zero, |match| will always
// be zero, which will leave |out| at infinity.
OPENSSL_memset(out, 0, sizeof(EC_JACOBIAN));
for (unsigned j = 0; j < std::size(precomp->comb); j++) {
BN_ULONG match = constant_time_eq_w(window, j + 1);
ec_felem_select(group, &out->X, match, &precomp->comb[j].X, &out->X);
ec_felem_select(group, &out->Y, match, &precomp->comb[j].Y, &out->Y);
}
BN_ULONG is_infinity = constant_time_is_zero_w(window);
ec_felem_select(group, &out->Z, is_infinity, &out->Z, ec_felem_one(group));
}
void ec_GFp_mont_mul_precomp(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_PRECOMP *p0, const EC_SCALAR *scalar0,
const EC_PRECOMP *p1, const EC_SCALAR *scalar1,
const EC_PRECOMP *p2, const EC_SCALAR *scalar2) {
unsigned stride = ec_GFp_mont_comb_stride(group);
int r_is_at_infinity = 1;
for (unsigned i = stride - 1; i < stride; i--) {
if (!r_is_at_infinity) {
ec_GFp_mont_dbl(group, r, r);
}
EC_JACOBIAN tmp;
ec_GFp_mont_get_comb_window(group, &tmp, p0, scalar0, i);
if (r_is_at_infinity) {
ec_GFp_simple_point_copy(r, &tmp);
r_is_at_infinity = 0;
} else {
ec_GFp_mont_add(group, r, r, &tmp);
}
if (p1 != nullptr) {
ec_GFp_mont_get_comb_window(group, &tmp, p1, scalar1, i);
ec_GFp_mont_add(group, r, r, &tmp);
}
if (p2 != nullptr) {
ec_GFp_mont_get_comb_window(group, &tmp, p2, scalar2, i);
ec_GFp_mont_add(group, r, r, &tmp);
}
}
if (r_is_at_infinity) {
ec_GFp_simple_point_set_to_infinity(group, r);
}
}