secp256k1 - [mainnet]
This module implements ECDSA signatures based on the prime-order secp256k1 ellptic curve (i.e., cofactor is 1).
use 0x1::error;use 0x1::option;
Constants
The size of a secp256k1-based ECDSA signature, in bytes.
const SIGNATURE_NUM_BYTES: u64 = 64;
An error occurred while deserializing, for example due to wrong input size.
const E_DESERIALIZE: u64 = 1;
The size of a secp256k1-based ECDSA public key, in bytes.
const RAW_PUBLIC_KEY_NUM_BYTES: u64 = 64;
Recovery ID needs to be either 0, 1, 2 or 3. If you are recovering from an (r, s, v) Ethereum signature, take its v value and, set the recovery_id as follows: if v == 27, set to 0, if v == 28, set to 1, if v == 37, set to 0, if v == 38, set to 1.
const E_BAD_RECOVERY_ID: u64 = 2;
Structs
ECDSARawPublicKey
A 64-byte ECDSA public key.
struct ECDSARawPublicKey has copy, drop, store
Fields
-
bytes: vector<u8>
ECDSASignature
A 64-byte ECDSA signature.
struct ECDSASignature has copy, drop, store
Fields
-
bytes: vector<u8>
Functions
ecdsa_signature_from_bytes
Constructs an ECDSASignature struct from the given 64 bytes.
public fun ecdsa_signature_from_bytes(bytes: vector<u8>): secp256k1::ECDSASignature
Implementation
public fun ecdsa_signature_from_bytes(bytes: vector<u8>): ECDSASignature { assert!(bytes.length() == SIGNATURE_NUM_BYTES, std::error::invalid_argument(E_DESERIALIZE)); ECDSASignature { bytes }}
ecdsa_raw_public_key_from_64_bytes
Constructs an ECDSARawPublicKey struct, given a 64-byte raw representation.
public fun ecdsa_raw_public_key_from_64_bytes(bytes: vector<u8>): secp256k1::ECDSARawPublicKey
Implementation
public fun ecdsa_raw_public_key_from_64_bytes(bytes: vector<u8>): ECDSARawPublicKey { assert!(bytes.length() == RAW_PUBLIC_KEY_NUM_BYTES, std::error::invalid_argument(E_DESERIALIZE)); ECDSARawPublicKey { bytes }}
ecdsa_raw_public_key_to_bytes
Serializes an ECDSARawPublicKey struct to 64-bytes.
public fun ecdsa_raw_public_key_to_bytes(pk: &secp256k1::ECDSARawPublicKey): vector<u8>
Implementation
public fun ecdsa_raw_public_key_to_bytes(pk: &ECDSARawPublicKey): vector<u8> { pk.bytes}
ecdsa_signature_to_bytes
Serializes an ECDSASignature struct to 64-bytes.
public fun ecdsa_signature_to_bytes(sig: &secp256k1::ECDSASignature): vector<u8>
Implementation
public fun ecdsa_signature_to_bytes(sig: &ECDSASignature): vector<u8> { sig.bytes}
ecdsa_recover
Recovers the signer’s raw (64-byte) public key from a secp256k1 ECDSA signature
given the (2-bit) recovery_id
and the signed message
(32 byte digest).
This recovery algorithm can only be used to check validity of a signature if the signer’s public key (or its
hash) is known beforehand. When the algorithm returns a public key pk
, this means that the signature in
signature
verified on message
under that pk
. But, again, that is only meaningful if pk
is the “right”
one (e.g., in Ethereum, the “right” pk
is the one whose hash matches the account’s address).
If you do not understand this nuance, please learn more about ECDSA and pubkey recovery (see https://alinush.github.io/ecdsa#pubkey-recovery), or you risk writing completely-insecure code.
Note: This function does not apply any additional hashing on the message
; it simply passes in the message as
raw bytes to the ECDSA recovery function. (The max allowed size ~32 bytes.)
- Nonetheless, most applications will first hash the message to be signed. So, typically,
message
here tends to be a hash rather than an actual message. Therefore, the developer should be aware of what hash function was used for this. - In particular, if using this function to verify an Ethereum signature, you will likely have to input
a keccak256 hash of the message as the
message
parameter.
public fun ecdsa_recover(message: vector<u8>, recovery_id: u8, signature: &secp256k1::ECDSASignature): option::Option<secp256k1::ECDSARawPublicKey>
Implementation
public fun ecdsa_recover( message: vector<u8>, recovery_id: u8, signature: &ECDSASignature,): Option<ECDSARawPublicKey> {
// If recovery ID is not 0 or 1 or 2 or 3, help the caller out by aborting with `E_BAD_RECOVERY_ID` if(recovery_id != 0 && recovery_id != 1 && recovery_id != 2 && recovery_id != 3) { abort std::error::invalid_argument(E_BAD_RECOVERY_ID); };
let (pk, success) = ecdsa_recover_internal(message, recovery_id, signature.bytes);
if (success) { std::option::some(ecdsa_raw_public_key_from_64_bytes(pk)) } else { std::option::none<ECDSARawPublicKey>() }}
ecdsa_recover_internal
Returns (public_key, true)
if signature
verifies on message
under the recovered public_key
and returns ([], false)
otherwise.
fun ecdsa_recover_internal(message: vector<u8>, recovery_id: u8, signature: vector<u8>): (vector<u8>, bool)
Implementation
native fun ecdsa_recover_internal( message: vector<u8>, recovery_id: u8, signature: vector<u8>): (vector<u8>, bool);
Specification
ecdsa_signature_from_bytes
public fun ecdsa_signature_from_bytes(bytes: vector<u8>): secp256k1::ECDSASignature
aborts_if len(bytes) != SIGNATURE_NUM_BYTES;ensures result == ECDSASignature { bytes };
ecdsa_raw_public_key_from_64_bytes
public fun ecdsa_raw_public_key_from_64_bytes(bytes: vector<u8>): secp256k1::ECDSARawPublicKey
aborts_if len(bytes) != RAW_PUBLIC_KEY_NUM_BYTES;ensures result == ECDSARawPublicKey { bytes };
ecdsa_raw_public_key_to_bytes
public fun ecdsa_raw_public_key_to_bytes(pk: &secp256k1::ECDSARawPublicKey): vector<u8>
aborts_if false;ensures result == pk.bytes;
ecdsa_signature_to_bytes
public fun ecdsa_signature_to_bytes(sig: &secp256k1::ECDSASignature): vector<u8>
aborts_if false;ensures result == sig.bytes;
ecdsa_recover
public fun ecdsa_recover(message: vector<u8>, recovery_id: u8, signature: &secp256k1::ECDSASignature): option::Option<secp256k1::ECDSARawPublicKey>
aborts_if recovery_id > 3;aborts_if ecdsa_recover_internal_abort_condition(message, recovery_id, signature.bytes);let pk = spec_ecdsa_recover_internal_result_1(message, recovery_id, signature.bytes);let success = spec_ecdsa_recover_internal_result_2(message, recovery_id, signature.bytes);ensures success ==> result == std::option::spec_some(ecdsa_raw_public_key_from_64_bytes(pk));ensures !success ==> result == std::option::spec_none<ECDSARawPublicKey>();
ecdsa_recover_internal
fun ecdsa_recover_internal(message: vector<u8>, recovery_id: u8, signature: vector<u8>): (vector<u8>, bool)
pragma opaque;aborts_if ecdsa_recover_internal_abort_condition(message, recovery_id, signature);ensures result_1 == spec_ecdsa_recover_internal_result_1(message, recovery_id, signature);ensures result_2 == spec_ecdsa_recover_internal_result_2(message, recovery_id, signature);ensures len(result_1) == if (result_2) { RAW_PUBLIC_KEY_NUM_BYTES } else { 0 };
fun ecdsa_recover_internal_abort_condition(message: vector<u8>, recovery_id: u8, signature: vector<u8>): bool;
fun spec_ecdsa_recover_internal_result_1(message: vector<u8>, recovery_id: u8, signature: vector<u8>): vector<u8>;
fun spec_ecdsa_recover_internal_result_2(message: vector<u8>, recovery_id: u8, signature: vector<u8>): bool;