-
Notifications
You must be signed in to change notification settings - Fork 896
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
df7d7cf
commit 8d42cbd
Showing
9 changed files
with
590 additions
and
0 deletions.
There are no files selected for viewing
61 changes: 61 additions & 0 deletions
61
chromium_src/third_party/boringssl/src/crypto/curve25519/curve25519.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* Copyright (c) 2024 The Brave Authors. All rights reserved. | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* You can obtain one at https://mozilla.org/MPL/2.0/. */ | ||
|
||
#include "third_party/boringssl/src/include/openssl/curve25519.h" | ||
|
||
#include "src/third_party/boringssl/src/crypto/curve25519/curve25519.c" | ||
|
||
#ifdef UNSAFE_BUFFERS_BUILD | ||
#pragma allow_unsafe_buffers | ||
#endif | ||
|
||
// Produces pubkey form scalar. | ||
// `scalar` must be pruned. https://www.rfc-editor.org/rfc/rfc8032.html#section-5.1.5 | ||
// See `ED25519_keypair_from_seed` as origin. | ||
void ED25519_pubkey_from_scalar(uint8_t out_public_key[32], | ||
const uint8_t scalar[32]) { | ||
ge_p3 A; | ||
|
||
x25519_ge_scalarmult_base(&A, scalar); | ||
ge_p3_tobytes(out_public_key, &A); | ||
|
||
CONSTTIME_DECLASSIFY(out_public_key, 32); | ||
} | ||
|
||
// Same as `ED25519_sign` but without hashing private key. `scalar` and `prefix` | ||
// come from ED25519_BIP32 algorithm. | ||
// `scalar` must be pruned. https://www.rfc-editor.org/rfc/rfc8032.html#section-5.1.5 | ||
int ED25519_sign_with_scalar_and_prefix(uint8_t out_sig[64], | ||
const uint8_t* message, | ||
size_t message_len, | ||
const uint8_t scalar[32], | ||
const uint8_t prefix[32], | ||
const uint8_t public_key[32]) { | ||
SHA512_CTX hash_ctx; | ||
SHA512_Init(&hash_ctx); | ||
SHA512_Update(&hash_ctx, prefix, 32); | ||
SHA512_Update(&hash_ctx, message, message_len); | ||
uint8_t nonce[SHA512_DIGEST_LENGTH]; | ||
SHA512_Final(nonce, &hash_ctx); | ||
|
||
x25519_sc_reduce(nonce); | ||
ge_p3 R; | ||
x25519_ge_scalarmult_base(&R, nonce); | ||
ge_p3_tobytes(out_sig, &R); | ||
|
||
SHA512_Init(&hash_ctx); | ||
SHA512_Update(&hash_ctx, out_sig, 32); | ||
SHA512_Update(&hash_ctx, public_key, 32); | ||
SHA512_Update(&hash_ctx, message, message_len); | ||
uint8_t hram[SHA512_DIGEST_LENGTH]; | ||
SHA512_Final(hram, &hash_ctx); | ||
|
||
x25519_sc_reduce(hram); | ||
sc_muladd(out_sig + 32, hram, scalar, nonce); | ||
|
||
// The signature is computed from the private key, but is public. | ||
CONSTTIME_DECLASSIFY(out_sig, 64); | ||
return 1; | ||
} |
24 changes: 24 additions & 0 deletions
24
chromium_src/third_party/boringssl/src/include/openssl/curve25519.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* Copyright (c) 2024 The Brave Authors. All rights reserved. | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* You can obtain one at https://mozilla.org/MPL/2.0/. */ | ||
|
||
#include "src/third_party/boringssl/src/include/openssl/curve25519.h" // IWYU pragma: export | ||
|
||
#if defined(__cplusplus) | ||
extern "C" { | ||
#endif | ||
|
||
OPENSSL_EXPORT void ED25519_pubkey_from_scalar(uint8_t out_public_key[32], | ||
const uint8_t scalar[32]); | ||
OPENSSL_EXPORT int ED25519_sign_with_scalar_and_prefix( | ||
uint8_t out_sig[64], | ||
const uint8_t* message, | ||
size_t message_len, | ||
const uint8_t scalar[32], | ||
const uint8_t prefix[32], | ||
const uint8_t public_key[32]); | ||
|
||
#if defined(__cplusplus) | ||
} // extern C | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
235 changes: 235 additions & 0 deletions
235
components/brave_wallet/browser/internal/hd_key_ed25519_slip23.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
/* Copyright (c) 2024 The Brave Authors. All rights reserved. | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* You can obtain one at https://mozilla.org/MPL/2.0/. */ | ||
|
||
#include "brave/components/brave_wallet/browser/internal/hd_key_ed25519_slip23.h" | ||
|
||
#include <array> | ||
#include <utility> | ||
#include <vector> | ||
|
||
#include "base/check.h" | ||
#include "base/containers/span.h" | ||
#include "base/containers/span_writer.h" | ||
#include "base/memory/ptr_util.h" | ||
#include "base/strings/string_number_conversions.h" | ||
#include "brave/components/brave_wallet/common/hash_utils.h" | ||
#include "crypto/hmac.h" | ||
#include "third_party/boringssl/src/include/openssl/curve25519.h" | ||
#include "third_party/boringssl/src/include/openssl/evp.h" | ||
|
||
namespace brave_wallet { | ||
namespace { | ||
|
||
struct DerivedHmacs { | ||
std::array<uint8_t, crypto::hash::kSha512Size> z_hmac = {}; | ||
std::array<uint8_t, crypto::hash::kSha512Size> cc_hmac = {}; | ||
}; | ||
|
||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-eddsa-05#section-5.1.5 | ||
// requires scalar to follow this requirements 'The lowest 3 bits of the first | ||
// octet are cleared, the highest bit of the last octet is cleared, and the | ||
// second highest bit of the last octet is set'. | ||
// https://input-output-hk.github.io/adrestia/static/Ed25519_BIP.pdf expands | ||
// this requirement to `We admit only those k such that the third highest bit | ||
// of the last byte of k is zero` | ||
base::span<uint8_t, kSlip23ScalarSize> ClampScalarEd25519Bip32( | ||
base::span<uint8_t, kSlip23ScalarSize> scalar) { | ||
scalar[0] &= 0b1111'1000; // The lowest 3 bits of the first | ||
// octet are cleared | ||
|
||
scalar[31] &= 0b0111'1111; // highest bit of the last octet is cleared and | ||
scalar[31] &= 0b1101'1111; // third highest bit of the last byte of k is zero | ||
|
||
scalar[31] |= 0b0100'0000; // the second highest bit of the last octet is set | ||
return scalar; | ||
} | ||
|
||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-eddsa-05#section-5.1.5 | ||
// requires scalar to follow this requirements 'The lowest 3 bits of the first | ||
// octet are cleared, the highest bit of the last octet is cleared, and the | ||
// second highest bit of the last octet is set'. | ||
bool IsValidEd25519Scalar(base::span<const uint8_t, kSlip23ScalarSize> scalar) { | ||
return (scalar[0] & 0b0000'0111) == 0b0000'0000 && | ||
(scalar[31] & 0b1100'0000) == 0b0100'0000; | ||
} | ||
|
||
std::array<uint8_t, 32> PubkeyFromScalar(base::span<const uint8_t, 32> scalar) { | ||
DCHECK(IsValidEd25519Scalar(scalar)); | ||
std::array<uint8_t, 32> public_key; | ||
ED25519_pubkey_from_scalar(public_key.data(), scalar.data()); | ||
return public_key; | ||
} | ||
|
||
DerivedHmacs DeriveHardenedHmacs( | ||
uint32_t index, | ||
base::span<const uint8_t, kSlip23ScalarSize> scalar, | ||
base::span<const uint8_t, kSlip23PrefixSize> prefix, | ||
base::span<const uint8_t> cc) { | ||
std::array<uint8_t, 1 + 32 + 32 + 4> data; | ||
auto span_writer = base::SpanWriter(base::span(data)); | ||
span_writer.Skip(1u); | ||
span_writer.Write(scalar); | ||
span_writer.Write(prefix); | ||
span_writer.WriteU32LittleEndian(index); | ||
|
||
DerivedHmacs result; | ||
|
||
data[0] = 0x00; | ||
result.z_hmac = crypto::hmac::SignSha512(cc, data); | ||
|
||
data[0] = 0x01; | ||
result.cc_hmac = crypto::hmac::SignSha512(cc, data); | ||
|
||
return result; | ||
} | ||
|
||
DerivedHmacs DeriveNormalHmacs( | ||
uint32_t index, | ||
base::span<const uint8_t, kSlip23ScalarSize> scalar, | ||
base::span<const uint8_t, kEd25519PublicKeySize> public_key, | ||
base::span<const uint8_t> cc) { | ||
std::array<uint8_t, 1 + 32 + 4> data; | ||
auto span_writer = base::SpanWriter(base::span(data)); | ||
span_writer.Skip(1u); | ||
span_writer.Write(public_key); | ||
span_writer.WriteU32LittleEndian(index); | ||
|
||
DerivedHmacs result; | ||
|
||
data[0] = 0x02; | ||
result.z_hmac = crypto::hmac::SignSha512(cc, data); | ||
|
||
data[0] = 0x03; | ||
result.cc_hmac = crypto::hmac::SignSha512(cc, data); | ||
|
||
return result; | ||
} | ||
|
||
std::array<uint8_t, kSlip23ScalarSize> CalculateDerivedScalar( | ||
base::span<const uint8_t, kSlip23ScalarSize> parent_scalar, | ||
base::span<const uint8_t, kSlip23DerivationScalarSize> zl) { | ||
std::array<uint8_t, kSlip23ScalarSize> out = {}; | ||
|
||
uint8_t carry = 0; | ||
for (auto i = 0u; i < kSlip23DerivationScalarSize; i++) { | ||
uint32_t r = parent_scalar[i] + (zl[i] << 3) + carry; | ||
out[i] = r & 0xff; | ||
carry = r >> 8; | ||
} | ||
for (auto i = kSlip23DerivationScalarSize; i < kSlip23ScalarSize; i++) { | ||
uint32_t r = parent_scalar[i] + carry; | ||
out[i] = r & 0xff; | ||
carry = r >> 8; | ||
} | ||
return out; | ||
} | ||
|
||
std::array<uint8_t, kSlip23PrefixSize> CalculateDerivedPrefix( | ||
base::span<const uint8_t, kSlip23PrefixSize> parent_prefix, | ||
base::span<const uint8_t, kSlip23PrefixSize> zr) { | ||
std::array<uint8_t, kSlip23PrefixSize> out = {}; | ||
|
||
uint8_t carry = 0; | ||
for (auto i = 0u; i < kSlip23PrefixSize; i++) { | ||
uint32_t r = parent_prefix[i] + zr[i] + carry; | ||
out[i] = r; | ||
carry = r >> 8; | ||
} | ||
|
||
return out; | ||
} | ||
|
||
std::array<uint8_t, kSlip23ChainCodeSize> CalculateDerivedChainCode( | ||
base::span<const uint8_t, crypto::hash::kSha512Size> z_hmac) { | ||
std::array<uint8_t, kSlip23ChainCodeSize> chain_code; | ||
base::span(chain_code) | ||
.copy_from(base::span(z_hmac).last<kSlip23ChainCodeSize>()); | ||
return chain_code; | ||
} | ||
|
||
} // namespace | ||
|
||
HDKeyEd25519Slip23::HDKeyEd25519Slip23() = default; | ||
HDKeyEd25519Slip23::~HDKeyEd25519Slip23() = default; | ||
|
||
// Child key derivation constructor. | ||
HDKeyEd25519Slip23::HDKeyEd25519Slip23( | ||
base::span<const uint8_t, kSlip23ScalarSize> scalar, | ||
base::span<const uint8_t, kSlip23PrefixSize> prefix, | ||
base::span<const uint8_t, kSlip23ChainCodeSize> chain_code) { | ||
base::span(scalar_).copy_from(scalar); | ||
base::span(prefix_).copy_from(prefix); | ||
base::span(chain_code_).copy_from(chain_code); | ||
public_key_ = PubkeyFromScalar(scalar_); | ||
} | ||
|
||
std::unique_ptr<HDKeyEd25519Slip23> HDKeyEd25519Slip23::DeriveChild( | ||
DerivationIndex index) { | ||
auto raw_index_value = index.GetValue(); | ||
if (!raw_index_value) { | ||
return nullptr; | ||
} | ||
|
||
auto derived = | ||
index.is_hardened() | ||
? DeriveHardenedHmacs(*raw_index_value, scalar_, prefix_, chain_code_) | ||
: DeriveNormalHmacs(*raw_index_value, scalar_, public_key_, | ||
chain_code_); | ||
|
||
return base::WrapUnique(new HDKeyEd25519Slip23( | ||
CalculateDerivedScalar( | ||
scalar_, | ||
base::span(derived.z_hmac).first<kSlip23DerivationScalarSize>()), | ||
CalculateDerivedPrefix( | ||
prefix_, base::span(derived.z_hmac).last<kSlip23PrefixSize>()), | ||
CalculateDerivedChainCode(derived.cc_hmac))); | ||
} | ||
|
||
// static | ||
std::unique_ptr<HDKeyEd25519Slip23> | ||
HDKeyEd25519Slip23::GenerateMasterKeyFromBip39Entropy( | ||
base::span<const uint8_t> entropy) { | ||
// https://github.com/cardano-foundation/CIPs/blob/master/CIP-0003/Icarus.md | ||
std::array<uint8_t, | ||
kSlip23ScalarSize + kSlip23PrefixSize + kSlip23ChainCodeSize> | ||
xprv; | ||
std::string passphrase; | ||
if (PKCS5_PBKDF2_HMAC(passphrase.data(), passphrase.size(), entropy.data(), | ||
entropy.size(), 4096, EVP_sha512(), xprv.size(), | ||
xprv.data())) { | ||
} else { | ||
return nullptr; | ||
} | ||
|
||
auto xprv_span = base::span(xprv); | ||
|
||
return base::WrapUnique(new HDKeyEd25519Slip23( | ||
ClampScalarEd25519Bip32(xprv_span.first<kSlip23ScalarSize>()), | ||
xprv_span.subspan<kSlip23ScalarSize, kSlip23PrefixSize>(), | ||
xprv_span.last<kSlip23ChainCodeSize>())); | ||
} | ||
|
||
std::optional<std::array<uint8_t, kEd25519SignatureSize>> | ||
HDKeyEd25519Slip23::Sign(base::span<const uint8_t> msg) { | ||
if (!IsValidEd25519Scalar(scalar_)) { | ||
return std::nullopt; | ||
} | ||
|
||
std::array<uint8_t, kEd25519SignatureSize> signature = {}; | ||
|
||
if (!ED25519_sign_with_scalar_and_prefix( | ||
signature.data(), msg.data(), msg.size(), scalar_.data(), | ||
prefix_.data(), public_key_.data())) { | ||
return std::nullopt; | ||
} | ||
return signature; | ||
} | ||
|
||
base::span<const uint8_t, kEd25519PublicKeySize> | ||
HDKeyEd25519Slip23::GetPublicKeyAsSpan() const { | ||
return base::span(public_key_); | ||
} | ||
|
||
} // namespace brave_wallet |
Oops, something went wrong.