diff --git a/Cargo.lock b/Cargo.lock index ed852193c85dc..9d4e9ff253cf6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2622,7 +2622,7 @@ dependencies = [ [[package]] name = "fastcrypto" version = "0.1.4" -source = "git+https://github.com/MystenLabs/fastcrypto?rev=54c0db503f35560ed25b2d084fface8acdd8ee96#54c0db503f35560ed25b2d084fface8acdd8ee96" +source = "git+https://github.com/MystenLabs/fastcrypto?rev=285e3f238112703cdfb7eb21e0ea3100e2882e14#285e3f238112703cdfb7eb21e0ea3100e2882e14" dependencies = [ "aes", "aes-gcm", @@ -2670,7 +2670,7 @@ dependencies = [ [[package]] name = "fastcrypto-derive" version = "0.1.2" -source = "git+https://github.com/MystenLabs/fastcrypto?rev=54c0db503f35560ed25b2d084fface8acdd8ee96#54c0db503f35560ed25b2d084fface8acdd8ee96" +source = "git+https://github.com/MystenLabs/fastcrypto?rev=285e3f238112703cdfb7eb21e0ea3100e2882e14#285e3f238112703cdfb7eb21e0ea3100e2882e14" dependencies = [ "convert_case 0.6.0", "proc-macro2 1.0.51", @@ -2681,7 +2681,7 @@ dependencies = [ [[package]] name = "fastcrypto-tbls" version = "0.1.0" -source = "git+https://github.com/MystenLabs/fastcrypto?rev=54c0db503f35560ed25b2d084fface8acdd8ee96#54c0db503f35560ed25b2d084fface8acdd8ee96" +source = "git+https://github.com/MystenLabs/fastcrypto?rev=285e3f238112703cdfb7eb21e0ea3100e2882e14#285e3f238112703cdfb7eb21e0ea3100e2882e14" dependencies = [ "bincode", "digest 0.10.6", @@ -2697,7 +2697,7 @@ dependencies = [ [[package]] name = "fastcrypto-zkp" version = "0.1.0" -source = "git+https://github.com/MystenLabs/fastcrypto?rev=54c0db503f35560ed25b2d084fface8acdd8ee96#54c0db503f35560ed25b2d084fface8acdd8ee96" +source = "git+https://github.com/MystenLabs/fastcrypto?rev=285e3f238112703cdfb7eb21e0ea3100e2882e14#285e3f238112703cdfb7eb21e0ea3100e2882e14" dependencies = [ "ark-bls12-381", "ark-ec", diff --git a/Cargo.toml b/Cargo.toml index e1fc4b7a2f4f9..0cfff6403986c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -127,9 +127,9 @@ move-prover-boogie-backend = { git = "https://github.com/move-language/move", re move-stackless-bytecode = { git = "https://github.com/move-language/move", rev = "7343821f67c070d28dcdb5bf7d2e07ced046b52f" } move-symbol-pool = { git = "https://github.com/move-language/move", rev = "7343821f67c070d28dcdb5bf7d2e07ced046b52f" } -fastcrypto = { git = "https://github.com/MystenLabs/fastcrypto", rev = "54c0db503f35560ed25b2d084fface8acdd8ee96" } -fastcrypto-zkp = { git = "https://github.com/MystenLabs/fastcrypto", rev = "54c0db503f35560ed25b2d084fface8acdd8ee96", package = "fastcrypto-zkp" } -fastcrypto-tbls = { git = "https://github.com/MystenLabs/fastcrypto", rev = "54c0db503f35560ed25b2d084fface8acdd8ee96", package = "fastcrypto-tbls" } +fastcrypto = { git = "https://github.com/MystenLabs/fastcrypto", rev = "285e3f238112703cdfb7eb21e0ea3100e2882e14" } +fastcrypto-zkp = { git = "https://github.com/MystenLabs/fastcrypto", rev = "285e3f238112703cdfb7eb21e0ea3100e2882e14", package = "fastcrypto-zkp" } +fastcrypto-tbls = { git = "https://github.com/MystenLabs/fastcrypto", rev = "285e3f238112703cdfb7eb21e0ea3100e2882e14", package = "fastcrypto-tbls" } # anemo dependencies anemo = { git = "https://github.com/mystenlabs/anemo.git", rev = "d4017b6cefad7ebc5e84b5c6b8eeff4668f719ff" } diff --git a/crates/sui-framework/docs/ecdsa_k1.md b/crates/sui-framework/docs/ecdsa_k1.md index 00a7caa3274fb..61f7499575770 100644 --- a/crates/sui-framework/docs/ecdsa_k1.md +++ b/crates/sui-framework/docs/ecdsa_k1.md @@ -6,10 +6,9 @@ - [Constants](#@Constants_0) -- [Function `ecrecover`](#0x2_ecdsa_k1_ecrecover) +- [Function `secp256k1_ecrecover`](#0x2_ecdsa_k1_secp256k1_ecrecover) - [Function `decompress_pubkey`](#0x2_ecdsa_k1_decompress_pubkey) - [Function `secp256k1_verify`](#0x2_ecdsa_k1_secp256k1_verify) -- [Function `secp256k1_verify_recoverable`](#0x2_ecdsa_k1_secp256k1_verify_recoverable)
@@ -23,6 +22,7 @@
+Error if the public key cannot be recovered from the signature.
const EFailToRecoverPubKey: u64 = 0;
@@ -32,6 +32,7 @@
+Error if the signature is invalid.
const EInvalidSignature: u64 = 1;
@@ -39,24 +40,42 @@
-
+
-## Function `ecrecover`
+Hash function name that are valid for ecrecover and secp256k1_verify.
+
+
+const KECCAK256: u8 = 0;
+
+
+
+
+
+
+
+
+const SHA256: u8 = 1;
+
+
+
+
+
+
+## Function `secp256k1_ecrecover`
@param signature: A 65-bytes signature in form (r, s, v) that is signed using
Secp256k1. Reference implementation on signature generation using RFC6979:
https://github.com/MystenLabs/narwhal/blob/5d6f6df8ccee94446ff88786c0dbbc98be7cfc09/crypto/src/secp256k1.rs
The accepted v values are {0, 1, 2, 3}.
-
-@param hashed_msg: the hashed 32-bytes message. The message must be hashed instead
-of plain text to be secure.
+@param msg: The message that the signature is signed against, this is raw message without hashing.
+@param hash: The hash function used to hash the message when signing.
If the signature is valid, return the corresponding recovered Secpk256k1 public
key, otherwise throw error. This is similar to ecrecover in Ethereum, can only be
applied to Secp256k1 signatures.
-public fun ecrecover(signature: &vector<u8>, hashed_msg: &vector<u8>): vector<u8>
+public fun secp256k1_ecrecover(signature: &vector<u8>, msg: &vector<u8>, hash: u8): vector<u8>
@@ -65,7 +84,7 @@ applied to Secp256k1 signatures.
Implementation
-public native fun ecrecover(signature: &vector<u8>, hashed_msg: &vector<u8>): vector<u8>;
+public native fun secp256k1_ecrecover(signature: &vector<u8>, msg: &vector<u8>, hash: u8): vector<u8>;
@@ -132,58 +151,14 @@ otherwise throw error.
Secp256k1. This is an non-recoverable signature without recovery id.
Reference implementation on signature generation using RFC6979:
https://github.com/MystenLabs/fastcrypto/blob/74aec4886e62122a5b769464c2bea5f803cf8ecc/fastcrypto/src/secp256k1/mod.rs#L193
-
-@param public_key: The public key to verify the signature against
-@param hashed_msg: The hashed 32-bytes message, same as what the signature is signed against.
-
-If the signature is valid to the pubkey and hashed message, return true. Else false.
-
-
-public fun secp256k1_verify(signature: &vector<u8>, public_key: &vector<u8>, hashed_msg: &vector<u8>): bool
-
-
-
-
-
-Implementation
-
-
-public native fun secp256k1_verify(signature: &vector<u8>, public_key: &vector<u8>, hashed_msg: &vector<u8>): bool;
-
-
-
-
-
-
-
-Specification
-
-
-
-pragma opaque;
-aborts_if [abstract] true;
-
-
-
-
-
-
-
-
-## Function `secp256k1_verify_recoverable`
-
-@param signature: A 65-bytes signature in form (r, s, v) that is signed using
-Secp256k1. This is an recoverable signature with recovery id denoted as v.
-Reference implementation on signature generation using RFC6979:
-https://github.com/MystenLabs/fastcrypto/blob/74aec4886e62122a5b769464c2bea5f803cf8ecc/fastcrypto/src/secp256k1/mod.rs#L193
-
@param public_key: The public key to verify the signature against
-@param hashed_msg: The hashed 32-bytes message, same as what the signature is signed against.
+@param msg: The message that the signature is signed against, this is raw message without hashing.
+@param hash: The hash function used to hash the message when signing.
If the signature is valid to the pubkey and hashed message, return true. Else false.
-public fun secp256k1_verify_recoverable(signature: &vector<u8>, public_key: &vector<u8>, hashed_msg: &vector<u8>): bool
+public fun secp256k1_verify(signature: &vector<u8>, public_key: &vector<u8>, msg: &vector<u8>, hash: u8): bool
@@ -192,7 +167,7 @@ If the signature is valid to the pubkey and hashed message, return true. Else fa
Implementation
-public native fun secp256k1_verify_recoverable(signature: &vector<u8>, public_key: &vector<u8>, hashed_msg: &vector<u8>): bool;
+public native fun secp256k1_verify(signature: &vector<u8>, public_key: &vector<u8>, msg: &vector<u8>, hash: u8): bool;
diff --git a/crates/sui-framework/docs/ecdsa_r1.md b/crates/sui-framework/docs/ecdsa_r1.md
new file mode 100644
index 0000000000000..b7791b23e5614
--- /dev/null
+++ b/crates/sui-framework/docs/ecdsa_r1.md
@@ -0,0 +1,148 @@
+
+
+
+# Module `0x2::ecdsa_r1`
+
+
+
+- [Constants](#@Constants_0)
+- [Function `secp256r1_ecrecover`](#0x2_ecdsa_r1_secp256r1_ecrecover)
+- [Function `secp256r1_verify`](#0x2_ecdsa_r1_secp256r1_verify)
+
+
+
+
+
+
+
+
+## Constants
+
+
+
+
+Error if the public key cannot be recovered from the signature.
+
+
+const EFailToRecoverPubKey: u64 = 0;
+
+
+
+
+
+
+Error if the signature is invalid.
+
+
+const EInvalidSignature: u64 = 1;
+
+
+
+
+
+
+Hash function name that are valid for ecrecover and secp256k1_verify.
+
+
+const KECCAK256: u8 = 0;
+
+
+
+
+
+
+
+
+const SHA256: u8 = 1;
+
+
+
+
+
+
+## Function `secp256r1_ecrecover`
+
+@param signature: A 65-bytes signature in form (r, s, v) that is signed using
+Secp256r1. Reference implementation on signature generation using RFC6979:
+https://github.com/MystenLabs/fastcrypto/blob/74aec4886e62122a5b769464c2bea5f803cf8ecc/fastcrypto/src/secp256r1/mod.rs
+The accepted v values are {0, 1, 2, 3}.
+@param msg: The message that the signature is signed against, this is raw message without hashing.
+@param hash: The u8 representing the name of hash function used to hash the message when signing.
+
+If the signature is valid, return the corresponding recovered Secpk256r1 public
+key, otherwise throw error. This is similar to ecrecover in Ethereum, can only be
+applied to Secp256r1 signatures.
+
+
+public fun secp256r1_ecrecover(signature: &vector<u8>, msg: &vector<u8>, hash: u8): vector<u8>
+
+
+
+
+
+Implementation
+
+
+public native fun secp256r1_ecrecover(signature: &vector<u8>, msg: &vector<u8>, hash: u8): vector<u8>;
+
+
+
+
+
+
+
+Specification
+
+
+
+pragma opaque;
+aborts_if [abstract] true;
+
+
+
+
+
+
+
+
+## Function `secp256r1_verify`
+
+@param signature: A 64-bytes signature in form (r, s) that is signed using
+Secp256r1. This is an non-recoverable signature without recovery id.
+Reference implementation on signature generation using RFC6979:
+https://github.com/MystenLabs/fastcrypto/blob/74aec4886e62122a5b769464c2bea5f803cf8ecc/fastcrypto/src/secp256r1/mod.rs
+@param public_key: The public key to verify the signature against
+@param msg: The message that the signature is signed against, this is raw message without hashing.
+@param hash: The u8 representing the name of hash function used to hash the message when signing.
+
+If the signature is valid to the pubkey and hashed message, return true. Else false.
+
+
+public fun secp256r1_verify(signature: &vector<u8>, public_key: &vector<u8>, msg: &vector<u8>, hash: u8): bool
+
+
+
+
+
+Implementation
+
+
+public native fun secp256r1_verify(signature: &vector<u8>, public_key: &vector<u8>, msg: &vector<u8>, hash: u8): bool;
+
+
+
+
+
+
+
+Specification
+
+
+
+pragma opaque;
+aborts_if [abstract] true;
+
+
+
+
+
diff --git a/crates/sui-framework/sources/crypto/ecdsa_k1.move b/crates/sui-framework/sources/crypto/ecdsa_k1.move
index 07322ddc21d1b..43110ba94b6f7 100644
--- a/crates/sui-framework/sources/crypto/ecdsa_k1.move
+++ b/crates/sui-framework/sources/crypto/ecdsa_k1.move
@@ -3,22 +3,27 @@
module sui::ecdsa_k1 {
- // TODO document this
+ /// Error if the public key cannot be recovered from the signature.
const EFailToRecoverPubKey: u64 = 0;
- const EInvalidSignature: u64 = 1;
+ /// Error if the signature is invalid.
+ const EInvalidSignature: u64 = 1;
+
+ /// Hash function name that are valid for ecrecover and secp256k1_verify.
+ const KECCAK256: u8 = 0;
+ const SHA256: u8 = 1;
+
/// @param signature: A 65-bytes signature in form (r, s, v) that is signed using
/// Secp256k1. Reference implementation on signature generation using RFC6979:
/// https://github.com/MystenLabs/narwhal/blob/5d6f6df8ccee94446ff88786c0dbbc98be7cfc09/crypto/src/secp256k1.rs
/// The accepted v values are {0, 1, 2, 3}.
- ///
- /// @param hashed_msg: the hashed 32-bytes message. The message must be hashed instead
- /// of plain text to be secure.
+ /// @param msg: The message that the signature is signed against, this is raw message without hashing.
+ /// @param hash: The hash function used to hash the message when signing.
///
/// If the signature is valid, return the corresponding recovered Secpk256k1 public
/// key, otherwise throw error. This is similar to ecrecover in Ethereum, can only be
/// applied to Secp256k1 signatures.
- public native fun ecrecover(signature: &vector, hashed_msg: &vector): vector;
+ public native fun secp256k1_ecrecover(signature: &vector, msg: &vector, hash: u8): vector;
/// @param pubkey: A 33-bytes compressed public key, a prefix either 0x02 or 0x03 and a 256-bit integer.
///
@@ -30,21 +35,10 @@ module sui::ecdsa_k1 {
/// Secp256k1. This is an non-recoverable signature without recovery id.
/// Reference implementation on signature generation using RFC6979:
/// https://github.com/MystenLabs/fastcrypto/blob/74aec4886e62122a5b769464c2bea5f803cf8ecc/fastcrypto/src/secp256k1/mod.rs#L193
- ///
- /// @param public_key: The public key to verify the signature against
- /// @param hashed_msg: The hashed 32-bytes message, same as what the signature is signed against.
- ///
- /// If the signature is valid to the pubkey and hashed message, return true. Else false.
- public native fun secp256k1_verify(signature: &vector, public_key: &vector, hashed_msg: &vector): bool;
-
- /// @param signature: A 65-bytes signature in form (r, s, v) that is signed using
- /// Secp256k1. This is an recoverable signature with recovery id denoted as v.
- /// Reference implementation on signature generation using RFC6979:
- /// https://github.com/MystenLabs/fastcrypto/blob/74aec4886e62122a5b769464c2bea5f803cf8ecc/fastcrypto/src/secp256k1/mod.rs#L193
- ///
/// @param public_key: The public key to verify the signature against
- /// @param hashed_msg: The hashed 32-bytes message, same as what the signature is signed against.
+ /// @param msg: The message that the signature is signed against, this is raw message without hashing.
+ /// @param hash: The hash function used to hash the message when signing.
///
/// If the signature is valid to the pubkey and hashed message, return true. Else false.
- public native fun secp256k1_verify_recoverable(signature: &vector, public_key: &vector, hashed_msg: &vector): bool;
+ public native fun secp256k1_verify(signature: &vector, public_key: &vector, msg: &vector, hash: u8): bool;
}
diff --git a/crates/sui-framework/sources/crypto/ecdsa_k1.spec.move b/crates/sui-framework/sources/crypto/ecdsa_k1.spec.move
index cb5ee8a51e16f..2253eaf8086b5 100644
--- a/crates/sui-framework/sources/crypto/ecdsa_k1.spec.move
+++ b/crates/sui-framework/sources/crypto/ecdsa_k1.spec.move
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
spec sui::ecdsa_k1 {
- spec ecrecover {
+ spec secp256k1_ecrecover {
pragma opaque;
// TODO: stub to be replaced by actual abort conditions if any
aborts_if [abstract] true;
@@ -22,11 +22,4 @@ spec sui::ecdsa_k1 {
aborts_if [abstract] true;
// TODO: specify actual function behavior
}
-
- spec secp256k1_verify_recoverable {
- pragma opaque;
- // TODO: stub to be replaced by actual abort conditions if any
- aborts_if [abstract] true;
- // TODO: specify actual function behavior
- }
}
diff --git a/crates/sui-framework/sources/crypto/ecdsa_r1.move b/crates/sui-framework/sources/crypto/ecdsa_r1.move
new file mode 100644
index 0000000000000..f6a3c4bcc0e9d
--- /dev/null
+++ b/crates/sui-framework/sources/crypto/ecdsa_r1.move
@@ -0,0 +1,38 @@
+// Copyright (c) Mysten Labs, Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+module sui::ecdsa_r1 {
+
+ /// Error if the public key cannot be recovered from the signature.
+ const EFailToRecoverPubKey: u64 = 0;
+
+ /// Error if the signature is invalid.
+ const EInvalidSignature: u64 = 1;
+
+ /// Hash function name that are valid for ecrecover and secp256k1_verify.
+ const KECCAK256: u8 = 0;
+ const SHA256: u8 = 1;
+
+ /// @param signature: A 65-bytes signature in form (r, s, v) that is signed using
+ /// Secp256r1. Reference implementation on signature generation using RFC6979:
+ /// https://github.com/MystenLabs/fastcrypto/blob/74aec4886e62122a5b769464c2bea5f803cf8ecc/fastcrypto/src/secp256r1/mod.rs
+ /// The accepted v values are {0, 1, 2, 3}.
+ /// @param msg: The message that the signature is signed against, this is raw message without hashing.
+ /// @param hash: The u8 representing the name of hash function used to hash the message when signing.
+ ///
+ /// If the signature is valid, return the corresponding recovered Secpk256r1 public
+ /// key, otherwise throw error. This is similar to ecrecover in Ethereum, can only be
+ /// applied to Secp256r1 signatures.
+ public native fun secp256r1_ecrecover(signature: &vector, msg: &vector, hash: u8): vector;
+
+ /// @param signature: A 64-bytes signature in form (r, s) that is signed using
+ /// Secp256r1. This is an non-recoverable signature without recovery id.
+ /// Reference implementation on signature generation using RFC6979:
+ /// https://github.com/MystenLabs/fastcrypto/blob/74aec4886e62122a5b769464c2bea5f803cf8ecc/fastcrypto/src/secp256r1/mod.rs
+ /// @param public_key: The public key to verify the signature against
+ /// @param msg: The message that the signature is signed against, this is raw message without hashing.
+ /// @param hash: The u8 representing the name of hash function used to hash the message when signing.
+ ///
+ /// If the signature is valid to the pubkey and hashed message, return true. Else false.
+ public native fun secp256r1_verify(signature: &vector, public_key: &vector, msg: &vector, hash: u8): bool;
+}
diff --git a/crates/sui-framework/sources/crypto/ecdsa_r1.spec.move b/crates/sui-framework/sources/crypto/ecdsa_r1.spec.move
new file mode 100644
index 0000000000000..ae6a58414a146
--- /dev/null
+++ b/crates/sui-framework/sources/crypto/ecdsa_r1.spec.move
@@ -0,0 +1,18 @@
+// Copyright (c) Mysten Labs, Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+spec sui::ecdsa_r1 {
+ spec secp256r1_ecrecover {
+ pragma opaque;
+ // TODO: stub to be replaced by actual abort conditions if any
+ aborts_if [abstract] true;
+ // TODO: specify actual function behavior
+ }
+
+ spec secp256r1_verify {
+ pragma opaque;
+ // TODO: stub to be replaced by actual abort conditions if any
+ aborts_if [abstract] true;
+ // TODO: specify actual function behavior
+ }
+}
diff --git a/crates/sui-framework/src/natives/crypto/ecdsa_k1.rs b/crates/sui-framework/src/natives/crypto/ecdsa_k1.rs
index a854d1b27defd..34610363c5bad 100644
--- a/crates/sui-framework/src/natives/crypto/ecdsa_k1.rs
+++ b/crates/sui-framework/src/natives/crypto/ecdsa_k1.rs
@@ -2,10 +2,12 @@
// SPDX-License-Identifier: Apache-2.0
use crate::legacy_empty_cost;
use fastcrypto::{
+ error::FastCryptoError,
+ hash::{Keccak256, Sha256},
secp256k1::{
recoverable::Secp256k1RecoverableSignature, Secp256k1PublicKey, Secp256k1Signature,
},
- traits::ToFromBytes,
+ traits::{RecoverableSignature, ToFromBytes},
};
use move_binary_format::errors::PartialVMResult;
use move_vm_runtime::native_functions::NativeContext;
@@ -17,52 +19,52 @@ use move_vm_types::{
};
use smallvec::smallvec;
use std::collections::VecDeque;
-use sui_types::error::SuiError;
pub const FAIL_TO_RECOVER_PUBKEY: u64 = 0;
pub const INVALID_SIGNATURE: u64 = 1;
pub const INVALID_PUBKEY: u64 = 2;
+pub const KECCAK256: u8 = 0;
+pub const SHA256: u8 = 1;
+
pub fn ecrecover(
_context: &mut NativeContext,
ty_args: Vec,
mut args: VecDeque,
) -> PartialVMResult {
debug_assert!(ty_args.is_empty());
- debug_assert!(args.len() == 2);
+ debug_assert!(args.len() == 3);
- let hashed_msg = pop_arg!(args, VectorRef);
+ let hash = pop_arg!(args, u8);
+ let msg = pop_arg!(args, VectorRef);
let signature = pop_arg!(args, VectorRef);
- let hashed_msg_ref = hashed_msg.as_bytes_ref();
+ let msg_ref = msg.as_bytes_ref();
let signature_ref = signature.as_bytes_ref();
// TODO: implement native gas cost estimation https://github.com/MystenLabs/sui/issues/3593
let cost = legacy_empty_cost();
- match recover_pubkey(&signature_ref, &hashed_msg_ref) {
- Ok(pubkey) => Ok(NativeResult::ok(
+
+ let sig = match ::from_bytes(&signature_ref) {
+ Ok(s) => s,
+ Err(_) => return Ok(NativeResult::err(cost, INVALID_SIGNATURE)),
+ };
+
+ let pk = match hash {
+ KECCAK256 => sig.recover_with_hash::(&msg_ref),
+ SHA256 => sig.recover_with_hash::(&msg_ref),
+ _ => Err(FastCryptoError::InvalidInput),
+ };
+
+ match pk {
+ Ok(pk) => Ok(NativeResult::ok(
cost,
- smallvec![Value::vector_u8(pubkey.as_bytes().to_vec())],
+ smallvec![Value::vector_u8(pk.as_bytes().to_vec())],
)),
- Err(SuiError::InvalidSignature { error: _ }) => {
- Ok(NativeResult::err(cost, INVALID_SIGNATURE))
- }
Err(_) => Ok(NativeResult::err(cost, FAIL_TO_RECOVER_PUBKEY)),
}
}
-fn recover_pubkey(signature: &[u8], hashed_msg: &[u8]) -> Result {
- match ::from_bytes(signature) {
- Ok(signature) => match signature.recover_hashed(hashed_msg) {
- Ok(pubkey) => Ok(pubkey),
- Err(e) => Err(SuiError::KeyConversionError(e.to_string())),
- },
- Err(e) => Err(SuiError::InvalidSignature {
- error: e.to_string(),
- }),
- }
-}
-
pub fn decompress_pubkey(
_context: &mut NativeContext,
ty_args: Vec,
@@ -95,67 +97,35 @@ pub fn secp256k1_verify(
mut args: VecDeque,
) -> PartialVMResult {
debug_assert!(ty_args.is_empty());
- debug_assert!(args.len() == 3);
+ debug_assert!(args.len() == 4);
- let hashed_msg = pop_arg!(args, VectorRef);
+ let hash = pop_arg!(args, u8);
+ let msg = pop_arg!(args, VectorRef);
let public_key_bytes = pop_arg!(args, VectorRef);
let signature_bytes = pop_arg!(args, VectorRef);
- let hashed_msg_ref = hashed_msg.as_bytes_ref();
+ let msg_ref = msg.as_bytes_ref();
let public_key_bytes_ref = public_key_bytes.as_bytes_ref();
let signature_bytes_ref = signature_bytes.as_bytes_ref();
// TODO: implement native gas cost estimation https://github.com/MystenLabs/sui/issues/4086
let cost = legacy_empty_cost();
- let signature = match ::from_bytes(&signature_bytes_ref) {
- Ok(signature) => signature,
+ let sig = match ::from_bytes(&signature_bytes_ref) {
+ Ok(s) => s,
Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
};
- let public_key = match ::from_bytes(&public_key_bytes_ref) {
- Ok(public_key) => public_key,
+ let pk = match ::from_bytes(&public_key_bytes_ref) {
+ Ok(p) => p,
Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
};
- let result = public_key
- .verify_hashed(&hashed_msg_ref, &signature)
- .is_ok();
- Ok(NativeResult::ok(cost, smallvec![Value::bool(result)]))
-}
-
-pub fn secp256k1_verify_recoverable(
- _context: &mut NativeContext,
- ty_args: Vec,
- mut args: VecDeque,
-) -> PartialVMResult {
- debug_assert!(ty_args.is_empty());
- debug_assert!(args.len() == 3);
-
- let hashed_msg = pop_arg!(args, VectorRef);
- let public_key_bytes = pop_arg!(args, VectorRef);
- let signature_bytes = pop_arg!(args, VectorRef);
-
- let hashed_msg_ref = hashed_msg.as_bytes_ref();
- let public_key_bytes_ref = public_key_bytes.as_bytes_ref();
- let signature_bytes_ref = signature_bytes.as_bytes_ref();
-
- // TODO: implement native gas cost estimation https://github.com/MystenLabs/sui/issues/4086
- let cost = legacy_empty_cost();
-
- let signature =
- match ::from_bytes(&signature_bytes_ref) {
- Ok(signature) => signature,
- Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
- };
-
- let public_key = match ::from_bytes(&public_key_bytes_ref) {
- Ok(public_key) => public_key,
- Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
+ let result = match hash {
+ KECCAK256 => pk.verify_with_hash::(&msg_ref, &sig).is_ok(),
+ SHA256 => pk.verify_with_hash::(&msg_ref, &sig).is_ok(),
+ _ => false,
};
- let result = public_key
- .verify_recoverable_hashed(&hashed_msg_ref, &signature)
- .is_ok();
Ok(NativeResult::ok(cost, smallvec![Value::bool(result)]))
}
diff --git a/crates/sui-framework/src/natives/crypto/ecdsa_r1.rs b/crates/sui-framework/src/natives/crypto/ecdsa_r1.rs
new file mode 100644
index 0000000000000..6c0c8772ca1c2
--- /dev/null
+++ b/crates/sui-framework/src/natives/crypto/ecdsa_r1.rs
@@ -0,0 +1,105 @@
+// Copyright (c) Mysten Labs, Inc.
+// SPDX-License-Identifier: Apache-2.0
+use crate::legacy_empty_cost;
+use fastcrypto::error::FastCryptoError;
+use fastcrypto::hash::{Keccak256, Sha256};
+use fastcrypto::traits::RecoverableSignature;
+use fastcrypto::{
+ secp256r1::{
+ recoverable::Secp256r1RecoverableSignature, Secp256r1PublicKey, Secp256r1Signature,
+ },
+ traits::ToFromBytes,
+};
+use move_binary_format::errors::PartialVMResult;
+use move_vm_runtime::native_functions::NativeContext;
+use move_vm_types::{
+ loaded_data::runtime_types::Type,
+ natives::function::NativeResult,
+ pop_arg,
+ values::{Value, VectorRef},
+};
+use smallvec::smallvec;
+use std::collections::VecDeque;
+
+pub const FAIL_TO_RECOVER_PUBKEY: u64 = 0;
+pub const INVALID_SIGNATURE: u64 = 1;
+
+pub const KECCAK256: u8 = 0;
+pub const SHA256: u8 = 1;
+
+pub fn ecrecover(
+ _context: &mut NativeContext,
+ ty_args: Vec,
+ mut args: VecDeque,
+) -> PartialVMResult {
+ debug_assert!(ty_args.is_empty());
+ debug_assert!(args.len() == 3);
+
+ let hash = pop_arg!(args, u8);
+ let msg = pop_arg!(args, VectorRef);
+ let signature = pop_arg!(args, VectorRef);
+
+ let msg_ref = msg.as_bytes_ref();
+ let signature_ref = signature.as_bytes_ref();
+
+ // TODO: implement native gas cost estimation https://github.com/MystenLabs/sui/issues/3593
+ let cost = legacy_empty_cost();
+
+ let sig = match ::from_bytes(&signature_ref) {
+ Ok(s) => s,
+ Err(_) => return Ok(NativeResult::err(cost, INVALID_SIGNATURE)),
+ };
+
+ let pk = match hash {
+ KECCAK256 => sig.recover_with_hash::(&msg_ref),
+ SHA256 => sig.recover_with_hash::(&msg_ref),
+ _ => Err(FastCryptoError::InvalidInput),
+ };
+
+ match pk {
+ Ok(pk) => Ok(NativeResult::ok(
+ cost,
+ smallvec![Value::vector_u8(pk.as_bytes().to_vec())],
+ )),
+ Err(_) => Ok(NativeResult::err(cost, FAIL_TO_RECOVER_PUBKEY)),
+ }
+}
+
+pub fn secp256r1_verify(
+ _context: &mut NativeContext,
+ ty_args: Vec,
+ mut args: VecDeque,
+) -> PartialVMResult {
+ debug_assert!(ty_args.is_empty());
+ debug_assert!(args.len() == 4);
+
+ let hash = pop_arg!(args, u8);
+ let msg = pop_arg!(args, VectorRef);
+ let public_key_bytes = pop_arg!(args, VectorRef);
+ let signature_bytes = pop_arg!(args, VectorRef);
+
+ let msg_ref = msg.as_bytes_ref();
+ let public_key_bytes_ref = public_key_bytes.as_bytes_ref();
+ let signature_bytes_ref = signature_bytes.as_bytes_ref();
+
+ // TODO: implement native gas cost estimation https://github.com/MystenLabs/sui/issues/4086
+ let cost = legacy_empty_cost();
+
+ let sig = match ::from_bytes(&signature_bytes_ref) {
+ Ok(s) => s,
+ Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
+ };
+
+ let pk = match ::from_bytes(&public_key_bytes_ref) {
+ Ok(p) => p,
+ Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
+ };
+
+ let result = match hash {
+ KECCAK256 => pk.verify_with_hash::(&msg_ref, &sig).is_ok(),
+ SHA256 => pk.verify_with_hash::(&msg_ref, &sig).is_ok(),
+ _ => false,
+ };
+
+ Ok(NativeResult::ok(cost, smallvec![Value::bool(result)]))
+}
diff --git a/crates/sui-framework/src/natives/crypto/mod.rs b/crates/sui-framework/src/natives/crypto/mod.rs
index a339f02ba082e..9b3fa05143001 100644
--- a/crates/sui-framework/src/natives/crypto/mod.rs
+++ b/crates/sui-framework/src/natives/crypto/mod.rs
@@ -4,6 +4,7 @@
pub mod bls12381;
pub mod bulletproofs;
pub mod ecdsa_k1;
+pub mod ecdsa_r1;
pub mod ecvrf;
pub mod ed25519;
pub mod elliptic_curve;
diff --git a/crates/sui-framework/src/natives/mod.rs b/crates/sui-framework/src/natives/mod.rs
index a9a00ee821a71..2559aa9b7da87 100644
--- a/crates/sui-framework/src/natives/mod.rs
+++ b/crates/sui-framework/src/natives/mod.rs
@@ -24,7 +24,8 @@ use move_vm_types::{
use std::sync::Arc;
use self::crypto::{
- bls12381, bulletproofs, ecdsa_k1, ecvrf, ed25519, elliptic_curve, groth16, hash, hmac, tbls,
+ bls12381, bulletproofs, ecdsa_k1, ecdsa_r1, ecvrf, ed25519, elliptic_curve, groth16, hash,
+ hmac, tbls,
};
pub fn all_natives(
@@ -86,7 +87,11 @@ pub fn all_natives(
"has_child_object_with_ty",
make_native!(dynamic_field::has_child_object_with_ty),
),
- ("ecdsa_k1", "ecrecover", make_native!(ecdsa_k1::ecrecover)),
+ (
+ "ecdsa_k1",
+ "secp256k1_ecrecover",
+ make_native!(ecdsa_k1::ecrecover),
+ ),
(
"ecdsa_k1",
"decompress_pubkey",
@@ -97,12 +102,17 @@ pub fn all_natives(
"secp256k1_verify",
make_native!(ecdsa_k1::secp256k1_verify),
),
+ ("ecvrf", "ecvrf_verify", make_native!(ecvrf::ecvrf_verify)),
+ (
+ "ecdsa_r1",
+ "secp256r1_ecrecover",
+ make_native!(ecdsa_r1::ecrecover),
+ ),
(
- "ecdsa_k1",
- "secp256k1_verify_recoverable",
- make_native!(ecdsa_k1::secp256k1_verify_recoverable),
+ "ecdsa_r1",
+ "secp256r1_verify",
+ make_native!(ecdsa_r1::secp256r1_verify),
),
- ("ecvrf", "ecvrf_verify", make_native!(ecvrf::ecvrf_verify)),
(
"ed25519",
"ed25519_verify",
diff --git a/crates/sui-framework/tests/crypto/ecdsa_k1_tests.move b/crates/sui-framework/tests/crypto/ecdsa_k1_tests.move
index bc326999954e2..d30fdc16544ea 100644
--- a/crates/sui-framework/tests/crypto/ecdsa_k1_tests.move
+++ b/crates/sui-framework/tests/crypto/ecdsa_k1_tests.move
@@ -2,142 +2,101 @@
// SPDX-License-Identifier: Apache-2.0
#[test_only]
-module sui::ecdsa_tests {
+module sui::ecdsa_k1_tests {
use sui::ecdsa_k1;
use std::vector;
use sui::hash;
#[test]
fun test_ecrecover_pubkey() {
- // test case generated against https://docs.rs/secp256k1/latest/secp256k1/
- let hashed_msg = x"57caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd6";
+ // test case generated against https://github.com/MystenLabs/fastcrypto/blob/f9e64dc028040f863a53a6a88072bda71abd9946/fastcrypto/src/tests/secp256k1_recoverable_tests.rs
+ let msg = b"Hello, world!";
- let sig = x"84dc8043979a2d8f3238b086893adfa6bfe6b2b87b0b13453bcd48ce99bbb807104a492d26ee51608ae1eb8f5f8eb9386303611b42634fe18b1543fe4efbb0b000";
- let pubkey_bytes = x"020257e02f7cff75df5bbcbe9717f1ad946b14673f9b6c97fb98cdcdef47e05609";
-
- let pubkey = ecdsa_k1::ecrecover(&sig, &hashed_msg);
+ // recover with keccak256 hash
+ let sig = x"7e4237ebfbc36613e166bfc5f6229360a9c1949242da97ca04867e4de57b2df30c8340bcb320328cf46d71bda51fcb519e3ce53b348eec62de852e350edbd88600";
+ let pubkey_bytes = x"02337cca2171fdbfcfd657fa59881f46269f1e590b5ffab6023686c7ad2ecc2c1c";
+ let pubkey = ecdsa_k1::secp256k1_ecrecover(&sig, &msg, 0);
assert!(pubkey == pubkey_bytes, 0);
- }
-
- #[test]
- fun test_ecrecover_pubkey_2() {
- // Test case from go-ethereum: https://github.com/ethereum/go-ethereum/blob/master/crypto/signature_test.go#L37
- let hashed_msg = x"ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008";
- let sig = x"90f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e549984a691139ad57a3f0b906637673aa2f63d1f55cb1a69199d4009eea23ceaddc9301";
- let pubkey_bytes = x"02e32df42865e97135acfb65f3bae71bdc86f4d49150ad6a440b6f15878109880a";
- let pubkey = ecdsa_k1::ecrecover(&sig, &hashed_msg);
+ // recover with sha256 hash
+ let sig = x"e5847245b38548547f613aaea3421ad47f5b95a222366fb9f9b8c57568feb19c7077fc31e7d83e00acc1347d08c3e1ad50a4eeb6ab044f25c861ddc7be5b8f9f01";
+ let pubkey_bytes = x"02337cca2171fdbfcfd657fa59881f46269f1e590b5ffab6023686c7ad2ecc2c1c";
+ let pubkey = ecdsa_k1::secp256k1_ecrecover(&sig, &msg, 1);
assert!(pubkey == pubkey_bytes, 0);
}
#[test]
#[expected_failure(abort_code = ecdsa_k1::EFailToRecoverPubKey)]
fun test_ecrecover_pubkey_fail_to_recover() {
- let hashed_msg = x"00";
+ let msg = x"00";
let sig = x"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
- ecdsa_k1::ecrecover(&sig, &hashed_msg);
+ ecdsa_k1::secp256k1_ecrecover(&sig, &msg, 1);
}
#[test]
#[expected_failure(abort_code = ecdsa_k1::EInvalidSignature)]
fun test_ecrecover_pubkey_invalid_sig() {
- let hashed_msg = x"ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008";
+ let msg = b"Hello, world!";
// incorrect length sig
- let sig = x"90f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e549984a691139ad57a3f0b906637673aa2f63d1f55cb1a69199d4009eea23ceaddc93";
- ecdsa_k1::ecrecover(&sig, &hashed_msg);
+ let sig = x"7e4237ebfbc36613e166bfc5f6229360a9c1949242da97ca04867e4de57b2df30c8340bcb320328cf46d71bda51fcb519e3ce53b348eec62de852e350edbd886";
+ ecdsa_k1::secp256k1_ecrecover(&sig, &msg, 1);
}
#[test]
fun test_secp256k1_verify_fails_with_recoverable_sig() {
- let msg = x"57caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd6";
- let pk = x"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
- let sig = x"9c7a72ff1e7db1646b9f9443cb1a3563aa3a6344e4e513efb96258c7676ac4895953629d409a832472b710a028285dfec4733a2c1bb0a2749e465a18292b8bd601";
- let verify = ecdsa_k1::secp256k1_verify(&sig, &pk, &msg);
+ let msg = b"Hello, world!";
+ let pk = x"02337cca2171fdbfcfd657fa59881f46269f1e590b5ffab6023686c7ad2ecc2c1c";
+ let sig = x"7e4237ebfbc36613e166bfc5f6229360a9c1949242da97ca04867e4de57b2df30c8340bcb320328cf46d71bda51fcb519e3ce53b348eec62de852e350edbd88600";
+ let verify = ecdsa_k1::secp256k1_verify(&sig, &pk, &msg, 0);
assert!(verify == false, 0);
- let sig_1 = x"9c7a72ff1e7db1646b9f9443cb1a3563aa3a6344e4e513efb96258c7676ac4895953629d409a832472b710a028285dfec4733a2c1bb0a2749e465a18292b8bd600";
- let verify_1 = ecdsa_k1::secp256k1_verify(&sig_1, &pk, &msg);
+ let sig_1 = x"7e4237ebfbc36613e166bfc5f6229360a9c1949242da97ca04867e4de57b2df30c8340bcb320328cf46d71bda51fcb519e3ce53b348eec62de852e350edbd88601";
+ let verify_1 = ecdsa_k1::secp256k1_verify(&sig_1, &pk, &msg, 0);
assert!(verify_1 == false, 0);
}
#[test]
fun test_secp256k1_verify_success_with_nonrecoverable_sig() {
- let msg = x"57caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd6";
- let pk = x"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
- let sig = x"9c7a72ff1e7db1646b9f9443cb1a3563aa3a6344e4e513efb96258c7676ac4895953629d409a832472b710a028285dfec4733a2c1bb0a2749e465a18292b8bd6";
- let verify = ecdsa_k1::secp256k1_verify(&sig, &pk, &msg);
- assert!(verify == true, 0)
- }
-
- #[test]
- fun test_secp256k1_verify_recoverable_sig_success() {
- let msg = x"57caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd6";
- let pk = x"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
- let sig = x"9c7a72ff1e7db1646b9f9443cb1a3563aa3a6344e4e513efb96258c7676ac4895953629d409a832472b710a028285dfec4733a2c1bb0a2749e465a18292b8bd601";
- let verify = ecdsa_k1::secp256k1_verify_recoverable(&sig, &pk, &msg);
+ let msg = b"Hello, world!";
+ // verify with keccak256 hash
+ let pk = x"02337cca2171fdbfcfd657fa59881f46269f1e590b5ffab6023686c7ad2ecc2c1c";
+ let sig = x"7e4237ebfbc36613e166bfc5f6229360a9c1949242da97ca04867e4de57b2df30c8340bcb320328cf46d71bda51fcb519e3ce53b348eec62de852e350edbd886";
+ let verify = ecdsa_k1::secp256k1_verify(&sig, &pk, &msg, 0);
assert!(verify == true, 0);
- let sig_1 = x"9c7a72ff1e7db1646b9f9443cb1a3563aa3a6344e4e513efb96258c7676ac4895953629d409a832472b710a028285dfec4733a2c1bb0a2749e465a18292b8bd600";
- let verify_1 = ecdsa_k1::secp256k1_verify_recoverable(&sig_1, &pk, &msg);
- assert!(verify_1 == false, 0);
- }
-
- #[test]
- fun test_secp256k1_verify_recoverable_sig_fails() {
- let msg = x"57caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd6";
- let pk = x"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
- let sig = x"9c7a72ff1e7db1646b9f9443cb1a3563aa3a6344e4e513efb96258c7676ac4895953629d409a832472b710a028285dfec4733a2c1bb0a2749e465a18292b8bd6";
- let verify = ecdsa_k1::secp256k1_verify_recoverable(&sig, &pk, &msg);
- assert!(verify == false, 0)
+ // verify with sha256 hash
+ let sig = x"e5847245b38548547f613aaea3421ad47f5b95a222366fb9f9b8c57568feb19c7077fc31e7d83e00acc1347d08c3e1ad50a4eeb6ab044f25c861ddc7be5b8f9f";
+ let pk = x"02337cca2171fdbfcfd657fa59881f46269f1e590b5ffab6023686c7ad2ecc2c1c";
+ let verify = ecdsa_k1::secp256k1_verify(&sig, &pk, &msg, 1);
+ assert!(verify == true, 0);
}
#[test]
- fun test_secp256k1_invalid_hashed_msg_length() {
- let msg = x"01";
- let pk = x"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
- let sig = x"9c7a72ff1e7db1646b9f9443cb1a3563aa3a6344e4e513efb96258c7676ac4895953629d409a832472b710a028285dfec4733a2c1bb0a2749e465a18292b8bd6";
-
- let verify = ecdsa_k1::secp256k1_verify(&sig, &pk, &msg);
- assert!(verify == false, 0)
- }
+ fun test_secp256k1_invalid() {
+ let msg = b"Hello, world!";
+ let sig = x"e5847245b38548547f613aaea3421ad47f5b95a222366fb9f9b8c57568feb19c7077fc31e7d83e00acc1347d08c3e1ad50a4eeb6ab044f25c861ddc7be5b8f9f";
+ let pk = x"02337cca2171fdbfcfd657fa59881f46269f1e590b5ffab6023686c7ad2ecc2c";
+ let verify = ecdsa_k1::secp256k1_verify(&sig, &pk, &msg, 1);
+ assert!(verify == false, 0);
- #[test]
- fun test_secp256k1_invalid_public_key_length() {
- let msg = x"57caa176af1ac0433c5df30e8dabcd2ec1af1e92a26eced5f719b88458777cd6";
- let pk = x"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
- let sig = x"9c7a72ff1e7db1646b9f9443cb1a3563aa3a6344e4e513efb96258c7676ac4895953629d409a832472b710a028285dfec4733a2c1bb0a2749e465a18292b8bd601";
-
- let verify = ecdsa_k1::secp256k1_verify(&sig, &pk, &msg);
- assert!(verify == false, 0)
+ let sig = x"e5847245b38548547f613aaea3421ad47f5b95a222366fb9f9b8c57568feb19c7077fc31e7d83e00acc1347d08c3e1ad50a4eeb6ab044f25c861ddc7be5b8f9f";
+ let pk = x"02337cca2171fdbfcfd657fa59881f46269f1e590b5ffab6023686c7ad2ecc2c1c";
+ let verify = ecdsa_k1::secp256k1_verify(&sig, &pk, &msg, 2);
+ assert!(verify == false, 0);
}
#[test]
fun test_ecrecover_eth_address() {
- // Test case from https://web3js.readthedocs.io/en/v1.7.5/web3-eth-accounts.html#recover
- let sig = x"b91467e570a6466aa9e9876cbcd013baba02900b8979d43fe208a4a4f339f5fd6007e74cd82e037b800186422fc2da167c747ef045e5d18a5f5d4300f8e1a0291c";
- let hashed_msg = x"1da44b586eb0729ff70a73c326926f6ed5a25f5b056e7f47fbc6e58d86871655";
-
- let addr1 = x"2c7536e3605d9c16a7a3d7b1898e529396a65c23";
- let addr = ecrecover_eth_address(sig, hashed_msg);
- assert!(addr == addr1, 0);
-
- // Test case from https://etherscan.io/verifySig/9754
- let sig = x"cb614cba67d6a37b9cb90d21635d81ed035b8ccb99f0befe05495b819111119b17ecf0c0cb4bcc781de387206f6dfcd9f1b99e1b54b44c376412d8f5c919b1981b";
- let hashed_msg = x"1da44b586eb0729ff70a73c326926f6ed5a25f5b056e7f47fbc6e58d86871655";
- let addr1 = x"4cbf668fca6f10d01f161122534044436b80702e";
- let addr = ecrecover_eth_address(sig, hashed_msg);
- assert!(addr == addr1, 0);
-
- // Test case from https://goerli.etherscan.io/tx/0x18f72457b356f367db214de9dda07f5d253ebfeb5c426b0d9d5b346b4ba8d021
- let sig = x"8e809da5ca76e6371ba8dcaa748fc2973f0d9862f76ed08f55b869f5e73591dd24a7367f1ee9e6e3723d13bb0a7092fafb8851f7eecd4a8d34c977013e1551482e";
- let hashed_msg = x"529283629f75203330f0acf68bdbc4e879047fe75da8071c079c495bbb9fb78a";
- let addr1 = x"4cbf668fca6f10d01f161122534044436b80702e";
- let addr = ecrecover_eth_address(sig, hashed_msg);
+ // Test case from https://stackoverflow.com/questions/67278243/how-to-verify-the-signature-made-by-metamask-for-ethereum
+ let sig = x"382a3e04daf88f322730f6a2972475fc5646ea8c4a7f3b5e83a90b10ba08a7364cd2f55348f2b6d210fbed7fc485abf19ecb2f3967e410d6349dd7dd1d4487751b";
+ let msg = x"19457468657265756d205369676e6564204d6573736167653a0a3533307836336639613932643864363162343861396666663864353830383034323561333031326430356338696777796b3472316f376f";
+ let addr1 = x"63f9a92d8d61b48a9fff8d58080425a3012d05c8";
+ let addr = ecrecover_eth_address(sig, msg);
assert!(addr == addr1, 0);
}
// Helper Move function to recover signature directly to an ETH address.
- fun ecrecover_eth_address(sig: vector, hashed_msg: vector): vector {
+ fun ecrecover_eth_address(sig: vector, msg: vector): vector {
// Normalize the last byte of the signature to be 0 or 1.
let v = vector::borrow_mut(&mut sig, 64);
if (*v == 27) {
@@ -148,7 +107,8 @@ module sui::ecdsa_tests {
*v = (*v - 1) % 2;
};
- let pubkey = ecdsa_k1::ecrecover(&sig, &hashed_msg);
+ let pubkey = ecdsa_k1::secp256k1_ecrecover(&sig, &msg, 0);
+
let uncompressed = ecdsa_k1::decompress_pubkey(&pubkey);
// Take the last 64 bytes of the uncompressed pubkey.
@@ -169,6 +129,7 @@ module sui::ecdsa_tests {
vector::push_back(&mut addr, *value);
i = i + 1;
};
+
addr
}
}
diff --git a/crates/sui-framework/tests/crypto/ecdsa_r1_tests.move b/crates/sui-framework/tests/crypto/ecdsa_r1_tests.move
new file mode 100644
index 0000000000000..11ca6a7a4e0f0
--- /dev/null
+++ b/crates/sui-framework/tests/crypto/ecdsa_r1_tests.move
@@ -0,0 +1,71 @@
+// Copyright (c) Mysten Labs, Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+#[test_only]
+module sui::ecdsa_r1_tests {
+ use sui::ecdsa_r1;
+
+ #[test]
+ fun test_ecrecover_pubkey() {
+ // test case generated against https://github.com/MystenLabs/fastcrypto/blob/285e3f238112703cdfb7eb21e0ea3100e2882e14/fastcrypto/src/tests/secp256r1_recoverable_tests.rs
+ let msg = b"Hello, world!";
+
+ // recover with Keccak256
+ let sig = x"209841acabd0fdf6d25fa0948b2f5c6c74f930eede89c6fce59502218a3134a147535921bf0cdf5d1990f6f0b3dadb8c05069ddc531db057d325857ce198a52900";
+ let pubkey_bytes = x"0227322b3a891a0a280d6bc1fb2cbb23d28f54906fd6407f5f741f6def5762609a";
+ let pubkey = ecdsa_r1::secp256r1_ecrecover(&sig, &msg, 0);
+ assert!(pubkey == pubkey_bytes, 0);
+
+ // recover with Sha256
+ let sig = x"26d84720652d8bc4ddd1986434a10b3b7b69f0e35a17c6a5987e6d1cba69652f4384a342487642df5e44592d304bea0ceb0fae2e347fa3cec5ce1a8144cfbbb200";
+ let pubkey = ecdsa_r1::secp256r1_ecrecover(&sig, &msg, 1);
+ assert!(pubkey == pubkey_bytes, 0);
+ }
+
+ #[test]
+ #[expected_failure(abort_code = ecdsa_r1::EInvalidSignature)]
+ fun test_ecrecover_pubkey_invalid_sig() {
+ let msg = b"Hello, world!";
+ let sig = x"26d84720652d8bc4ddd1986434a10b3b7b69f0e35a17c6a5987e6d1cba69652f4384a342487642df5e44592d304bea0ceb0fae2e347fa3cec5ce1a8144cfbbb2";
+ ecdsa_r1::secp256r1_ecrecover(&sig, &msg, 1);
+ }
+
+ #[test]
+ fun test_secp256r1_verify_fails_with_recoverable_sig() {
+ let msg = b"Hello, world!";
+ let pk = x"0227322b3a891a0a280d6bc1fb2cbb23d28f54906fd6407f5f741f6def5762609a";
+ // signature is a 65-byte recoverable one with recovery id 0
+ let sig = x"209841acabd0fdf6d25fa0948b2f5c6c74f930eede89c6fce59502218a3134a147535921bf0cdf5d1990f6f0b3dadb8c05069ddc531db057d325857ce198a52900";
+ let verify = ecdsa_r1::secp256r1_verify(&sig, &pk, &msg, 0);
+ assert!(verify == false, 0);
+
+ // signature is a 65-byte recoverable one with recovery id 1
+ let sig = x"209841acabd0fdf6d25fa0948b2f5c6c74f930eede89c6fce59502218a3134a147535921bf0cdf5d1990f6f0b3dadb8c05069ddc531db057d325857ce198a52901";
+ let verify = ecdsa_r1::secp256r1_verify(&sig, &pk, &msg, 0);
+ assert!(verify == false, 0);
+ }
+
+ #[test]
+ fun test_secp256r1_verify_success_with_nonrecoverable_sig() {
+ let msg = b"Hello, world!";
+ let pk = x"0227322b3a891a0a280d6bc1fb2cbb23d28f54906fd6407f5f741f6def5762609a";
+
+ let sig = x"209841acabd0fdf6d25fa0948b2f5c6c74f930eede89c6fce59502218a3134a147535921bf0cdf5d1990f6f0b3dadb8c05069ddc531db057d325857ce198a529";
+ let verify = ecdsa_r1::secp256r1_verify(&sig, &pk, &msg, 0);
+ assert!(verify == true, 0);
+
+ let sig = x"26d84720652d8bc4ddd1986434a10b3b7b69f0e35a17c6a5987e6d1cba69652f4384a342487642df5e44592d304bea0ceb0fae2e347fa3cec5ce1a8144cfbbb2";
+ let verify = ecdsa_r1::secp256r1_verify(&sig, &pk, &msg, 1);
+ assert!(verify == true, 0);
+ }
+
+ #[test]
+ fun test_secp256r1_invalid_public_key_length() {
+ let msg = b"Hello, world!";
+ let pk = x"0227322b3a891a0a280d6bc1fb2cbb23d28f54906fd6407f5f741f6def576260";
+
+ let sig = x"209841acabd0fdf6d25fa0948b2f5c6c74f930eede89c6fce59502218a3134a147535921bf0cdf5d1990f6f0b3dadb8c05069ddc531db057d325857ce198a529";
+ let verify = ecdsa_r1::secp256r1_verify(&sig, &pk, &msg, 0);
+ assert!(verify == false, 0);
+ }
+}
diff --git a/crates/sui-rosetta/src/construction.rs b/crates/sui-rosetta/src/construction.rs
index 9386de4930d03..9f9536aad3f9c 100644
--- a/crates/sui-rosetta/src/construction.rs
+++ b/crates/sui-rosetta/src/construction.rs
@@ -64,7 +64,7 @@ pub async fn payloads(
unsigned_transaction: Hex::from_bytes(&intent_msg_bytes),
payloads: vec![SigningPayload {
account_identifier: address.into(),
- hex_bytes: Hex::encode(&bcs::to_bytes(&intent_msg)?),
+ hex_bytes: Hex::encode(bcs::to_bytes(&intent_msg)?),
signature_type: Some(SignatureType::Ed25519),
}],
})
diff --git a/crates/workspace-hack/Cargo.toml b/crates/workspace-hack/Cargo.toml
index 2c8372b39ba34..6ef300c716ff2 100644
--- a/crates/workspace-hack/Cargo.toml
+++ b/crates/workspace-hack/Cargo.toml
@@ -201,9 +201,9 @@ expect-test = { version = "1", default-features = false }
eyre = { version = "0.6" }
fail-9fbad63c4bcf4a8f = { package = "fail", version = "0.4", default-features = false }
fail-d8f496e17d97b5cb = { package = "fail", version = "0.5", default-features = false }
-fastcrypto = { git = "https://github.com/MystenLabs/fastcrypto", rev = "54c0db503f35560ed25b2d084fface8acdd8ee96", features = ["copy_key"] }
-fastcrypto-tbls = { git = "https://github.com/MystenLabs/fastcrypto", rev = "54c0db503f35560ed25b2d084fface8acdd8ee96", default-features = false }
-fastcrypto-zkp = { git = "https://github.com/MystenLabs/fastcrypto", rev = "54c0db503f35560ed25b2d084fface8acdd8ee96", default-features = false }
+fastcrypto = { git = "https://github.com/MystenLabs/fastcrypto", rev = "285e3f238112703cdfb7eb21e0ea3100e2882e14", features = ["copy_key"] }
+fastcrypto-tbls = { git = "https://github.com/MystenLabs/fastcrypto", rev = "285e3f238112703cdfb7eb21e0ea3100e2882e14", default-features = false }
+fastcrypto-zkp = { git = "https://github.com/MystenLabs/fastcrypto", rev = "285e3f238112703cdfb7eb21e0ea3100e2882e14", default-features = false }
fastrand = { version = "1", default-features = false }
fd-lock = { version = "3", default-features = false }
fdlimit = { version = "0.2", default-features = false }
@@ -877,10 +877,10 @@ expect-test = { version = "1", default-features = false }
eyre = { version = "0.6" }
fail-9fbad63c4bcf4a8f = { package = "fail", version = "0.4", default-features = false }
fail-d8f496e17d97b5cb = { package = "fail", version = "0.5", default-features = false }
-fastcrypto = { git = "https://github.com/MystenLabs/fastcrypto", rev = "54c0db503f35560ed25b2d084fface8acdd8ee96", features = ["copy_key"] }
-fastcrypto-derive = { git = "https://github.com/MystenLabs/fastcrypto", rev = "54c0db503f35560ed25b2d084fface8acdd8ee96", default-features = false }
-fastcrypto-tbls = { git = "https://github.com/MystenLabs/fastcrypto", rev = "54c0db503f35560ed25b2d084fface8acdd8ee96", default-features = false }
-fastcrypto-zkp = { git = "https://github.com/MystenLabs/fastcrypto", rev = "54c0db503f35560ed25b2d084fface8acdd8ee96", default-features = false }
+fastcrypto = { git = "https://github.com/MystenLabs/fastcrypto", rev = "285e3f238112703cdfb7eb21e0ea3100e2882e14", features = ["copy_key"] }
+fastcrypto-derive = { git = "https://github.com/MystenLabs/fastcrypto", rev = "285e3f238112703cdfb7eb21e0ea3100e2882e14", default-features = false }
+fastcrypto-tbls = { git = "https://github.com/MystenLabs/fastcrypto", rev = "285e3f238112703cdfb7eb21e0ea3100e2882e14", default-features = false }
+fastcrypto-zkp = { git = "https://github.com/MystenLabs/fastcrypto", rev = "285e3f238112703cdfb7eb21e0ea3100e2882e14", default-features = false }
fastrand = { version = "1", default-features = false }
fd-lock = { version = "3", default-features = false }
fdlimit = { version = "0.2", default-features = false }