Compare commits

...

11 Commits

Author SHA1 Message Date
bzp99 7047793fd2
update README 2022-12-07 10:32:59 +01:00
bzp99 b04dc83ae1
Add RMRK proposal 2022-12-07 09:22:15 +01:00
bzp99 1737245885
rename kusamaverse proposal directory 2022-12-07 09:22:15 +01:00
jazzysnake 1911680b62 Merge branch 'main' of https://git.hsbp.org/BMEta/solutions 2022-12-07 08:51:50 +01:00
jazzysnake e14f77b5fa skeleton 2022-12-07 08:51:05 +01:00
bzp99 69cfe72035
Factor more potentially offline operations out of JS code 2022-12-07 08:39:40 +01:00
jazzysnake 86f5bae9b5 kusamaverse proposal 2022-12-07 08:35:51 +01:00
Bazsalanszky 82eb729ae2
Merge remote-tracking branch 'origin/frontend' 2022-12-07 06:05:36 +01:00
ProMate04 de8b6dae44 FAVICON 2022-12-07 05:24:28 +01:00
ProMate04 2c1c360de3 Basics of the Kusamaverse Proposal 2022-12-07 05:13:48 +01:00
Bazsalanszky dfb39edb99
Better UI elements 2022-12-07 03:36:09 +01:00
11 changed files with 378 additions and 86 deletions

View File

