Skip to content

Commit 50ed630

Browse files
authored
fix: audit (#126)
* add verify function * fix dex single_asset_provide to use more explicit condition * fix nft to mintable by collection object owner * fix tests and add comments
1 parent 7513151 commit 50ed630

33 files changed

+797
-477
lines changed

crates/gas/src/initia_stdlib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ crate::macros::define_gas_parameters!(
4747
[crypto_ed25519_per_msg_byte_hashing: InternalGasPerByte, "crypto.ed25519.per_msg_byte_hashing", 220],
4848

4949
[crypto_secp256k1_base: InternalGas, "crypto.secp256k1.base", 551],
50+
[crypto_secp256k1_per_sig_verify: InternalGasPerArg, "crypto.secp256k1.per_sig_verify", 981492],
5051
[crypto_secp256k1_per_ecdsa_recover: InternalGasPerArg, "crypto.secp256k1.per_ecdsa_recover", 5918360],
5152
[crypto_secp256k1_per_pubkey_deserialize: InternalGasPerArg, "crypto.secp256k1.per_pubkey_deserialize", 139688],
5253
[crypto_secp256k1_per_sig_deserialize: InternalGasPerArg, "crypto.secp256k1.per_sig_deserialize", 1378],

crates/natives/src/crypto/secp256k1.rs

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use move_vm_runtime::native_functions::NativeFunction;
44
use move_vm_types::{loaded_data::runtime_types::Type, values::Value};
55

66
use libsecp256k1::{
7-
recover, util::MESSAGE_SIZE, util::SIGNATURE_SIZE, Message, RecoveryId, Signature,
7+
recover,
8+
util::{COMPRESSED_PUBLIC_KEY_SIZE, MESSAGE_SIZE, SIGNATURE_SIZE},
9+
verify, Message, PublicKey, RecoveryId, Signature,
810
};
911

1012
use smallvec::{smallvec, SmallVec};
@@ -33,6 +35,56 @@ fn read_hash(data: &[u8]) -> Result<[u8; MESSAGE_SIZE], TryFromSliceError> {
3335
data.try_into()
3436
}
3537

38+
fn read_pubkey(data: &[u8]) -> Result<[u8; COMPRESSED_PUBLIC_KEY_SIZE], TryFromSliceError> {
39+
data.try_into()
40+
}
41+
42+
pub fn native_verify(
43+
context: &mut SafeNativeContext,
44+
_ty_args: Vec<Type>,
45+
mut arguments: VecDeque<Value>,
46+
) -> SafeNativeResult<SmallVec<[Value; 1]>> {
47+
let gas_params = &context.native_gas_params.initia_stdlib;
48+
context.charge(gas_params.crypto_secp256k1_base)?;
49+
50+
debug_assert!(_ty_args.is_empty());
51+
debug_assert!(arguments.len() == 3);
52+
53+
let signature = safely_pop_arg!(arguments, Vec<u8>);
54+
let pubkey = safely_pop_arg!(arguments, Vec<u8>);
55+
let message = safely_pop_arg!(arguments, Vec<u8>);
56+
57+
let msg = match read_hash(&message) {
58+
Ok(mh) => Message::parse(&mh),
59+
Err(_) => {
60+
return Err(SafeNativeError::Abort {
61+
abort_code: UNABLE_TO_DESERIALIZE,
62+
});
63+
}
64+
};
65+
66+
context.charge(gas_params.crypto_secp256k1_per_pubkey_deserialize * NumArgs::one())?;
67+
let pk = match read_pubkey(&pubkey) {
68+
Ok(pk) => match PublicKey::parse_compressed(&pk) {
69+
Ok(pk) => pk,
70+
Err(_) => return Ok(smallvec![Value::bool(false)]),
71+
},
72+
Err(_) => return Ok(smallvec![Value::bool(false)]),
73+
};
74+
75+
context.charge(gas_params.crypto_secp256k1_per_sig_deserialize * NumArgs::one())?;
76+
let sig = match read_signature(&signature) {
77+
Ok(sig) => match Signature::parse_standard(&sig) {
78+
Ok(sig) => sig,
79+
Err(_) => return Ok(smallvec![Value::bool(false)]),
80+
},
81+
Err(_) => return Ok(smallvec![Value::bool(false)]),
82+
};
83+
84+
context.charge(gas_params.crypto_secp256k1_per_sig_verify * NumArgs::one())?;
85+
Ok(smallvec![Value::bool(verify(&msg, &sig, &pk))])
86+
}
87+
3688
pub fn native_recover_public_key(
3789
context: &mut SafeNativeContext,
3890
_ty_args: Vec<Type>,
@@ -102,7 +154,7 @@ pub fn native_recover_public_key(
102154
use rand_core::OsRng;
103155

104156
#[cfg(feature = "testing")]
105-
use libsecp256k1::{sign, PublicKey, SecretKey};
157+
use libsecp256k1::{sign, SecretKey};
106158

107159
#[cfg(feature = "testing")]
108160
pub fn native_test_only_generate_keys(
@@ -151,18 +203,18 @@ pub fn make_all(
151203
builder: &SafeNativeBuilder,
152204
) -> impl Iterator<Item = (String, NativeFunction)> + '_ {
153205
let mut natives = vec![];
154-
natives.extend([(
155-
"recover_public_key_internal",
156-
native_recover_public_key as RawSafeNative,
157-
)]);
206+
natives.extend([
207+
("verify_internal", native_verify as RawSafeNative),
208+
("recover_public_key_internal", native_recover_public_key),
209+
]);
158210

159211
#[cfg(feature = "testing")]
160212
natives.extend([
161213
(
162214
"generate_keys",
163215
native_test_only_generate_keys as RawSafeNative,
164216
),
165-
("sign", native_test_only_sign as RawSafeNative),
217+
("sign", native_test_only_sign),
166218
]);
167219

168220
builder.make_named_natives(natives)
-116 Bytes
Binary file not shown.

precompile/binaries/minlib/dex.mv

0 Bytes
Binary file not shown.
45 Bytes
Binary file not shown.

precompile/binaries/minlib/nft.mv

78 Bytes
Binary file not shown.

precompile/binaries/minlib/object.mv

64 Bytes
Binary file not shown.
125 Bytes
Binary file not shown.
45 Bytes
Binary file not shown.
-116 Bytes
Binary file not shown.

precompile/binaries/stdlib/dex.mv

0 Bytes
Binary file not shown.
45 Bytes
Binary file not shown.

precompile/binaries/stdlib/nft.mv

78 Bytes
Binary file not shown.

precompile/binaries/stdlib/object.mv

64 Bytes
Binary file not shown.
125 Bytes
Binary file not shown.
45 Bytes
Binary file not shown.

precompile/modules/initia_stdlib/sources/block.move

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ module initia_std::block {
4545
vm: &signer, _fake_block_hash: address
4646
) {
4747
if (!exists<HasGenesisBlock>(signer::address_of(vm))) {
48-
move_to(vm, HasGenesisBlock{});
48+
move_to(vm, HasGenesisBlock {});
4949
return
5050
};
5151

precompile/modules/initia_stdlib/sources/crypto/secp256k1.move

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,24 @@ module initia_std::secp256k1 {
9191
sig.bytes
9292
}
9393

94+
/// Returns `true` if the signature can verify the public key on the message
95+
public fun verify(
96+
message: vector<u8>,
97+
public_key: &ECDSACompressedPublicKey,
98+
signature: &ECDSASignature
99+
): bool {
100+
assert!(
101+
std::vector::length(&message) == MESSAGE_SIZE,
102+
std::error::invalid_argument(E_DESERIALIZE)
103+
);
104+
105+
return verify_internal(
106+
message,
107+
public_key.bytes,
108+
signature.bytes
109+
)
110+
}
111+
94112
/// Recovers the signer's raw (64-byte) public key from a secp256k1 ECDSA `signature` given the `recovery_id` and the signed
95113
/// `message` (32 byte digest).
96114
///
@@ -151,6 +169,18 @@ module initia_std::secp256k1 {
151169
// Native functions
152170
//
153171

172+
/// Returns `true` if `signature` verifies on `public_key` and `message`
173+
/// and returns `false` otherwise.
174+
///
175+
/// - `message`: A 32-byte hashed message.
176+
/// - `public_key`: A compressed public key in bytes.
177+
/// - `signature`: A 64-byte ECDSA signature.
178+
native fun verify_internal(
179+
message: vector<u8>,
180+
public_key: vector<u8>,
181+
signature: vector<u8>
182+
): bool;
183+
154184
/// Returns `(public_key, true)` if `signature` verifies on `message` under the recovered `public_key`
155185
/// and returns `([], false)` otherwise.
156186
native fun recover_public_key_internal(
@@ -172,6 +202,29 @@ module initia_std::secp256k1 {
172202
// Tests
173203
//
174204

205+
#[test]
206+
fun test_secp256k1_sign_verify() {
207+
use std::hash;
208+
209+
let (sk, vk) = generate_keys(true);
210+
let pk = ecdsa_compressed_public_key_from_bytes(vk);
211+
212+
let msg: vector<u8> = hash::sha2_256(b"test initia secp256k1");
213+
let (_rid, sig_bytes) = sign(msg, sk);
214+
let sig = ecdsa_signature_from_bytes(sig_bytes);
215+
assert!(verify(msg, &pk, &sig), 1);
216+
217+
// Test with an incorrect message
218+
let wrong_msg: vector<u8> = hash::sha2_256(b"wrong message");
219+
assert!(!verify(wrong_msg, &pk, &sig), 2);
220+
221+
// Test with an incorrect signature
222+
let invalid_sig_bytes = sig_bytes;
223+
*std::vector::borrow_mut(&mut invalid_sig_bytes, 0) = 0xFF; // Corrupt the signature
224+
let invalid_sig = ecdsa_signature_from_bytes(invalid_sig_bytes);
225+
assert!(!verify(msg, &pk, &invalid_sig), 3);
226+
}
227+
175228
#[test]
176229
fun test_gen_sign_recover() {
177230
use std::hash;

0 commit comments

Comments
 (0)