66 lines
4.7 KiB
HTML
66 lines
4.7 KiB
HTML
|
<!DOCTYPE html>
|
||
|
<html>
|
||
|
<head>
|
||
|
<meta charset="utf-8"/>
|
||
|
<title>CryptoCTF zero-knowledge flag-submission encoder v0.5</title>
|
||
|
<script type="text/javascript" src="bn.js"></script>
|
||
|
<script type="text/javascript" src="nano-ethereum-signer-mod.js"></script>
|
||
|
</head>
|
||
|
|
||
|
<body>
|
||
|
|
||
|
<label for="inp-contestant-address">contestant's address:</label> <input id="inp-contestant-address" type="text" size="42" maxlength="42" pattern="0x[0-9a-fA-F]{40}" required placeholder="0x0000000000000000000000000000000000000000" autocomplete="cryptocurrency address" title="The cryptocurrency address of the contestant who is submitting the flag. It will be used as the message that is signed using an ECDSA signature scheme. It is incorporated to prevent submission forgery and theft. The resulting signature will be accepted by the CCTF smart-contract from only this address."/> <input id="inp-only-checksum-address" type="checkbox" checked autocomplete="checksum address" title="As an optional mechanism for protection against typos in the contestant's address field, this control panel can be set to reject an address value that fails the checksum test."/> <label for="inp-only-checksum-address">only accept correct checksum address</label><br/>
|
||
|
<label for="inp-flag">flag:</label> <input id="inp-flag" type="text" size="48" pattern="CCTF\{[ -~]*\}" required placeholder="CCTF{…}" autocomplete="flag" title="The flag for the challenge in question: a piece of data that can be found through solving the problem. It can be an outstanding character sequence of the form CCTF{…} that can be stumbled upon; otherwise its location/calculation (e.g. the deciphered message) and its formatting (e.g. hexadecimal) are precisely specified, and formatting always includes enclosing by CCTF{…}. The flag will be used as the secret key for signing using an ECDSA signature scheme." accesskey="f"/> <label for="outp-obscured-flag">⇒ obscured flag: </label><input id="outp-obscured-flag" type="text" size="42" maxlength="42" readonly title="The obscured flag: data to allow zero-knowledge verification of knowledge of the flag. It is the elliptic-curve public key related to the flag as the private key. It is the thing to be loaded into the CCTF smart-contract for the respective challenge."/><br />
|
||
|
<label for="outp-signature">⇒ signature: </label><input id="outp-signature" type="text" size="132" maxlength="132" readonly title="The signature: a zero-knowledge proof of knowledge of the flag, bound to the given address. It's an ECDSA signature of the address as the message (hash) with the flag as the key. It is to be passed to the CCTF smart-contract's flag submission function."/><!--<br />
|
||
|
<label for="inp-contract-address">CCTF smart-contract address:</label> <input id="inp-contract-address" type="text" size="42" maxlength="42" pattern="0x[0-9a-fA-F]{40}" placeholder="0x0000000000000000000000000000000000000000"/><br/>
|
||
|
<label for="inp-contest-id">contest ID:</label> <input id="inp-contest-id" type="text" size="66" pattern="0x[0-9a-fA-F]+|[0-9]+" placeholder="0x0000000000000000000000000000000000000000000000000000000000000000"/><br/>
|
||
|
<label for="inp-challenge-id">challenge ID:</label> <input id="inp-challenge-id" type="integer" size="4" placeholder="0" accesskey="c"/>-->
|
||
|
|
||
|
<script type="text/javascript">
|
||
|
var inpContestantAddress = document.querySelector("#inp-contestant-address");
|
||
|
var inpOnlyChecksumAddress = document.querySelector("#inp-only-checksum-address");
|
||
|
var inpFlag = document.querySelector("#inp-flag");
|
||
|
var outpObscuredFlag = document.querySelector("#outp-obscured-flag");
|
||
|
var outpSignature = document.querySelector("#outp-signature");
|
||
|
var secp256k1n = new BN('115792089237316195423570985008687907852837564279074904382605163141518161494337', 10);
|
||
|
|
||
|
function getPrivateKey() {
|
||
|
var s = inpFlag.value;
|
||
|
var h = "0x";
|
||
|
if (s.slice(0, 5) !== "CCTF{" || s.slice(-1) !== "}")
|
||
|
return null;
|
||
|
for (i in s) {
|
||
|
var c = s.charCodeAt(i);
|
||
|
if (c < 32 || c > 126)
|
||
|
return null;
|
||
|
h += c.toString(16).padStart(2, "0");
|
||
|
}
|
||
|
return "0x" + new BN(keccak256(h).slice(2), 16).mod(secp256k1n.sub(new BN(1))).add(new BN(1)).toString(16).padStart(64, 0);
|
||
|
}
|
||
|
|
||
|
function updateOutputValues(ev) {
|
||
|
var k = getPrivateKey();
|
||
|
if (k === null) {
|
||
|
outpObscuredFlag.value = "";
|
||
|
outpSignature.value = "";
|
||
|
} else {
|
||
|
outpObscuredFlag.value = addressFromKey(k);
|
||
|
var m = inpContestantAddress.value;
|
||
|
if (!/^0x[0-9a-fA-F]{40}$/.test(m) || inpOnlyChecksumAddress.checked && m !== addressChecksum(m)) {
|
||
|
outpSignature.value = "";
|
||
|
} else {
|
||
|
outpSignature.value = signMessage(m, k);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inpContestantAddress.oninput = updateOutputValues;
|
||
|
inpOnlyChecksumAddress.oninput = updateOutputValues;
|
||
|
inpFlag.oninput = updateOutputValues;
|
||
|
|
||
|
updateOutputValues();
|
||
|
</script>
|
||
|
|
||
|
</body>
|
||
|
</html>
|