ComingChat Team MoveCTF Competition Full Marks Answer Sharing

ComingChat
4 min readNov 8, 2022

The MoveCTF, a major Move security competition sponsored by Sui and hosted by MoveBit, has ended. three participants from the ComingChat team answered all the questions correctly and all received perfect scores!

Check out the competition score rankings:

The following are the full-scoring answers to the competition questions provided by the ComingChat team:

Question 1:

/ SPDX-License-Identifier: Apache-2.0
// Based on: https://github.com/starcoinorg/starcoin-framework-commons/blob/main/sources/PseudoRandom.move
/// @title pseudorandom
/// @notice A pseudo random module on-chain.
/// @dev Warning:
/// The random mechanism in smart contracts is different from
/// that in traditional programming languages. The value generated
/// by random is predictable to Miners, so it can only be used in
/// simple scenarios where Miners have no incentive to cheat. If
/// large amounts of money are involved, DO NOT USE THIS MODULE to
/// generate random numbers; try a more secure way.
module 0x0::test {
use std::hash;
use std::vector;
use sui::bcs;
use sui::tx_context::TxContext;
use game::hero::{Hero, level_up};
use game::adventure::{slay_boar, slay_boar_king};
use sui::object;
use game::inventory::{get_flag, TreasuryBox};
const ERR_HIGH_ARG_GREATER_THAN_LOW_ARG: u64 = 101;
public fun vector_slice<T: copy>(vec: &vector<T>, start: u64, end: u64): vector<T> {
let slice = vector::empty<T>();
let i = start;
while (i < end) {
vector::push_back(&mut slice, *vector::borrow(vec, i));
i = i + 1;
};
slice
}
public fun vector_to_u64(d: &vector<u8>): u64 {
let i = 0;
let m = 0;
let len = vector::length(d);
while (i < vector::length(d)) {
m = (m << 8) + ((*vector::borrow(d, len - 1 - i)) as u64);
i = i + 1;
};
m
}
public fun u64_to_vector(d: u64): vector<u8> {
bcs::to_bytes(&d)
}
public fun seed(ctx: &mut TxContext, m: u64): vector<u8> {
let ctx_bytes = bcs::to_bytes(ctx);
let tx_hash = vector_slice(&ctx_bytes, 21, 21 + ((*vector::borrow(&ctx_bytes, 20)) as u64));
let len = vector::length(&ctx_bytes);
let created_vector = vector_slice(&ctx_bytes, len - 8, len);
let created_num = vector_to_u64(&created_vector) + m;
let created_vector = u64_to_vector(created_num);
assert!(created_vector == u64_to_vector(created_num), 1);
let data = vector::empty<u8>();
vector::append(&mut data, vector_slice(&ctx_bytes, 0, len - 8));
vector::append(&mut data, created_vector);
let ctx_bytes = data;
let info: vector<u8> = vector::empty<u8>();
vector::append<u8>(&mut info, tx_hash);
vector::append<u8>(&mut info, created_vector);
let uid_bytes = vector_slice(&hash::sha3_256(info), 0, 20);
let info: vector<u8> = vector::empty<u8>();
vector::append<u8>(&mut info, ctx_bytes);
vector::append<u8>(&mut info, uid_bytes);
let hash: vector<u8> = hash::sha3_256(info);
hash
}
fun bytes_to_u64(bytes: vector<u8>): u64 {
let value = 0u64;
let i = 0u64;
while (i < 8) {
value = value | ((*vector::borrow(&bytes, i) as u64) << ((8 * (7 - i)) as u8));
i = i + 1;
};
return value
}
/// Generate a random u64
fun rand_u64_with_seed(_seed: vector<u8>): u64 {
bytes_to_u64(_seed)
}
/// Generate a random integer range in [low, high).
fun rand_u64_range_with_seed(_seed: vector<u8>, low: u64, high: u64): u64 {
assert!(high > low, ERR_HIGH_ARG_GREATER_THAN_LOW_ARG);
let value = rand_u64_with_seed(_seed);
(value % (high - low)) + low
}
/// Generate a random u64
public fun rand_u64(ctx: &mut TxContext): u64 {
rand_u64_with_seed(seed(ctx, 0))
}
/// Generate a random integer range in [low, high).
public fun rand_u64_range(low: u64, high: u64, ctx: &mut TxContext): u64 {
rand_u64_range_with_seed(seed(ctx, 0), low, high)
}
public entry fun win(hero: &mut Hero, ctx: &mut TxContext) {
let i = 0;
while (i < 125) {
slay_boar(hero, ctx);
i = i + 1;
};
level_up(hero);
let next = next_zero_rand_u64_range(0, 100, ctx) - 4;
while (next > 0) {
object::delete(object::new(ctx));
next = next - 1;
};
slay_boar_king(hero, ctx);
}
public fun next_zero_rand_u64_range(low: u64, high: u64, ctx: &mut TxContext): u64 {
let next = 0;
while (true) {
let data = rand_u64_range_with_seed(seed(ctx, next), low, high);
if ((data == 0) && (next >= 4)) {
break
};
next = next + 1;
};
next
}
public entry fun win_flag(box: TreasuryBox, ctx: &mut TxContext) {
let next = next_zero_rand_u64_range(0, 100, ctx);
while (next > 0) {
object::delete(object::new(ctx));
next = next - 1;
};
get_flag(box, ctx);
}
}

Question 2:

module 0x0::test {
use sui::tx_context::TxContext;
use movectf::flash::{loan, FlashLender, deposit, check, withdraw, get_flag};
entry fun fight(
self: &mut FlashLender,
ctx: &mut TxContext
) {
let (coins, receipt) = loan(self, 1000, ctx);
deposit(self, coins, ctx);
check(self, receipt);
withdraw(self, 1000, ctx);
get_flag(self, ctx)
}
}

Question 3:

module 0x0::test {
use sui::tx_context::TxContext;
use movectf::move_lock::{
movectf_unlock, get_flag, ResourceObject
};
entry fun fight(
r: &mut ResourceObject,
ctx: &mut TxContext
) {
let data1 = vector<u64>[
2, 14, 13,
6, 17, 0,
19, 20, 11,
0, 19, 8,
14, 13, 18,
24, 14, 20,
12, 0, 13,
0, 6, 4,
3, 19, 14,
1, 17, 4,
0, 10, 19,
7, 4, 7,
8, 11, 11,
2, 8, 15,
7, 4, 17,
7, 0, 2,
10, 19, 7,
4, 7, 0,
2, 10, 24,
15, 11, 0,
13, 4, 19
];
let data2 = vector<u64>[25, 11, 6, 10, 13, 25, 12, 19, 2];
movectf_unlock(data1, data2, r, ctx);
get_flag(r, ctx)
}
}

About ComingChat

ComingChat is a SocialFi-based Web3 portal application with #DeFi and #GameFi functions.

In ComingChat, SocialFi means the collection of the following three:
1. Decentralized Account System (CID)
2. Payment tool (omnichain wallet)
3. Social system (Chat+DAO Moments)
The above solves the three problems of “people”, “money”, and “connection”respectively, and provides the basis for DeFi and GameFi.

Website | Twitter | Medium | Telegram

--

--

ComingChat

ComingChat is a lifestyle tool in the age of #web3 and #AI. It bridges #Web3( @SuiNetwork ) and ChatGPT( @OpenAI ), allowing users to leverage their advantages.