import sha256 from 'crypto-js/sha256.js'; import { initialize } from 'zokrates-js'; const ZEROSTR = '0'; /* Converts a string into a stringified hexadecimal number */ function str2hex(string) { return string.split('') .map(c => c.charCodeAt(0).toString(16).padStart(2, '0')) .join(''); } /* Converts a stringified hexadecimal number into a string */ function hex2str(hex) { return hex.split(/(\w\w)/g) .filter(p => !!p) .map(c => String.fromCharCode(parseInt(c, 16))) .join(''); } /* Prefix each element of a string a array with 0x */ function map_0xprefix(arr) { return arr.map(s => '0x' + s); } /* Convert a string to a byte array */ function str2asciiarr(s) { let charCodeArr = []; for (let i = 0; i < s.length; i++) { let code = s.charCodeAt(i); charCodeArr.push(code); } return charCodeArr; } /* Convert a byte array to a string */ function asciiarr2str(arr) { return String.fromCharCode(...arr); } /* * Expand a simple number into a stringified u32[8] array for ZoKrates. */ function expand_number(number) { const revstr = s => Array.from(s).reverse().join(''); const split8 = s => s.match(/.{1,8}/g); const parts = split8(revstr(number.toString(16))) .map(p => '0x' + revstr(p)) .map(p => parseInt(p, 16).toString()) .reverse(); return [...Array(8 - parts.length).fill(ZEROSTR), ...parts]; } /* Hard coded zokrates program source code */ const zokSrc = ` 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 */ const PROVING_KEY_URI = 'http://localhost:8080/proving.key'; const proving_key = await (await fetch(PROVING_KEY_URI)).text(); function submitFlag(flag) { initialize().then((defaultProvider) => { const zokProvider = defaultProvider.withOptions({ backend: 'ark', scheme: 'gm17', }); const artefacts = zokProvider.compile(zokSrc); const flag_ascii = str2asciiarr(flag); const flag_ascii_padded = flag_ascii.concat(new Array(64 - flag_ascii.length).fill(0)); const flag_padded = asciiarr2str(flag_ascii_padded); const hash = sha256(flag_padded).toString(); /* TODO get this from contract */ const addr = 'f6e3a49fca2eb57f286d516fa60154ebfd10d5ad'; /* TODO get this from metamask */ const flag_split = map_0xprefix(str2hex(flag).match(/.{1,2}/g)); const flag_split_padded = flag_split.concat(new Array(64 - flag_split.length).fill('0x0')); const hash_split = map_0xprefix(hash.match(/.{1,8}/g)); const addr_split = map_0xprefix(addr.match(/.{1,8}/g)); // witness computation const { witness, output } = zokProvider.computeWitness(artefacts, [hash_split, addr_split, flag_split_padded]); // generate proof const proof = zokProvider.generateProof(artefacts.program, witness, proving_key); console.log(proof); }); } document.getElementById('submitFlagBtn').addEventListener('click', () => { submitFlag(document.getElementById('flagbox').value); });