@ -2,6 +2,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins { plugins {
kotlin("jvm") version "1.7.10" kotlin("jvm") version "1.7.10"
id("org.jetbrains.compose") version "1.2.1"
application application
} }
@ -10,9 +11,12 @@ version = "1.0-SNAPSHOT"
repositories { repositories {
mavenCentral() mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
google()
} }
dependencies { dependencies {
implementation(compose.desktop.currentOs)
testImplementation(kotlin("test")) testImplementation(kotlin("test"))
} }
@ -24,6 +28,8 @@ tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8" kotlinOptions.jvmTarget = "1.8"
} }
application { application {
mainClass.set("MainKt") mainClass.set("MainKt")
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -1,69 +1,115 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<title>Flag Submission Page</title> <title>Flag Submission Page</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script src="dist/bundle.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.6.1/web3.min.js" integrity="sha512-5erpERW8MxcHDF7Xea9eBQPiRtxbse70pFcaHJuOhdEBQeAxGQjUwgJbuBDWve+xP/u5IoJbKjyJk50qCnMD7A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body style="height:1500px">
<nav class="navbar navbar-inverse navbar-fixed-top"> <!--<script src="dist/bundle.js"></script>-->
<div class="container-fluid"> </head>
<div class="navbar-header"> <body style="height:1500px">
<a class="navbar-brand" href="#">Flag Submission Page</a>
</div>
<ul class="nav navbar-nav">
<li><a href="leaderboard.html">Leaderboard</a></li>
<li class="active"><a href="sendflag.html">Send Flag</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><button class="btn btn-default navbar-btn" id="metamask-login" type="button" style="margin-right:20px"><span class="glyphicon glyphicon-log-in"></span> Connect Wallet</button></li> <nav class="navbar navbar-inverse navbar-fixed-top">
<!--<button class="btn btn-danger navbar-btn">Button</button>--> <div class="container-fluid">
</ul> <div class="navbar-header">
</div> <a class="navbar-brand" href="#">Flag Submission Page</a>
</nav> </div>
<ul class="nav navbar-nav">
<li>
<a href="leaderboard.html">Leaderboard</a>
</li>
<li class="active">
<a href="sendflag.html">Send Flag</a>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<div class="container" style="margin-top:50px"> <li>
<h1>Send the flag</h1> <button class="btn btn-default navbar-btn" id="metamask-login" type="button" style="margin-right:20px">
<form class="form-inline" id="flag-form" style="display:none"> <span class="glyphicon glyphicon-log-in"></span>
<div class="form-group"> Connect Wallet</button>
<label for="flagbox">Flag:</label> </li>
<input type="text" class="form-control" id="flagbox"> <!--<button class="btn btn-danger navbar-btn">Button</button>-->
</div> </ul>
<button id="submitFlagBtn" type="button" class="btn btn-default">Submit Flag</button> </div>
</form> </nav>
</div>
<script type='module'> <div class="container" style="margin-top:50px">
window.addEventListener("load", function () { <h1>Send the flag</h1>
let loginbutton = document.getElementById('metamask-login'); <form class="form-inline" id="flag-form" style="display:none">
let accounts; <div class="form-group">
ethereum.request({method: 'eth_requestAccounts'}).then(accounts => { <label for="flagbox">Flag id:</label>
console.log(accounts); <input type="number" class="form-control" id="flagID">
if (accounts.length > 0) { </div>
document.getElementById('flag-form').style.display = "block"; <div class="form-group">
loginbutton.textContent = accounts[0]; <label for="flagbox">Proof:</label>
loginbutton.disabled = true; <input type="text" class="form-control" id="flagbox">
} </div>
}); <button id="submitFlagBtn" type="button" class="btn btn-default btn-warning">Submit Flag</button>
}); </form>
</div>
let loginbutton = document.getElementById('metamask-login'); <script type='module'>
loginbutton.addEventListener('click', event => { var web3js;
let account; var accounts;
ethereum.request({method: 'eth_requestAccounts'}).then(accounts =>{ const contractAddress = "0x970e1d481CEDbeaeFE776275F0d1b4E1B301bB3b";
account = accounts[0]; window.addEventListener("load", function () {
document.getElementById('flag-form').style.display = "block"; let loginbutton = document.getElementById('metamask-login');
loginbutton.textContent = account;
loginbutton.disabled = true;
})
})
</script>
</body> ethereum.request({method: 'eth_requestAccounts'}).then(acc => {
console.log(acc);
accounts = acc;
if (acc.length > 0) {
document.getElementById('flag-form').style.display = "block";
loginbutton.textContent = accounts[0];
loginbutton.disabled = true;
}
});
});
let loginbutton = document.getElementById('metamask-login');
loginbutton.addEventListener('click', event => {
let account;
ethereum.request({method: 'eth_requestAccounts'}).then(accounts => {
account = accounts[0];
document.getElementById('flag-form').style.display = "block";
loginbutton.textContent = account;
loginbutton.disabled = true;
})
})
let flagID = document.getElementById('flagID');
let flagbox = document.getElementById('flagbox');
let submitFlagBtn = document.getElementById('submitFlagBtn');
submitFlagBtn.addEventListener('click', event => {
contract.methods.SubmitFlag(JSON.parse(flagbox.value),flagID.value).send( { from: accounts[0] });
})
var contactABI;
var contract;
async function getAbi() {
fetch("/abi.json").then(a => a.json().then(abi => {
contactABI = abi
contract = new web3js.eth.Contract(contactABI, contractAddress);
}));
}
window.addEventListener("load", function () {
if (typeof web3 !== "undefined") {
web3js = new Web3(web3.currentProvider);
// console.log(web3);
getAbi();
} else {
console.log("No web3? You should consider trying MetaMask!");
}
});
</script>
</body>
</html> </html>

View File

@ -1,6 +1,13 @@
import sha256 from 'crypto-js/sha256.js'; import sha256 from 'crypto-js/sha256.js';
import { initialize } from 'zokrates-js'; import { initialize } from 'zokrates-js';
window.addEventListener('load', () => {
document.getElementById('submitFlagBtn')
.addEventListener('click', () => {
submitFlag(document.getElementById('flagbox').value);
});
});
const ZEROSTR = '0'; const ZEROSTR = '0';
/* Converts a string into a stringified hexadecimal number */ /* Converts a string into a stringified hexadecimal number */
@ -54,25 +61,15 @@ function expand_number(number) {
return [...Array(8 - parts.length).fill(ZEROSTR), ...parts]; return [...Array(8 - parts.length).fill(ZEROSTR), ...parts];
} }
const proving_key = await (await fetch('/zok_proving.key')).text();
/* Hard coded zokrates program source code */ const program = await (await fetch('/zok_program')).arrayBuffer();
const zokSrc = ` const abi = await (await fetch('/zok_abi.json')).json();
import "hashes/sha256/sha256Padded.zok" as sha256;
from "utils/casts.zok" import cast;
def main(public u32[8] hash,public u32[5] address,private u8[64] flag){
u8[20] addr8 = cast(address);
u32[8] genHash = sha256(flag);
log("Hash: {} {} {} {} {} {} {} {}",genHash[0],genHash[1],genHash[2],genHash[3],genHash[4],genHash[5],genHash[6],genHash[7]);
assert(genHash == hash);
return;
}
`;
/* Get the proving key from the local server */ /* Get the proving key from the local server */
const PROVING_KEY_URI = 'http://localhost:8080/proving.key'; const PROVING_KEY_URI = 'http://localhost:8080/proving.key';
const proving_key = await (await fetch(PROVING_KEY_URI)).text(); const proving_key = await (await fetch(PROVING_KEY_URI)).text();
const artefacts = { program: new Uint8Array(program), abi: abi };
console.log(artefacts);
function submitFlag(flag) { function submitFlag(flag) {
initialize().then((defaultProvider) => { initialize().then((defaultProvider) => {
@ -81,8 +78,6 @@ function submitFlag(flag) {
scheme: 'gm17', scheme: 'gm17',
}); });
const artefacts = zokProvider.compile(zokSrc);
const flag_ascii = str2asciiarr(flag); const flag_ascii = str2asciiarr(flag);
const flag_ascii_padded = flag_ascii.concat(new Array(64 - flag_ascii.length).fill(0)); const flag_ascii_padded = flag_ascii.concat(new Array(64 - flag_ascii.length).fill(0));
const flag_padded = asciiarr2str(flag_ascii_padded); const flag_padded = asciiarr2str(flag_ascii_padded);
@ -96,15 +91,13 @@ function submitFlag(flag) {
const addr_split = map_0xprefix(addr.match(/.{1,8}/g)); const addr_split = map_0xprefix(addr.match(/.{1,8}/g));
// witness computation // witness computation
console.log('witness');
const { witness, output } = zokProvider.computeWitness(artefacts, [hash_split, addr_split, flag_split_padded]); const { witness, output } = zokProvider.computeWitness(artefacts, [hash_split, addr_split, flag_split_padded]);
// generate proof // generate proof
console.log('proof');
const proof = zokProvider.generateProof(artefacts.program, witness, proving_key); const proof = zokProvider.generateProof(artefacts.program, witness, proving_key);
console.log(proof); console.log(proof);
}); });
} };
document.getElementById('submitFlagBtn').addEventListener('click', () => {
submitFlag(document.getElementById('flagbox').value);
});

