Repository: aptos-labs/aptos-core
File: aptos-move/framework/src/natives/cryptography/secp256k1.rs (Rust)

Code before:
 *   gas cost: base_cost +? ecdsa_recover
 *
 **************************************************************************************************/
fn native_ecdsa_recover(
    context: &mut SafeNativeContext,
    _ty_args: &[Type],
    mut arguments: VecDeque<Value>,
) -> SafeNativeResult<SmallVec<[Value; 1]>> {
    debug_assert!(_ty_args.is_empty());
    debug_assert!(arguments.len() == 3);

    let signature = safely_pop_arg!(arguments, Vec<u8>);
    let recovery_id = safely_pop_arg!(arguments, u8);
    let msg = safely_pop_arg!(arguments, Vec<u8>);

    context.charge(SECP256K1_BASE)?;

    // NOTE(Gas): O(1) cost
    // (In reality, O(|msg|) deserialization cost, with |msg| < libsecp256k1_core::util::MESSAGE_SIZE
    // which seems to be 32 bytes, so O(1) cost for all intents and purposes.)
    let msg = match libsecp256k1::Message::parse_slice(&msg) {
        Ok(msg) => msg,
        Err(err) => {
            return Err(SafeNativeError::abort_with_message(
                abort_codes::NFE_DESERIALIZE,
                format!("Failed to parse message: {}", err),
            ));
        },
    };

    // NOTE(Gas): O(1) cost
    let rid = match libsecp256k1::RecoveryId::parse(recovery_id) {
        Ok(rid) => rid,
        Err(err) => {
            return Err(SafeNativeError::abort_with_message(
                abort_codes::NFE_DESERIALIZE,
                format!("Failed to parse recovery ID: {}", err),
            ));
        },
    };

    // NOTE(Gas): O(1) deserialization cost
    // which seems to be 64 bytes, so O(1) cost for all intents and purposes.
    let sig = match libsecp256k1::Signature::parse_standard_slice(&signature) {
        Ok(sig) => sig,
        Err(err) => {
            return Err(SafeNativeError::abort_with_message(
                abort_codes::NFE_DESERIALIZE,
                format!("Failed to parse signature: {}", err),
            ));
        },

Review comment (bug):
Can you look into `parse_slice` and what it does? I think the only time it fails is when the size is wrong.

If so, you can give a better message!

Code after:
 *   gas cost: base_cost +? ecdsa_recover
 *
 **************************************************************************************************/
fn native_ecdsa_recover(
    context: &mut SafeNativeContext,
    _ty_args: &[Type],
    mut arguments: VecDeque<Value>,
) -> SafeNativeResult<SmallVec<[Value; 1]>> {
    debug_assert!(_ty_args.is_empty());
    debug_assert!(arguments.len() == 3);

    let signature = safely_pop_arg!(arguments, Vec<u8>);
    let recovery_id = safely_pop_arg!(arguments, u8);
    let msg = safely_pop_arg!(arguments, Vec<u8>);

    context.charge(SECP256K1_BASE)?;

    // NOTE(Gas): O(1) cost
    // (In reality, O(|msg|) deserialization cost, with |msg| < libsecp256k1_core::util::MESSAGE_SIZE
    // which seems to be 32 bytes, so O(1) cost for all intents and purposes.)
    let msg = match libsecp256k1::Message::parse_slice(&msg) {
        Ok(msg) => msg,
        Err(_) => {
            return Err(SafeNativeError::abort_with_message(
                abort_codes::NFE_DESERIALIZE,
                "Message must be exactly 32 bytes",
            ));
        },
    };

    // NOTE(Gas): O(1) cost
    let rid = match libsecp256k1::RecoveryId::parse(recovery_id) {
        Ok(rid) => rid,
        Err(_) => {
            return Err(SafeNativeError::abort_with_message(
                abort_codes::NFE_DESERIALIZE,
                "Recovery ID must be 0, 1, 2, or 3",
            ));
        },
    };

    // NOTE(Gas): O(1) deserialization cost
    // which seems to be 64 bytes, so O(1) cost for all intents and purposes.
    let sig = match libsecp256k1::Signature::parse_standard_slice(&signature) {
        Ok(sig) => sig,
        Err(_) => {
            return Err(SafeNativeError::abort_with_message(
                abort_codes::NFE_DESERIALIZE,
                "Signature must be exactly 64 bytes",
            ));
        },