Skip to content

Commit

Permalink
finish task8
Browse files Browse the repository at this point in the history
  • Loading branch information
JasonRUAN committed Dec 7, 2024
1 parent eeac265 commit 3934583
Show file tree
Hide file tree
Showing 14 changed files with 1,250 additions and 0 deletions.
79 changes: 79 additions & 0 deletions mover/JasonRUAN/code/task8/calc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { bcs, fromHex, toHex } from '@mysten/bcs';
import { sha3_256 } from '@noble/hashes/sha3';

// Address type for 32-byte addresses
const Address = bcs.bytes(32).transform({
input: (val: string) => fromHex(val),
output: (val) => toHex(val),
});

// UID type for 32-byte unique identifiers
const UID = bcs.fixedArray(32, bcs.u8()).transform({
input: (id: string) => fromHex(id),
output: (id) => toHex(Uint8Array.from(id)),
});

// Test sender address
const sender = '0x77083d27beec05358aff1356c1826fc582ae381440c028646b817705aabca3a8';
const senderBytes = Address.serialize(sender).toBytes();

// Challenge struct definition
const ChallengeStruct = bcs.struct('Challenge', {
id: UID,
str: bcs.string(),
difficulity: bcs.u64(),
ture_num: bcs.u64(),
});

// Test challenge data
const challengeBytes = ChallengeStruct.serialize({
id: '0x19e76ca504c5a5fa5e214a45fca6c058171ba333f6da897b82731094504d5ab9',
str: "]c:_}|)[iB'G*$p1E\"$",
difficulity: 3,
ture_num: 100,
}).toBytes();

/**
* Calculates proof of work by finding a number that results in a hash with specific properties
* @param maxAttempts Maximum number of attempts before giving up
* @returns The proof number if found, null otherwise
*/
function calculateProof(maxAttempts = 10000000): number | null {
const targetPrefixSum = 0;
const prefixLength = 3;

for (let attempts = 1; attempts <= maxAttempts; attempts++) {
// Generate random proof between 0 and 100M
const proof = Math.floor(Math.random() * 100000000);

if (attempts % 1000 === 0) {
console.log(`Attempt ${attempts}: ${proof}`);
}

const proofBytes = bcs.u64().serialize(proof).toBytes();

// Combine all components for hashing
const combined = new Uint8Array([...proofBytes, ...senderBytes, ...challengeBytes]);
const hash = sha3_256(combined);

// Calculate prefix sum of first N bytes
const prefix_sum = hash
.slice(0, prefixLength)
.reduce((sum, byte) => sum + byte, 0);

if (prefix_sum === targetPrefixSum) {
console.log(`Success! Found proof after ${attempts} attempts: ${proof}`);
console.log(`Proof bytes: [${proofBytes.toString()}]`);
return proof;
}
}

console.error(`Failed to find proof after ${maxAttempts} attempts`);
return null;
}

// Execute proof calculation
calculateProof();

// Success! Found proof after 7158758 attempts: 5860720
// Proof bytes: [112,109,89,0,0,0,0,0]
78 changes: 78 additions & 0 deletions mover/JasonRUAN/code/task8/call.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { bcs, fromBase64 } from "@mysten/bcs";
import { getFullnodeUrl, SuiClient } from "@mysten/sui/dist/cjs/client";
import { Transaction } from "@mysten/sui/transactions";
import { execSync } from "child_process";
import { readFileSync } from "fs";
import { homedir } from "os";
import path from "path";
import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";

export const getAddressByAlias = (alias: string): string => {
const str = execSync(`sui client switch --address ${alias}`, {
encoding: "utf8",
}).trim();

const regex = /Active address switched to (\S+)/;
const match = str.match(regex);

return match ? match[1] : "";
};

export const getSigner = (alias: string) => {
const sender = getAddressByAlias(alias);

const keystore = JSON.parse(
readFileSync(
path.join(homedir(), ".sui", "sui_config", "sui.keystore"),
"utf8"
)
);

for (const priv of keystore) {
const raw = fromBase64(priv);
if (raw[0] !== 0) {
continue;
}

const pair = Ed25519Keypair.fromSecretKey(raw.slice(1));
if (pair.getPublicKey().toSuiAddress() === sender) {
return pair;
}
}

throw new Error(`keypair not found for sender: ${sender}`);
};

async function call() {
const rpcUrl = getFullnodeUrl("testnet");
const client = new SuiClient({ url: rpcUrl });

const pkgId =
"0x097a3833b6b5c62ca6ad10f0509dffdadff7ce31e1d86e63e884a14860cedc0f";
const moduleName = "lets_move";
const funcName = "get_flag";

const tx = new Transaction();

tx.moveCall({
target: `${pkgId}::${moduleName}::${funcName}`,

arguments: [
tx.pure(bcs.vector(bcs.u8()).serialize([112, 109, 89, 0, 0, 0, 0, 0])),
tx.pure.string("JasonRUAN"),
tx.object(
"0x19e76ca504c5a5fa5e214a45fca6c058171ba333f6da897b82731094504d5ab9"
),
tx.object("0x8"),
],
});

const signer = getSigner("JasonRUAN");
const result = await client.signAndExecuteTransaction({
signer,
transaction: tx,
});
return result;
}

