Skip to content
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
30 changes: 30 additions & 0 deletions build/BUILD.libsecp256k1
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
load("@rules_cc//cc:cc_library.bzl", "cc_library")

cc_library(
name = "secp256k1",
srcs = [
"src/precomputed_ecmult.c",
"src/precomputed_ecmult_gen.c",
"src/secp256k1.c",
],
hdrs = [
"include/secp256k1.h",
"include/secp256k1_preallocated.h",
],
copts = [
"-Wno-unused-function",
"-Wno-nonnull",
],
local_defines = [
"SECP256K1_STATIC",
# 5x52 / 4x64 / __int128 require a 64-bit target, which workerd always builds for.
"USE_FIELD_5X52=1",
"USE_SCALAR_4X64=1",
"USE_FORCE_WIDEMUL_INT128=1",
"ECMULT_WINDOW_SIZE=15",
"ECMULT_GEN_PREC_BITS=4",
],
strip_include_prefix = "include",
textual_hdrs = glob(["src/**/*.h"]),
visibility = ["//visibility:public"],
)
8 changes: 8 additions & 0 deletions build/deps/deps.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@
"build_file": "//:build/BUILD.simdutf",
"file_regex": "singleheader.zip"
},
{
"name": "libsecp256k1",
"type": "github_tarball",
"owner": "bitcoin-core",
"repo": "secp256k1",
"branch": "master",
"build_file": "//:build/BUILD.libsecp256k1"
},
// In theory this should match the version specified in V8 DEPS, but in practice we should get
// the latest commit – zlib is very stable and its API has not changed in a long time, but we
// want to pick up any bug fixes, security patches and performance improvements more quickly
Expand Down
11 changes: 11 additions & 0 deletions build/deps/gen/deps.MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ archive_override(
url = "https://github.com/google/highway/tarball/84379d1c73de9681b54fbe1c035a23c7bd5d272d",
)

# libsecp256k1
http.archive(
name = "libsecp256k1",
build_file = "//:build/BUILD.libsecp256k1",
sha256 = "8ab7b72826f8c843e3ce25ca0d33f76cf1f96a4418ebd0168a33a2281d23c5de",
strip_prefix = "bitcoin-core-secp256k1-ea174fe",
type = "tgz",
url = "https://github.com/bitcoin-core/secp256k1/tarball/ea174fe045e1832548cd3b7090958afe9573ad2b",
)
use_repo(http, "libsecp256k1")

# nbytes
http.archive(
name = "nbytes",
Expand Down
38 changes: 33 additions & 5 deletions src/workerd/api/crypto/ec.c++
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "impl.h"
#include "keys.h"
#include "secp256k1-key.h"

#include <workerd/api/util.h>
#include <workerd/io/features.h>
Expand Down Expand Up @@ -429,8 +430,8 @@ class EllipticKey final: public AsymmetricKeyCryptoKeyImpl {

struct EllipticCurveInfo {
kj::StringPtr normalizedName;
int opensslCurveId;
uint rsSize; // size of "r" and "s" in the signature
int opensslCurveId; // 0 for curves BoringSSL doesn't support (e.g. secp256k1).
uint rsSize; // Size of "r" and "s" in the signature.
};

EllipticCurveInfo lookupEllipticCurve(kj::StringPtr curveName) {
Expand All @@ -446,6 +447,15 @@ EllipticCurveInfo lookupEllipticCurve(kj::StringPtr curveName) {
return iter->second;
}

// Overload that adds secp256k1 to the table when the compat flag is set.
EllipticCurveInfo lookupEllipticCurve(jsg::Lock& js, kj::StringPtr curveName) {
if (FeatureFlags::get(js).getSecp256k1EcdsaCurve() &&
strcasecmp(curveName.cStr(), "secp256k1") == 0) {
return {"secp256k1", 0, 32};
}
return lookupEllipticCurve(curveName);
}

kj::OneOf<jsg::Ref<CryptoKey>, CryptoKeyPair> EllipticKey::generateElliptic(jsg::Lock& js,
kj::StringPtr normalizedName,
SubtleCrypto::GenerateKeyAlgorithm&& algorithm,
Expand All @@ -455,7 +465,16 @@ kj::OneOf<jsg::Ref<CryptoKey>, CryptoKeyPair> EllipticKey::generateElliptic(jsg:
kj::StringPtr namedCurve = JSG_REQUIRE_NONNULL(
algorithm.namedCurve, TypeError, "Missing field \"namedCurve\" in \"algorithm\".");

auto [normalizedNamedCurve, curveId, rsSize] = lookupEllipticCurve(namedCurve);
auto [normalizedNamedCurve, curveId, rsSize] = lookupEllipticCurve(js, namedCurve);

// The compat flag scopes secp256k1 support to ECDSA; ECDH is rejected.
if (strcasecmp(normalizedNamedCurve.cStr(), "secp256k1") == 0) {
JSG_REQUIRE(normalizedName == "ECDSA", DOMNotSupportedError, "\"", normalizedName,
"\" is not supported for curve \"secp256k1\".");
return Secp256k1Key::generatePair(js,
CryptoKey::EllipticKeyAlgorithm{normalizedName, normalizedNamedCurve}, extractable,
privateKeyUsages, publicKeyUsages);
}

auto keyAlgorithm = CryptoKey::EllipticKeyAlgorithm{
normalizedName,
Expand Down Expand Up @@ -700,7 +719,13 @@ kj::Own<CryptoKey::Impl> CryptoKey::Impl::importEcdsa(jsg::Lock& js,
kj::StringPtr namedCurve = JSG_REQUIRE_NONNULL(
algorithm.namedCurve, TypeError, "Missing field \"namedCurve\" in \"algorithm\".");

auto [normalizedNamedCurve, curveId, rsSize] = lookupEllipticCurve(namedCurve);
auto [normalizedNamedCurve, curveId, rsSize] = lookupEllipticCurve(js, namedCurve);

if (strcasecmp(normalizedNamedCurve.cStr(), "secp256k1") == 0) {
return Secp256k1Key::import(js, normalizedName, format, kj::mv(keyData),
CryptoKey::EllipticKeyAlgorithm{normalizedName, normalizedNamedCurve}, extractable,
keyUsages);
}

auto importedKey = [&, curveId = curveId] {
if (format != "raw") {
Expand Down Expand Up @@ -758,7 +783,10 @@ kj::Own<CryptoKey::Impl> CryptoKey::Impl::importEcdh(jsg::Lock& js,
kj::StringPtr namedCurve = JSG_REQUIRE_NONNULL(
algorithm.namedCurve, TypeError, "Missing field \"namedCurve\" in \"algorithm\".");

auto [normalizedNamedCurve, curveId, rsSize] = lookupEllipticCurve(namedCurve);
auto [normalizedNamedCurve, curveId, rsSize] = lookupEllipticCurve(js, namedCurve);

JSG_REQUIRE(strcasecmp(normalizedNamedCurve.cStr(), "secp256k1") != 0, DOMNotSupportedError,
"ECDH is not supported for curve \"secp256k1\".");

auto importedKey = [&, curveId = curveId] {
auto strictCrypto = FeatureFlags::get(js).getStrictCrypto();
Expand Down
Loading
Loading