View File

@ -0,0 +1,37 @@
{
"inputs": [
{
"name": "hash",
"public": true,
"type": "array",
"components": {
"size": 8,
"type": "u32"
}
},
{
"name": "address",
"public": true,
"type": "array",
"components": {
"size": 5,
"type": "u32"
}
},
{
"name": "flag",
"public": false,
"type": "array",
"components": {
"size": 64,
"type": "u8"
}
}
],
"output": {
"type": "tuple",
"components": {
"elements": []
}
}
}

Binary file not shown.

View File

@ -1,8 +1,94 @@
package hu.bmeta.cctf package hu.bmeta.cctf
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.*
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
fun main() { fun main() {
Zokrates.initZokrates()
application {
Window(
onCloseRequest = ::exitApplication,
title = "ZoKrates CTF Proof generator",
state = rememberWindowState(width = 300.dp, height = 300.dp)
) {
val count = remember { mutableStateOf(0) }
val address = remember { mutableStateOf("") }
val flag = remember { mutableStateOf("") }
val enabled = remember { mutableStateOf(true) }
MaterialTheme {
Column(Modifier.fillMaxSize().padding(5.dp), Arrangement.spacedBy(5.dp)) {
Text("ZoKrates Proof generator")
OutlinedTextField(address.value, {
address.value = it
}, placeholder = {
Text("Address")
})
OutlinedTextField(flag.value, {
flag.value = it
}, placeholder = {
Text("Flag")
})
Button(modifier = Modifier.align(Alignment.CenterHorizontally),
onClick = {
enabled.value = false
val address_ch = address.value.replace("0x","").chunked(8).map { java.lang.Long.parseLong(it.uppercase(),16).toString() }
val message = flag.value.map { it.code.toByte().toInt().toString() }.toMutableList()
for (i in 0 until 64 - message.size) {
message.add("0")
}
val hashArgs = mutableListOf<String>()
hashArgs.addAll(address_ch)
hashArgs.addAll(message)
GlobalScope.launch(Dispatchers.IO) {
Zokrates.compile("hash.zok","hash")
val result = Zokrates.computeWithness(hashArgs,"hash")
println(result)
val zkpArgs = mutableListOf<String>()
zkpArgs.addAll(result)
zkpArgs.addAll(address_ch)
zkpArgs.addAll(message)
Zokrates.compile("root.zok")
val results2 = Zokrates.computeWithness(zkpArgs)
println(results2)
Zokrates.generateProof(scheme = Zokrates.ProvingScheme.GM17)
println("Proof done!")
}
enabled.value = true
}, enabled = enabled.value) {
Text("Generate Proof!")
}
if(enabled.value.not()){
CircularProgressIndicator()
}
}
}
}
}
}
/*fun main() {
val address = listOf("1530452586","1880905349","1172110512","1070303071","1455349188") val address = listOf("1530452586","1880905349","1172110512","1070303071","1455349188")
val message = listOf("104","116","116","112","115","58","47","47","119","119","119","46","121","111","117","116","117","98","101","46","99","111","109","47","119","97","116","99","104","63","118","61","100","81","119","52","119","57","87","103","88","99","81","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0") val message = mutableListOf("116", "101", "115","116","0")
val random = Random()
for(i in 0 until 64-message.size){
message.add("0")
}
Zokrates.initZokrates() Zokrates.initZokrates()
Zokrates.compile("hash.zok","hash") Zokrates.compile("hash.zok","hash")
val hashArgs = mutableListOf<String>() val hashArgs = mutableListOf<String>()
@ -23,4 +109,4 @@ fun main() {
Zokrates.generateProof(scheme = Zokrates.ProvingScheme.GM17) Zokrates.generateProof(scheme = Zokrates.ProvingScheme.GM17)
Zokrates.verify() Zokrates.verify()
} }*/

View File

@ -0,0 +1,54 @@
# Kusamaverse Proposal
- Authors: {Péter Bertalan, Nagymarosi Máté, Toldi Balázs, Debreczeni Máté}
- Status: {Draft}
- Created: {2022-12-07}
## Summary
Our first proposal is to create more comprehensive learning materials, because we found the
UX clarity to be somewhat lacking. It shall convey the values and objectives of the platform
clearly. Kusamaverse needs to improve its authentication and authorization capabilities.
## Motivation
In our experience, Kusamaverse is hard to understand for new users. The user's first impressions are
important, but in the current version it is formed by marketing materials and forms. The user is not
presented with what the platform provides and how it can be used.
## Specification
proposed changes:
1. Game-like guided learning experience
2. Guide/Mascot character
3. Written materials, stories, and resources
4. The integration of authorization and authentication
### 1. Game-like guided learning experience
Most games start with a introductory quest, which eases the player into the in-game environment.
Kusamaverse would greatly benefit from such an addition. The user would receive valuable context
via a story told by an "in-game" character.
### 2. Guide/Mascot character
A fun mascot that could introduce the player to the Kusamaverse environment. It would always
be avaliable to offer guidance, especially during the first steps. Instead of forms, initial
user preferences could be attained through conversation with the mascot. The objective is to
make the process as fun as possible.
### 3. Written materials, stories, resources
Even after deliberate searching, information about the Kusamaverse was hard to find. For those
that are interested in the background, easily digestable materials should be made more avaliable.
### 4. The integration of authorization and authentication
To the best of our knowledge, currently there is no way to ensure that only select people can
attend a space. Collaboration can be enhanced by limiting unwanted access, which can degrade
the experience.

23
README.md 100644
View File

@ -0,0 +1,23 @@
# BMEta solutions
## Proposals
### 1. Kusamaverse
Our proposal focuses on usability and UX.
It can be found [here](./Kusamaverse_Proposal).
### 2. RMRK
We propose a few [improvements and enhancements ](./RMRK_Proposal) to
the ticketing sytem use case of RMRK.
## Main track: CCTF
We were presented with a vulnerable Capture The Flag
smart contract, which we fixed by the help of ZKPs.
Using ZKPs allows some unique features and it could
help provide the community with new and exciting
ways to organize CTF events. The solution can be found
[here](./CCTF_Solutions_main).

View File

@ -0,0 +1,47 @@
# RMRK Proposal
- Authors: {Péter Bertalan, Nagymarosi Máté, Toldi Balázs, Debreczeni Máté}
- Status: {Draft}
- Created: {2022-12-07}
## Summary
The RMRK documentation currently includes a use case description of a
ticketing system, built on revealable and multi-resource NFTs.
We extend this application with a few additional ideas that take
advantage of RMRKs toolbox.
## Motivation
Classic solutions to ticketing come with their drawbacks. RMRK offers
new and versatile building blocks for making NFTs more powerful and
rich, while also eliminating a lot of the downsides. However, one aspect
not addressed by the current draft is scalping. Scalping is the practice
of buying large amounts of a scarce asset to resell it at a higher
price. Even centralized systems struggle to combat this issue. Our
proposal offers a possible mitigation.
## Specification
### Multi-use tickets
Instead of following the traditional scheme of one ticket per event, a
ticket could possibly be valid for a number of select or arbitrary
events. In this case, ticket validation would entail verifying a counter
or the presence of a specific PoA besides the secret keyword.
### A loyalty system
Dedicated fans deserve extra perks for their support. Our proposal
utilizes multi-resource NFTs to enable customers to attain a collection
of PoAs as part of a single NFT. This could be used to set up the basis
of a loyalty system. Owners of such collections would be able to
participate in presales, ensuring that they dont miss out on their
favourite event.
### Scalping mitigation
The loyalty system outlined already offers some level of protection
against scalpers, but we would further enhance this with the use of
Verifiable Credentials. These could be issued by a trusted organization
and the amount of tickets per capita could be limited.