|
| 1 | +/* |
| 2 | + Copyright 2022 The Silkpre Authors |
| 3 | +
|
| 4 | + Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | + you may not use this file except in compliance with the License. |
| 6 | + You may obtain a copy of the License at |
| 7 | +
|
| 8 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | +
|
| 10 | + Unless required by applicable law or agreed to in writing, software |
| 11 | + distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + See the License for the specific language governing permissions and |
| 14 | + limitations under the License. |
| 15 | +*/ |
| 16 | + |
| 17 | +#include "ecdsa.h" |
| 18 | + |
| 19 | +#include <string.h> |
| 20 | + |
| 21 | +#include <ethash/keccak.h> |
| 22 | +#include <secp256k1_recovery.h> |
| 23 | + |
| 24 | +//! \brief Tries recover public key used for message signing. |
| 25 | +//! \return An optional Bytes. Should it has no value the recovery has failed |
| 26 | +//! This is different from recover_address as the whole 64 bytes are returned. |
| 27 | +static bool recover(uint8_t* out, const uint8_t message[32], const uint8_t signature[64], bool odd_y_parity, |
| 28 | + secp256k1_context* context) { |
| 29 | + secp256k1_ecdsa_recoverable_signature sig; |
| 30 | + if (!secp256k1_ecdsa_recoverable_signature_parse_compact(context, &sig, signature, odd_y_parity)) { |
| 31 | + return false; |
| 32 | + } |
| 33 | + |
| 34 | + secp256k1_pubkey pub_key; |
| 35 | + if (!secp256k1_ecdsa_recover(context, &pub_key, &sig, &message[0])) { |
| 36 | + return false; |
| 37 | + } |
| 38 | + |
| 39 | + size_t out_len = 65; |
| 40 | + secp256k1_ec_pubkey_serialize(context, out, &out_len, &pub_key, SECP256K1_EC_UNCOMPRESSED); |
| 41 | + return true; |
| 42 | +} |
| 43 | + |
| 44 | +//! Tries extract address from recovered public key |
| 45 | +//! \param [in] public_key: The recovered public key |
| 46 | +//! \return Whether the recovery has succeeded. |
| 47 | +static bool public_key_to_address(uint8_t* out, const uint8_t public_key[65]) { |
| 48 | + if (public_key[0] != 4u) { |
| 49 | + return false; |
| 50 | + } |
| 51 | + // Ignore first byte of public key |
| 52 | + const union ethash_hash256 key_hash = ethash_keccak256(public_key + 1, 64); |
| 53 | + memcpy(out, &key_hash.bytes[12], 20); |
| 54 | + return true; |
| 55 | +} |
| 56 | + |
| 57 | +bool recover_address(uint8_t* out, const uint8_t message[32], const uint8_t signature[64], bool odd_y_parity, |
| 58 | + secp256k1_context* context) { |
| 59 | + uint8_t public_key[65]; |
| 60 | + bool converted = false; |
| 61 | + if (recover(public_key, message, signature, odd_y_parity, context)) { |
| 62 | + converted = public_key_to_address(out, public_key); |
| 63 | + } |
| 64 | + return converted; |
| 65 | +} |
0 commit comments