Skip to content

Commit

Permalink
crypto: add secp256k1 verify move function (MystenLabs#4088)
Browse files Browse the repository at this point in the history
  • Loading branch information
joyqvq authored Aug 19, 2022
1 parent 7a32715 commit 0ab65ca
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 9 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,27 @@ source: crates/sui-cost/tests/snapshot_tests.rs
expression: common_costs
---
Publish:
computationCost: 561
computationCost: 562
storageCost: 84
storageRebate: 16
MergeCoin:
computationCost: 501
computationCost: 502
storageCost: 32
storageRebate: 0
? SplitCoin: 0
: computationCost: 484
: computationCost: 485
storageCost: 32
storageRebate: 0
? SplitCoin: 1
: computationCost: 527
: computationCost: 528
storageCost: 48
storageRebate: 0
? SplitCoin: 2
: computationCost: 570
: computationCost: 571
storageCost: 64
storageRebate: 0
? SplitCoin: 3
: computationCost: 613
: computationCost: 614
storageCost: 80
storageRebate: 0
TransferWholeCoin:
Expand Down
11 changes: 11 additions & 0 deletions crates/sui-framework/sources/crypto.move
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ module sui::crypto {
/// Otherwise, return false.
public native fun bls12381_verify_g1_sig(signature: vector<u8>, public_key: vector<u8>, msg: vector<u8>): bool;

/// @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
///
/// @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<u8>, public_key: vector<u8>, hashed_msg: vector<u8>): bool;

use sui::elliptic_curve::{Self as ec, RistrettoPoint};

/// Only bit_length = 64, 32, 16, 8 will work.
Expand Down
2 changes: 1 addition & 1 deletion crates/sui-framework/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ mod tests {
use std::path::PathBuf;

#[test]
fn run_framework_move_unit_tests() {
fn cmework_move_unit_tests() {
get_sui_framework();
get_move_stdlib();
build_move_package(
Expand Down
34 changes: 33 additions & 1 deletion crates/sui-framework/src/natives/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use curve25519_dalek_ng::scalar::Scalar;
use fastcrypto::{
bls12381::{BLS12381PublicKey, BLS12381Signature},
bulletproofs::{BulletproofsRangeProof, PedersenCommitment},
secp256k1::Secp256k1Signature,
secp256k1::{Secp256k1PublicKey, Secp256k1Signature},
traits::ToFromBytes,
Verifier,
};
Expand Down Expand Up @@ -76,6 +76,38 @@ pub fn keccak256(
))
}

/// Native implemention of secp256k1_verify in public Move API, see crypto.move for specifications.
pub fn secp256k1_verify(
context: &mut NativeContext,
ty_args: Vec<Type>,
mut args: VecDeque<Value>,
) -> PartialVMResult<NativeResult> {
debug_assert!(ty_args.is_empty());
debug_assert!(args.len() == 3);

let hashed_msg = pop_arg!(args, Vec<u8>);
let public_key_bytes = pop_arg!(args, Vec<u8>);
let signature_bytes = pop_arg!(args, Vec<u8>);

// TODO: implement native gas cost estimation https://github.com/MystenLabs/sui/issues/4086
let cost = native_gas(context.cost_table(), NativeCostIndex::EMPTY, 0);

let signature = match <Secp256k1Signature as ToFromBytes>::from_bytes(&signature_bytes) {
Ok(signature) => signature,
Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
};

let public_key = match <Secp256k1PublicKey as ToFromBytes>::from_bytes(&public_key_bytes) {
Ok(public_key) => public_key,
Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
};

match public_key.verify_hashed(&hashed_msg, &signature) {
Ok(_) => Ok(NativeResult::ok(cost, smallvec![Value::bool(true)])),
Err(_) => Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
}
}

/// Native implemention of bls12381_verify in public Move API, see crypto.move for specifications.
/// Note that this function only works for signatures in G1 and public keys in G2.
pub fn bls12381_verify_g1_sig(
Expand Down
1 change: 1 addition & 0 deletions crates/sui-framework/src/natives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub fn all_natives(
const SUI_NATIVES: &[(&str, &str, NativeFunction)] = &[
("crypto", "ecrecover", crypto::ecrecover),
("crypto", "keccak256", crypto::keccak256),
("crypto", "secp256k1_verify", crypto::secp256k1_verify),
(
"crypto",
"bls12381_verify_g1_sig",
Expand Down
46 changes: 46 additions & 0 deletions crates/sui-framework/tests/crypto_tests.move
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,50 @@ module sui::crypto_tests {

crypto::verify_full_range_proof(bulletproof, point, bit_length);
}

#[test]
fun test_secp256k1_valid_sig() {
let msg = vector[87, 202, 161, 118, 175, 26, 192, 67, 60, 93, 243, 14, 141, 171, 205, 46, 193, 175, 30, 146, 162, 110, 206, 213, 247, 25, 184, 132, 88, 119, 124, 214];
let pk = vector[2, 121, 190, 102, 126, 249, 220, 187, 172, 85, 160, 98, 149, 206, 135, 11, 7, 2, 155, 252, 219, 45, 206, 40, 217, 89, 242, 129, 91, 22, 248, 23, 152];
let sig = vector[156, 122, 114, 255, 30, 125, 177, 100, 107, 159, 148, 67, 203, 26, 53, 99, 170, 58, 99, 68, 228, 229, 19, 239, 185, 98, 88, 199, 103, 106, 196, 137, 89, 83, 98, 157, 64, 154, 131, 36, 114, 183, 16, 160, 40, 40, 93, 254, 196, 115, 58, 44, 27, 176, 162, 116, 158, 70, 90, 24, 41, 43, 139, 214, 1];
let verify = crypto::secp256k1_verify(sig, pk, msg);
assert!(verify == true, 0)
}

#[test]
fun test_secp256k1_invalid_sig() {
let msg = vector[87, 202, 161, 118, 175, 26, 192, 67, 60, 93, 243, 14, 141, 171, 205, 46, 193, 175, 30, 146, 162, 110, 206, 213, 247, 25, 184, 132, 88, 119, 124, 214];
let pk = vector[2, 121, 190, 102, 126, 249, 220, 187, 172, 85, 160, 98, 149, 206, 135, 11, 7, 2, 155, 252, 219, 45, 206, 40, 217, 89, 242, 129, 91, 22, 248, 23, 152];
// sig in the form of (r, s, 0) instead of (r, s, 1)
let sig = vector[156, 122, 114, 255, 30, 125, 177, 100, 107, 159, 148, 67, 203, 26, 53, 99, 170, 58, 99, 68, 228, 229, 19, 239, 185, 98, 88, 199, 103, 106, 196, 137, 89, 83, 98, 157, 64, 154, 131, 36, 114, 183, 16, 160, 40, 40, 93, 254, 196, 115, 58, 44, 27, 176, 162, 116, 158, 70, 90, 24, 41, 43, 139, 214, 0];
let verify = crypto::secp256k1_verify(sig, pk, msg);
assert!(verify == false, 0)
}

#[test]
fun test_secp256k1_invalid_sig_length() {
let msg = vector[87, 202, 161, 118, 175, 26, 192, 67, 60, 93, 243, 14, 141, 171, 205, 46, 193, 175, 30, 146, 162, 110, 206, 213, 247, 25, 184, 132, 88, 119, 124, 214];
let pk = vector[2, 121, 190, 102, 126, 249, 220, 187, 172, 85, 160, 98, 149, 206, 135, 11, 7, 2, 155, 252, 219, 45, 206, 40, 217, 89, 242, 129, 91, 22, 248, 23, 152];
let sig = vector[156, 122, 114, 255, 30, 125, 177, 100, 107, 159, 148, 67, 203, 26, 53, 99, 170, 58, 99, 68, 228, 229, 19, 239, 185, 98, 88, 199, 103, 106, 196, 137, 89, 83, 98, 157, 64, 154, 131, 36, 114, 183, 16, 160, 40, 40, 93, 254, 196, 115, 58, 44, 27, 176, 162, 116, 158, 70, 90, 24, 41, 43, 139, 214];
let verify = crypto::secp256k1_verify(sig, pk, msg);
assert!(verify == false, 0)
}

#[test]
fun test_secp256k1_invalid_hashed_msg_length() {
let msg = vector[1];
let pk = vector[2, 121, 190, 102, 126, 249, 220, 187, 172, 85, 160, 98, 149, 206, 135, 11, 7, 2, 155, 252, 219, 45, 206, 40, 217, 89, 242, 129, 91, 22, 248, 23, 152];
let sig = vector[156, 122, 114, 255, 30, 125, 177, 100, 107, 159, 148, 67, 203, 26, 53, 99, 170, 58, 99, 68, 228, 229, 19, 239, 185, 98, 88, 199, 103, 106, 196, 137, 89, 83, 98, 157, 64, 154, 131, 36, 114, 183, 16, 160, 40, 40, 93, 254, 196, 115, 58, 44, 27, 176, 162, 116, 158, 70, 90, 24, 41, 43, 139, 214];
let verify = crypto::secp256k1_verify(sig, pk, msg);
assert!(verify == false, 0)
}

#[test]
fun test_secp256k1_invalid_public_key_length() {
let msg = vector[87, 202, 161, 118, 175, 26, 192, 67, 60, 93, 243, 14, 141, 171, 205, 46, 193, 175, 30, 146, 162, 110, 206, 213, 247, 25, 184, 132, 88, 119, 124, 214];
let pk = vector[121, 190, 102, 126, 249, 220, 187, 172, 85, 160, 98, 149, 206, 135, 11, 7, 2, 155, 252, 219, 45, 206, 40, 217, 89, 242, 129, 91, 22, 248, 23, 152];
let sig = vector[156, 122, 114, 255, 30, 125, 177, 100, 107, 159, 148, 67, 203, 26, 53, 99, 170, 58, 99, 68, 228, 229, 19, 239, 185, 98, 88, 199, 103, 106, 196, 137, 89, 83, 98, 157, 64, 154, 131, 36, 114, 183, 16, 160, 40, 40, 93, 254, 196, 115, 58, 44, 27, 176, 162, 116, 158, 70, 90, 24, 41, 43, 139, 214, 1];
let verify = crypto::secp256k1_verify(sig, pk, msg);
assert!(verify == false, 0)
}
}

0 comments on commit 0ab65ca

Please sign in to comment.