call().then(console.log).catch(console.error);
26 changes: 26 additions & 0 deletions mover/JasonRUAN/code/task8/contract/lets_move/Move.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# @generated by Move, please check-in and do not edit manually.

[move]
version = 3
manifest_digest = "786B91A5B97E30CFE4109DB806C7FDAA208AD34906C77AB899770D4D0AEB5DB1"
deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082"
dependencies = [
{ id = "Sui", name = "Sui" },
]

[[move.package]]
id = "MoveStdlib"
source = { git = "https://github.com/MystenLabs/sui.git", rev = "framework/testnet", subdir = "crates/sui-framework/packages/move-stdlib" }

[[move.package]]
id = "Sui"
source = { git = "https://github.com/MystenLabs/sui.git", rev = "framework/testnet", subdir = "crates/sui-framework/packages/sui-framework" }

dependencies = [
{ id = "MoveStdlib", name = "MoveStdlib" },
]

[move.toolchain-version]
compiler-version = "1.39.0"
edition = "2024.beta"
flavor = "sui"
37 changes: 37 additions & 0 deletions mover/JasonRUAN/code/task8/contract/lets_move/Move.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[package]
name = "lets_move"
edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move
# license = "" # e.g., "MIT", "GPL", "Apache 2.0"
# authors = ["..."] # e.g., ["Joe Smith ([email protected])", "John Snow ([email protected])"]

[dependencies]
Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/testnet" }

# For remote import, use the `{ git = "...", subdir = "...", rev = "..." }`.
# Revision can be a branch, a tag, and a commit hash.
# MyRemotePackage = { git = "https://some.remote/host.git", subdir = "remote/path", rev = "main" }

# For local dependencies use `local = path`. Path is relative to the package root
# Local = { local = "../path/to" }

# To resolve a version conflict and force a specific version for dependency
# override use `override = true`
# Override = { local = "../conflicting/version", override = true }

[addresses]
lets_move = "0x0"

# Named addresses will be accessible in Move as `@name`. They're also exported:
# for example, `std = "0x1"` is exported by the Standard Library.
# alice = "0xA11CE"

[dev-dependencies]
# The dev-dependencies section allows overriding dependencies for `--test` and
# `--dev` modes. You can introduce test-only dependencies here.
# Local = { local = "../path/to/dev-build" }

[dev-addresses]
# The dev-addresses section allows overwriting named addresses for the `--test`
# and `--dev` modes.
# alice = "0xB0B"

Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
module lets_move::lets_move {
use std::ascii::{String, string};
use std::hash;
use sui::event;
use sui::bcs;
use sui::random;
use sui::random::Random;
use sui::transfer::share_object;

const EPROOF: u64 = 0;

public struct Flag has copy, drop {
sender: address,
flag: bool,
ture_num: u64,
github_id: String
}

public struct Challenge has key {
id: UID,
str: String,
difficulity: u64,
ture_num: u64
}

fun init(ctx: &mut TxContext) {
let flag_str = Challenge {
id: object::new(ctx),
str: string(b"LetsMoveCTF"),
difficulity: 3,
ture_num: 0,
};
share_object(flag_str);
}


entry fun get_flag(
proof: vector<u8>,
github_id: String,
challenge: &mut Challenge,
rand: &Random,
ctx: &mut TxContext
) {
let mut full_proof: vector<u8> = vector::empty<u8>();
vector::append<u8>(&mut full_proof, proof);
vector::append<u8>(&mut full_proof, tx_context::sender(ctx).to_bytes());
vector::append<u8>(&mut full_proof, bcs::to_bytes(challenge));

let hash: vector<u8> = hash::sha3_256(full_proof);

let mut prefix_sum: u32 = 0;
let mut i: u64 = 0;
while (i < challenge.difficulity) {
prefix_sum = prefix_sum + (*vector::borrow(&hash, i) as u32);
i = i + 1;
};

assert!(prefix_sum == 0, EPROOF);

challenge.str = getRandomString(rand, ctx);
challenge.ture_num = challenge.ture_num + 1;

event::emit(Flag {
sender: tx_context::sender(ctx),
flag: true,
ture_num: challenge.ture_num,
github_id
});
}


fun getRandomString(rand: &Random, ctx: &mut TxContext): String {
let mut gen = random::new_generator(rand, ctx);

let mut str_len = random::generate_u8_in_range(&mut gen, 4, 30);

let mut rand: vector<u8> = b"";
while (str_len != 0) {
let rand_num = random::generate_u8_in_range(&mut gen, 34, 126);
vector::push_back(&mut rand, rand_num);
str_len = str_len - 1;
};

string(rand)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
#[test_only]
module lets_move::lets_move_tests;
// uncomment this line to import the module
// use lets_move::lets_move;
const ENotImplemented: u64 = 0;
#[test]
fun test_lets_move() {
// pass
}
#[test, expected_failure(abort_code = ::lets_move::lets_move_tests::ENotImplemented)]
fun test_lets_move_fail() {
abort ENotImplemented
}
*/
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 3934583

Please sign in to comment.