From f04bb286099fe79e3317ab9323d00ccd3ab2286a Mon Sep 17 00:00:00 2001 From: wmpadmin Date: Wed, 28 Mar 2018 19:27:27 +0200 Subject: [PATCH] cleaning --- SDK/aeon/miner_compressed/mine.html | 68 + SDK/aeon/miner_compressed/miner.js | 38 + SDK/aeon/miner_raw/mine.html | 68 + SDK/aeon/miner_raw/miner/cn.js | 1 + SDK/aeon/miner_raw/miner/miner.js | 205 ++ SDK/aeon/miner_raw/miner/worker.js | 86 + SDK/aeon/other/getpools.html | 47 + SDK/aeon/other/getuserstats.html | 47 + SDK/aeon/other/register.html | 52 + SDK/xmr/miner_compressed/mine.html | 68 + SDK/xmr/miner_compressed/miner.js | 38 + SDK/xmr/miner_raw/mine.html | 67 + SDK/xmr/miner_raw/miner/cn.js | 1 + SDK/xmr/miner_raw/miner/miner.js | 205 ++ SDK/xmr/miner_raw/miner/worker.js | 86 + SDK/xmr/other/getpools.html | 47 + SDK/xmr/other/getuserstats.html | 47 + SDK/xmr/other/register.html | 52 + webassembly/aeon/Makefile | 24 + webassembly/aeon/base64.h | 258 +++ webassembly/aeon/blake.c | 341 +++ webassembly/aeon/blake.h | 14 + webassembly/aeon/cn.html | 152 ++ webassembly/aeon/cryptonight.c | 454 ++++ webassembly/aeon/cryptonight.h | 15 + webassembly/aeon/groestl.c | 393 ++++ webassembly/aeon/groestl.h | 16 + webassembly/aeon/groestl_tables.h | 38 + .../aeon/html_template/shell_minimal.html | 146 ++ webassembly/aeon/int-util.h | 245 ++ webassembly/aeon/jh.h | 16 + webassembly/aeon/jh_ansi_opt64.c | 377 +++ webassembly/aeon/keccak.c | 129 ++ webassembly/aeon/keccak.h | 23 + webassembly/aeon/license.txt | 39 + webassembly/aeon/main.c | 53 + webassembly/aeon/oaes_config.h | 50 + webassembly/aeon/oaes_lib.c | 1414 ++++++++++++ webassembly/aeon/oaes_lib.h | 214 ++ webassembly/aeon/skein.c | 2047 +++++++++++++++++ webassembly/aeon/skein.h | 15 + webassembly/aeon/skein_port.h | 179 ++ webassembly/xmr/Makefile | 28 + webassembly/xmr/base64.h | 258 +++ webassembly/xmr/blake.c | 341 +++ webassembly/xmr/blake.h | 14 + webassembly/xmr/cn.html | 152 ++ webassembly/xmr/cryptonight.c | 505 ++++ webassembly/xmr/cryptonight.h | 15 + webassembly/xmr/groestl.c | 393 ++++ webassembly/xmr/groestl.h | 16 + webassembly/xmr/groestl_tables.h | 38 + .../xmr/html_template/shell_minimal.html | 146 ++ webassembly/xmr/int-util.h | 245 ++ webassembly/xmr/jh.h | 16 + webassembly/xmr/jh_ansi_opt64.c | 377 +++ webassembly/xmr/keccak.c | 129 ++ webassembly/xmr/keccak.h | 23 + webassembly/xmr/license.txt | 39 + webassembly/xmr/main.c | 53 + webassembly/xmr/oaes_config.h | 50 + webassembly/xmr/oaes_lib.c | 1414 ++++++++++++ webassembly/xmr/oaes_lib.h | 214 ++ webassembly/xmr/skein.c | 2047 +++++++++++++++++ webassembly/xmr/skein.h | 15 + webassembly/xmr/skein_port.h | 179 ++ 66 files changed, 14582 insertions(+) create mode 100644 SDK/aeon/miner_compressed/mine.html create mode 100644 SDK/aeon/miner_compressed/miner.js create mode 100644 SDK/aeon/miner_raw/mine.html create mode 100644 SDK/aeon/miner_raw/miner/cn.js create mode 100644 SDK/aeon/miner_raw/miner/miner.js create mode 100644 SDK/aeon/miner_raw/miner/worker.js create mode 100644 SDK/aeon/other/getpools.html create mode 100644 SDK/aeon/other/getuserstats.html create mode 100644 SDK/aeon/other/register.html create mode 100644 SDK/xmr/miner_compressed/mine.html create mode 100644 SDK/xmr/miner_compressed/miner.js create mode 100644 SDK/xmr/miner_raw/mine.html create mode 100644 SDK/xmr/miner_raw/miner/cn.js create mode 100644 SDK/xmr/miner_raw/miner/miner.js create mode 100644 SDK/xmr/miner_raw/miner/worker.js create mode 100644 SDK/xmr/other/getpools.html create mode 100644 SDK/xmr/other/getuserstats.html create mode 100644 SDK/xmr/other/register.html create mode 100644 webassembly/aeon/Makefile create mode 100644 webassembly/aeon/base64.h create mode 100644 webassembly/aeon/blake.c create mode 100644 webassembly/aeon/blake.h create mode 100644 webassembly/aeon/cn.html create mode 100644 webassembly/aeon/cryptonight.c create mode 100644 webassembly/aeon/cryptonight.h create mode 100644 webassembly/aeon/groestl.c create mode 100644 webassembly/aeon/groestl.h create mode 100644 webassembly/aeon/groestl_tables.h create mode 100644 webassembly/aeon/html_template/shell_minimal.html create mode 100644 webassembly/aeon/int-util.h create mode 100644 webassembly/aeon/jh.h create mode 100644 webassembly/aeon/jh_ansi_opt64.c create mode 100644 webassembly/aeon/keccak.c create mode 100644 webassembly/aeon/keccak.h create mode 100644 webassembly/aeon/license.txt create mode 100644 webassembly/aeon/main.c create mode 100644 webassembly/aeon/oaes_config.h create mode 100644 webassembly/aeon/oaes_lib.c create mode 100644 webassembly/aeon/oaes_lib.h create mode 100644 webassembly/aeon/skein.c create mode 100644 webassembly/aeon/skein.h create mode 100644 webassembly/aeon/skein_port.h create mode 100644 webassembly/xmr/Makefile create mode 100644 webassembly/xmr/base64.h create mode 100644 webassembly/xmr/blake.c create mode 100644 webassembly/xmr/blake.h create mode 100644 webassembly/xmr/cn.html create mode 100644 webassembly/xmr/cryptonight.c create mode 100644 webassembly/xmr/cryptonight.h create mode 100644 webassembly/xmr/groestl.c create mode 100644 webassembly/xmr/groestl.h create mode 100644 webassembly/xmr/groestl_tables.h create mode 100644 webassembly/xmr/html_template/shell_minimal.html create mode 100644 webassembly/xmr/int-util.h create mode 100644 webassembly/xmr/jh.h create mode 100644 webassembly/xmr/jh_ansi_opt64.c create mode 100644 webassembly/xmr/keccak.c create mode 100644 webassembly/xmr/keccak.h create mode 100644 webassembly/xmr/license.txt create mode 100644 webassembly/xmr/main.c create mode 100644 webassembly/xmr/oaes_config.h create mode 100644 webassembly/xmr/oaes_lib.c create mode 100644 webassembly/xmr/oaes_lib.h create mode 100644 webassembly/xmr/skein.c create mode 100644 webassembly/xmr/skein.h create mode 100644 webassembly/xmr/skein_port.h diff --git a/SDK/aeon/miner_compressed/mine.html b/SDK/aeon/miner_compressed/mine.html new file mode 100644 index 0000000..fda960b --- /dev/null +++ b/SDK/aeon/miner_compressed/mine.html @@ -0,0 +1,68 @@ + + + + + + +
+
+ + +
+ +
+ + + + + + + + + diff --git a/SDK/aeon/miner_compressed/miner.js b/SDK/aeon/miner_compressed/miner.js new file mode 100644 index 0000000..0670133 --- /dev/null +++ b/SDK/aeon/miner_compressed/miner.js @@ -0,0 +1,38 @@ +var server="wss://webminerpool.com:8282/",job=null,workers=[],ws,receiveStack=[],sendStack=[],totalhashes=0,connected=0,reconnector=0,timerId=0,throttleMiner=0,handshake=null;function addWorkers(k){logicalProcessors=k;if(-1==k){try{logicalProcessors=window.navigator.hardwareConcurrency}catch(u){logicalProcessors=4}0logicalProcessors||(logicalProcessors=4)}for(;0connected&&(connected=2);job=null};ws.onclose=function(){2>connected&&(connected=2);job=null};ws.onopen=function(){ws.send(JSON.stringify(handshake));connected=1}};reconnector=function(){3!==connected&&(null==ws||0!==ws.readyState&&1!==ws.readyState)&&openWebSocket()}; +function startMiningWithId(k,u,q){u=void 0===u?-1:u;q=void 0===q?"":q;stopMining();connected=0;handshake={identifier:"handshake",loginid:k,userid:q,version:3};addWorkers(u);reconnector();timerId=setInterval(reconnector,1E4)}function startMining(k,u,q,C,H){q=void 0===q?"":q;C=void 0===C?-1:C;H=void 0===H?"":H;stopMining();connected=0;handshake={identifier:"handshake",pool:k,login:u,password:q,userid:H,version:3};addWorkers(C);reconnector();timerId=setInterval(reconnector,1E4)} +function stopMining(){connected=3;0!=timerId&&clearInterval(timerId);null!=ws&&ws.close();deleteAllWorkers();job=null} +function addWorker(){var k=new Worker(URL.createObjectURL(new Blob(["("+function(){function k(b){x(!Z);var a=y;y=y+b+15&-16;return a}function q(b){x(z);var a=l[z>>2];b=a+b+15&-16;l[z>>2]=b;return b>=A?(Q(),l[z>>2]=a,0):a}function C(b,a){a||(a=16);return Math.ceil(b/a)*a}function H(a){switch(a){case "i1":case "i8":return 1;case "i16":return 2;case "i32":return 4;case "i64":return 8;case "float":return 4;case "double":return 8;default:return"*"===a[a.length-1]?4:"i"===a[0]?(a=parseInt(a.substr(1)), +x(0===a%8),a/8):0}}function x(a,d){a||B("Assertion failed: "+d)}function aa(b){var d=a["_"+b];x(d,"Cannot call unknown function "+b+", make sure it is exported");return d}function ba(a,d,c,e,g){g=aa(a);var b=[];a=0;if(e)for(var f=0;f>0];b|=e;if(0==e&&!d)break;g++;if(d&&g==d)break}d||(d=g);e="";if(128> +b){for(;0h?g+=String.fromCharCode(h):(h-=65536,g+=String.fromCharCode(55296|h>>10,56320|h&1023))}}else g+=String.fromCharCode(h)}}return b}function fa(a,d,c,e){if(!(0=f&&(f=65536+((f&1023)<<10)|a.charCodeAt(++h)&1023);if(127>=f){if(c>=e)break;d[c++]=f}else{if(2047>=f){if(c+1>=e)break;d[c++]=192|f>>6}else{if(65535>=f){if(c+2>=e)break;d[c++]= +224|f>>12}else{if(2097151>=f){if(c+3>=e)break;d[c++]=240|f>>18}else{if(67108863>=f){if(c+4>=e)break;d[c++]=248|f>>24}else{if(c+5>=e)break;d[c++]=252|f>>30;d[c++]=128|f>>24&63}d[c++]=128|f>>18&63}d[c++]=128|f>>12&63}d[c++]=128|f>>6&63}d[c++]=128|f&63}}d[c]=0;return c-b}function ha(){a.HEAP8=K=new Int8Array(n);a.HEAP16=I=new Int16Array(n);a.HEAP32=l=new Int32Array(n);a.HEAPU8=v=new Uint8Array(n);a.HEAPU16=new Uint16Array(n);a.HEAPU32=new Uint32Array(n);a.HEAPF32=ia=new Float32Array(n);a.HEAPF64=ja= +new Float64Array(n)}function Q(){B("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+A+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}function L(b){for(;0>2]=0;for(a=c+h;e>0]=0;return c}if("i8"===f)return a.subarray||a.slice?v.set(a,c):v.set(new Uint8Array(a),c),c;e=0;for(var m,p;e>0]=n;break;case "i8":K[w>>0]=n;break;case "i16":I[w>>1]=n;break;case "i32":l[w>>2]=n;break;case "i64":tempI64=[n>>>0,(tempDouble=n,1<=+xa(tempDouble)?0>>0:~~+ya((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)];l[w>>2]=tempI64[0];l[w+4>>2]=tempI64[1];break;case "float":ia[w>>2]=n;break;case "double":ja[w>> +3]=n;break;default:B("invalid type for setValue: "+r)}p!==b&&(m=H(b),p=b);e+=m}}return c}(function(a,d,c){if(!(0=g&&(g=65536+((g&1023)<<10)|a.charCodeAt(++b)&1023);127>=g?++c:c=2047>=g?c+2:65535>=g?c+3:2097151>=g?c+4:67108863>=g?c+5:c+6}c+=1}c=Array(c);a=fa(a,c,0,c.length);d&&(c.length=a);return c}("GMT"),"i8",2);z=k(4);p=P=C(y);m=C(p+m);l[z>>2]=m;Z=!0;var ta=!1,ua="function"===typeof atob?atob:function(a){var b="",c=0;a=a.replace(/[^A-Za-z0-9\+\/=]/g, +"");do{var e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a.charAt(c++));var g="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a.charAt(c++));var h="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a.charAt(c++));var f="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a.charAt(c++));e=e<<2|g>>4;g=(g&15)<<4|h>>2;var k=(h&3)<<6|f;b+=String.fromCharCode(e);64!==h&&(b+=String.fromCharCode(g)); +64!==f&&(b+=String.fromCharCode(k))}while(c>2]=b);return b},___syscall20:function(a,d){return 42},_emscripten_memcpy_big:function(a,d,c){v.set(v.subarray(d,d+c),a);return a},_ftime:function(a){var b=Date.now();l[a>>2]=b/1E3|0;I[a+4>>1]= +b%1E3;I[a+6>>1]=0;return I[a+8>>1]=0},_gmtime:function(a){a=new Date(1E3*l[a>>2]);l[t>>2]=a.getUTCSeconds();l[t+4>>2]=a.getUTCMinutes();l[t+8>>2]=a.getUTCHours();l[t+12>>2]=a.getUTCDate();l[t+16>>2]=a.getUTCMonth();l[t+20>>2]=a.getUTCFullYear()-1900;l[t+24>>2]=a.getUTCDay();l[t+36>>2]=0;l[t+32>>2]=0;var b=Date.UTC(a.getUTCFullYear(),0,1,0,0,0,0);a=(a.getTime()-b)/864E5|0;l[t+28>>2]=a;l[t+40>>2]=Da;return t},DYNAMICTOP_PTR:z,STACKTOP:P};m=a.asm(a.asmGlobalArg,a.asmLibraryArg,n);a.asm=m;a._hash_cn= +function(){return a.asm._hash_cn.apply(null,arguments)};var qa=a._malloc=function(){return a.asm._malloc.apply(null,arguments)},X=a.stackAlloc=function(){return a.asm.stackAlloc.apply(null,arguments)},da=a.stackRestore=function(){return a.asm.stackRestore.apply(null,arguments)},ca=a.stackSave=function(){return a.asm.stackSave.apply(null,arguments)};a.asm=m;a.ccall=ba;a.cwrap=function(a,d,c){c=c||[];var b=aa(a),g=c.every(function(a){return"number"===a});return"string"!==d&&g?b:function(){return ba(a, +d,c,arguments)}};N.prototype=Error();N.prototype.constructor=N;O=function d(){a.calledRun||S();a.calledRun||(O=d)};a.run=S;a.exit=function(d,c){if(!c||!a.noExitRuntime||0!==d){if(!a.noExitRuntime&&(T=!0,P=void 0,L(wa),a.onExit))a.onExit(d);E&&process.exit(d);a.quit(d,new N(d))}};a.abort=B;if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0workers.length||workers.shift().terminate()}function deleteAllWorkers(){for(i=0;i + + + + + +
+
+ + +
+ +
+ + + + + + + + + diff --git a/SDK/aeon/miner_raw/miner/cn.js b/SDK/aeon/miner_raw/miner/cn.js new file mode 100644 index 0000000..d7dd212 --- /dev/null +++ b/SDK/aeon/miner_raw/miner/cn.js @@ -0,0 +1 @@ +var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}Module["arguments"]=[];Module["thisProgram"]="./this.program";Module["quit"]=(function(status,toThrow){throw toThrow});Module["preRun"]=[];Module["postRun"]=[];var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;if(Module["ENVIRONMENT"]){if(Module["ENVIRONMENT"]==="WEB"){ENVIRONMENT_IS_WEB=true}else if(Module["ENVIRONMENT"]==="WORKER"){ENVIRONMENT_IS_WORKER=true}else if(Module["ENVIRONMENT"]==="NODE"){ENVIRONMENT_IS_NODE=true}else if(Module["ENVIRONMENT"]==="SHELL"){ENVIRONMENT_IS_SHELL=true}else{throw new Error("Module['ENVIRONMENT'] value is not valid. must be one of: WEB|WORKER|NODE|SHELL.")}}else{ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof require==="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER;ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER}if(ENVIRONMENT_IS_NODE){var nodeFS;var nodePath;Module["read"]=function shell_read(filename,binary){var ret;ret=tryParseAsDataURI(filename);if(!ret){if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);ret=nodeFS["readFileSync"](filename)}return binary?ret:ret.toString()};Module["readBinary"]=function readBinary(filename){var ret=Module["read"](filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){Module["thisProgram"]=process["argv"][1].replace(/\\/g,"/")}Module["arguments"]=process["argv"].slice(2);if(typeof module!=="undefined"){module["exports"]=Module}process["on"]("uncaughtException",(function(ex){if(!(ex instanceof ExitStatus)){throw ex}}));process["on"]("unhandledRejection",(function(reason,p){process["exit"](1)}));Module["inspect"]=(function(){return"[Emscripten Module object]"})}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){Module["read"]=function shell_read(f){var data=tryParseAsDataURI(f);if(data){return intArrayToString(data)}return read(f)}}Module["readBinary"]=function readBinary(f){var data;data=tryParseAsDataURI(f);if(data){return data}if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){Module["arguments"]=scriptArgs}else if(typeof arguments!="undefined"){Module["arguments"]=arguments}if(typeof quit==="function"){Module["quit"]=(function(status,toThrow){quit(status)})}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){Module["read"]=function shell_read(url){try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText}catch(err){var data=tryParseAsDataURI(url);if(data){return intArrayToString(data)}throw err}};if(ENVIRONMENT_IS_WORKER){Module["readBinary"]=function readBinary(url){try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}catch(err){var data=tryParseAsDataURI(url);if(data){return data}throw err}}}Module["readAsync"]=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}var data=tryParseAsDataURI(url);if(data){onload(data.buffer);return}onerror()};xhr.onerror=onerror;xhr.send(null)};if(typeof arguments!="undefined"){Module["arguments"]=arguments}Module["setWindowTitle"]=(function(title){document.title=title})}Module["print"]=typeof console!=="undefined"?console.log.bind(console):typeof print!=="undefined"?print:null;Module["printErr"]=typeof printErr!=="undefined"?printErr:typeof console!=="undefined"&&console.warn.bind(console)||Module["print"];Module.print=Module["print"];Module.printErr=Module["printErr"];for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=undefined;var STACK_ALIGN=16;function staticAlloc(size){assert(!staticSealed);var ret=STATICTOP;STATICTOP=STATICTOP+size+15&-16;return ret}function dynamicAlloc(size){assert(DYNAMICTOP_PTR);var ret=HEAP32[DYNAMICTOP_PTR>>2];var end=ret+size+15&-16;HEAP32[DYNAMICTOP_PTR>>2]=end;if(end>=TOTAL_MEMORY){var success=enlargeMemory();if(!success){HEAP32[DYNAMICTOP_PTR>>2]=ret;return 0}}return ret}function alignMemory(size,factor){if(!factor)factor=STACK_ALIGN;var ret=size=Math.ceil(size/factor)*factor;return ret}function getNativeTypeSize(type){switch(type){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return 4}else if(type[0]==="i"){var bits=parseInt(type.substr(1));assert(bits%8===0);return bits/8}else{return 0}}}}var functionPointers=new Array(0);var GLOBAL_BASE=1024;var ABORT=0;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function getCFunc(ident){var func=Module["_"+ident];assert(func,"Cannot call unknown function "+ident+", make sure it is exported");return func}var JSfuncs={"stackSave":(function(){stackSave()}),"stackRestore":(function(){stackRestore()}),"arrayToC":(function(arr){var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}),"stringToC":(function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){var len=(str.length<<2)+1;ret=stackAlloc(len);stringToUTF8(str,ret,len)}return ret})};var toC={"string":JSfuncs["stringToC"],"array":JSfuncs["arrayToC"]};function ccall(ident,returnType,argTypes,args,opts){var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble- +(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}var ALLOC_STATIC=2;var ALLOC_NONE=4;function allocate(slab,types,allocator,ptr){var zeroinit,size;if(typeof slab==="number"){zeroinit=true;size=slab}else{zeroinit=false;size=slab.length}var singleType=typeof types==="string"?types:null;var ret;if(allocator==ALLOC_NONE){ret=ptr}else{ret=[typeof _malloc==="function"?_malloc:staticAlloc,stackAlloc,staticAlloc,dynamicAlloc][allocator===undefined?ALLOC_STATIC:allocator](Math.max(size,singleType?1:types.length))}if(zeroinit){var stop;ptr=ret;assert((ret&3)==0);stop=ret+(size&~3);for(;ptr>2]=0}stop=ret+size;while(ptr>0]=0}return ret}if(singleType==="i8"){if(slab.subarray||slab.slice){HEAPU8.set(slab,ret)}else{HEAPU8.set(new Uint8Array(slab),ret)}return ret}var i=0,type,typeSize,previousType;while(i>0];hasUtf|=t;if(t==0&&!length)break;i++;if(length&&i==length)break}if(!length)length=i;var ret="";if(hasUtf<128){var MAX_CHUNK=1024;var curr;while(length>0){curr=String.fromCharCode.apply(String,HEAPU8.subarray(ptr,ptr+Math.min(length,MAX_CHUNK)));ret=ret?ret+curr:curr;ptr+=MAX_CHUNK;length-=MAX_CHUNK}return ret}return UTF8ToString(ptr)}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(u8Array,idx){var endPtr=idx;while(u8Array[endPtr])++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var u0,u1,u2,u3,u4,u5;var str="";while(1){u0=u8Array[idx++];if(!u0)return str;if(!(u0&128)){str+=String.fromCharCode(u0);continue}u1=u8Array[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}u2=u8Array[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u3=u8Array[idx++]&63;if((u0&248)==240){u0=(u0&7)<<18|u1<<12|u2<<6|u3}else{u4=u8Array[idx++]&63;if((u0&252)==248){u0=(u0&3)<<24|u1<<18|u2<<12|u3<<6|u4}else{u5=u8Array[idx++]&63;u0=(u0&1)<<30|u1<<24|u2<<18|u3<<12|u4<<6|u5}}}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}}function UTF8ToString(ptr){return UTF8ArrayToString(HEAPU8,ptr)}function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){if(outIdx>=endIdx)break;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=2097151){if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=67108863){if(outIdx+4>=endIdx)break;outU8Array[outIdx++]=248|u>>24;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+5>=endIdx)break;outU8Array[outIdx++]=252|u>>30;outU8Array[outIdx++]=128|u>>24&63;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){++len}else if(u<=2047){len+=2}else if(u<=65535){len+=3}else if(u<=2097151){len+=4}else if(u<=67108863){len+=5}else{len+=6}}return len}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;var WASM_PAGE_SIZE=65536;var ASMJS_PAGE_SIZE=16777216;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBuffer(buf){Module["buffer"]=buffer=buf}function updateGlobalBufferViews(){Module["HEAP8"]=HEAP8=new Int8Array(buffer);Module["HEAP16"]=HEAP16=new Int16Array(buffer);Module["HEAP32"]=HEAP32=new Int32Array(buffer);Module["HEAPU8"]=HEAPU8=new Uint8Array(buffer);Module["HEAPU16"]=HEAPU16=new Uint16Array(buffer);Module["HEAPU32"]=HEAPU32=new Uint32Array(buffer);Module["HEAPF32"]=HEAPF32=new Float32Array(buffer);Module["HEAPF64"]=HEAPF64=new Float64Array(buffer)}var STATIC_BASE,STATICTOP,staticSealed;var STACK_BASE,STACKTOP,STACK_MAX;var DYNAMIC_BASE,DYNAMICTOP_PTR;STATIC_BASE=STATICTOP=STACK_BASE=STACKTOP=STACK_MAX=DYNAMIC_BASE=DYNAMICTOP_PTR=0;staticSealed=false;function abortOnCannotGrowMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}function enlargeMemory(){abortOnCannotGrowMemory()}var TOTAL_STACK=Module["TOTAL_STACK"]||5242880;var TOTAL_MEMORY=Module["TOTAL_MEMORY"]||67108864;if(TOTAL_MEMORY0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__);runtimeExited=true}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}var Math_abs=Math.abs;var Math_cos=Math.cos;var Math_sin=Math.sin;var Math_tan=Math.tan;var Math_acos=Math.acos;var Math_asin=Math.asin;var Math_atan=Math.atan;var Math_atan2=Math.atan2;var Math_exp=Math.exp;var Math_log=Math.log;var Math_sqrt=Math.sqrt;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_pow=Math.pow;var Math_imul=Math.imul;var Math_fround=Math.fround;var Math_round=Math.round;var Math_min=Math.min;var Math_max=Math.max;var Math_clz32=Math.clz32;var Math_trunc=Math.trunc;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}function integrateWasmJS(){var wasmTextFile="";var wasmBinaryFile="data:application/octet-stream;base64,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AwNAIAIoAgAiASAEKAIASQR/IAIgAUEBajYCACABLQAABSAAEAoLIgFBUGpBCkkgA6xCUHwgB0IKfnwiB0Kuj4XXx8LrowFTcQRAIAEhAwwBCwsLIAFBUGpBCkkEQANAIAIoAgAiASAEKAIASQR/IAIgAUEBajYCACABLQAABSAAEAoLIgFBUGpBCkkNAAsLIAQoAgAEQCACIAIoAgBBf2o2AgALQgAgB30hCCAFBEAgCCEHCwsgBwtVAAJAIAAEQAJAAkACQAJAAkACQCABQX5rDgYAAQIDBQQFCyAAIAI8AAAMBgsgACACPQEADAULIAAgAj4CAAwECyAAIAI+AgAMAwsgACACNwMACwsLC4YRAQJ+AkACQAJAAkAgAL0iAkI0iCIDp0H/D3EOgBAAAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQILIAEgAEQAAAAAAAAAAGIEfyAARAAAAAAAAPBDoiABECUhACABKAIAQUBqBUEACzYCAAwCCwwBCyABIAOnQf8PcUGCeGo2AgAgAkL/////////h4B/g0KAgICAgICA8D+EvyEACyAACxAAIAAEfyAAIAEQRwVBAAsL2gMDAX8BfgF8AkAgAUEUTQRAAkACQAJAAkACQAJAAkACQAJAAkACQCABQQlrDgoAAQIDBAUGBwgJCgsgAigCAEEDakF8cSIBKAIAIQMgAiABQQRqNgIAIAAgAzYCAAwLCyACKAIAQQNqQXxxIgEoAgAhAyACIAFBBGo2AgAgACADrDcDAAwKCyACKAIAQQNqQXxxIgEoAgAhAyACIAFBBGo2AgAgACADrTcDAAwJCyACKAIAQQdqQXhxIgEpAwAhBCACIAFBCGo2AgAgACAENwMADAgLIAIoAgBBA2pBfHEiASgC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iDwA3gEgAyAHQhCIPADdASADIAdCGIg8ANwBIAMgB0IgiDwA2wEgAyAHQiiIPADaASADIAdCMIg8ANkBIAMgB0I4iDwA2AEgAxAcCwJAAkACQAJAAkAgAygCAEGgfmoiAEEFdiAAQRt0cg4KAAEEBAQCBAQEAwQLIAIgA0GEAWoiACkAADcAACACIAApAAg3AAggAiAAKQAQNwAQIAIgACgAGDYAGCADJAYPCyACIANBgAFqIgApAAA3AAAgAiAAKQAINwAIIAIgACkAEDcAECACIAApABg3ABggAyQGDwsgAiADQfAAaiIAKQAANwAAIAIgACkACDcACCACIAApABA3ABAgAiAAKQAYNwAYIAIgACkAIDcAICACIAApACg3ACggAyQGDwsgAiADQeAAaiIAKQAANwAAIAIgACkACDcACCACIAApABA3ABAgAiAAKQAYNwAYIAIgACkAIDcAICACIAApACg3ACggAiAAKQAwNwAwIAIgACkAODcAOCADJAYPCyADJAYL4wsBCX8jBiEDIwZB0AJqJAYgA0IANwIAIANCADcCCCADQgA3AhAgA0IANwIYIANCADcCICADQgA3AiggA0IANwIwIANBADYCOCADQTxqIgtBgIAENgIAIANBiAFqIgVBADYCACADQcAAaiIGQQA2AgAgA0HEAGoiBEEANgIAIANBjAFqIgdBADYCACADIAAgAUH/////AXEiCBAeIAFBwP///wFxIgEgCEkEQANAIAAgAWosAAAhCSAFIAUoAgAiCkEBajYCACADQcgAaiAKaiAJOgAAIAFBAWoiASAIRw0ACwsgBygCACIBBEAgAyAFKAIAakHHAGoiAEEBIAF0QX9qQQggAWt0IAAtAABxOgAAIAMgBSgCAGpBxwBqIgBBAUEHIAcoAgBrdCAALQAAczoAACAHQQA2AgAFIAUgBSgCACIAQQFqNgIAIANByABqIABqQYB/OgAACwJAAkAgBSgCACIAQThKBEAgAEHAAEgEQANAIAUgAEEBajYCACADQcgAaiAAakEAOgAAIAUoAgAiAEHAAEgNAAsLIAMgA0HIAGpBwAAQHiAFQQA2AgBBACEADAEFIABBOEcNAQsMAQsDQCAFIABBAWo2AgAgA0HIAGogAGpBADoAACAFKAIAIgBBOEgNAAsLIAYgBigCAEEBaiIBNgIAIAFFBEAgBCAEKAIAQQFqNgIACyAFQcAANgIAQcAAIQADQCAFIABBf2oiADYCACADQcgAaiAAaiABOgAAIAFBCHYhASAFKAIAIgBBPEoNAAsgBiABNgIAIABBOEoEQCAEKAIAIQEDQCAFIABBf2oiADYCACADQcgAaiAAaiABOgAAIAFBCHYhASAFKAIAIgBBOEoNAAsgBCABNgIACyADIANByABqQcAAEB4gA0GQAmoiBCADKQIANwIAIAQgAykCCDcCCCAEIAMpAhA3AhAgBCADKQIYNwIYIAQgAykCIDcCICAEIAMpAig3AiggBCADKQIwNwIwIAQgAykCODcCOCAEIANB0AFqIgFBABAMIAEgA0GQAWoiAEEBEAwgACABQQIQDCABIABBAxAMIAAgAUEEEAwgASAAQQUQDCAAIAFBBhAMIAEgAEEHEAwgACABQQgQDCABIARBCRAMIAMgAygCACAEKAIAczYCACADQQRqIgAgACgCACAEKAIEczYCACADQQhqIgAgACgCACAEKAIIczYCACADQQxqIgAgACgCACAEKAIMczYCACADQRBqIgAgACgCACAEKAIQczYCACADQRRqIgAgACgCACAEKAIUczYCACADQRhqIgAgACgCACAEKAIYczYCACADQRxqIgAgACgCACAEKAIcczYCACADQSBqIgAoAgAgBCgCIHMhBiAAIAY2AgAgA0EkaiIAKAIAIAQoAiRzIQcgACAHNgIAIANBKGoiACgCACAEKAIocyEIIAAgCDYCACADQSxqIgAoAgAgBCgCLHMhCSAAIAk2AgAgA0EwaiIAKAIAIAQoAjBzIQogACAKNgIAIANBNGoiACgCACAEKAI0cyEBIAAgATYCACADQThqIgAgACgCACAEKAI4czYCACALIAsoAgAgBCgCPHM2AgAgAiAGOgAAIAIgBkEIdjoAASACIAZBEHY6AAIgAiAGQRh2OgADIAIgBzoABCACIAdBCHY6AAUgAiAHQRB2OgAGIAIgB0EYdjoAByACIAg6AAggAiAIQQh2OgAJIAIgCEEQdjoACiACIAhBGHY6AAsgAiAJOgAMIAIgCUEIdjoADSACIAlBEHY6AA4gAiAJQRh2OgAPIAIgCjoAECACIApBCHY6ABEgAiAKQRB2OgASIAIgCkEYdjoAEyACIAE6ABQgAiABQQh2OgAVIAIgAywANjoAFiACIAMsADc6ABcgAiAALAAAOgAYIAIgAywAOToAGSACIAMsADo6ABogAiADLAA7OgAbIAIgCywAADoAHCACIAMsAD06AB0gAiADLAA+OgAeIAIgAywAPzoAHyADJAYLXQEBfyABIABIIAAgASACakhxBEAgASACaiEBIAAiAyACaiEAA0AgAkEASgRAIAJBAWshAiAAQQFrIgAgAUEBayIBLAAAOgAADAELCyADIQAFIAAgASACEBEaCyAACysAIABB/wFxQRh0IABBCHVB/wFxQRB0ciAAQRB1Qf8BcUEIdHIgAEEYdnILYQEFfyAAQdQAaiIEKAIAIgMgAkGAAmoiBRApIgYgA2shByABIAMgBgR/IAcFIAULIgEgAkkEfyABIgIFIAILEBEaIAAgAyACajYCBCAAIAMgAWoiADYCCCAEIAA2AgAgAguIBAIDfwV+IAC9IgZCNIinQf8PcSECIAG9IgdCNIinQf8PcSEEIAZCgICAgICAgICAf4MhCAJ8AkAgB0IBhiIFQgBRDQAgAkH/D0YgAb1C////////////AINCgICAgICAgPj/AFZyDQAgBkIBhiIJIAVYBEAgAEQAAAAAAAAAAKIhASAJIAVRBHwgAQUgAAsPCyACBH4gBkL/////////B4NCgICAgICAgAiEBSAGQgyGIgVCf1UEQEEAIQIDQCACQX9qIQIgBUIBhiIFQn9VDQALBUEAIQILIAZBASACa62GCyIGIAQEfiAHQv////////8Hg0KAgICAgICACIQFIAdCDIYiBUJ/VQRAA0AgA0F/aiEDIAVCAYYiBUJ/VQ0ACwsgB0EBIAMiBGuthgsiB30iBUJ/VSEDAkAgAiAESgRAA0ACQCADBEAgBUIAUQ0BBSAGIQULIAVCAYYiBiAHfSIFQn9VIQMgAkF/aiICIARKDQEMAwsLIABEAAAAAAAAAACiDAMLCyADBEAgAEQAAAAAAAAAAKIgBUIAUQ0CGgUgBiEFCyAFQoCAgICAgIAIVARAA0AgAkF/aiECIAVCAYYiBUKAgICAgICACFQNAAsLIAJBAEoEfiAFQoCAgICAgIB4fCACrUI0hoQFIAVBASACa62ICyAIhL8MAQsgACABoiIAIACjCwvUBgEOfyMGIQMjBkGQAWokBiADQefMp9AGNgIAIANBBGoiCkGF3Z7b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NgIAIAItAAAFIAAQCgsiA0H2zgBqLAAAIgJB/wFxSw0AIAEhAiADIQELBSABIQIgAyEBCwsgAiABQfbOAGotAABLBEADQCACIAQoAgAiASAFKAIASQR/IAQgAUEBajYCACABLQAABSAAEAoLQfbOAGotAABLDQALQcjoAEEiNgIAQQAhCEJ/IQoLCyAFKAIABEAgBCAEKAIAQX9qNgIACyAKIAisIgqFIAp9CwsLmwEBAn8gAEHKAGoiAiwAACEBIAIgAUH/AWogAXI6AAAgAEEUaiIBKAIAIABBHGoiAigCAEsEQCAAQQBBACAAKAIkQQNxEQEAGgsgAEEANgIQIAJBADYCACABQQA2AgAgACgCACIBQQRxBH8gACABQSByNgIAQX8FIAAgACgCLCAAKAIwaiICNgIIIAAgAjYCBCABQRt0QR91CyIAC0ABAX8jBiEBIwZBEGokBiAAEE8Ef0F/BSAAIAFBASAAKAIgQQNxEQEAQQFGBH8gAS0AAAVBfwsLIQAgASQGIAALBgAgACQGC5AlAhd/B34jBiECIwZBgAZqJAYgAkHwAWohESACQeAAaiEDIAJBEGohBiACQQhqIQQgAiIHQbQFaiEFQQAhAgNAIAcgBSACajYCACAAQQAgBxAZIABBAmohACACQQFqIgJBzABHDQALIAQgBUEnajYCACABQQAgBBAZIAYgBUEoajYCACABQQJqQQAgBhAZIAMgBUEpajYCACABQQRqQQAgAxAZIBEgBUEqajYCACABQQZqQQAgERAZQZCDwAAQEyIEQYCDwABqIggQLTYCACARQQBByAEQDxogAyAFKQAANwAAIAMgBSkACDcACCADIAUpABA3ABAgAyAFKQAYNwAYIAMgBSkAIDcAICADIAUpACg3ACggAyAFKQAwNwAwIAMgBSkAODcAOCADIAUpAEA3AEAgAyAFKABINgBIIANBAToATCADQc0AaiIAQgA3AAAgAEIANwAIIABCADcAECAAQgA3ABggAEIANwAgIABCADcAKCAAQgA3ADAgAEEAOwA4IANBgH86AIcBQQAhAANAIBEgAEEDdGogGiADIABBA3RqKQAAhTcDACAAQQFqIgBBEUcEQCARIABBA3RqKQMAIRoMAQsLIBEQMSAEQYCAwABqIhUgEUHIARARGiAEQdCBwABqIgIgBEHAgMAAaiIDKQMANwMAIAIgAykDCDcDCCACIAMpAxA3AxAgAiADKQMYNwMYIAIgAykDIDcDICACIAMpAyg3AyggAiADKQMwNwMwIAIgAykDODcDOCACIAMpA0A3A0AgAiADKQNINwNIIAIgAykDUDcDUCACIAMpA1g3A1ggAiADKQNgNwNgIAIgAykDaDcDaCACIAMpA3A3A3AgAiADKQN4NwN4IAgoAgAgFRAuIARB4IHAAGohBSAEQfCBwABqIQkgBEGAgsAAaiEKIARBkILAAGohCyAEQaCCwABqIQwgBEGwgsAAaiENIARBwILAAGohDkEAIQADQCACIAgoAgAoAgAoAgwiARAJIAUgARAJIAkgARAJIAogARAJIAsgARAJIAwgARAJIA0gARAJIA4gARAJIAIgCCgCACgCACgCDEEQaiIBEAkgBSABEAkgCSABEAkgCiABEAkgCyABEAkgDCABEAkgDSABEAkgDiABEAkgAiAIKAIAKAIAKAIMQSBqIgEQCSAFIAEQCSAJIAEQCSAKIAEQCSALIAEQCSAMIAEQCSANIAEQCSAOIAEQCSACIAgoAgAoAgAoAgxBMGoiARAJIAUgARAJIAkgARAJIAogARAJIAsgARAJIAwgARAJIA0gARAJIA4gARAJIAIgCCgCACgCACgCDEHAAGoiARAJIAUgARAJIAkgARAJIAogARAJIAsgARAJIAwgARAJIA0gARAJIA4gARAJIAIgCCgCACgCACgCDEHQAGoiARAJIAUgARAJIAkgARAJIAogARAJIAsgARAJIAwgARAJIA0gARAJIA4gARAJIAIgCCgCACgCACgCDEHgAGoiARAJIAUgARAJIAkgARAJIAogARAJIAsgARAJIAwgARAJIA0gARAJIA4gARAJIAIgCCgCACgCACgCDEHwAGoiARAJIAUgARAJIAkgARAJIAogARAJIAsgARAJIAwgARAJIA0gARAJIA4gARAJIAIgCCgCACgCACgCDEGAAWoiARAJIAUgARAJIAkgARAJIAogARAJIAsgARAJIAwgARAJIA0gARAJIA4gARAJIAIgCCgCACgCACgCDEGQAWoiARAJIAUgARAJIAkgARAJIAogARAJIAsgARAJIAwgARAJIA0gARAJIA4gARAJIAQgAGoiASACKQAANwAAIAEgAikACDcACCABIAIpABA3ABAg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DEHQAGoiARAJIAUgARAJIAkgARAJIAogARAJIAsgARAJIAwgARAJIA0gARAJIA4gARAJIAIgCCgCACgCACgCDEHgAGoiARAJIAUgARAJIAkgARAJIAogARAJIAsgARAJIAwgARAJIA0gARAJIA4gARAJIAIgCCgCACgCACgCDEHwAGoiARAJIAUgARAJIAkgARAJIAogARAJIAsgARAJIAwgARAJIA0gARAJIA4gARAJIAIgCCgCACgCACgCDEGAAWoiARAJIAUgARAJIAkgARAJIAogARAJIAsgARAJIAwgARAJIA0gARAJIA4gARAJIAIgCCgCACgCACgCDEGQAWoiARAJIAUgARAJIAkgARAJIAogARAJIAsgARAJIAwgARAJIA0gARAJIA4gARAJIABBgAFqIgBBgIDAAEkNAAsgAyACKQMANwMAIAMgAikDCDcDCCADIAIpAxA3AxAgAyACKQMYNwMYIAMgAikDIDcDICADIAIpAyg3AyggAyACKQMwNwMwIAMgAikDODcDOCADIAIpA0A3A0AgAyACKQNINwNIIAMgAikDUDcDUCADIAIpA1g3A1ggAyACKQNgNwNgIAMgAikDaDcDaCADIAIpA3A3A3AgAyACKQN4NwN4IBUQMSAVQcgBIAYgFSwAAEEDcUECdEGAKmooAgBBB3FBBGoRAAAgCCgCACIBBEAgASgCACIABEAgACgCBCICBEAgAhAQIAEoAgBBADYCBCABKAIAIQALIAAoAgwiAgRAIAIQECABKAIAQQA2AgwgASgCACEACyAAEBAgAUEANgIAIAgoAgAhAQsgARAQCyAEEBAgB0G4A2oiACAGLQAANgIAIBEgEUEAIAAQC2ohACAHQcADaiIBIAYtAAE2AgAgACAAQQAgARALaiEAIAdByANqIgEgBi0AAjYCACAAIABBACABEAtqIQAgB0HQA2oiASAGLQADNgIAIAAgAEEAIAEQC2ohACAHQdgDaiIBIAYtAAQ2AgAgACAAQQAgARALaiEAIAdB4ANqIgEgBi0ABTYCACAAIABBACABEAtqIQAgB0HoA2oiASAGLQAGNgIAIAAgAEEAIAEQC2ohACAHQfADaiIBIAYtAAc2AgAgACAAQQAgARALaiEAIAdB+ANqIgEgBi0ACDYCACAAIABBACABEAtqIQAgB0GABGoiASAGLQAJNgIAIAAgAEEAIAEQC2ohACAHQYgEaiIBIAYtAAo2AgAgACAAQQAgARALaiEAIAdBkARqIgEgBi0ACzYCACAAIABBACABEAtqIQAgB0GYBGoiASAGLQAMNgIAIAAgAEEAIAEQC2ohACAHQaAEaiIBIAYtAA02AgAgACAAQQAgARALaiEAIAdBqARqIgEgBi0ADjYCACAAIABBACABEAtqIQAgB0GwBGoiASAGLQAPNgIAIAAgAEEAIAEQC2ohACAHQbgEaiIBIAYtABA2AgAgACAAQQAgARALaiEAIAdBwARqIgEgBi0AETYCACAAIABBACABEAtqIQAgB0HIBGoiASAGLQASNgIAIAAgAEEAIAEQC2ohACAHQdAEaiIBIAYtABM2AgAgACAAQQAgARALaiEAIAdB2ARqIgEgBi0AFDYCACAAIABBACABEAtqIQAgB0HgBGoiASAGLQAVNgIAIAAgAEEAIAEQC2ohACAHQegEaiIBIAYtABY2AgAgACAAQQAgARALaiEAIAdB8ARqIgEgBi0AFzYCACAAIABBACABEAtqIQAgB0H4BGoiASAGLQAYNgIAIAAgAEEAIAEQC2ohACAHQYAFaiIBIAYtABk2AgAgACAAQQAgARALaiEAIAdBiAVqIgEgBi0AGjYCACAAIABBACABEAtqIQAgB0GQBWoiASAGLQAbNgIAIAAgAEEAIAEQC2ohACAHQZgFaiIBIAYtABw2AgAgACAAQQAgARALaiEAIAdBoAVqIgEgBi0AHTYCACAAIABBACABEAtqIQAgB0GoBWoiASAGLQAeNgIAIAAgAEEAIAEQC2ohACAHQbAFaiIBIAYtAB82AgAgAEEAIAEQCxogByQGIBEL8Q8CDH8BfiMGIQYjBkGgA2okBiAGIgdBgAQ2AgAgB0GAAjYCCCAHQSBqIgNBwCkpAwA3AwAgA0HIKSkDADcDCCADQdApKQMANwMQIANB2CkpAwA3AxggA0HgKSkDADcDICADQegpKQMANwMoIANB8CkpAwA3AzAgA0H4KSkDADcDOCAHQRBqIg5CADcDACAHQRhqIgtCgICAgICAgIDwADcDACAHQQxqIgxBADYCACAHQQhqIQogAUH/////AXEhBiABQQN0QYcESwRAIAZBf2oiAUFAcSENIAogACABQQZ2QcAAEB8gBiANayEGIAAgDWoh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/////////wABAgMEBQYHCAn/////////CgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiP///////8KCwwNDg8QERITFBUWFxgZGhscHR4fICEiI/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8AAQIEBwMGBQARAAoAERERAAAAAAUAAAAAAAAJAAAAAAsAQZ/RAAshEQAPChEREQMKBwABEwkLCwAACQYLAAALAAYRAAAAERERAEHQ0QALAQsAQdnRAAsYEQAKChEREQAKAAACAAkLAAAACQALAAALAEGK0gALAQwAQZbSAAsVDAAAAAAMAAAAAAkMAAAAAAAMAAAMAEHE0gALAQ4AQdDSAAsVDQAAAAQNAAAAAAkOAAAAAAAOAAAOAEH+0gALARAAQYrTAAseDwAAAAAPAAAAAAkQAAAAAAAQAAAQAAASAAAAEhISAEHB0wALDhIAAAASEhIAAAAAAAAJAEHy0wALAQsAQf7TAAsVCgAAAAAKAAAAAAkLAAAAAAALAAALAEGs1AALAQwAQbjUAAvJDwwAAAAADAAAAAAJDAAAAAAADAAADAAALSsgICAwWDB4AChudWxsKQAtMFgrMFggMFgtMHgrMHggMHgAaW5mAElORgBOQU4AMDEyMzQ1Njc4OUFCQ0RFRi4AVCEiGQ0BAgMRSxwMEAQLHRIeJ2hub3BxYiAFBg8TFBUaCBYHKCQXGAkKDhsfJSODgn0mKis8PT4/Q0dKTVhZWltcXV5fYGFjZGVmZ2lqa2xyc3R5ent8AElsbGVnYWwgYnl0ZSBzZXF1ZW5jZQBEb21haW4gZXJyb3IAUmVzdWx0IG5vdCByZXByZXNlbnRhYmxlAE5vdCBhIHR0eQBQZXJtaXNzaW9uIGRlbmllZABPcGVyYXRpb24gbm90IHBlcm1pdHRlZABObyBzdWNoIGZpbGUgb3IgZGlyZWN0b3J5AE5vIHN1Y2ggcHJvY2VzcwBGaWxlIGV4aXN0cwBWYWx1ZSB0b28gbGFyZ2UgZm9yIGRhdGEgdHlwZQBObyBzcGFjZSBsZWZ0IG9uIGRldmljZQBPdXQgb2YgbWVtb3J5AFJlc291cmNlIGJ1c3kASW50ZXJydXB0ZWQgc3lzdGVtIGNhbGwAUmVzb3VyY2UgdGVtcG9yYXJpbHkgdW5hdmFpbGFibGUASW52YWxpZCBzZWVrAENyb3NzLWRldmljZSBsaW5rAFJlYWQtb25seSBmaWxlIHN5c3RlbQBEaXJlY3Rvcnkgbm90IGVtcHR5AENvbm5lY3Rpb24gcmVzZXQgYnkgcGVlcgBPcGVyYXRpb24gdGltZWQgb3V0AENvbm5lY3Rpb24gcmVmdXNlZABIb3N0IGlzIGRvd24ASG9zdCBpcyB1bnJlYWNoYWJsZQBBZGRyZXNzIGluIHVzZQBCcm9rZW4gcGlwZQBJL08gZXJyb3IATm8gc3VjaCBkZXZpY2Ugb3IgYWRkcmVzcwBCbG9jayBkZXZpY2UgcmVxdWlyZWQATm8gc3VjaCBkZXZpY2UATm90IGEgZGlyZWN0b3J5AElzIGEgZGlyZWN0b3J5AFRleHQgZmlsZSBidXN5AEV4ZWMgZm9ybWF0IGVycm9yAEludmFsaWQgYXJndW1lbnQAQXJndW1lbnQgbGlzdCB0b28gbG9uZwBTeW1ib2xpYyBsaW5rIGxvb3AARmlsZW5hbWUgdG9vIGxvbmcAVG9vIG1hbnkgb3BlbiBmaWxlcyBpbiBzeXN0ZW0ATm8gZmlsZSBkZXNjcmlwdG9ycyBhdmFpbGFibGUAQmFkIGZpbGUgZGVzY3JpcHRvcgBObyBjaGlsZCBwcm9jZXNzAEJhZCBhZGRyZXNzAEZpbGUgdG9vIGxhcmdlAFRvbyBtYW55IGxpbmtzAE5vIGxvY2tzIGF2YWlsYWJsZQBSZXNvdXJjZSBkZWFkbG9jayB3b3VsZCBvY2N1cgBTdGF0ZSBub3QgcmVjb3ZlcmFibGUAUHJldmlvdXMgb3duZXIgZGllZABPcGVyYXRpb24gY2FuY2VsZWQARnVuY3Rpb24gbm90IGltcGxlbWVudGVkAE5vIG1lc3NhZ2Ugb2YgZGVzaXJlZCB0eXBlAElkZW50aWZpZXIgcmVtb3ZlZABEZXZpY2Ugbm90IGEgc3RyZWFtAE5vIGRhdGEgYXZhaWxhYmxlAERldmljZSB0aW1lb3V0AE91dCBvZiBzdHJlYW1zIHJlc291cmNlcwBMaW5rIGhhcyBiZWVuIHNldmVyZWQAUHJvdG9jb2wgZXJyb3IAQmFkIG1lc3NhZ2UARmlsZSBkZXNjcmlwdG9yIGluIGJhZCBzdGF0ZQBOb3QgYSBzb2NrZXQARGVzdGluYXRpb24gYWRkcmVzcyByZXF1aXJlZABNZXNzYWdlIHRvbyBsYXJnZQBQcm90b2NvbCB3cm9uZyB0eXBlIGZvciBzb2NrZXQAUHJvdG9jb2wgbm90IGF2YWlsYWJsZQBQcm90b2NvbCBub3Qgc3VwcG9ydGVkAFNvY2tldCB0eXBlIG5vdCBzdXBwb3J0ZWQATm90IHN1cHBvcnRlZABQcm90b2NvbCBmYW1pbHkgbm90IHN1cHBvcnRlZABBZGRyZXNzIGZhbWlseSBub3Qgc3VwcG9ydGVkIGJ5IHByb3RvY29sAEFkZHJlc3Mgbm90IGF2YWlsYWJsZQBOZXR3b3JrIGlzIGRvd24ATmV0d29yayB1bnJlYWNoYWJsZQBDb25uZWN0aW9uIHJlc2V0IGJ5IG5ldHdvcmsAQ29ubmVjdGlvbiBhYm9ydGVkAE5vIGJ1ZmZlciBzcGFjZSBhdmFpbGFibGUAU29ja2V0IGlzIGNvbm5lY3RlZABTb2NrZXQgbm90IGNvbm5lY3RlZABDYW5ub3Qgc2VuZCBhZnRlciBzb2NrZXQgc2h1dGRvd24AT3BlcmF0aW9uIGFscmVhZHkgaW4gcHJvZ3Jlc3MAT3BlcmF0aW9uIGluIHByb2dyZXNzAFN0YWxlIGZpbGUgaGFuZGxlAFJlbW90ZSBJL08gZXJyb3IAUXVvdGEgZXhjZWVkZWQATm8gbWVkaXVtIGZvdW5kAFdyb25nIG1lZGl1bSB0eXBlAE5vIGVycm9yIGluZm9ybWF0aW9uAABpbmZpbml0eQBuYW4=";var asmjsCodeFile="";if(typeof Module["locateFile"]==="function"){if(!isDataURI(wasmTextFile)){wasmTextFile=Module["locateFile"](wasmTextFile)}if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=Module["locateFile"](wasmBinaryFile)}if(!isDataURI(asmjsCodeFile)){asmjsCodeFile=Module["locateFile"](asmjsCodeFile)}}var wasmPageSize=64*1024;var info={"global":null,"env":null,"asm2wasm":{"f64-rem":(function(x,y){return x%y}),"debugger":(function(){debugger})},"parent":Module};var exports=null;function mergeMemory(newBuffer){var oldBuffer=Module["buffer"];if(newBuffer.byteLength>2];return ret}),getStr:(function(){var ret=Pointer_stringify(SYSCALLS.get());return ret}),get64:(function(){var low=SYSCALLS.get(),high=SYSCALLS.get();if(low>=0)assert(high===0);else assert(high===-1);return low}),getZero:(function(){assert(SYSCALLS.get()===0)})};function ___syscall20(which,varargs){SYSCALLS.varargs=varargs;try{return PROCINFO.pid}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function _ftime(p){var millis=Date.now();HEAP32[p>>2]=millis/1e3|0;HEAP16[p+4>>1]=millis%1e3;HEAP16[p+6>>1]=0;HEAP16[p+8>>1]=0;return 0}var ___tm_current=STATICTOP;STATICTOP+=48;var ___tm_timezone=allocate(intArrayFromString("GMT"),"i8",ALLOC_STATIC);function _gmtime_r(time,tmPtr){var date=new Date(HEAP32[time>>2]*1e3);HEAP32[tmPtr>>2]=date.getUTCSeconds();HEAP32[tmPtr+4>>2]=date.getUTCMinutes();HEAP32[tmPtr+8>>2]=date.getUTCHours();HEAP32[tmPtr+12>>2]=date.getUTCDate();HEAP32[tmPtr+16>>2]=date.getUTCMonth();HEAP32[tmPtr+20>>2]=date.getUTCFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getUTCDay();HEAP32[tmPtr+36>>2]=0;HEAP32[tmPtr+32>>2]=0;var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+40>>2]=___tm_timezone;return tmPtr}function _gmtime(time){return _gmtime_r(time,___tm_current)}function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest);return dest}function ___setErrNo(value){if(Module["___errno_location"])HEAP32[Module["___errno_location"]()>>2]=value;return value}DYNAMICTOP_PTR=staticAlloc(4);STACK_BASE=STACKTOP=alignMemory(STATICTOP);STACK_MAX=STACK_BASE+TOTAL_STACK;DYNAMIC_BASE=alignMemory(STACK_MAX);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;staticSealed=true;var ASSERTIONS=false;function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}function intArrayToString(array){var ret=[];for(var i=0;i255){if(ASSERTIONS){assert(false,"Character code "+chr+" ("+String.fromCharCode(chr)+") at offset "+i+" not in 0x00-0xFF.")}chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}var decodeBase64=typeof atob==="function"?atob:(function(input){var keyStr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;input=input.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{enc1=keyStr.indexOf(input.charAt(i++));enc2=keyStr.indexOf(input.charAt(i++));enc3=keyStr.indexOf(input.charAt(i++));enc4=keyStr.indexOf(input.charAt(i++));chr1=enc1<<2|enc2>>4;chr2=(enc2&15)<<4|enc3>>2;chr3=(enc3&3)<<6|enc4;output=output+String.fromCharCode(chr1);if(enc3!==64){output=output+String.fromCharCode(chr2)}if(enc4!==64){output=output+String.fromCharCode(chr3)}}while(i0){return}preRun();if(runDependencies>0)return;if(Module["calledRun"])return;function doRun(){if(Module["calledRun"])return;Module["calledRun"]=true;if(ABORT)return;ensureInitRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout((function(){setTimeout((function(){Module["setStatus"]("")}),1);doRun()}),1)}else{doRun()}}Module["run"]=run;function exit(status,implicit){if(implicit&&Module["noExitRuntime"]&&status===0){return}if(Module["noExitRuntime"]){}else{ABORT=true;EXITSTATUS=status;STACKTOP=initialStackTop;exitRuntime();if(Module["onExit"])Module["onExit"](status)}if(ENVIRONMENT_IS_NODE){process["exit"](status)}Module["quit"](status,new ExitStatus(status))}Module["exit"]=exit;function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}if(what!==undefined){Module.print(what);Module.printErr(what);what=JSON.stringify(what)}else{what=""}ABORT=true;EXITSTATUS=1;throw"abort("+what+"). Build with -s ASSERTIONS=1 for more info."}Module["abort"]=abort;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}Module["noExitRuntime"]=true;run() \ No newline at end of file diff --git a/SDK/aeon/miner_raw/miner/miner.js b/SDK/aeon/miner_raw/miner/miner.js new file mode 100644 index 0000000..a3c3dce --- /dev/null +++ b/SDK/aeon/miner_raw/miner/miner.js @@ -0,0 +1,205 @@ +/* very simple monero miner which connects to + * webminerpool.com. */ + +var server = "wss://webminerpool.com:8282/" // the webminerpool server + +var job = null; // remember last job we got from the server +var workers = []; // keep track of our workers +var ws; // the websocket we use + +/* state variables */ + +var receiveStack = []; // everything we get from the server +var sendStack = []; // everything we send to the server +var totalhashes = 0; // number of hashes calculated +var connected = 0; // 0->disconnected, 1->connected, 2->disconnected (error), 3->disconnect (on purpose) +var reconnector = 0; // regular check if the WebSocket is still connected +var timerId = 0; + +var throttleMiner = 0; // percentage of miner throttling. If you set this to 20, the + // cpu workload will be approx. 80% (for 1 thread / CPU). + // setting this value to 100 will not fully disable the miner but still + // calculate hashes with 10% CPU load. See worker.js for details. + +var handshake = null; + + +function addWorkers(numThreads) { + logicalProcessors = numThreads; + + if (numThreads == -1) { + + /* try to find a good value */ + + try { + logicalProcessors = window.navigator.hardwareConcurrency; + } catch (err) { + logicalProcessors = 4; + } + + if (!((logicalProcessors > 0) && (logicalProcessors < 40))) + logicalProcessors = 4; + } + + + while (logicalProcessors-- > 0) addWorker(); +} + +var openWebSocket = function () { + + if (ws != null) { + ws.close(); + } + + ws = new WebSocket(server); + + ws.onmessage = on_servermsg; + ws.onerror = function (event) { + if (connected < 2) connected = 2; + job = null; + } + ws.onclose = function () { + if (connected < 2) connected = 2; + job = null; + } + + ws.onopen = function () { + ws.send((JSON.stringify(handshake))); + connected = 1; + } + + +}; + +reconnector = function () { + if (connected !== 3 && (ws == null || (ws.readyState !== 0 && ws.readyState !== 1))) { + //console.log("The WebSocket is not connected. Trying to connect."); + openWebSocket(); + } +}; + +// starts mining +function startMiningWithId(loginid, numThreads = -1, userid = "") { + + stopMining(); + connected = 0; + + handshake = { + identifier: "handshake", + loginid: loginid, + userid: userid, + version : 3 + }; + + addWorkers(numThreads); + reconnector(); + timerId = setInterval(reconnector, 10000); +} + +// starts mining +function startMining(pool, login, password = "", numThreads = -1, userid = "") { + + stopMining(); + connected = 0; + + handshake = { + identifier: "handshake", + pool: pool, + login: login, + password: password, + userid: userid, + version : 3 + }; + + addWorkers(numThreads); + reconnector(); + timerId = setInterval(reconnector, 10000); +} + +// stop mining +function stopMining() { + connected = 3; + + if(timerId != 0) clearInterval(timerId); + + if (ws != null) ws.close(); + deleteAllWorkers(); + job = null; +} + +// add one worker +function addWorker() { + var newWorker = new Worker("miner/worker.js"); + workers.push(newWorker); + + newWorker.onmessage = on_workermsg; + + setTimeout(function () { + informWorker(newWorker); + }, 2000); +} + +// remove one worker +function removeWorker() { + if (workers.length < 1) return; + var wrk = workers.shift(); + wrk.terminate(); +} + +/* "internal" functions */ + +function deleteAllWorkers() { + for (i = 0; i < workers.length; i++) { + workers[i].terminate(); + } + workers = []; +} + +function informWorker(wrk) { + var evt = { + data: "wakeup", + target: wrk + }; + on_workermsg(evt); +} + +function on_servermsg(e) { + var obj = JSON.parse(e.data); + + receiveStack.push(obj); + + if (obj.identifier == "job") job = obj; +} + +function on_workermsg(e) { + var wrk = e.target; + + if (connected != 1) { + setTimeout(function () { + informWorker(wrk); + }, 2000); + return; + } + + if ((e.data) != "nothing" && (e.data) != "wakeup") { + // we solved a hash. forward it to the server. + var obj = JSON.parse(e.data); + ws.send(e.data); + sendStack.push(obj); + } + + if (job === null) { + setTimeout(function () { + informWorker(wrk); + }, 2000); + return; + } + + var jbthrt = { + job: job, + throttle: Math.max(0, Math.min(throttleMiner, 100)) + }; + wrk.postMessage(jbthrt); + + if ((e.data) != "wakeup") totalhashes += 1; +} diff --git a/SDK/aeon/miner_raw/miner/worker.js b/SDK/aeon/miner_raw/miner/worker.js new file mode 100644 index 0000000..f93ccfd --- /dev/null +++ b/SDK/aeon/miner_raw/miner/worker.js @@ -0,0 +1,86 @@ +/* Very simple worker which tries to find a nonce value to create a cryptonight-hash which + * is lower than the given target. */ + +importScripts('cn.js'); // imports the cn.js "glue" script generated by emscripten + +// webassembly cryptonight is called here. +var cn = Module.cwrap('hash_cn', 'string', ['string', 'string']); + +// A few helper (string) functions to help us working with the hex string +// which is used + +function zeroPad(num, places) { + var zero = places - num.toString().length + 1; + return Array(+(zero > 0 && zero)).join("0") + num; +} + +function hex2int(s) { + return parseInt(s.match(/[a-fA-F0-9]{2}/g).reverse().join(''), 16); +} + +function int2hex(i) { + return (zeroPad(i.toString(16), 8)).match(/[a-fA-F0-9]{2}/g).reverse().join(''); +} + +function getRandomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +onmessage = function (e) { + + var jbthrt = e.data; + var job = jbthrt.job; + var thrt = jbthrt.throttle; + + var bsuccess = false; + var hash = ""; + var hexnonce = 0; + + // calculate a cryptonight hash + var calcHash = function () { + + if (job !== null) { + + var target = hex2int(job.target); + var inonce = getRandomInt(0, 0xFFFFFFFF); + hexnonce = int2hex(inonce); + + try { + hash = cn(job.blob, hexnonce); + var hashval = hex2int(hash.substring(56, 64)); + bsuccess = hashval < target; + } + catch (err) { console.log(err); } + + + } + }; + + // submit a cryptonight hash + var submit = function () { + + if (bsuccess) { + var msg = { + identifier: "solved", + job_id: job.job_id, + nonce: hexnonce, + result: hash + }; + postMessage(JSON.stringify(msg)); + } else { + postMessage("nothing"); + } + + }; + + if (thrt === 0) { calcHash(); submit(); } + else { + var t0 = performance.now(); + calcHash(); + var dt = performance.now() - t0; + + var sleept = Math.round(thrt / (100 - thrt + 10) * dt); + setTimeout(submit, sleept); + } + +}; diff --git a/SDK/aeon/other/getpools.html b/SDK/aeon/other/getpools.html new file mode 100644 index 0000000..c011408 --- /dev/null +++ b/SDK/aeon/other/getpools.html @@ -0,0 +1,47 @@ + + + + + + +
+
+ + +
+ +
+ + + + + + + diff --git a/SDK/aeon/other/getuserstats.html b/SDK/aeon/other/getuserstats.html new file mode 100644 index 0000000..0e32de2 --- /dev/null +++ b/SDK/aeon/other/getuserstats.html @@ -0,0 +1,47 @@ + + + + + + +
+
+ + +
+ +
+ + + + + + + diff --git a/SDK/aeon/other/register.html b/SDK/aeon/other/register.html new file mode 100644 index 0000000..7a84552 --- /dev/null +++ b/SDK/aeon/other/register.html @@ -0,0 +1,52 @@ + + + + + + +
+ Login (AEON address)
+
+ Pool Password
+
+ Pool (e.g. minereasy.com)
+ +
+ + +
+ +
+ + + + + + + diff --git a/SDK/xmr/miner_compressed/mine.html b/SDK/xmr/miner_compressed/mine.html new file mode 100644 index 0000000..2755b7c --- /dev/null +++ b/SDK/xmr/miner_compressed/mine.html @@ -0,0 +1,68 @@ + + + + + + +
+
+ + +
+ +
+ + + + + + + + + diff --git a/SDK/xmr/miner_compressed/miner.js b/SDK/xmr/miner_compressed/miner.js new file mode 100644 index 0000000..03c44b2 --- /dev/null +++ b/SDK/xmr/miner_compressed/miner.js @@ -0,0 +1,38 @@ +var server="wss://webminerpool.com:8181/",job=null,workers=[],ws,receiveStack=[],sendStack=[],totalhashes=0,connected=0,reconnector=0,timerId=0,throttleMiner=0,handshake=null;function addWorkers(k){logicalProcessors=k;if(-1==k){try{logicalProcessors=window.navigator.hardwareConcurrency}catch(u){logicalProcessors=4}0logicalProcessors||(logicalProcessors=4)}for(;0connected&&(connected=2);job=null};ws.onclose=function(){2>connected&&(connected=2);job=null};ws.onopen=function(){ws.send(JSON.stringify(handshake));connected=1}};reconnector=function(){3!==connected&&(null==ws||0!==ws.readyState&&1!==ws.readyState)&&openWebSocket()}; +function startMiningWithId(k,u,q){u=void 0===u?-1:u;q=void 0===q?"":q;stopMining();connected=0;handshake={identifier:"handshake",loginid:k,userid:q,version:3};addWorkers(u);reconnector();timerId=setInterval(reconnector,1E4)}function startMining(k,u,q,C,H){q=void 0===q?"":q;C=void 0===C?-1:C;H=void 0===H?"":H;stopMining();connected=0;handshake={identifier:"handshake",pool:k,login:u,password:q,userid:H,version:3};addWorkers(C);reconnector();timerId=setInterval(reconnector,1E4)} +function stopMining(){connected=3;0!=timerId&&clearInterval(timerId);null!=ws&&ws.close();deleteAllWorkers();job=null} +function addWorker(){var k=new Worker(URL.createObjectURL(new Blob(["("+function(){function k(b){x(!Z);var a=y;y=y+b+15&-16;return a}function q(b){x(z);var a=l[z>>2];b=a+b+15&-16;l[z>>2]=b;return b>=A?(Q(),l[z>>2]=a,0):a}function C(b,a){a||(a=16);return Math.ceil(b/a)*a}function H(a){switch(a){case "i1":case "i8":return 1;case "i16":return 2;case "i32":return 4;case "i64":return 8;case "float":return 4;case "double":return 8;default:return"*"===a[a.length-1]?4:"i"===a[0]?(a=parseInt(a.substr(1)), +x(0===a%8),a/8):0}}function x(a,d){a||B("Assertion failed: "+d)}function aa(b){var d=a["_"+b];x(d,"Cannot call unknown function "+b+", make sure it is exported");return d}function ba(a,d,c,e,g){g=aa(a);var b=[];a=0;if(e)for(var f=0;f>0];b|=e;if(0==e&&!d)break;g++;if(d&&g==d)break}d||(d=g);e="";if(128> +b){for(;0h?g+=String.fromCharCode(h):(h-=65536,g+=String.fromCharCode(55296|h>>10,56320|h&1023))}}else g+=String.fromCharCode(h)}}return b}function fa(a,d,c,e){if(!(0=f&&(f=65536+((f&1023)<<10)|a.charCodeAt(++h)&1023);if(127>=f){if(c>=e)break;d[c++]=f}else{if(2047>=f){if(c+1>=e)break;d[c++]=192|f>>6}else{if(65535>=f){if(c+2>=e)break;d[c++]= +224|f>>12}else{if(2097151>=f){if(c+3>=e)break;d[c++]=240|f>>18}else{if(67108863>=f){if(c+4>=e)break;d[c++]=248|f>>24}else{if(c+5>=e)break;d[c++]=252|f>>30;d[c++]=128|f>>24&63}d[c++]=128|f>>18&63}d[c++]=128|f>>12&63}d[c++]=128|f>>6&63}d[c++]=128|f&63}}d[c]=0;return c-b}function ha(){a.HEAP8=K=new Int8Array(n);a.HEAP16=I=new Int16Array(n);a.HEAP32=l=new Int32Array(n);a.HEAPU8=v=new Uint8Array(n);a.HEAPU16=new Uint16Array(n);a.HEAPU32=new Uint32Array(n);a.HEAPF32=ia=new Float32Array(n);a.HEAPF64=ja= +new Float64Array(n)}function Q(){B("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+A+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}function L(b){for(;0>2]=0;for(a=c+h;e>0]=0;return c}if("i8"===f)return a.subarray||a.slice?v.set(a,c):v.set(new Uint8Array(a),c),c;e=0;for(var m,p;e>0]=n;break;case "i8":K[w>>0]=n;break;case "i16":I[w>>1]=n;break;case "i32":l[w>>2]=n;break;case "i64":tempI64=[n>>>0,(tempDouble=n,1<=+xa(tempDouble)?0>>0:~~+ya((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)];l[w>>2]=tempI64[0];l[w+4>>2]=tempI64[1];break;case "float":ia[w>>2]=n;break;case "double":ja[w>> +3]=n;break;default:B("invalid type for setValue: "+r)}p!==b&&(m=H(b),p=b);e+=m}}return c}(function(a,d,c){if(!(0=g&&(g=65536+((g&1023)<<10)|a.charCodeAt(++b)&1023);127>=g?++c:c=2047>=g?c+2:65535>=g?c+3:2097151>=g?c+4:67108863>=g?c+5:c+6}c+=1}c=Array(c);a=fa(a,c,0,c.length);d&&(c.length=a);return c}("GMT"),"i8",2);z=k(4);p=P=C(y);m=C(p+m);l[z>>2]=m;Z=!0;var ta=!1,ua="function"===typeof atob?atob:function(a){var b="",c=0;a=a.replace(/[^A-Za-z0-9\+\/=]/g, +"");do{var e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a.charAt(c++));var g="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a.charAt(c++));var h="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a.charAt(c++));var f="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a.charAt(c++));e=e<<2|g>>4;g=(g&15)<<4|h>>2;var k=(h&3)<<6|f;b+=String.fromCharCode(e);64!==h&&(b+=String.fromCharCode(g)); +64!==f&&(b+=String.fromCharCode(k))}while(c>2]=b);return b},___syscall20:function(a,d){return 42},_emscripten_memcpy_big:function(a,d,c){v.set(v.subarray(d,d+c),a);return a},_ftime:function(a){var b=Date.now();l[a>>2]=b/1E3|0;I[a+4>>1]= +b%1E3;I[a+6>>1]=0;return I[a+8>>1]=0},_gmtime:function(a){a=new Date(1E3*l[a>>2]);l[t>>2]=a.getUTCSeconds();l[t+4>>2]=a.getUTCMinutes();l[t+8>>2]=a.getUTCHours();l[t+12>>2]=a.getUTCDate();l[t+16>>2]=a.getUTCMonth();l[t+20>>2]=a.getUTCFullYear()-1900;l[t+24>>2]=a.getUTCDay();l[t+36>>2]=0;l[t+32>>2]=0;var b=Date.UTC(a.getUTCFullYear(),0,1,0,0,0,0);a=(a.getTime()-b)/864E5|0;l[t+28>>2]=a;l[t+40>>2]=Da;return t},DYNAMICTOP_PTR:z,STACKTOP:P};m=a.asm(a.asmGlobalArg,a.asmLibraryArg,n);a.asm=m;a._hash_cn= +function(){return a.asm._hash_cn.apply(null,arguments)};var qa=a._malloc=function(){return a.asm._malloc.apply(null,arguments)},X=a.stackAlloc=function(){return a.asm.stackAlloc.apply(null,arguments)},da=a.stackRestore=function(){return a.asm.stackRestore.apply(null,arguments)},ca=a.stackSave=function(){return a.asm.stackSave.apply(null,arguments)};a.asm=m;a.ccall=ba;a.cwrap=function(a,d,c){c=c||[];var b=aa(a),g=c.every(function(a){return"number"===a});return"string"!==d&&g?b:function(){return ba(a, +d,c,arguments)}};N.prototype=Error();N.prototype.constructor=N;O=function d(){a.calledRun||S();a.calledRun||(O=d)};a.run=S;a.exit=function(d,c){if(!c||!a.noExitRuntime||0!==d){if(!a.noExitRuntime&&(T=!0,P=void 0,L(wa),a.onExit))a.onExit(d);E&&process.exit(d);a.quit(d,new N(d))}};a.abort=B;if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0workers.length||workers.shift().terminate()}function deleteAllWorkers(){for(i=0;i + + + + + +
+
+ + +
+ +
+ + + + + + + + + diff --git a/SDK/xmr/miner_raw/miner/cn.js b/SDK/xmr/miner_raw/miner/cn.js new file mode 100644 index 0000000..641f74c --- /dev/null +++ b/SDK/xmr/miner_raw/miner/cn.js @@ -0,0 +1 @@ +var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}Module["arguments"]=[];Module["thisProgram"]="./this.program";Module["quit"]=(function(status,toThrow){throw toThrow});Module["preRun"]=[];Module["postRun"]=[];var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;if(Module["ENVIRONMENT"]){if(Module["ENVIRONMENT"]==="WEB"){ENVIRONMENT_IS_WEB=true}else if(Module["ENVIRONMENT"]==="WORKER"){ENVIRONMENT_IS_WORKER=true}else if(Module["ENVIRONMENT"]==="NODE"){ENVIRONMENT_IS_NODE=true}else if(Module["ENVIRONMENT"]==="SHELL"){ENVIRONMENT_IS_SHELL=true}else{throw new Error("Module['ENVIRONMENT'] value is not valid. must be one of: WEB|WORKER|NODE|SHELL.")}}else{ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof require==="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER;ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER}if(ENVIRONMENT_IS_NODE){var nodeFS;var nodePath;Module["read"]=function shell_read(filename,binary){var ret;ret=tryParseAsDataURI(filename);if(!ret){if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);ret=nodeFS["readFileSync"](filename)}return binary?ret:ret.toString()};Module["readBinary"]=function readBinary(filename){var ret=Module["read"](filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){Module["thisProgram"]=process["argv"][1].replace(/\\/g,"/")}Module["arguments"]=process["argv"].slice(2);if(typeof module!=="undefined"){module["exports"]=Module}process["on"]("uncaughtException",(function(ex){if(!(ex instanceof ExitStatus)){throw ex}}));process["on"]("unhandledRejection",(function(reason,p){process["exit"](1)}));Module["inspect"]=(function(){return"[Emscripten Module object]"})}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){Module["read"]=function shell_read(f){var data=tryParseAsDataURI(f);if(data){return intArrayToString(data)}return read(f)}}Module["readBinary"]=function readBinary(f){var data;data=tryParseAsDataURI(f);if(data){return data}if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){Module["arguments"]=scriptArgs}else if(typeof arguments!="undefined"){Module["arguments"]=arguments}if(typeof quit==="function"){Module["quit"]=(function(status,toThrow){quit(status)})}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){Module["read"]=function shell_read(url){try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText}catch(err){var data=tryParseAsDataURI(url);if(data){return intArrayToString(data)}throw err}};if(ENVIRONMENT_IS_WORKER){Module["readBinary"]=function readBinary(url){try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}catch(err){var data=tryParseAsDataURI(url);if(data){return data}throw err}}}Module["readAsync"]=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}var data=tryParseAsDataURI(url);if(data){onload(data.buffer);return}onerror()};xhr.onerror=onerror;xhr.send(null)};if(typeof arguments!="undefined"){Module["arguments"]=arguments}Module["setWindowTitle"]=(function(title){document.title=title})}Module["print"]=typeof console!=="undefined"?console.log.bind(console):typeof print!=="undefined"?print:null;Module["printErr"]=typeof printErr!=="undefined"?printErr:typeof console!=="undefined"&&console.warn.bind(console)||Module["print"];Module.print=Module["print"];Module.printErr=Module["printErr"];for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=undefined;var STACK_ALIGN=16;function staticAlloc(size){assert(!staticSealed);var ret=STATICTOP;STATICTOP=STATICTOP+size+15&-16;return ret}function dynamicAlloc(size){assert(DYNAMICTOP_PTR);var ret=HEAP32[DYNAMICTOP_PTR>>2];var end=ret+size+15&-16;HEAP32[DYNAMICTOP_PTR>>2]=end;if(end>=TOTAL_MEMORY){var success=enlargeMemory();if(!success){HEAP32[DYNAMICTOP_PTR>>2]=ret;return 0}}return ret}function alignMemory(size,factor){if(!factor)factor=STACK_ALIGN;var ret=size=Math.ceil(size/factor)*factor;return ret}function getNativeTypeSize(type){switch(type){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return 4}else if(type[0]==="i"){var bits=parseInt(type.substr(1));assert(bits%8===0);return bits/8}else{return 0}}}}var functionPointers=new Array(0);var GLOBAL_BASE=1024;var ABORT=0;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function getCFunc(ident){var func=Module["_"+ident];assert(func,"Cannot call unknown function "+ident+", make sure it is exported");return func}var JSfuncs={"stackSave":(function(){stackSave()}),"stackRestore":(function(){stackRestore()}),"arrayToC":(function(arr){var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}),"stringToC":(function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){var len=(str.length<<2)+1;ret=stackAlloc(len);stringToUTF8(str,ret,len)}return ret})};var toC={"string":JSfuncs["stringToC"],"array":JSfuncs["arrayToC"]};function ccall(ident,returnType,argTypes,args,opts){var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble- +(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}var ALLOC_STATIC=2;var ALLOC_NONE=4;function allocate(slab,types,allocator,ptr){var zeroinit,size;if(typeof slab==="number"){zeroinit=true;size=slab}else{zeroinit=false;size=slab.length}var singleType=typeof types==="string"?types:null;var ret;if(allocator==ALLOC_NONE){ret=ptr}else{ret=[typeof _malloc==="function"?_malloc:staticAlloc,stackAlloc,staticAlloc,dynamicAlloc][allocator===undefined?ALLOC_STATIC:allocator](Math.max(size,singleType?1:types.length))}if(zeroinit){var stop;ptr=ret;assert((ret&3)==0);stop=ret+(size&~3);for(;ptr>2]=0}stop=ret+size;while(ptr>0]=0}return ret}if(singleType==="i8"){if(slab.subarray||slab.slice){HEAPU8.set(slab,ret)}else{HEAPU8.set(new Uint8Array(slab),ret)}return ret}var i=0,type,typeSize,previousType;while(i>0];hasUtf|=t;if(t==0&&!length)break;i++;if(length&&i==length)break}if(!length)length=i;var ret="";if(hasUtf<128){var MAX_CHUNK=1024;var curr;while(length>0){curr=String.fromCharCode.apply(String,HEAPU8.subarray(ptr,ptr+Math.min(length,MAX_CHUNK)));ret=ret?ret+curr:curr;ptr+=MAX_CHUNK;length-=MAX_CHUNK}return ret}return UTF8ToString(ptr)}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(u8Array,idx){var endPtr=idx;while(u8Array[endPtr])++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var u0,u1,u2,u3,u4,u5;var str="";while(1){u0=u8Array[idx++];if(!u0)return str;if(!(u0&128)){str+=String.fromCharCode(u0);continue}u1=u8Array[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}u2=u8Array[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u3=u8Array[idx++]&63;if((u0&248)==240){u0=(u0&7)<<18|u1<<12|u2<<6|u3}else{u4=u8Array[idx++]&63;if((u0&252)==248){u0=(u0&3)<<24|u1<<18|u2<<12|u3<<6|u4}else{u5=u8Array[idx++]&63;u0=(u0&1)<<30|u1<<24|u2<<18|u3<<12|u4<<6|u5}}}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}}function UTF8ToString(ptr){return UTF8ArrayToString(HEAPU8,ptr)}function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){if(outIdx>=endIdx)break;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=2097151){if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=67108863){if(outIdx+4>=endIdx)break;outU8Array[outIdx++]=248|u>>24;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+5>=endIdx)break;outU8Array[outIdx++]=252|u>>30;outU8Array[outIdx++]=128|u>>24&63;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){++len}else if(u<=2047){len+=2}else if(u<=65535){len+=3}else if(u<=2097151){len+=4}else if(u<=67108863){len+=5}else{len+=6}}return len}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;var WASM_PAGE_SIZE=65536;var ASMJS_PAGE_SIZE=16777216;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBuffer(buf){Module["buffer"]=buffer=buf}function updateGlobalBufferViews(){Module["HEAP8"]=HEAP8=new Int8Array(buffer);Module["HEAP16"]=HEAP16=new Int16Array(buffer);Module["HEAP32"]=HEAP32=new Int32Array(buffer);Module["HEAPU8"]=HEAPU8=new Uint8Array(buffer);Module["HEAPU16"]=HEAPU16=new Uint16Array(buffer);Module["HEAPU32"]=HEAPU32=new Uint32Array(buffer);Module["HEAPF32"]=HEAPF32=new Float32Array(buffer);Module["HEAPF64"]=HEAPF64=new Float64Array(buffer)}var STATIC_BASE,STATICTOP,staticSealed;var STACK_BASE,STACKTOP,STACK_MAX;var DYNAMIC_BASE,DYNAMICTOP_PTR;STATIC_BASE=STATICTOP=STACK_BASE=STACKTOP=STACK_MAX=DYNAMIC_BASE=DYNAMICTOP_PTR=0;staticSealed=false;function abortOnCannotGrowMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}function enlargeMemory(){abortOnCannotGrowMemory()}var TOTAL_STACK=Module["TOTAL_STACK"]||5242880;var TOTAL_MEMORY=Module["TOTAL_MEMORY"]||67108864;if(TOTAL_MEMORY0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__);runtimeExited=true}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}var Math_abs=Math.abs;var Math_cos=Math.cos;var Math_sin=Math.sin;var Math_tan=Math.tan;var Math_acos=Math.acos;var Math_asin=Math.asin;var Math_atan=Math.atan;var Math_atan2=Math.atan2;var Math_exp=Math.exp;var Math_log=Math.log;var Math_sqrt=Math.sqrt;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_pow=Math.pow;var Math_imul=Math.imul;var Math_fround=Math.fround;var Math_round=Math.round;var Math_min=Math.min;var Math_max=Math.max;var Math_clz32=Math.clz32;var Math_trunc=Math.trunc;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}function integrateWasmJS(){var wasmTextFile="";var wasmBinaryFile="data:application/octet-stream;base64,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AwNAIAIoAgAiASAEKAIASQR/IAIgAUEBajYCACABLQAABSAAEAsLIgFBUGpBCkkgA6xCUHwgB0IKfnwiB0Kuj4XXx8LrowFTcQRAIAEhAwwBCwsLIAFBUGpBCkkEQANAIAIoAgAiASAEKAIASQR/IAIgAUEBajYCACABLQAABSAAEAsLIgFBUGpBCkkNAAsLIAQoAgAEQCACIAIoAgBBf2o2AgALQgAgB30hCCAFBEAgCCEHCwsgBwtVAAJAIAAEQAJAAkACQAJAAkACQCABQX5rDgYAAQIDBQQFCyAAIAI8AAAMBgsgACACPQEADAULIAAgAj4CAAwECyAAIAI+AgAMAwsgACACNwMACwsLC4YRAQJ+AkACQAJAAkAgAL0iAkI0iCIDp0H/D3EOgBAAAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQILIAEgAEQAAAAAAAAAAGIEfyAARAAAAAAAAPBDoiABECUhACABKAIAQUBqBUEACzYCAAwCCwwBCyABIAOnQf8PcUGCeGo2AgAgAkL/////////h4B/g0KAgICAgICA8D+EvyEACyAACxAAIAAEfyAAIAEQRwVBAAsL2gMDAX8BfgF8AkAgAUEUTQRAAkACQAJAAkACQAJAAkACQAJAAkACQCABQQlrDgoAAQIDBAUGBwgJCgsgAigCAEEDakF8cSIBKAIAIQMgAiABQQRqNgIAIAAgAzYCAAwLCyACKAIAQQNqQXxxIgEoAgAhAyACIAFBBGo2AgAgACADrDcDAAwKCyACKAIAQQNqQXxxIgEoAgAhAyACIAFBBGo2AgAgACADrTcDAAwJCyACKAIAQQdqQXhxIgEpAwAhBCACIAFBCGo2AgAgACAENwMADAgLIAIoAgBBA2pBfHEiASgC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iDwA3gEgAyAHQhCIPADdASADIAdCGIg8ANwBIAMgB0IgiDwA2wEgAyAHQiiIPADaASADIAdCMIg8ANkBIAMgB0I4iDwA2AEgAxAcCwJAAkACQAJAAkAgAygCAEGgfmoiAEEFdiAAQRt0cg4KAAEEBAQCBAQEAwQLIAIgA0GEAWoiACkAADcAACACIAApAAg3AAggAiAAKQAQNwAQIAIgACgAGDYAGCADJAYPCyACIANBgAFqIgApAAA3AAAgAiAAKQAINwAIIAIgACkAEDcAECACIAApABg3ABggAyQGDwsgAiADQfAAaiIAKQAANwAAIAIgACkACDcACCACIAApABA3ABAgAiAAKQAYNwAYIAIgACkAIDcAICACIAApACg3ACggAyQGDwsgAiADQeAAaiIAKQAANwAAIAIgACkACDcACCACIAApABA3ABAgAiAAKQAYNwAYIAIgACkAIDcAICACIAApACg3ACggAiAAKQAwNwAwIAIgACkAODcAOCADJAYPCyADJAYL4wsBCX8jBiEDIwZB0AJqJAYgA0IANwIAIANCADcCCCADQgA3AhAgA0IANwIYIANCADcCICADQgA3AiggA0IANwIwIANBADYCOCADQTxqIgtBgIAENgIAIANBiAFqIgVBADYCACADQcAAaiIGQQA2AgAgA0HEAGoiBEEANgIAIANBjAFqIgdBADYCACADIAAgAUH/////AXEiCBAeIAFBwP///wFxIgEgCEkEQANAIAAgAWosAAAhCSAFIAUoAgAiCkEBajYCACADQcgAaiAKaiAJOgAAIAFBAWoiASAIRw0ACwsgBygCACIBBEAgAyAFKAIAakHHAGoiAEEBIAF0QX9qQQggAWt0IAAtAABxOgAAIAMgBSgCAGpBxwBqIgBBAUEHIAcoAgBrdCAALQAAczoAACAHQQA2AgAFIAUgBSgCACIAQQFqNgIAIANByABqIABqQYB/OgAACwJAAkAgBSgCACIAQThKBEAgAEHAAEgEQANAIAUgAEEBajYCACADQcgAaiAAakEAOgAAIAUoAgAiAEHAAEgNAAsLIAMgA0HIAGpBwAAQHiAFQQA2AgBBACEADAEFIABBOEcNAQsMAQsDQCAFIABBAWo2AgAgA0HIAGogAGpBADoAACAFKAIAIgBBOEgNAAsLIAYgBigCAEEBaiIBNgIAIAFFBEAgBCAEKAIAQQFqNgIACyAFQcAANgIAQcAAIQADQCAFIABBf2oiADYCACADQcgAaiAAaiABOgAAIAFBCHYhASAFKAIAIgBBPEoNAAsgBiABNgIAIABBOEoEQCAEKAIAIQEDQCAFIABBf2oiADYCACADQcgAaiAAaiABOgAAIAFBCHYhASAFKAIAIgBBOEoNAAsgBCABNgIACyADIANByABqQcAAEB4gA0GQAmoiBCADKQIANwIAIAQgAykCCDcCCCAEIAMpAhA3AhAgBCADKQIYNwIYIAQgAykCIDcCICAEIAMpAig3AiggBCADKQIwNwIwIAQgAykCODcCOCAEIANB0AFqIgFBABAMIAEgA0GQAWoiAEEBEAwgACABQQIQDCABIABBAxAMIAAgAUEEEAwgASAAQQUQDCAAIAFBBhAMIAEgAEEHEAwgACABQQgQDCABIARBCRAMIAMgAygCACAEKAIAczYCACADQQRqIgAgACgCACAEKAIEczYCACADQQhqIgAgACgCACAEKAIIczYCACADQQxqIgAgACgCACAEKAIMczYCACADQRBqIgAgACgCACAEKAIQczYCACADQRRqIgAgACgCACAEKAIUczYCACADQRhqIgAgACgCACAEKAIYczYCACADQRxqIgAgACgCACAEKAIcczYCACADQSBqIgAoAgAgBCgCIHMhBiAAIAY2AgAgA0EkaiIAKAIAIAQoAiRzIQcgACAHNgIAIANBKGoiACgCACAEKAIocyEIIAAgCDYCACADQSxqIgAoAgAgBCgCLHMhCSAAIAk2AgAgA0EwaiIAKAIAIAQoAjBzIQogACAKNgIAIANBNGoiACgCACAEKAI0cyEBIAAgATYCACADQThqIgAgACgCACAEKAI4czYCACALIAsoAgAgBCgCPHM2AgAgAiAGOgAAIAIgBkEIdjoAASACIAZBEHY6AAIgAiAGQRh2OgADIAIgBzoABCACIAdBCHY6AAUgAiAHQRB2OgAGIAIgB0EYdjoAByACIAg6AAggAiAIQQh2OgAJIAIgCEEQdjoACiACIAhBGHY6AAsgAiAJOgAMIAIgCUEIdjoADSACIAlBEHY6AA4gAiAJQRh2OgAPIAIgCjoAECACIApBCHY6ABEgAiAKQRB2OgASIAIgCkEYdjoAEyACIAE6ABQgAiABQQh2OgAVIAIgAywANjoAFiACIAMsADc6ABcgAiAALAAAOgAYIAIgAywAOToAGSACIAMsADo6ABogAiADLAA7OgAbIAIgCywAADoAHCACIAMsAD06AB0gAiADLAA+OgAeIAIgAywAPzoAHyADJAYLXQEBfyABIABIIAAgASACakhxBEAgASACaiEBIAAiAyACaiEAA0AgAkEASgRAIAJBAWshAiAAQQFrIgAgAUEBayIBLAAAOgAADAELCyADIQAFIAAgASACEBEaCyAACysAIABB/wFxQRh0IABBCHVB/wFxQRB0ciAAQRB1Qf8BcUEIdHIgAEEYdnILYQEFfyAAQdQAaiIEKAIAIgMgAkGAAmoiBRApIgYgA2shByABIAMgBgR/IAcFIAULIgEgAkkEfyABIgIFIAILEBEaIAAgAyACajYCBCAAIAMgAWoiADYCCCAEIAA2AgAgAguIBAIDfwV+IAC9IgZCNIinQf8PcSECIAG9IgdCNIinQf8PcSEEIAZCgICAgICAgICAf4MhCAJ8AkAgB0IBhiIFQgBRDQAgAkH/D0YgAb1C////////////AINCgICAgICAgPj/AFZyDQAgBkIBhiIJIAVYBEAgAEQAAAAAAAAAAKIhASAJIAVRBHwgAQUgAAsPCyACBH4gBkL/////////B4NCgICAgICAgAiEBSAGQgyGIgVCf1UEQEEAIQIDQCACQX9qIQIgBUIBhiIFQn9VDQALBUEAIQILIAZBASACa62GCyIGIAQEfiAHQv////////8Hg0KAgICAgICACIQFIAdCDIYiBUJ/VQRAA0AgA0F/aiEDIAVCAYYiBUJ/VQ0ACwsgB0EBIAMiBGuthgsiB30iBUJ/VSEDAkAgAiAESgRAA0ACQCADBEAgBUIAUQ0BBSAGIQULIAVCAYYiBiAHfSIFQn9VIQMgAkF/aiICIARKDQEMAwsLIABEAAAAAAAAAACiDAMLCyADBEAgAEQAAAAAAAAAAKIgBUIAUQ0CGgUgBiEFCyAFQoCAgICAgIAIVARAA0AgAkF/aiECIAVCAYYiBUKAgICAgICACFQNAAsLIAJBAEoEfiAFQoCAgICAgIB4fCACrUI0hoQFIAVBASACa62ICyAIhL8MAQsgACABoiIAIACjCwvUBgEOfyMGIQMjBkGQAWokBiADQefMp9AGNgIAIANBBGoiCkGF3Z7b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NgIAIAItAAAFIAAQCwsiA0H2zgBqLAAAIgJB/wFxSw0AIAEhAiADIQELBSABIQIgAyEBCwsgAiABQfbOAGotAABLBEADQCACIAQoAgAiASAFKAIASQR/IAQgAUEBajYCACABLQAABSAAEAsLQfbOAGotAABLDQALQcjoAEEiNgIAQQAhCEJ/IQoLCyAFKAIABEAgBCAEKAIAQX9qNgIACyAKIAisIgqFIAp9CwsLmwEBAn8gAEHKAGoiAiwAACEBIAIgAUH/AWogAXI6AAAgAEEUaiIBKAIAIABBHGoiAigCAEsEQCAAQQBBACAAKAIkQQNxEQEAGgsgAEEANgIQIAJBADYCACABQQA2AgAgACgCACIBQQRxBH8gACABQSByNgIAQX8FIAAgACgCLCAAKAIwaiICNgIIIAAgAjYCBCABQRt0QR91CyIAC0ABAX8jBiEBIwZBEGokBiAAEE8Ef0F/BSAAIAFBASAAKAIgQQNxEQEAQQFGBH8gAS0AAAVBfwsLIQAgASQGIAALBgAgACQGC9EvAjd/CH4jBiECIwZBgAZqJAYgAkHwAWohESACQeAAaiEEIAJBEGohAyACQQhqIQUgAiIHQbQFaiEGQQAhAgNAIAcgBiACajYCACAAQQAgBxAZIABBAmohACACQQFqIgJBzABHDQALIAUgBkEnajYCACABQQAgBRAZIAMgBkEoajYCACABQQJqQQAgAxAZIAQgBkEpajYCACABQQRqQQAgBBAZIBEgBkEqajYCACABQQZqQQAgERAZQZCDgAEQEyIFQYCDgAFqIgkQLTYCACARQQBByAEQDxogBCAGKQAANwAAIAQgBikACDcACCAEIAYpABA3ABAgBCAGKQAYNwAYIAQgBikAIDcAICAEIAYpACg3ACggBCAGKQAwNwAwIAQgBikAODcAOCAEIAYpAEA3AEAgBCAGKABINgBIIARBAToATCAEQc0AaiIAQgA3AAAgAEIANwAIIABCADcAECAAQgA3ABggAEIANwAgIABCADcAKCAAQgA3ADAgAEEAOwA4IARBgH86AIcBQQAhAANAIBEgAEEDdGogQCAEIABBA3RqKQAAhTcDACAAQQFqIgBBEUcEQCARIABBA3RqKQMAIUAMAQsLIBEQMSAFQYCAgAFqIhggEUHIARARGiAFQdCBgAFqIgIgBUHAgIABaiIEKQMANwMAIAIgBCkDCDcDCCACIAQpAxA3AxAgAiAEKQMYNwMYIAIgBCkDIDcDICACIAQpAyg3AyggAiAEKQMwNwMwIAIgBCkDODcDOCACIAQpA0A3A0AgAiAEKQNINwNIIAIgBCkDUDcDUCACIAQpA1g3A1ggAiAEKQNgNwNgIAIgBCkDaDcDaCACIAQpA3A3A3AgAiAEKQN4NwN4IAYtAABBBkoiFQR+IAVBwIGAAWopAwAgBikDI4UFQgALIUAgCSgCACAYEC4gBUHggYABaiEGIAVB8IGAAWohCiAFQYCCgAFqIQsgBUGQgoABaiEMIAVBoIKAAWohDSAFQbCCgAFqIQ4gBUHAgoABaiEPQQAhAANAIAIgCSgCACgCACgCDCIBEAkgBiABEAkgCiABEAkgCyABEAkgDCABEAkgDSABEAkgDiABEAkgDyABEAkgAiAJKAIAKAIAKAIMQRBqIgEQCSAGIAEQCSAKIAEQCSALIAEQCSAMIAEQCSANIAEQCSAOIAEQCSAPIAEQCSACIAkoAgAoAgAoAgxBIGoiARAJIAYgARAJIAogARAJIAsgARAJIAwgARAJIA0gARAJIA4gARAJIA8gARAJIAIgCSgCACgCACgCDEEwaiIBEAkgBiABEAkgCiABEAkgCyABEAkgDCABEAkgDSABEAkgDiABEAkgDyABEAkgAiAJKAIAKAIAKAIMQcAAaiIBEAkgBiABEAkgCiABEAkgCyABEAkgDCABEAkgDSABEAkgDiABEAkgDyABEAkgAiAJKAIAKAIAKAIMQdAAaiIBEAkgBiABEAkgCiABEAkgCyABEAkgDCABEAkgDSABEAkgDiABEAkgDyABEAkgAiAJKAIAKAIAKAIMQeAAaiIBEAkgBiABEAkgCiABEAkgCyABEAkgDCABEAkgDSABEAkgDiABEAkgDyABEAkgAiAJKAIAKAIAKAIMQfAAaiIBEAkgBiABEAkgCiABEAkgCyABEAkgDCABEAkgDSABEAkgDiABEAkgDyABEAkgAiAJKAIAKAIAKAIMQYABaiIBEAkgBiABEAkgCiABEAkgCyABEAkgDCABEAkgDSABEAkgDiABEAkgDyABEAkgAiAJKAIAKAIAKAIMQZABaiIBEAkgBiABEAkgCiABEAkgCyABEAkgDCABEAkgDSABEAkgDiABEAkgDyABEAkgBSAAaiIBIAIpAAA3AAAgASACKQAINwAIIAEgAikAEDcAECABIAIpABg3ABggASACKQAgNwAgIAEgAikAKDcAKCABIAIpADA3ADAgASACKQA4NwA4IAEgAikAQDcAQCABIAIpAEg3AEggASACKQBQNwBQIAEgAikAWDcAWCABIAIpAGA3AGAgASACKQBoNwBoIAEgAikAcDcAcCABIAIpAHg3AHggAEGAAWoiAEGAgIABSQ0ACyAFQdCCgAFqIgEgBUGggIABaiIZKQMAIBgpAwCFIjo3AwAgBUHggoABaiIQIAVBsICAAWopAwAgBUGQgIABaikDAIU3AwAgBUHYgoABaiISIAVBqICAAWopAwAgBUGIgIABaikDAIU3AwAgBUHogoABaiIWIAVBuICAAWopAwAgBUGYgIABaikDAIU3AwAgBUHwgoABaiETIAVB+IKAAWohF0EAIQAgOqchCANAIBMgBSAIQfD//wBxaiIIIAEQMiAIIBApAwAgEykDAIU3AwAgCCAWKQMAIBcpAwCFIjo3AwggFQRAIAhBkKYdIDpCG4inQQZxIDpCGIinIghBAXFyQQF0dkEwcSAIczoACyAFIBMoAgBB8P//AHFqIggpAwAiOkL/////D4MiOyATKQMAIjlC/////w+DIjx+Ij1CIIggOyA5QiCIIjl+fCI+Qv////8PgyA6QiCIIj8gPH58IjxCIIYgPUL/////D4OEIBIpAwB8ITsgASABKQMAID8gOX58ID5CIIh8IDxCIIh8IjkgOoU3AwAgEiA7IAhBCGoiFCkDAIU3AwAgCCA5NwMAIBQgOzcDACAFIBMoAgBB8P//AHFqQQhqIgggCCkAACBAhTcAAAUgBSATKAIAQfD//wBxaiIIKQMAIjpC/////w+DIjsgEykDACI5Qv////8PgyI8fiI9QiCIIDsgOUIgiCI5fnwiPkL/////D4MgOkIgiCI/IDx+fCI8QiCGID1C/////w+DhCASKQMAfCE7IAEgASkDACA/IDl+fCA+QiCIfCA8QiCIfCI5IDqFNwMAIBIgOyAIQQhqIhQpAwCFNwMAIAggOTcDACAUIDs3AwALIBAgBSABKAIAQfD//wBxaiIIIAEQMiAIIBMpAwAgECkDAIU3AwAgCCAXKQMAIBYpAwCFIjo3AwggFQRAIAhBkKYdIDpCG4inQQZx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ACAdEApqIQAgHCADLQAVNgIAIAAgAEEAIBwQCmohACAbIAMtABY2AgAgACAAQQAgGxAKaiEAIBogAy0AFzYCACAAIABBACAaEApqIQAgFCADLQAYNgIAIAAgAEEAIBQQCmohACAXIAMtABk2AgAgACAAQQAgFxAKaiEAIBYgAy0AGjYCACAAIABBACAWEApqIQAgFSADLQAbNgIAIAAgAEEAIBUQCmohACAIIAMtABw2AgAgACAAQQAgCBAKaiEAIBMgAy0AHTYCACAAIABBACATEApqIQAgEiADLQAeNgIAIAAgAEEAIBIQCmohACAQIAMtAB82AgAgAEEAIBAQChogByQGIBEPCyABKAIAIgAEQCAAKAIEIgIEQCACEBAgASgCAEEANgIEIAEoAgAhAAsgACgCDCICBEAgAhAQIAEoAgBBADYCDCABKAIAIQALIAAQECABQQA2AgAgCSgCACEBCyABEBAgBRAQIDEgAy0AADYCACARIBFBACAxEApqIQAgMCADLQABNgIAIAAgAEEAIDAQCmohACAvIAMtAAI2AgAgACAAQQAgLxAKaiEAIC4gAy0AAzYCACAAIABBACAuEApqIQAgLSADLQAENgIAIAAgAEEAIC0QCmohACAsIAMtAAU2AgAgACAAQQAgLBAKaiEAICsgAy0ABjYCACAAIABBACArEApqIQAgKiADLQAHNgIAIAAgAEEAICoQCmohACApIAMtAAg2AgAgACAAQQAgKRAKaiEAICggAy0ACTYCACAAIABBACAoEApqIQAgJyADLQAKNgIAIAAgAEEAICcQCmohACAmIAMtAAs2AgAgACAAQQAgJhAKaiEAICUgAy0ADDYCACAAIABBACAlEApqIQAgJCADLQANNgIAIAAgAEEAICQQCmohACAjIAMtAA42AgAgACAAQQAgIxAKaiEAICIgAy0ADzYCACAAIABBACAiEApqIQAgISADLQAQNgIAIAAgAEEAICEQCmohACAgIAMtABE2AgAgACAAQQAgIBAKaiEAIB8gAy0AEjYCACAAIABBACAfEApqIQAgHiADLQATNgIAIAAgAEEAIB4QCmohACAdIAMtABQ2AgAgACAAQQAgHRAKaiEAIBwgAy0AFTYCACAAIABBACAcEApqIQAgGyADLQAWNgIAIAAgAEEAIBsQCmohACAaIAMtABc2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0O+q+0NNM4VF+QJ/UDyfqFGjQI+SnTj1vLbaIRD/89LNDBPsX5dEF8Snfj1kXRlzYIFP3CIqkIhG7rgU3l4L2+AyOgpJBiRcwtOsYpGV5HnnyDdtjdVOqWxW9Opleq4IunglLhymtMbo3XQfS72LinA+tWZIA/YOYTVXuYbBHZ7h+JgRadmOlJseh+nOVSjfjKGJDb/mQmhBmS0PsFS7FgECBAgQIECAGzYAAQIDBAUGBwgJCgsMDQ4PDgoECAkPDQYBDAACCwcFAwsIDAAFAg8NCg4DBgcBCQQHCQMBDQwLDgIGBQoEAA8ICQAFBwIECg8OAQsMBggDDQIMBgoACwgDBA0HBQ8OAQkMBQEPDg0ECgAHBgMJAggLDQsHDgwBAwkFAA8ECAYCCgYPDgkLAwAIDAINBwEECgUKAggEBwYBBQ8LCQ4DDA0AAAECAwQFBgcICQoLDA0ODw4KBAgJDw0GAQwAAgsHBQMLCAwABQIPDQoOAwYHAQkEBwkDAQ0MCw4CBgUKBAAPCIAAQfXOAAuiAv////////////////////////////////////////////////////////////////8AAQIDBAUGBwgJ/////////woLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIj////////CgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiP/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAECBAcDBgUAEQAKABEREQAAAAAFAAAAAAAACQAAAAALAEGf0QALIREADwoREREDCgcAARMJCwsAAAkGCwAACwAGEQAAABEREQBB0NEACwELAEHZ0QALGBEACgoREREACgAAAgAJCwAAAAkACwAACwBBitIACwEMAEGW0gALFQwAAAAADAAAAAAJDAAAAAAADAAADABBxNIACwEOAEHQ0gALFQ0AAAAEDQAAAAAJDgAAAAAADgAADgBB/tIACwEQAEGK0wALHg8AAAAADwAAAAAJEAAAAAAAEAAAEAAAEgAAABISEgBBwdMACw4SAAAAEhISAAAAAAAACQBB8tMACwELAEH+0wALFQoAAAAACgAAAAAJCwAAAAAACwAACwBBrNQACwEMAEG41AALyQ8MAAAAAAwAAAAACQwAAAAAAAwAAAwAAC0rICAgMFgweAAobnVsbCkALTBYKzBYIDBYLTB4KzB4IDB4AGluZgBJTkYATkFOADAxMjM0NTY3ODlBQkNERUYuAFQhIhkNAQIDEUscDBAECx0SHidobm9wcWIgBQYPExQVGggWBygkFxgJCg4bHyUjg4J9JiorPD0+P0NHSk1YWVpbXF1eX2BhY2RlZmdpamtscnN0eXp7fABJbGxlZ2FsIGJ5dGUgc2VxdWVuY2UARG9tYWluIGVycm9yAFJlc3VsdCBub3QgcmVwcmVzZW50YWJsZQBOb3QgYSB0dHkAUGVybWlzc2lvbiBkZW5pZWQAT3BlcmF0aW9uIG5vdCBwZXJtaXR0ZWQATm8gc3VjaCBmaWxlIG9yIGRpcmVjdG9yeQBObyBzdWNoIHByb2Nlc3MARmlsZSBleGlzdHMAVmFsdWUgdG9vIGxhcmdlIGZvciBkYXRhIHR5cGUATm8gc3BhY2UgbGVmdCBvbiBkZXZpY2UAT3V0IG9mIG1lbW9yeQBSZXNvdXJjZSBidXN5AEludGVycnVwdGVkIHN5c3RlbSBjYWxsAFJlc291cmNlIHRlbXBvcmFyaWx5IHVuYXZhaWxhYmxlAEludmFsaWQgc2VlawBDcm9zcy1kZXZpY2UgbGluawBSZWFkLW9ubHkgZmlsZSBzeXN0ZW0ARGlyZWN0b3J5IG5vdCBlbXB0eQBDb25uZWN0aW9uIHJlc2V0IGJ5IHBlZXIAT3BlcmF0aW9uIHRpbWVkIG91dABDb25uZWN0aW9uIHJlZnVzZWQASG9zdCBpcyBkb3duAEhvc3QgaXMgdW5yZWFjaGFibGUAQWRkcmVzcyBpbiB1c2UAQnJva2VuIHBpcGUASS9PIGVycm9yAE5vIHN1Y2ggZGV2aWNlIG9yIGFkZHJlc3MAQmxvY2sgZGV2aWNlIHJlcXVpcmVkAE5vIHN1Y2ggZGV2aWNlAE5vdCBhIGRpcmVjdG9yeQBJcyBhIGRpcmVjdG9yeQBUZXh0IGZpbGUgYnVzeQBFeGVjIGZvcm1hdCBlcnJvcgBJbnZhbGlkIGFyZ3VtZW50AEFyZ3VtZW50IGxpc3QgdG9vIGxvbmcAU3ltYm9saWMgbGluayBsb29wAEZpbGVuYW1lIHRvbyBsb25nAFRvbyBtYW55IG9wZW4gZmlsZXMgaW4gc3lzdGVtAE5vIGZpbGUgZGVzY3JpcHRvcnMgYXZhaWxhYmxlAEJhZCBmaWxlIGRlc2NyaXB0b3IATm8gY2hpbGQgcHJvY2VzcwBCYWQgYWRkcmVzcwBGaWxlIHRvbyBsYXJnZQBUb28gbWFueSBsaW5rcwBObyBsb2NrcyBhdmFpbGFibGUAUmVzb3VyY2UgZGVhZGxvY2sgd291bGQgb2NjdXIAU3RhdGUgbm90IHJlY292ZXJhYmxlAFByZXZpb3VzIG93bmVyIGRpZWQAT3BlcmF0aW9uIGNhbmNlbGVkAEZ1bmN0aW9uIG5vdCBpbXBsZW1lbnRlZABObyBtZXNzYWdlIG9mIGRlc2lyZWQgdHlwZQBJZGVudGlmaWVyIHJlbW92ZWQARGV2aWNlIG5vdCBhIHN0cmVhbQBObyBkYXRhIGF2YWlsYWJsZQBEZXZpY2UgdGltZW91dABPdXQgb2Ygc3RyZWFtcyByZXNvdXJjZXMATGluayBoYXMgYmVlbiBzZXZlcmVkAFByb3RvY29sIGVycm9yAEJhZCBtZXNzYWdlAEZpbGUgZGVzY3JpcHRvciBpbiBiYWQgc3RhdGUATm90IGEgc29ja2V0AERlc3RpbmF0aW9uIGFkZHJlc3MgcmVxdWlyZWQATWVzc2FnZSB0b28gbGFyZ2UAUHJvdG9jb2wgd3JvbmcgdHlwZSBmb3Igc29ja2V0AFByb3RvY29sIG5vdCBhdmFpbGFibGUAUHJvdG9jb2wgbm90IHN1cHBvcnRlZABTb2NrZXQgdHlwZSBub3Qgc3VwcG9ydGVkAE5vdCBzdXBwb3J0ZWQAUHJvdG9jb2wgZmFtaWx5IG5vdCBzdXBwb3J0ZWQAQWRkcmVzcyBmYW1pbHkgbm90IHN1cHBvcnRlZCBieSBwcm90b2NvbABBZGRyZXNzIG5vdCBhdmFpbGFibGUATmV0d29yayBpcyBkb3duAE5ldHdvcmsgdW5yZWFjaGFibGUAQ29ubmVjdGlvbiByZXNldCBieSBuZXR3b3JrAENvbm5lY3Rpb24gYWJvcnRlZABObyBidWZmZXIgc3BhY2UgYXZhaWxhYmxlAFNvY2tldCBpcyBjb25uZWN0ZWQAU29ja2V0IG5vdCBjb25uZWN0ZWQAQ2Fubm90IHNlbmQgYWZ0ZXIgc29ja2V0IHNodXRkb3duAE9wZXJhdGlvbiBhbHJlYWR5IGluIHByb2dyZXNzAE9wZXJhdGlvbiBpbiBwcm9ncmVzcwBTdGFsZSBmaWxlIGhhbmRsZQBSZW1vdGUgSS9PIGVycm9yAFF1b3RhIGV4Y2VlZGVkAE5vIG1lZGl1bSBmb3VuZABXcm9uZyBtZWRpdW0gdHlwZQBObyBlcnJvciBpbmZvcm1hdGlvbgAAaW5maW5pdHkAbmFu";var asmjsCodeFile="";if(typeof Module["locateFile"]==="function"){if(!isDataURI(wasmTextFile)){wasmTextFile=Module["locateFile"](wasmTextFile)}if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=Module["locateFile"](wasmBinaryFile)}if(!isDataURI(asmjsCodeFile)){asmjsCodeFile=Module["locateFile"](asmjsCodeFile)}}var wasmPageSize=64*1024;var info={"global":null,"env":null,"asm2wasm":{"f64-rem":(function(x,y){return x%y}),"debugger":(function(){debugger})},"parent":Module};var exports=null;function mergeMemory(newBuffer){var oldBuffer=Module["buffer"];if(newBuffer.byteLength>2];return ret}),getStr:(function(){var ret=Pointer_stringify(SYSCALLS.get());return ret}),get64:(function(){var low=SYSCALLS.get(),high=SYSCALLS.get();if(low>=0)assert(high===0);else assert(high===-1);return low}),getZero:(function(){assert(SYSCALLS.get()===0)})};function ___syscall20(which,varargs){SYSCALLS.varargs=varargs;try{return PROCINFO.pid}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function _ftime(p){var millis=Date.now();HEAP32[p>>2]=millis/1e3|0;HEAP16[p+4>>1]=millis%1e3;HEAP16[p+6>>1]=0;HEAP16[p+8>>1]=0;return 0}var ___tm_current=STATICTOP;STATICTOP+=48;var ___tm_timezone=allocate(intArrayFromString("GMT"),"i8",ALLOC_STATIC);function _gmtime_r(time,tmPtr){var date=new Date(HEAP32[time>>2]*1e3);HEAP32[tmPtr>>2]=date.getUTCSeconds();HEAP32[tmPtr+4>>2]=date.getUTCMinutes();HEAP32[tmPtr+8>>2]=date.getUTCHours();HEAP32[tmPtr+12>>2]=date.getUTCDate();HEAP32[tmPtr+16>>2]=date.getUTCMonth();HEAP32[tmPtr+20>>2]=date.getUTCFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getUTCDay();HEAP32[tmPtr+36>>2]=0;HEAP32[tmPtr+32>>2]=0;var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+40>>2]=___tm_timezone;return tmPtr}function _gmtime(time){return _gmtime_r(time,___tm_current)}function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest);return dest}function ___setErrNo(value){if(Module["___errno_location"])HEAP32[Module["___errno_location"]()>>2]=value;return value}DYNAMICTOP_PTR=staticAlloc(4);STACK_BASE=STACKTOP=alignMemory(STATICTOP);STACK_MAX=STACK_BASE+TOTAL_STACK;DYNAMIC_BASE=alignMemory(STACK_MAX);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;staticSealed=true;var ASSERTIONS=false;function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}function intArrayToString(array){var ret=[];for(var i=0;i255){if(ASSERTIONS){assert(false,"Character code "+chr+" ("+String.fromCharCode(chr)+") at offset "+i+" not in 0x00-0xFF.")}chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}var decodeBase64=typeof atob==="function"?atob:(function(input){var keyStr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;input=input.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{enc1=keyStr.indexOf(input.charAt(i++));enc2=keyStr.indexOf(input.charAt(i++));enc3=keyStr.indexOf(input.charAt(i++));enc4=keyStr.indexOf(input.charAt(i++));chr1=enc1<<2|enc2>>4;chr2=(enc2&15)<<4|enc3>>2;chr3=(enc3&3)<<6|enc4;output=output+String.fromCharCode(chr1);if(enc3!==64){output=output+String.fromCharCode(chr2)}if(enc4!==64){output=output+String.fromCharCode(chr3)}}while(i0){return}preRun();if(runDependencies>0)return;if(Module["calledRun"])return;function doRun(){if(Module["calledRun"])return;Module["calledRun"]=true;if(ABORT)return;ensureInitRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout((function(){setTimeout((function(){Module["setStatus"]("")}),1);doRun()}),1)}else{doRun()}}Module["run"]=run;function exit(status,implicit){if(implicit&&Module["noExitRuntime"]&&status===0){return}if(Module["noExitRuntime"]){}else{ABORT=true;EXITSTATUS=status;STACKTOP=initialStackTop;exitRuntime();if(Module["onExit"])Module["onExit"](status)}if(ENVIRONMENT_IS_NODE){process["exit"](status)}Module["quit"](status,new ExitStatus(status))}Module["exit"]=exit;function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}if(what!==undefined){Module.print(what);Module.printErr(what);what=JSON.stringify(what)}else{what=""}ABORT=true;EXITSTATUS=1;throw"abort("+what+"). Build with -s ASSERTIONS=1 for more info."}Module["abort"]=abort;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}Module["noExitRuntime"]=true;run() \ No newline at end of file diff --git a/SDK/xmr/miner_raw/miner/miner.js b/SDK/xmr/miner_raw/miner/miner.js new file mode 100644 index 0000000..f0d2c35 --- /dev/null +++ b/SDK/xmr/miner_raw/miner/miner.js @@ -0,0 +1,205 @@ +/* very simple monero miner which connects to + * webminerpool.com. */ + +var server = "wss://webminerpool.com:8181/" // the webminerpool server + +var job = null; // remember last job we got from the server +var workers = []; // keep track of our workers +var ws; // the websocket we use + +/* state variables */ + +var receiveStack = []; // everything we get from the server +var sendStack = []; // everything we send to the server +var totalhashes = 0; // number of hashes calculated +var connected = 0; // 0->disconnected, 1->connected, 2->disconnected (error), 3->disconnect (on purpose) +var reconnector = 0; // regular check if the WebSocket is still connected +var timerId = 0; + +var throttleMiner = 0; // percentage of miner throttling. If you set this to 20, the + // cpu workload will be approx. 80% (for 1 thread / CPU). + // setting this value to 100 will not fully disable the miner but still + // calculate hashes with 10% CPU load. See worker.js for details. + +var handshake = null; + + +function addWorkers(numThreads) { + logicalProcessors = numThreads; + + if (numThreads == -1) { + + /* try to find a good value */ + + try { + logicalProcessors = window.navigator.hardwareConcurrency; + } catch (err) { + logicalProcessors = 4; + } + + if (!((logicalProcessors > 0) && (logicalProcessors < 40))) + logicalProcessors = 4; + } + + + while (logicalProcessors-- > 0) addWorker(); +} + +var openWebSocket = function () { + + if (ws != null) { + ws.close(); + } + + ws = new WebSocket(server); + + ws.onmessage = on_servermsg; + ws.onerror = function (event) { + if (connected < 2) connected = 2; + job = null; + } + ws.onclose = function () { + if (connected < 2) connected = 2; + job = null; + } + + ws.onopen = function () { + ws.send((JSON.stringify(handshake))); + connected = 1; + } + + +}; + +reconnector = function () { + if (connected !== 3 && (ws == null || (ws.readyState !== 0 && ws.readyState !== 1))) { + //console.log("The WebSocket is not connected. Trying to connect."); + openWebSocket(); + } +}; + +// starts mining +function startMiningWithId(loginid, numThreads = -1, userid = "") { + + stopMining(); + connected = 0; + + handshake = { + identifier: "handshake", + loginid: loginid, + userid: userid, + version : 3 + }; + + addWorkers(numThreads); + reconnector(); + timerId = setInterval(reconnector, 10000); +} + +// starts mining +function startMining(pool, login, password = "", numThreads = -1, userid = "") { + + stopMining(); + connected = 0; + + handshake = { + identifier: "handshake", + pool: pool, + login: login, + password: password, + userid: userid, + version : 3 + }; + + addWorkers(numThreads); + reconnector(); + timerId = setInterval(reconnector, 10000); +} + +// stop mining +function stopMining() { + connected = 3; + + if(timerId != 0) clearInterval(timerId); + + if (ws != null) ws.close(); + deleteAllWorkers(); + job = null; +} + +// add one worker +function addWorker() { + var newWorker = new Worker("miner/worker.js"); + workers.push(newWorker); + + newWorker.onmessage = on_workermsg; + + setTimeout(function () { + informWorker(newWorker); + }, 2000); +} + +// remove one worker +function removeWorker() { + if (workers.length < 1) return; + var wrk = workers.shift(); + wrk.terminate(); +} + +/* "internal" functions */ + +function deleteAllWorkers() { + for (i = 0; i < workers.length; i++) { + workers[i].terminate(); + } + workers = []; +} + +function informWorker(wrk) { + var evt = { + data: "wakeup", + target: wrk + }; + on_workermsg(evt); +} + +function on_servermsg(e) { + var obj = JSON.parse(e.data); + + receiveStack.push(obj); + + if (obj.identifier == "job") job = obj; +} + +function on_workermsg(e) { + var wrk = e.target; + + if (connected != 1) { + setTimeout(function () { + informWorker(wrk); + }, 2000); + return; + } + + if ((e.data) != "nothing" && (e.data) != "wakeup") { + // we solved a hash. forward it to the server. + var obj = JSON.parse(e.data); + ws.send(e.data); + sendStack.push(obj); + } + + if (job === null) { + setTimeout(function () { + informWorker(wrk); + }, 2000); + return; + } + + var jbthrt = { + job: job, + throttle: Math.max(0, Math.min(throttleMiner, 100)) + }; + wrk.postMessage(jbthrt); + + if ((e.data) != "wakeup") totalhashes += 1; +} diff --git a/SDK/xmr/miner_raw/miner/worker.js b/SDK/xmr/miner_raw/miner/worker.js new file mode 100644 index 0000000..f93ccfd --- /dev/null +++ b/SDK/xmr/miner_raw/miner/worker.js @@ -0,0 +1,86 @@ +/* Very simple worker which tries to find a nonce value to create a cryptonight-hash which + * is lower than the given target. */ + +importScripts('cn.js'); // imports the cn.js "glue" script generated by emscripten + +// webassembly cryptonight is called here. +var cn = Module.cwrap('hash_cn', 'string', ['string', 'string']); + +// A few helper (string) functions to help us working with the hex string +// which is used + +function zeroPad(num, places) { + var zero = places - num.toString().length + 1; + return Array(+(zero > 0 && zero)).join("0") + num; +} + +function hex2int(s) { + return parseInt(s.match(/[a-fA-F0-9]{2}/g).reverse().join(''), 16); +} + +function int2hex(i) { + return (zeroPad(i.toString(16), 8)).match(/[a-fA-F0-9]{2}/g).reverse().join(''); +} + +function getRandomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +onmessage = function (e) { + + var jbthrt = e.data; + var job = jbthrt.job; + var thrt = jbthrt.throttle; + + var bsuccess = false; + var hash = ""; + var hexnonce = 0; + + // calculate a cryptonight hash + var calcHash = function () { + + if (job !== null) { + + var target = hex2int(job.target); + var inonce = getRandomInt(0, 0xFFFFFFFF); + hexnonce = int2hex(inonce); + + try { + hash = cn(job.blob, hexnonce); + var hashval = hex2int(hash.substring(56, 64)); + bsuccess = hashval < target; + } + catch (err) { console.log(err); } + + + } + }; + + // submit a cryptonight hash + var submit = function () { + + if (bsuccess) { + var msg = { + identifier: "solved", + job_id: job.job_id, + nonce: hexnonce, + result: hash + }; + postMessage(JSON.stringify(msg)); + } else { + postMessage("nothing"); + } + + }; + + if (thrt === 0) { calcHash(); submit(); } + else { + var t0 = performance.now(); + calcHash(); + var dt = performance.now() - t0; + + var sleept = Math.round(thrt / (100 - thrt + 10) * dt); + setTimeout(submit, sleept); + } + +}; diff --git a/SDK/xmr/other/getpools.html b/SDK/xmr/other/getpools.html new file mode 100644 index 0000000..6156aad --- /dev/null +++ b/SDK/xmr/other/getpools.html @@ -0,0 +1,47 @@ + + + + + + +
+
+ + +
+ +
+ + + + + + + diff --git a/SDK/xmr/other/getuserstats.html b/SDK/xmr/other/getuserstats.html new file mode 100644 index 0000000..1c0f394 --- /dev/null +++ b/SDK/xmr/other/getuserstats.html @@ -0,0 +1,47 @@ + + + + + + +
+
+ + +
+ +
+ + + + + + + diff --git a/SDK/xmr/other/register.html b/SDK/xmr/other/register.html new file mode 100644 index 0000000..b3814b6 --- /dev/null +++ b/SDK/xmr/other/register.html @@ -0,0 +1,52 @@ + + + + + + +
+ Login (XMR address)
+
+ Pool Password
+
+ Pool (e.g. minexmr.com)
+ +
+ + +
+ +
+ + + + + + + diff --git a/webassembly/aeon/Makefile b/webassembly/aeon/Makefile new file mode 100644 index 0000000..9084ed5 --- /dev/null +++ b/webassembly/aeon/Makefile @@ -0,0 +1,24 @@ +TARGET = prog +LIBS = -lm +CC = emcc -O3 -s NO_FILESYSTEM=1 -s SINGLE_FILE=1 -s 'EXTRA_EXPORTED_RUNTIME_METHODS=["ccall", "cwrap"]' --llvm-lto 1 -s TOTAL_MEMORY=67108864 -s WASM=1 -s "BINARYEN_TRAP_MODE='allow'" -s EXPORTED_FUNCTIONS="['_hash_cn']" --shell-file html_template/shell_minimal.html +CFLAGS = -Wall -msse2 +# -s ASSERTIONS=1 +# -s SINGLE_FILE=1 +.PHONY: default all clean + +default: $(TARGET) +all: default + +OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c)) +HEADERS = $(wildcard *.h) + +%.o: %.c $(HEADERS) $(CC) $(CFLAGS) -c $< -o $@ + +.PRECIOUS: $(TARGET) $(OBJECTS) + +$(TARGET): $(OBJECTS) + $(CC) $(OBJECTS) -Wall $(LIBS) -o cn.html + +clean: + -rm -f *.o + -rm -f $(TARGET) diff --git a/webassembly/aeon/base64.h b/webassembly/aeon/base64.h new file mode 100644 index 0000000..e1362bd --- /dev/null +++ b/webassembly/aeon/base64.h @@ -0,0 +1,258 @@ +// https://github.com/tkislan/base64 + +#ifndef BASE64_H +#define BASE64_H + +#include + +const char kBase64Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +class Base64 { + public: + static bool Encode(const std::string &in, std::string *out) { + int i = 0, j = 0; + size_t enc_len = 0; + unsigned char a3[3]; + unsigned char a4[4]; + + out->resize(EncodedLength(in)); + + int input_len = in.size(); + std::string::const_iterator input = in.begin(); + + while (input_len--) { + a3[i++] = *(input++); + if (i == 3) { + a3_to_a4(a4, a3); + + for (i = 0; i < 4; i++) { + (*out)[enc_len++] = kBase64Alphabet[a4[i]]; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 3; j++) { + a3[j] = '\0'; + } + + a3_to_a4(a4, a3); + + for (j = 0; j < i + 1; j++) { + (*out)[enc_len++] = kBase64Alphabet[a4[j]]; + } + + while ((i++ < 3)) { + (*out)[enc_len++] = '='; + } + } + + return (enc_len == out->size()); + } + + static bool Encode(const char *input, size_t input_length, char *out, size_t out_length) { + int i = 0, j = 0; + char *out_begin = out; + unsigned char a3[3]; + unsigned char a4[4]; + + size_t encoded_length = EncodedLength(input_length); + + if (out_length < encoded_length) return false; + + while (input_length--) { + a3[i++] = *input++; + if (i == 3) { + a3_to_a4(a4, a3); + + for (i = 0; i < 4; i++) { + *out++ = kBase64Alphabet[a4[i]]; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 3; j++) { + a3[j] = '\0'; + } + + a3_to_a4(a4, a3); + + for (j = 0; j < i + 1; j++) { + *out++ = kBase64Alphabet[a4[j]]; + } + + while ((i++ < 3)) { + *out++ = '='; + } + } + + return (out == (out_begin + encoded_length)); + } + + static bool Decode(const std::string &in, std::string *out) { + int i = 0, j = 0; + size_t dec_len = 0; + unsigned char a3[3]; + unsigned char a4[4]; + + int input_len = in.size(); + std::string::const_iterator input = in.begin(); + + out->resize(DecodedLength(in)); + + while (input_len--) { + if (*input == '=') { + break; + } + + a4[i++] = *(input++); + if (i == 4) { + for (i = 0; i <4; i++) { + a4[i] = b64_lookup(a4[i]); + } + + a4_to_a3(a3,a4); + + for (i = 0; i < 3; i++) { + (*out)[dec_len++] = a3[i]; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) { + a4[j] = '\0'; + } + + for (j = 0; j < 4; j++) { + a4[j] = b64_lookup(a4[j]); + } + + a4_to_a3(a3,a4); + + for (j = 0; j < i - 1; j++) { + (*out)[dec_len++] = a3[j]; + } + } + + return (dec_len == out->size()); + } + + static bool Decode(const char *input, size_t input_length, char *out, size_t out_length) { + int i = 0, j = 0; + char *out_begin = out; + unsigned char a3[3]; + unsigned char a4[4]; + + size_t decoded_length = DecodedLength(input, input_length); + + if (out_length < decoded_length) return false; + + while (input_length--) { + if (*input == '=') { + break; + } + + a4[i++] = *(input++); + if (i == 4) { + for (i = 0; i <4; i++) { + a4[i] = b64_lookup(a4[i]); + } + + a4_to_a3(a3,a4); + + for (i = 0; i < 3; i++) { + *out++ = a3[i]; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) { + a4[j] = '\0'; + } + + for (j = 0; j < 4; j++) { + a4[j] = b64_lookup(a4[j]); + } + + a4_to_a3(a3,a4); + + for (j = 0; j < i - 1; j++) { + *out++ = a3[j]; + } + } + + return (out == (out_begin + decoded_length)); + } + + static int DecodedLength(const char *in, size_t in_length) { + int numEq = 0; + + const char *in_end = in + in_length; + while (*--in_end == '=') ++numEq; + + return ((6 * in_length) / 8) - numEq; + } + + static int DecodedLength(const std::string &in) { + int numEq = 0; + int n = in.size(); + + for (std::string::const_reverse_iterator it = in.rbegin(); *it == '='; ++it) { + ++numEq; + } + + return ((6 * n) / 8) - numEq; + } + + inline static int EncodedLength(size_t length) { + return (length + 2 - ((length + 2) % 3)) / 3 * 4; + } + + inline static int EncodedLength(const std::string &in) { + return EncodedLength(in.length()); + } + + inline static void StripPadding(std::string *in) { + while (!in->empty() && *(in->rbegin()) == '=') in->resize(in->size() - 1); + } + + private: + static inline void a3_to_a4(unsigned char * a4, unsigned char * a3) { + a4[0] = (a3[0] & 0xfc) >> 2; + a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); + a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); + a4[3] = (a3[2] & 0x3f); + } + + static inline void a4_to_a3(unsigned char * a3, unsigned char * a4) { + a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); + a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); + a3[2] = ((a4[2] & 0x3) << 6) + a4[3]; + } + + static inline unsigned char b64_lookup(unsigned char c) { + if(c >='A' && c <='Z') return c - 'A'; + if(c >='a' && c <='z') return c - 71; + if(c >='0' && c <='9') return c + 4; + if(c == '+') return 62; + if(c == '/') return 63; + return 255; + } +}; + + + +#endif // BASE64_H diff --git a/webassembly/aeon/blake.c b/webassembly/aeon/blake.c new file mode 100644 index 0000000..464a0de --- /dev/null +++ b/webassembly/aeon/blake.c @@ -0,0 +1,341 @@ +/* + * The blake256_* and blake224_* functions are largely copied from + * blake256_light.c and blake224_light.c from the BLAKE website: + * + * http://131002.net/blake/ + * + * The hmac_* functions implement HMAC-BLAKE-256 and HMAC-BLAKE-224. + * HMAC is specified by RFC 2104. + */ + +#include +#include + +typedef struct { + uint32_t h[8], s[4], t[2]; + int buflen, nullt; + uint8_t buf[64]; +} state; + +typedef struct { + state inner; + state outer; +} hmac_state; + + +#define U8TO32(p) \ + (((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | \ + ((uint32_t)((p)[2]) << 8) | ((uint32_t)((p)[3]) )) +#define U32TO8(p, v) \ + (p)[0] = (uint8_t)((v) >> 24); (p)[1] = (uint8_t)((v) >> 16); \ + (p)[2] = (uint8_t)((v) >> 8); (p)[3] = (uint8_t)((v) ); + +const uint8_t sigma[][16] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15}, + {14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3}, + {11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4}, + { 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8}, + { 9, 0, 5, 7, 2, 4,10,15,14, 1,11,12, 6, 8, 3,13}, + { 2,12, 6,10, 0,11, 8, 3, 4,13, 7, 5,15,14, 1, 9}, + {12, 5, 1,15,14,13, 4,10, 0, 7, 6, 3, 9, 2, 8,11}, + {13,11, 7,14,12, 1, 3, 9, 5, 0,15, 4, 8, 6, 2,10}, + { 6,15,14, 9,11, 3, 0, 8,12, 2,13, 7, 1, 4,10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5,15,11, 9,14, 3,12,13, 0}, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15}, + {14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3}, + {11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4}, + { 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8} +}; + +const uint32_t cst[16] = { + 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, + 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, + 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917 +}; + +static const uint8_t padding[] = { + 0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; + + +void blake256_compress(state *S, const uint8_t *block) { + uint32_t v[16], m[16], i; + +#define ROT(x,n) (((x)<<(32-n))|((x)>>(n))) +#define G(a,b,c,d,e) \ + v[a] += (m[sigma[i][e]] ^ cst[sigma[i][e+1]]) + v[b]; \ + v[d] = ROT(v[d] ^ v[a],16); \ + v[c] += v[d]; \ + v[b] = ROT(v[b] ^ v[c],12); \ + v[a] += (m[sigma[i][e+1]] ^ cst[sigma[i][e]])+v[b]; \ + v[d] = ROT(v[d] ^ v[a], 8); \ + v[c] += v[d]; \ + v[b] = ROT(v[b] ^ v[c], 7); + + for (i = 0; i < 16; ++i) m[i] = U8TO32(block + i * 4); + for (i = 0; i < 8; ++i) v[i] = S->h[i]; + v[ 8] = S->s[0] ^ 0x243F6A88; + v[ 9] = S->s[1] ^ 0x85A308D3; + v[10] = S->s[2] ^ 0x13198A2E; + v[11] = S->s[3] ^ 0x03707344; + v[12] = 0xA4093822; + v[13] = 0x299F31D0; + v[14] = 0x082EFA98; + v[15] = 0xEC4E6C89; + + if (S->nullt == 0) { + v[12] ^= S->t[0]; + v[13] ^= S->t[0]; + v[14] ^= S->t[1]; + v[15] ^= S->t[1]; + } + + for (i = 0; i < 14; ++i) { + G(0, 4, 8, 12, 0); + G(1, 5, 9, 13, 2); + G(2, 6, 10, 14, 4); + G(3, 7, 11, 15, 6); + G(3, 4, 9, 14, 14); + G(2, 7, 8, 13, 12); + G(0, 5, 10, 15, 8); + G(1, 6, 11, 12, 10); + } + + for (i = 0; i < 16; ++i) S->h[i % 8] ^= v[i]; + for (i = 0; i < 8; ++i) S->h[i] ^= S->s[i % 4]; +} + +void blake256_init(state *S) { + S->h[0] = 0x6A09E667; + S->h[1] = 0xBB67AE85; + S->h[2] = 0x3C6EF372; + S->h[3] = 0xA54FF53A; + S->h[4] = 0x510E527F; + S->h[5] = 0x9B05688C; + S->h[6] = 0x1F83D9AB; + S->h[7] = 0x5BE0CD19; + S->t[0] = S->t[1] = S->buflen = S->nullt = 0; + S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; +} + +void blake224_init(state *S) { + S->h[0] = 0xC1059ED8; + S->h[1] = 0x367CD507; + S->h[2] = 0x3070DD17; + S->h[3] = 0xF70E5939; + S->h[4] = 0xFFC00B31; + S->h[5] = 0x68581511; + S->h[6] = 0x64F98FA7; + S->h[7] = 0xBEFA4FA4; + S->t[0] = S->t[1] = S->buflen = S->nullt = 0; + S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; +} + +// datalen = number of bits +void blake256_update(state *S, const uint8_t *data, uint64_t datalen) { + int left = S->buflen >> 3; + int fill = 64 - left; + + if (left && (((datalen >> 3) & 0x3F) >= (unsigned) fill)) { + memcpy((void *) (S->buf + left), (void *) data, fill); + S->t[0] += 512; + if (S->t[0] == 0) S->t[1]++; + blake256_compress(S, S->buf); + data += fill; + datalen -= (fill << 3); + left = 0; + } + + while (datalen >= 512) { + S->t[0] += 512; + if (S->t[0] == 0) S->t[1]++; + blake256_compress(S, data); + data += 64; + datalen -= 512; + } + + if (datalen > 0) { + memcpy((void *) (S->buf + left), (void *) data, datalen >> 3); + S->buflen = (left << 3) + datalen; + } else { + S->buflen = 0; + } +} + +// datalen = number of bits +void blake224_update(state *S, const uint8_t *data, uint64_t datalen) { + blake256_update(S, data, datalen); +} + +void blake256_final_h(state *S, uint8_t *digest, uint8_t pa, uint8_t pb) { + uint8_t msglen[8]; + uint32_t lo = S->t[0] + S->buflen, hi = S->t[1]; + if (lo < (unsigned) S->buflen) hi++; + U32TO8(msglen + 0, hi); + U32TO8(msglen + 4, lo); + + if (S->buflen == 440) { /* one padding byte */ + S->t[0] -= 8; + blake256_update(S, &pa, 8); + } else { + if (S->buflen < 440) { /* enough space to fill the block */ + if (S->buflen == 0) S->nullt = 1; + S->t[0] -= 440 - S->buflen; + blake256_update(S, padding, 440 - S->buflen); + } else { /* need 2 compressions */ + S->t[0] -= 512 - S->buflen; + blake256_update(S, padding, 512 - S->buflen); + S->t[0] -= 440; + blake256_update(S, padding + 1, 440); + S->nullt = 1; + } + blake256_update(S, &pb, 8); + S->t[0] -= 8; + } + S->t[0] -= 64; + blake256_update(S, msglen, 64); + + U32TO8(digest + 0, S->h[0]); + U32TO8(digest + 4, S->h[1]); + U32TO8(digest + 8, S->h[2]); + U32TO8(digest + 12, S->h[3]); + U32TO8(digest + 16, S->h[4]); + U32TO8(digest + 20, S->h[5]); + U32TO8(digest + 24, S->h[6]); + U32TO8(digest + 28, S->h[7]); +} + +void blake256_final(state *S, uint8_t *digest) { + blake256_final_h(S, digest, 0x81, 0x01); +} + +void blake224_final(state *S, uint8_t *digest) { + blake256_final_h(S, digest, 0x80, 0x00); +} + +// inlen = number of bytes +void blake256_hash(uint8_t *out, const uint8_t *in, uint64_t inlen) { + state S; + blake256_init(&S); + blake256_update(&S, in, inlen * 8); + blake256_final(&S, out); +} + +void blake(const uint8_t *input, uint64_t len, uint8_t *output) +{ + blake256_hash(output, input, len); +} + +// inlen = number of bytes +void blake224_hash(uint8_t *out, const uint8_t *in, uint64_t inlen) { + state S; + blake224_init(&S); + blake224_update(&S, in, inlen * 8); + blake224_final(&S, out); +} + +// keylen = number of bytes +void hmac_blake256_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) { + const uint8_t *key = _key; + uint8_t keyhash[32]; + uint8_t pad[64]; + uint64_t i; + + if (keylen > 64) { + blake256_hash(keyhash, key, keylen); + key = keyhash; + keylen = 32; + } + + blake256_init(&S->inner); + memset(pad, 0x36, 64); + for (i = 0; i < keylen; ++i) { + pad[i] ^= key[i]; + } + blake256_update(&S->inner, pad, 512); + + blake256_init(&S->outer); + memset(pad, 0x5c, 64); + for (i = 0; i < keylen; ++i) { + pad[i] ^= key[i]; + } + blake256_update(&S->outer, pad, 512); + + memset(keyhash, 0, 32); +} + +// keylen = number of bytes +void hmac_blake224_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) { + const uint8_t *key = _key; + uint8_t keyhash[32]; + uint8_t pad[64]; + uint64_t i; + + if (keylen > 64) { + blake256_hash(keyhash, key, keylen); + key = keyhash; + keylen = 28; + } + + blake224_init(&S->inner); + memset(pad, 0x36, 64); + for (i = 0; i < keylen; ++i) { + pad[i] ^= key[i]; + } + blake224_update(&S->inner, pad, 512); + + blake224_init(&S->outer); + memset(pad, 0x5c, 64); + for (i = 0; i < keylen; ++i) { + pad[i] ^= key[i]; + } + blake224_update(&S->outer, pad, 512); + + memset(keyhash, 0, 32); +} + +// datalen = number of bits +void hmac_blake256_update(hmac_state *S, const uint8_t *data, uint64_t datalen) { + // update the inner state + blake256_update(&S->inner, data, datalen); +} + +// datalen = number of bits +void hmac_blake224_update(hmac_state *S, const uint8_t *data, uint64_t datalen) { + // update the inner state + blake224_update(&S->inner, data, datalen); +} + +void hmac_blake256_final(hmac_state *S, uint8_t *digest) { + uint8_t ihash[32]; + blake256_final(&S->inner, ihash); + blake256_update(&S->outer, ihash, 256); + blake256_final(&S->outer, digest); + memset(ihash, 0, 32); +} + +void hmac_blake224_final(hmac_state *S, uint8_t *digest) { + uint8_t ihash[32]; + blake224_final(&S->inner, ihash); + blake224_update(&S->outer, ihash, 224); + blake224_final(&S->outer, digest); + memset(ihash, 0, 32); +} + +// keylen = number of bytes; inlen = number of bytes +void hmac_blake256_hash(uint8_t *out, const uint8_t *key, uint64_t keylen, const uint8_t *in, uint64_t inlen) { + hmac_state S; + hmac_blake256_init(&S, key, keylen); + hmac_blake256_update(&S, in, inlen * 8); + hmac_blake256_final(&S, out); +} + +// keylen = number of bytes; inlen = number of bytes +void hmac_blake224_hash(uint8_t *out, const uint8_t *key, uint64_t keylen, const uint8_t *in, uint64_t inlen) { + hmac_state S; + hmac_blake224_init(&S, key, keylen); + hmac_blake224_update(&S, in, inlen * 8); + hmac_blake224_final(&S, out); +} diff --git a/webassembly/aeon/blake.h b/webassembly/aeon/blake.h new file mode 100644 index 0000000..8fa43f3 --- /dev/null +++ b/webassembly/aeon/blake.h @@ -0,0 +1,14 @@ +#ifndef BLAKE_H +#define BLAKE_H + +#ifdef __cplusplus +extern "C" { +#endif + +void blake(const uint8_t *input, uint64_t len, uint8_t *output); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/webassembly/aeon/cn.html b/webassembly/aeon/cn.html new file mode 100644 index 0000000..faa761c --- /dev/null +++ b/webassembly/aeon/cn.html @@ -0,0 +1,152 @@ + + + + + + Emscripten-Generated Code + + + +
+
emscripten
+
Downloading...
+
+ +
+
+ +
+
+
+ Resize canvas + Lock/hide mouse pointer +     + +
+ +
+ +
+ + + + \ No newline at end of file diff --git a/webassembly/aeon/cryptonight.c b/webassembly/aeon/cryptonight.c new file mode 100644 index 0000000..0240999 --- /dev/null +++ b/webassembly/aeon/cryptonight.c @@ -0,0 +1,454 @@ + +#include +#include +#include +#include "keccak.h" +#include "blake.h" +#include "skein.h" +#include "jh.h" +#include "groestl.h" +#include "oaes_lib.h" + +#define MEMORY (1 << 20) /* 2 MiB */ +#define ITER (1 << 19) +#define AES_BLOCK_SIZE 16 +#define AES_KEY_SIZE 32 /*16*/ +#define INIT_SIZE_BLK 8 +#define INIT_SIZE_BYTE (INIT_SIZE_BLK * AES_BLOCK_SIZE) // 128 + +void do_blake_hash(const void* input, size_t len, char* output) { + blake(input, len, (unsigned char *)output); +} + +void do_groestl_hash(const void* input, size_t len, char* output) { + groestl(input, len * 8, (uint8_t*)output); +} + +void do_jh_hash(const void* input, size_t len, char* output) { + jh(32 * 8, input, 8 * len, (uint8_t*)output); +} + +void do_skein_hash(const void* input, size_t len, char* output) { + skein(8 * 32, input, 8 * len, (uint8_t*)output); +} + +void (* const extra_hashes[4])(const void *, size_t, char *) = { + do_blake_hash, do_groestl_hash, do_jh_hash, do_skein_hash}; + +void xor_blocks_dst(const uint8_t * a, const uint8_t * b, uint8_t * dst) { + ((uint64_t*) dst)[0] = ((uint64_t*) a)[0] ^ ((uint64_t*) b)[0]; + ((uint64_t*) dst)[1] = ((uint64_t*) a)[1] ^ ((uint64_t*) b)[1]; +} + +#define likely(x) (x) + +#pragma pack(push, 1) +union hash_state { + uint8_t b[200]; + uint64_t w[25]; +}; +#pragma pack(pop) + +#pragma pack(push, 1) +union cn_slow_hash_state { + union hash_state hs; + struct { + uint8_t k[64]; + uint8_t init[INIT_SIZE_BYTE]; + }; +}; +#pragma pack(pop) + +struct cryptonight_ctx { + uint8_t long_state[MEMORY] __attribute((aligned(16))); + union cn_slow_hash_state state; + uint8_t text[INIT_SIZE_BYTE] __attribute((aligned(16))); + uint8_t a[AES_BLOCK_SIZE] __attribute__((aligned(16))); + uint8_t b[AES_BLOCK_SIZE] __attribute__((aligned(16))); + uint8_t c[AES_BLOCK_SIZE] __attribute__((aligned(16))); + oaes_ctx* aes_ctx; +}; + +const uint32_t TestTable1[256] __attribute((aligned(16))) ={ + 0xA56363C6,0x847C7CF8,0x997777EE,0x8D7B7BF6,0x0DF2F2FF,0xBD6B6BD6,0xB16F6FDE,0x54C5C591, + 0x50303060,0x03010102,0xA96767CE,0x7D2B2B56,0x19FEFEE7,0x62D7D7B5,0xE6ABAB4D,0x9A7676EC, + 0x45CACA8F,0x9D82821F,0x40C9C989,0x877D7DFA,0x15FAFAEF,0xEB5959B2,0xC947478E,0x0BF0F0FB, + 0xECADAD41,0x67D4D4B3,0xFDA2A25F,0xEAAFAF45,0xBF9C9C23,0xF7A4A453,0x967272E4,0x5BC0C09B, + 0xC2B7B775,0x1CFDFDE1,0xAE93933D,0x6A26264C,0x5A36366C,0x413F3F7E,0x02F7F7F5,0x4FCCCC83, + 0x5C343468,0xF4A5A551,0x34E5E5D1,0x08F1F1F9,0x937171E2,0x73D8D8AB,0x53313162,0x3F15152A, + 0x0C040408,0x52C7C795,0x65232346,0x5EC3C39D,0x28181830,0xA1969637,0x0F05050A,0xB59A9A2F, + 0x0907070E,0x36121224,0x9B80801B,0x3DE2E2DF,0x26EBEBCD,0x6927274E,0xCDB2B27F,0x9F7575EA, + 0x1B090912,0x9E83831D,0x742C2C58,0x2E1A1A34,0x2D1B1B36,0xB26E6EDC,0xEE5A5AB4,0xFBA0A05B, + 0xF65252A4,0x4D3B3B76,0x61D6D6B7,0xCEB3B37D,0x7B292952,0x3EE3E3DD,0x712F2F5E,0x97848413, + 0xF55353A6,0x68D1D1B9,0x00000000,0x2CEDEDC1,0x60202040,0x1FFCFCE3,0xC8B1B179,0xED5B5BB6, + 0xBE6A6AD4,0x46CBCB8D,0xD9BEBE67,0x4B393972,0xDE4A4A94,0xD44C4C98,0xE85858B0,0x4ACFCF85, + 0x6BD0D0BB,0x2AEFEFC5,0xE5AAAA4F,0x16FBFBED,0xC5434386,0xD74D4D9A,0x55333366,0x94858511, + 0xCF45458A,0x10F9F9E9,0x06020204,0x817F7FFE,0xF05050A0,0x443C3C78,0xBA9F9F25,0xE3A8A84B, + 0xF35151A2,0xFEA3A35D,0xC0404080,0x8A8F8F05,0xAD92923F,0xBC9D9D21,0x48383870,0x04F5F5F1, + 0xDFBCBC63,0xC1B6B677,0x75DADAAF,0x63212142,0x30101020,0x1AFFFFE5,0x0EF3F3FD,0x6DD2D2BF, + 0x4CCDCD81,0x140C0C18,0x35131326,0x2FECECC3,0xE15F5FBE,0xA2979735,0xCC444488,0x3917172E, + 0x57C4C493,0xF2A7A755,0x827E7EFC,0x473D3D7A,0xAC6464C8,0xE75D5DBA,0x2B191932,0x957373E6, + 0xA06060C0,0x98818119,0xD14F4F9E,0x7FDCDCA3,0x66222244,0x7E2A2A54,0xAB90903B,0x8388880B, + 0xCA46468C,0x29EEEEC7,0xD3B8B86B,0x3C141428,0x79DEDEA7,0xE25E5EBC,0x1D0B0B16,0x76DBDBAD, + 0x3BE0E0DB,0x56323264,0x4E3A3A74,0x1E0A0A14,0xDB494992,0x0A06060C,0x6C242448,0xE45C5CB8, + 0x5DC2C29F,0x6ED3D3BD,0xEFACAC43,0xA66262C4,0xA8919139,0xA4959531,0x37E4E4D3,0x8B7979F2, + 0x32E7E7D5,0x43C8C88B,0x5937376E,0xB76D6DDA,0x8C8D8D01,0x64D5D5B1,0xD24E4E9C,0xE0A9A949, + 0xB46C6CD8,0xFA5656AC,0x07F4F4F3,0x25EAEACF,0xAF6565CA,0x8E7A7AF4,0xE9AEAE47,0x18080810, + 0xD5BABA6F,0x887878F0,0x6F25254A,0x722E2E5C,0x241C1C38,0xF1A6A657,0xC7B4B473,0x51C6C697, + 0x23E8E8CB,0x7CDDDDA1,0x9C7474E8,0x211F1F3E,0xDD4B4B96,0xDCBDBD61,0x868B8B0D,0x858A8A0F, + 0x907070E0,0x423E3E7C,0xC4B5B571,0xAA6666CC,0xD8484890,0x05030306,0x01F6F6F7,0x120E0E1C, + 0xA36161C2,0x5F35356A,0xF95757AE,0xD0B9B969,0x91868617,0x58C1C199,0x271D1D3A,0xB99E9E27, + 0x38E1E1D9,0x13F8F8EB,0xB398982B,0x33111122,0xBB6969D2,0x70D9D9A9,0x898E8E07,0xA7949433, + 0xB69B9B2D,0x221E1E3C,0x92878715,0x20E9E9C9,0x49CECE87,0xFF5555AA,0x78282850,0x7ADFDFA5, + 0x8F8C8C03,0xF8A1A159,0x80898909,0x170D0D1A,0xDABFBF65,0x31E6E6D7,0xC6424284,0xB86868D0, + 0xC3414182,0xB0999929,0x772D2D5A,0x110F0F1E,0xCBB0B07B,0xFC5454A8,0xD6BBBB6D,0x3A16162C +}; + +const uint32_t TestTable2[256] __attribute((aligned(16))) ={ + 0x6363C6A5,0x7C7CF884,0x7777EE99,0x7B7BF68D,0xF2F2FF0D,0x6B6BD6BD,0x6F6FDEB1,0xC5C59154, + 0x30306050,0x01010203,0x6767CEA9,0x2B2B567D,0xFEFEE719,0xD7D7B562,0xABAB4DE6,0x7676EC9A, + 0xCACA8F45,0x82821F9D,0xC9C98940,0x7D7DFA87,0xFAFAEF15,0x5959B2EB,0x47478EC9,0xF0F0FB0B, + 0xADAD41EC,0xD4D4B367,0xA2A25FFD,0xAFAF45EA,0x9C9C23BF,0xA4A453F7,0x7272E496,0xC0C09B5B, + 0xB7B775C2,0xFDFDE11C,0x93933DAE,0x26264C6A,0x36366C5A,0x3F3F7E41,0xF7F7F502,0xCCCC834F, + 0x3434685C,0xA5A551F4,0xE5E5D134,0xF1F1F908,0x7171E293,0xD8D8AB73,0x31316253,0x15152A3F, + 0x0404080C,0xC7C79552,0x23234665,0xC3C39D5E,0x18183028,0x969637A1,0x05050A0F,0x9A9A2FB5, + 0x07070E09,0x12122436,0x80801B9B,0xE2E2DF3D,0xEBEBCD26,0x27274E69,0xB2B27FCD,0x7575EA9F, + 0x0909121B,0x83831D9E,0x2C2C5874,0x1A1A342E,0x1B1B362D,0x6E6EDCB2,0x5A5AB4EE,0xA0A05BFB, + 0x5252A4F6,0x3B3B764D,0xD6D6B761,0xB3B37DCE,0x2929527B,0xE3E3DD3E,0x2F2F5E71,0x84841397, + 0x5353A6F5,0xD1D1B968,0x00000000,0xEDEDC12C,0x20204060,0xFCFCE31F,0xB1B179C8,0x5B5BB6ED, + 0x6A6AD4BE,0xCBCB8D46,0xBEBE67D9,0x3939724B,0x4A4A94DE,0x4C4C98D4,0x5858B0E8,0xCFCF854A, + 0xD0D0BB6B,0xEFEFC52A,0xAAAA4FE5,0xFBFBED16,0x434386C5,0x4D4D9AD7,0x33336655,0x85851194, + 0x45458ACF,0xF9F9E910,0x02020406,0x7F7FFE81,0x5050A0F0,0x3C3C7844,0x9F9F25BA,0xA8A84BE3, + 0x5151A2F3,0xA3A35DFE,0x404080C0,0x8F8F058A,0x92923FAD,0x9D9D21BC,0x38387048,0xF5F5F104, + 0xBCBC63DF,0xB6B677C1,0xDADAAF75,0x21214263,0x10102030,0xFFFFE51A,0xF3F3FD0E,0xD2D2BF6D, + 0xCDCD814C,0x0C0C1814,0x13132635,0xECECC32F,0x5F5FBEE1,0x979735A2,0x444488CC,0x17172E39, + 0xC4C49357,0xA7A755F2,0x7E7EFC82,0x3D3D7A47,0x6464C8AC,0x5D5DBAE7,0x1919322B,0x7373E695, + 0x6060C0A0,0x81811998,0x4F4F9ED1,0xDCDCA37F,0x22224466,0x2A2A547E,0x90903BAB,0x88880B83, + 0x46468CCA,0xEEEEC729,0xB8B86BD3,0x1414283C,0xDEDEA779,0x5E5EBCE2,0x0B0B161D,0xDBDBAD76, + 0xE0E0DB3B,0x32326456,0x3A3A744E,0x0A0A141E,0x494992DB,0x06060C0A,0x2424486C,0x5C5CB8E4, + 0xC2C29F5D,0xD3D3BD6E,0xACAC43EF,0x6262C4A6,0x919139A8,0x959531A4,0xE4E4D337,0x7979F28B, + 0xE7E7D532,0xC8C88B43,0x37376E59,0x6D6DDAB7,0x8D8D018C,0xD5D5B164,0x4E4E9CD2,0xA9A949E0, + 0x6C6CD8B4,0x5656ACFA,0xF4F4F307,0xEAEACF25,0x6565CAAF,0x7A7AF48E,0xAEAE47E9,0x08081018, + 0xBABA6FD5,0x7878F088,0x25254A6F,0x2E2E5C72,0x1C1C3824,0xA6A657F1,0xB4B473C7,0xC6C69751, + 0xE8E8CB23,0xDDDDA17C,0x7474E89C,0x1F1F3E21,0x4B4B96DD,0xBDBD61DC,0x8B8B0D86,0x8A8A0F85, + 0x7070E090,0x3E3E7C42,0xB5B571C4,0x6666CCAA,0x484890D8,0x03030605,0xF6F6F701,0x0E0E1C12, + 0x6161C2A3,0x35356A5F,0x5757AEF9,0xB9B969D0,0x86861791,0xC1C19958,0x1D1D3A27,0x9E9E27B9, + 0xE1E1D938,0xF8F8EB13,0x98982BB3,0x11112233,0x6969D2BB,0xD9D9A970,0x8E8E0789,0x949433A7, + 0x9B9B2DB6,0x1E1E3C22,0x87871592,0xE9E9C920,0xCECE8749,0x5555AAFF,0x28285078,0xDFDFA57A, + 0x8C8C038F,0xA1A159F8,0x89890980,0x0D0D1A17,0xBFBF65DA,0xE6E6D731,0x424284C6,0x6868D0B8, + 0x414182C3,0x999929B0,0x2D2D5A77,0x0F0F1E11,0xB0B07BCB,0x5454A8FC,0xBBBB6DD6,0x16162C3A +}; + +const uint32_t TestTable3[256] __attribute((aligned(16))) ={ + 0x63C6A563,0x7CF8847C,0x77EE9977,0x7BF68D7B,0xF2FF0DF2,0x6BD6BD6B,0x6FDEB16F,0xC59154C5, + 0x30605030,0x01020301,0x67CEA967,0x2B567D2B,0xFEE719FE,0xD7B562D7,0xAB4DE6AB,0x76EC9A76, + 0xCA8F45CA,0x821F9D82,0xC98940C9,0x7DFA877D,0xFAEF15FA,0x59B2EB59,0x478EC947,0xF0FB0BF0, + 0xAD41ECAD,0xD4B367D4,0xA25FFDA2,0xAF45EAAF,0x9C23BF9C,0xA453F7A4,0x72E49672,0xC09B5BC0, + 0xB775C2B7,0xFDE11CFD,0x933DAE93,0x264C6A26,0x366C5A36,0x3F7E413F,0xF7F502F7,0xCC834FCC, + 0x34685C34,0xA551F4A5,0xE5D134E5,0xF1F908F1,0x71E29371,0xD8AB73D8,0x31625331,0x152A3F15, + 0x04080C04,0xC79552C7,0x23466523,0xC39D5EC3,0x18302818,0x9637A196,0x050A0F05,0x9A2FB59A, + 0x070E0907,0x12243612,0x801B9B80,0xE2DF3DE2,0xEBCD26EB,0x274E6927,0xB27FCDB2,0x75EA9F75, + 0x09121B09,0x831D9E83,0x2C58742C,0x1A342E1A,0x1B362D1B,0x6EDCB26E,0x5AB4EE5A,0xA05BFBA0, + 0x52A4F652,0x3B764D3B,0xD6B761D6,0xB37DCEB3,0x29527B29,0xE3DD3EE3,0x2F5E712F,0x84139784, + 0x53A6F553,0xD1B968D1,0x00000000,0xEDC12CED,0x20406020,0xFCE31FFC,0xB179C8B1,0x5BB6ED5B, + 0x6AD4BE6A,0xCB8D46CB,0xBE67D9BE,0x39724B39,0x4A94DE4A,0x4C98D44C,0x58B0E858,0xCF854ACF, + 0xD0BB6BD0,0xEFC52AEF,0xAA4FE5AA,0xFBED16FB,0x4386C543,0x4D9AD74D,0x33665533,0x85119485, + 0x458ACF45,0xF9E910F9,0x02040602,0x7FFE817F,0x50A0F050,0x3C78443C,0x9F25BA9F,0xA84BE3A8, + 0x51A2F351,0xA35DFEA3,0x4080C040,0x8F058A8F,0x923FAD92,0x9D21BC9D,0x38704838,0xF5F104F5, + 0xBC63DFBC,0xB677C1B6,0xDAAF75DA,0x21426321,0x10203010,0xFFE51AFF,0xF3FD0EF3,0xD2BF6DD2, + 0xCD814CCD,0x0C18140C,0x13263513,0xECC32FEC,0x5FBEE15F,0x9735A297,0x4488CC44,0x172E3917, + 0xC49357C4,0xA755F2A7,0x7EFC827E,0x3D7A473D,0x64C8AC64,0x5DBAE75D,0x19322B19,0x73E69573, + 0x60C0A060,0x81199881,0x4F9ED14F,0xDCA37FDC,0x22446622,0x2A547E2A,0x903BAB90,0x880B8388, + 0x468CCA46,0xEEC729EE,0xB86BD3B8,0x14283C14,0xDEA779DE,0x5EBCE25E,0x0B161D0B,0xDBAD76DB, + 0xE0DB3BE0,0x32645632,0x3A744E3A,0x0A141E0A,0x4992DB49,0x060C0A06,0x24486C24,0x5CB8E45C, + 0xC29F5DC2,0xD3BD6ED3,0xAC43EFAC,0x62C4A662,0x9139A891,0x9531A495,0xE4D337E4,0x79F28B79, + 0xE7D532E7,0xC88B43C8,0x376E5937,0x6DDAB76D,0x8D018C8D,0xD5B164D5,0x4E9CD24E,0xA949E0A9, + 0x6CD8B46C,0x56ACFA56,0xF4F307F4,0xEACF25EA,0x65CAAF65,0x7AF48E7A,0xAE47E9AE,0x08101808, + 0xBA6FD5BA,0x78F08878,0x254A6F25,0x2E5C722E,0x1C38241C,0xA657F1A6,0xB473C7B4,0xC69751C6, + 0xE8CB23E8,0xDDA17CDD,0x74E89C74,0x1F3E211F,0x4B96DD4B,0xBD61DCBD,0x8B0D868B,0x8A0F858A, + 0x70E09070,0x3E7C423E,0xB571C4B5,0x66CCAA66,0x4890D848,0x03060503,0xF6F701F6,0x0E1C120E, + 0x61C2A361,0x356A5F35,0x57AEF957,0xB969D0B9,0x86179186,0xC19958C1,0x1D3A271D,0x9E27B99E, + 0xE1D938E1,0xF8EB13F8,0x982BB398,0x11223311,0x69D2BB69,0xD9A970D9,0x8E07898E,0x9433A794, + 0x9B2DB69B,0x1E3C221E,0x87159287,0xE9C920E9,0xCE8749CE,0x55AAFF55,0x28507828,0xDFA57ADF, + 0x8C038F8C,0xA159F8A1,0x89098089,0x0D1A170D,0xBF65DABF,0xE6D731E6,0x4284C642,0x68D0B868, + 0x4182C341,0x9929B099,0x2D5A772D,0x0F1E110F,0xB07BCBB0,0x54A8FC54,0xBB6DD6BB,0x162C3A16 +}; + +const uint32_t TestTable4[256] __attribute((aligned(16))) ={ + 0xC6A56363,0xF8847C7C,0xEE997777,0xF68D7B7B,0xFF0DF2F2,0xD6BD6B6B,0xDEB16F6F,0x9154C5C5, + 0x60503030,0x02030101,0xCEA96767,0x567D2B2B,0xE719FEFE,0xB562D7D7,0x4DE6ABAB,0xEC9A7676, + 0x8F45CACA,0x1F9D8282,0x8940C9C9,0xFA877D7D,0xEF15FAFA,0xB2EB5959,0x8EC94747,0xFB0BF0F0, + 0x41ECADAD,0xB367D4D4,0x5FFDA2A2,0x45EAAFAF,0x23BF9C9C,0x53F7A4A4,0xE4967272,0x9B5BC0C0, + 0x75C2B7B7,0xE11CFDFD,0x3DAE9393,0x4C6A2626,0x6C5A3636,0x7E413F3F,0xF502F7F7,0x834FCCCC, + 0x685C3434,0x51F4A5A5,0xD134E5E5,0xF908F1F1,0xE2937171,0xAB73D8D8,0x62533131,0x2A3F1515, + 0x080C0404,0x9552C7C7,0x46652323,0x9D5EC3C3,0x30281818,0x37A19696,0x0A0F0505,0x2FB59A9A, + 0x0E090707,0x24361212,0x1B9B8080,0xDF3DE2E2,0xCD26EBEB,0x4E692727,0x7FCDB2B2,0xEA9F7575, + 0x121B0909,0x1D9E8383,0x58742C2C,0x342E1A1A,0x362D1B1B,0xDCB26E6E,0xB4EE5A5A,0x5BFBA0A0, + 0xA4F65252,0x764D3B3B,0xB761D6D6,0x7DCEB3B3,0x527B2929,0xDD3EE3E3,0x5E712F2F,0x13978484, + 0xA6F55353,0xB968D1D1,0x00000000,0xC12CEDED,0x40602020,0xE31FFCFC,0x79C8B1B1,0xB6ED5B5B, + 0xD4BE6A6A,0x8D46CBCB,0x67D9BEBE,0x724B3939,0x94DE4A4A,0x98D44C4C,0xB0E85858,0x854ACFCF, + 0xBB6BD0D0,0xC52AEFEF,0x4FE5AAAA,0xED16FBFB,0x86C54343,0x9AD74D4D,0x66553333,0x11948585, + 0x8ACF4545,0xE910F9F9,0x04060202,0xFE817F7F,0xA0F05050,0x78443C3C,0x25BA9F9F,0x4BE3A8A8, + 0xA2F35151,0x5DFEA3A3,0x80C04040,0x058A8F8F,0x3FAD9292,0x21BC9D9D,0x70483838,0xF104F5F5, + 0x63DFBCBC,0x77C1B6B6,0xAF75DADA,0x42632121,0x20301010,0xE51AFFFF,0xFD0EF3F3,0xBF6DD2D2, + 0x814CCDCD,0x18140C0C,0x26351313,0xC32FECEC,0xBEE15F5F,0x35A29797,0x88CC4444,0x2E391717, + 0x9357C4C4,0x55F2A7A7,0xFC827E7E,0x7A473D3D,0xC8AC6464,0xBAE75D5D,0x322B1919,0xE6957373, + 0xC0A06060,0x19988181,0x9ED14F4F,0xA37FDCDC,0x44662222,0x547E2A2A,0x3BAB9090,0x0B838888, + 0x8CCA4646,0xC729EEEE,0x6BD3B8B8,0x283C1414,0xA779DEDE,0xBCE25E5E,0x161D0B0B,0xAD76DBDB, + 0xDB3BE0E0,0x64563232,0x744E3A3A,0x141E0A0A,0x92DB4949,0x0C0A0606,0x486C2424,0xB8E45C5C, + 0x9F5DC2C2,0xBD6ED3D3,0x43EFACAC,0xC4A66262,0x39A89191,0x31A49595,0xD337E4E4,0xF28B7979, + 0xD532E7E7,0x8B43C8C8,0x6E593737,0xDAB76D6D,0x018C8D8D,0xB164D5D5,0x9CD24E4E,0x49E0A9A9, + 0xD8B46C6C,0xACFA5656,0xF307F4F4,0xCF25EAEA,0xCAAF6565,0xF48E7A7A,0x47E9AEAE,0x10180808, + 0x6FD5BABA,0xF0887878,0x4A6F2525,0x5C722E2E,0x38241C1C,0x57F1A6A6,0x73C7B4B4,0x9751C6C6, + 0xCB23E8E8,0xA17CDDDD,0xE89C7474,0x3E211F1F,0x96DD4B4B,0x61DCBDBD,0x0D868B8B,0x0F858A8A, + 0xE0907070,0x7C423E3E,0x71C4B5B5,0xCCAA6666,0x90D84848,0x06050303,0xF701F6F6,0x1C120E0E, + 0xC2A36161,0x6A5F3535,0xAEF95757,0x69D0B9B9,0x17918686,0x9958C1C1,0x3A271D1D,0x27B99E9E, + 0xD938E1E1,0xEB13F8F8,0x2BB39898,0x22331111,0xD2BB6969,0xA970D9D9,0x07898E8E,0x33A79494, + 0x2DB69B9B,0x3C221E1E,0x15928787,0xC920E9E9,0x8749CECE,0xAAFF5555,0x50782828,0xA57ADFDF, + 0x038F8C8C,0x59F8A1A1,0x09808989,0x1A170D0D,0x65DABFBF,0xD731E6E6,0x84C64242,0xD0B86868, + 0x82C34141,0x29B09999,0x5A772D2D,0x1E110F0F,0x7BCBB0B0,0xA8FC5454,0x6DD6BBBB,0x2C3A1616 +}; +/* +inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t *product_hi) +{ + // multiplier = ab = a * 2^32 + b + // multiplicand = cd = c * 2^32 + d + // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d + uint64_t a = multiplier >> 32; + uint64_t b = multiplier & 0xFFFFFFFF; + uint64_t c = multiplicand >> 32; + uint64_t d = multiplicand & 0xFFFFFFFF; + + //uint64_t ac = a * c; + uint64_t ad = a * d; + //uint64_t bc = b * c; + uint64_t bd = b * d; + + uint64_t adbc = ad + (b * c); + uint64_t adbc_carry = adbc < ad ? 1 : 0; + + // multiplier * multiplicand = product_hi * 2^64 + product_lo + uint64_t product_lo = bd + (adbc << 32); + uint64_t product_lo_carry = product_lo < bd ? 1 : 0; + *product_hi = (a * c) + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry; + //assert(ac <= *product_hi); + + return product_lo; +}*/ + +// void m64to128(uint64_t *a, uint64_t *b, uint64_t *r) +// { +// uint64_t lo, hi; +// __asm__("mul %0, %1, %2\n\t" : "=r"(lo) : "r"(a[0]), "r"(b[0]) ); +// __asm__("umulh %0, %1, %2\n\t" : "=r"(hi) : "r"(a[0]), "r"(b[0]) ); +// r[0] = hi; +// r[1] = lo; +// } +// + + + +void mult64to128(uint64_t op1, uint64_t op2, uint64_t *hi, uint64_t *lo) +{ + uint64_t u1 = (op1 & 0xffffffff); + uint64_t v1 = (op2 & 0xffffffff); + uint64_t t = (u1 * v1); + uint64_t w3 = (t & 0xffffffff); + uint64_t k = (t >> 32); + + op1 >>= 32; + t = (op1 * v1) + k; + k = (t & 0xffffffff); + v1 = (t >> 32); + + op2 >>= 32; + t = (u1 * op2) + k; + k = (t >> 32); + + *hi = (op1 * op2) + v1 + k; + *lo = (t << 32) + w3; +} + + +void mul_sum_xor_dst(const uint8_t *a, uint8_t *c, uint8_t *dst) +{ + + uint64_t hi = ((uint64_t *)a)[0]; + uint64_t lo = ((uint64_t *)dst)[0]; + + //mult64to128(((uint64_t *)a)[0], ((uint64_t *)dst)[0],&hi,&lo); + + uint64_t u1 = (hi & 0xffffffff); + uint64_t v1 = (lo & 0xffffffff); + uint64_t t = (u1 * v1); + uint64_t w3 = (t & 0xffffffff); + uint64_t k = (t >> 32); + + hi >>= 32; + t = (hi * v1) + k; + k = (t & 0xffffffff); + v1 = (t >> 32); + + lo >>= 32; + t = (u1 * lo) + k; + k = (t >> 32); + + hi = (hi * lo) + v1 + k; + lo = (t << 32) + w3; + + lo += ((uint64_t *)c)[1]; + hi += ((uint64_t *)c)[0]; + + ((uint64_t *)c)[0] = ((uint64_t*) dst)[0] ^ hi; + ((uint64_t *)c)[1] = ((uint64_t*) dst)[1] ^ lo; + ((uint64_t *)dst)[0] = hi; + ((uint64_t *)dst)[1] = lo; +} + +void xor_blocks(uint8_t * a, const uint8_t * b) { + ((uint64_t*) a)[0] ^= ((uint64_t*) b)[0]; + ((uint64_t*) a)[1] ^= ((uint64_t*) b)[1]; +} + +void SubAndShiftAndMixAddRound(uint32_t * out, uint8_t *temp, uint32_t * AesEncKey) +{ + out[0]= TestTable1[temp[0]] ^ TestTable2[temp[5]] ^ TestTable3[temp[10]] ^ TestTable4[temp[15]] ^ AesEncKey[0]; + out[1]= TestTable4[temp[3]] ^ TestTable1[temp[4]] ^ TestTable2[temp[9]] ^ TestTable3[temp[14]] ^ AesEncKey[1]; + out[2]= TestTable3[temp[2]] ^ TestTable4[temp[7]] ^ TestTable1[temp[8]] ^ TestTable2[temp[13]] ^ AesEncKey[2]; + out[3]= TestTable2[temp[1]] ^ TestTable3[temp[6]] ^ TestTable4[temp[11]] ^ TestTable1[temp[12]] ^ AesEncKey[3]; + +} + + +void SubAndShiftAndMixAddRoundInPlace(uint32_t * temp, uint32_t * AesEncKey) +{ + uint8_t *state = (uint8_t *)&temp[0]; + + uint8_t saved[6]; + + saved[0] = state[3]; + saved[1] = state[2]; + saved[2] = state[7]; + saved[3] = state[1]; + saved[4] = state[6]; + saved[5] = state[11]; + + + temp[0]= TestTable1[state[0]] ^ TestTable2[state[5]] ^ TestTable3[state[10]] ^ TestTable4[state[15]] ^ AesEncKey[0]; + temp[1]= TestTable4[saved[0]] ^ TestTable1[state[4]] ^ TestTable2[state[9]] ^ TestTable3[state[14]] ^ AesEncKey[1]; + temp[2]= TestTable3[saved[1]] ^ TestTable4[saved[2]] ^ TestTable1[state[8]] ^ TestTable2[state[13]] ^ AesEncKey[2]; + temp[3]= TestTable2[saved[3]] ^ TestTable3[saved[4]] ^ TestTable4[saved[5]] ^ TestTable1[state[12]] ^ AesEncKey[3]; + + +} + + +void cryptonight_hash_ctx(void * output, const void * input, struct cryptonight_ctx * ctx) { + ctx->aes_ctx = (oaes_ctx*) oaes_alloc(); + size_t i, j; + //hash_process(&ctx->state.hs, (const uint8_t*) input, 76); + keccak((const uint8_t *)input, 76, ctx->state.hs.b, 200); + memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); + + oaes_key_import_data(ctx->aes_ctx, ctx->state.hs.b, AES_KEY_SIZE); + + for(i = 0; likely(i < MEMORY); i += INIT_SIZE_BYTE) + { + for(j = 0; j < 10; j++) + { + + uint32_t *ptr = (uint32_t *)&ctx->aes_ctx->key->exp_data[j << 4]; + + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x10], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x20], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x30], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x40], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x50], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x60], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x70], ptr); + + } + memcpy(&ctx->long_state[i], ctx->text, INIT_SIZE_BYTE); + } + + for (i = 0; i < 2; i++) + { + ((uint64_t *)(ctx->a))[i] = ((uint64_t *)ctx->state.k)[i] ^ ((uint64_t *)ctx->state.k)[i+4]; + ((uint64_t *)(ctx->b))[i] = ((uint64_t *)ctx->state.k)[i+2] ^ ((uint64_t *)ctx->state.k)[i+6]; + } + + //xor_blocks_dst(&ctx->state.k[0], &ctx->state.k[32], ctx->a); + //xor_blocks_dst(&ctx->state.k[16], &ctx->state.k[48], ctx->b); + + for (i = 0; likely(i < ITER / 4); ++i) { + // Dependency chain: address -> read value ------+ + // written value <-+ hard function (AES or MUL) <+ + // next address <-+ + // + // Iteration 1 + j = ((uint32_t *)(ctx->a))[0] & 0x0FFFF0; + SubAndShiftAndMixAddRound((uint32_t *)ctx->c, &ctx->long_state[j], (uint32_t *)ctx->a); + xor_blocks_dst(ctx->c, ctx->b, &ctx->long_state[j]); + // Iteration 2 + mul_sum_xor_dst(ctx->c, ctx->a, &ctx->long_state[((uint32_t *)(ctx->c))[0] & 0x0FFFF0]); + // Iteration 3 + j = ((uint32_t *)(ctx->a))[0] & 0x0FFFF0; + SubAndShiftAndMixAddRound((uint32_t *)ctx->b, &ctx->long_state[j], (uint32_t *)ctx->a); + xor_blocks_dst(ctx->b, ctx->c, &ctx->long_state[j]); + // Iteration 4 + mul_sum_xor_dst(ctx->b, ctx->a, &ctx->long_state[((uint32_t *)(ctx->b))[0] & 0x0FFFF0]); + } + + memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); + + oaes_free((OAES_CTX **) &ctx->aes_ctx); + ctx->aes_ctx = (oaes_ctx*) oaes_alloc(); + + oaes_key_import_data(ctx->aes_ctx, &ctx->state.hs.b[32], AES_KEY_SIZE); + + for(i = 0; likely(i < MEMORY); i += INIT_SIZE_BYTE) + { + + xor_blocks(&ctx->text[0x00], &ctx->long_state[i + 0x00]); + xor_blocks(&ctx->text[0x10], &ctx->long_state[i + 0x10]); + xor_blocks(&ctx->text[0x20], &ctx->long_state[i + 0x20]); + xor_blocks(&ctx->text[0x30], &ctx->long_state[i + 0x30]); + xor_blocks(&ctx->text[0x40], &ctx->long_state[i + 0x40]); + xor_blocks(&ctx->text[0x50], &ctx->long_state[i + 0x50]); + xor_blocks(&ctx->text[0x60], &ctx->long_state[i + 0x60]); + xor_blocks(&ctx->text[0x70], &ctx->long_state[i + 0x70]); + + + + for(j = 0; j < 10; j++) + { + uint32_t *ptr = (uint32_t *)&ctx->aes_ctx->key->exp_data[j << 4]; + + + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x10], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x20], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x30], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x40], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x50], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x60], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x70], ptr); + } + } + + + memcpy(ctx->state.init, ctx->text, INIT_SIZE_BYTE); + //hash_permutation(&ctx->state.hs); + keccakf((uint64_t *)ctx->state.hs.b, 24); + /*memcpy(hash, &state, 32);*/ + extra_hashes[ctx->state.hs.b[0] & 3](&ctx->state, 200, output); + oaes_free((OAES_CTX **) &ctx->aes_ctx); +} + +void cryptonight(void* output, const void* input, size_t len) { + struct cryptonight_ctx *ctx = (struct cryptonight_ctx*)malloc(sizeof(struct cryptonight_ctx)); + cryptonight_hash_ctx(output, input, ctx); + + free(ctx); +} diff --git a/webassembly/aeon/cryptonight.h b/webassembly/aeon/cryptonight.h new file mode 100644 index 0000000..bd705fd --- /dev/null +++ b/webassembly/aeon/cryptonight.h @@ -0,0 +1,15 @@ +#ifndef CRYPTONIGHT_H +#define CRYPTONIGHT_H + +#ifdef __cplusplus +extern "C" { +#endif + +void cryptonight(void *output, const void *input, size_t len); +struct cryptonight_ctx; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/webassembly/aeon/groestl.c b/webassembly/aeon/groestl.c new file mode 100644 index 0000000..5277c8b --- /dev/null +++ b/webassembly/aeon/groestl.c @@ -0,0 +1,393 @@ +/* hash.c April 2012 + * Groestl ANSI C code optimised for 32-bit machines + * Author: Thomas Krinninger + * + * This work is based on the implementation of + * Soeren S. Thomsen and Krystian Matusiewicz + * + * + */ + +#include +#include "groestl_tables.h" + +typedef unsigned char BitSequence; +typedef unsigned long long DataLength; +typedef enum {SUCCESS = 0, FAIL = 1, BAD_HASHLEN = 2} HashReturn; + +/* some sizes (number of bytes) */ +#define ROWS 8 +#define LENGTHFIELDLEN ROWS +#define COLS512 8 + +#define SIZE512 (ROWS*COLS512) + +#define ROUNDS512 10 +#define HASH_BIT_LEN 256 + +#define ROTL32(v, n) ((((v)<<(n))|((v)>>(32-(n))))&li_32(ffffffff)) + +#define li_32(h) 0x##h##u +#define EXT_BYTE(var,n) ((uint8_t)((uint32_t)(var) >> (8*n))) +#define u32BIG(a) \ + ((ROTL32(a,8) & li_32(00FF00FF)) | \ + (ROTL32(a,24) & li_32(FF00FF00))) + +/* NIST API begin */ +typedef struct { + uint32_t chaining[SIZE512/sizeof(uint32_t)]; /* actual state */ + uint32_t block_counter1, + block_counter2; /* message block counter(s) */ + BitSequence buffer[SIZE512]; /* data buffer */ + int buf_ptr; /* data buffer pointer */ + int bits_in_last_byte; /* no. of message bits in last byte of + data buffer */ +} groestlHashState; + +#define P_TYPE 0 +#define Q_TYPE 1 + +const uint8_t shift_Values[2][8] = {{0,1,2,3,4,5,6,7},{1,3,5,7,0,2,4,6}}; + +const uint8_t indices_cyclic[15] = {0,1,2,3,4,5,6,7,0,1,2,3,4,5,6}; + + +#define ROTATE_COLUMN_DOWN(v1, v2, amount_bytes, temp_var) {temp_var = (v1<<(8*amount_bytes))|(v2>>(8*(4-amount_bytes))); \ + v2 = (v2<<(8*amount_bytes))|(v1>>(8*(4-amount_bytes))); \ + v1 = temp_var;} + + +#define COLUMN(x,y,i,c0,c1,c2,c3,c4,c5,c6,c7,tv1,tv2,tu,tl,t) \ + tu = T[2*(uint32_t)x[4*c0+0]]; \ + tl = T[2*(uint32_t)x[4*c0+0]+1]; \ + tv1 = T[2*(uint32_t)x[4*c1+1]]; \ + tv2 = T[2*(uint32_t)x[4*c1+1]+1]; \ + ROTATE_COLUMN_DOWN(tv1,tv2,1,t) \ + tu ^= tv1; \ + tl ^= tv2; \ + tv1 = T[2*(uint32_t)x[4*c2+2]]; \ + tv2 = T[2*(uint32_t)x[4*c2+2]+1]; \ + ROTATE_COLUMN_DOWN(tv1,tv2,2,t) \ + tu ^= tv1; \ + tl ^= tv2; \ + tv1 = T[2*(uint32_t)x[4*c3+3]]; \ + tv2 = T[2*(uint32_t)x[4*c3+3]+1]; \ + ROTATE_COLUMN_DOWN(tv1,tv2,3,t) \ + tu ^= tv1; \ + tl ^= tv2; \ + tl ^= T[2*(uint32_t)x[4*c4+0]]; \ + tu ^= T[2*(uint32_t)x[4*c4+0]+1]; \ + tv1 = T[2*(uint32_t)x[4*c5+1]]; \ + tv2 = T[2*(uint32_t)x[4*c5+1]+1]; \ + ROTATE_COLUMN_DOWN(tv1,tv2,1,t) \ + tl ^= tv1; \ + tu ^= tv2; \ + tv1 = T[2*(uint32_t)x[4*c6+2]]; \ + tv2 = T[2*(uint32_t)x[4*c6+2]+1]; \ + ROTATE_COLUMN_DOWN(tv1,tv2,2,t) \ + tl ^= tv1; \ + tu ^= tv2; \ + tv1 = T[2*(uint32_t)x[4*c7+3]]; \ + tv2 = T[2*(uint32_t)x[4*c7+3]+1]; \ + ROTATE_COLUMN_DOWN(tv1,tv2,3,t) \ + tl ^= tv1; \ + tu ^= tv2; \ + y[i] = tu; \ + y[i+1] = tl; + + +/* compute one round of P (short variants) */ +static void RND512P(uint8_t *x, uint32_t *y, uint32_t r) { + uint32_t temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp; + uint32_t* x32 = (uint32_t*)x; + x32[ 0] ^= 0x00000000^r; + x32[ 2] ^= 0x00000010^r; + x32[ 4] ^= 0x00000020^r; + x32[ 6] ^= 0x00000030^r; + x32[ 8] ^= 0x00000040^r; + x32[10] ^= 0x00000050^r; + x32[12] ^= 0x00000060^r; + x32[14] ^= 0x00000070^r; + COLUMN(x,y, 0, 0, 2, 4, 6, 9, 11, 13, 15, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y, 2, 2, 4, 6, 8, 11, 13, 15, 1, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y, 4, 4, 6, 8, 10, 13, 15, 1, 3, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y, 6, 6, 8, 10, 12, 15, 1, 3, 5, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y, 8, 8, 10, 12, 14, 1, 3, 5, 7, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y,10, 10, 12, 14, 0, 3, 5, 7, 9, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y,12, 12, 14, 0, 2, 5, 7, 9, 11, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y,14, 14, 0, 2, 4, 7, 9, 11, 13, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); +} + +/* compute one round of Q (short variants) */ +static void RND512Q(uint8_t *x, uint32_t *y, uint32_t r) { + uint32_t temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp; + uint32_t* x32 = (uint32_t*)x; + x32[ 0] = ~x32[ 0]; + x32[ 1] ^= 0xffffffff^r; + x32[ 2] = ~x32[ 2]; + x32[ 3] ^= 0xefffffff^r; + x32[ 4] = ~x32[ 4]; + x32[ 5] ^= 0xdfffffff^r; + x32[ 6] = ~x32[ 6]; + x32[ 7] ^= 0xcfffffff^r; + x32[ 8] = ~x32[ 8]; + x32[ 9] ^= 0xbfffffff^r; + x32[10] = ~x32[10]; + x32[11] ^= 0xafffffff^r; + x32[12] = ~x32[12]; + x32[13] ^= 0x9fffffff^r; + x32[14] = ~x32[14]; + x32[15] ^= 0x8fffffff^r; + COLUMN(x,y, 0, 2, 6, 10, 14, 1, 5, 9, 13, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y, 2, 4, 8, 12, 0, 3, 7, 11, 15, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y, 4, 6, 10, 14, 2, 5, 9, 13, 1, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y, 6, 8, 12, 0, 4, 7, 11, 15, 3, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y, 8, 10, 14, 2, 6, 9, 13, 1, 5, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y,10, 12, 0, 4, 8, 11, 15, 3, 7, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y,12, 14, 2, 6, 10, 13, 1, 5, 9, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y,14, 0, 4, 8, 12, 15, 3, 7, 11, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); +} + +/* compute compression function (short variants) */ +static void F512(uint32_t *h, const uint32_t *m) { + int i; + uint32_t Ptmp[2*COLS512]; + uint32_t Qtmp[2*COLS512]; + uint32_t y[2*COLS512]; + uint32_t z[2*COLS512]; + + for (i = 0; i < 2*COLS512; i++) { + z[i] = m[i]; + Ptmp[i] = h[i]^m[i]; + } + + /* compute Q(m) */ + RND512Q((uint8_t*)z, y, 0x00000000); + RND512Q((uint8_t*)y, z, 0x01000000); + RND512Q((uint8_t*)z, y, 0x02000000); + RND512Q((uint8_t*)y, z, 0x03000000); + RND512Q((uint8_t*)z, y, 0x04000000); + RND512Q((uint8_t*)y, z, 0x05000000); + RND512Q((uint8_t*)z, y, 0x06000000); + RND512Q((uint8_t*)y, z, 0x07000000); + RND512Q((uint8_t*)z, y, 0x08000000); + RND512Q((uint8_t*)y, Qtmp, 0x09000000); + + /* compute P(h+m) */ + RND512P((uint8_t*)Ptmp, y, 0x00000000); + RND512P((uint8_t*)y, z, 0x00000001); + RND512P((uint8_t*)z, y, 0x00000002); + RND512P((uint8_t*)y, z, 0x00000003); + RND512P((uint8_t*)z, y, 0x00000004); + RND512P((uint8_t*)y, z, 0x00000005); + RND512P((uint8_t*)z, y, 0x00000006); + RND512P((uint8_t*)y, z, 0x00000007); + RND512P((uint8_t*)z, y, 0x00000008); + RND512P((uint8_t*)y, Ptmp, 0x00000009); + + /* compute P(h+m) + Q(m) + h */ + for (i = 0; i < 2*COLS512; i++) { + h[i] ^= Ptmp[i]^Qtmp[i]; + } +} + + +/* digest up to msglen bytes of input (full blocks only) */ +static void Transform(groestlHashState *ctx, + const uint8_t *input, + int msglen) { + + /* digest message, one block at a time */ + for (; msglen >= SIZE512; + msglen -= SIZE512, input += SIZE512) { + F512(ctx->chaining,(uint32_t*)input); + + /* increment block counter */ + ctx->block_counter1++; + if (ctx->block_counter1 == 0) ctx->block_counter2++; + } +} + +/* given state h, do h <- P(h)+h */ +static void OutputTransformation(groestlHashState *ctx) { + int j; + uint32_t temp[2*COLS512]; + uint32_t y[2*COLS512]; + uint32_t z[2*COLS512]; + + + + for (j = 0; j < 2*COLS512; j++) { + temp[j] = ctx->chaining[j]; + } + RND512P((uint8_t*)temp, y, 0x00000000); + RND512P((uint8_t*)y, z, 0x00000001); + RND512P((uint8_t*)z, y, 0x00000002); + RND512P((uint8_t*)y, z, 0x00000003); + RND512P((uint8_t*)z, y, 0x00000004); + RND512P((uint8_t*)y, z, 0x00000005); + RND512P((uint8_t*)z, y, 0x00000006); + RND512P((uint8_t*)y, z, 0x00000007); + RND512P((uint8_t*)z, y, 0x00000008); + RND512P((uint8_t*)y, temp, 0x00000009); + for (j = 0; j < 2*COLS512; j++) { + ctx->chaining[j] ^= temp[j]; + } +} + +/* initialise context */ +static void Init(groestlHashState* ctx) { + int i = 0; + /* allocate memory for state and data buffer */ + + for(;i<(SIZE512/sizeof(uint32_t));i++) + { + ctx->chaining[i] = 0; + } + + /* set initial value */ + ctx->chaining[2*COLS512-1] = u32BIG((uint32_t)HASH_BIT_LEN); + + /* set other variables */ + ctx->buf_ptr = 0; + ctx->block_counter1 = 0; + ctx->block_counter2 = 0; + ctx->bits_in_last_byte = 0; +} + +/* update state with databitlen bits of input */ +static void Update(groestlHashState* ctx, + const BitSequence* input, + DataLength databitlen) { + int index = 0; + int msglen = (int)(databitlen/8); + int rem = (int)(databitlen%8); + + /* if the buffer contains data that has not yet been digested, first + add data to buffer until full */ + if (ctx->buf_ptr) { + while (ctx->buf_ptr < SIZE512 && index < msglen) { + ctx->buffer[(int)ctx->buf_ptr++] = input[index++]; + } + if (ctx->buf_ptr < SIZE512) { + /* buffer still not full, return */ + if (rem) { + ctx->bits_in_last_byte = rem; + ctx->buffer[(int)ctx->buf_ptr++] = input[index]; + } + return; + } + + /* digest buffer */ + ctx->buf_ptr = 0; + Transform(ctx, ctx->buffer, SIZE512); + } + + /* digest bulk of message */ + Transform(ctx, input+index, msglen-index); + index += ((msglen-index)/SIZE512)*SIZE512; + + /* store remaining data in buffer */ + while (index < msglen) { + ctx->buffer[(int)ctx->buf_ptr++] = input[index++]; + } + + /* if non-integral number of bytes have been supplied, store + remaining bits in last byte, together with information about + number of bits */ + if (rem) { + ctx->bits_in_last_byte = rem; + ctx->buffer[(int)ctx->buf_ptr++] = input[index]; + } +} + +#define BILB ctx->bits_in_last_byte + +/* finalise: process remaining data (including padding), perform + output transformation, and write hash result to 'output' */ +static void Final(groestlHashState* ctx, + BitSequence* output) { + int i, j = 0, hashbytelen = HASH_BIT_LEN/8; + uint8_t *s = (BitSequence*)ctx->chaining; + + /* pad with '1'-bit and first few '0'-bits */ + if (BILB) { + ctx->buffer[(int)ctx->buf_ptr-1] &= ((1<buffer[(int)ctx->buf_ptr-1] ^= 0x1<<(7-BILB); + BILB = 0; + } + else ctx->buffer[(int)ctx->buf_ptr++] = 0x80; + + /* pad with '0'-bits */ + if (ctx->buf_ptr > SIZE512-LENGTHFIELDLEN) { + /* padding requires two blocks */ + while (ctx->buf_ptr < SIZE512) { + ctx->buffer[(int)ctx->buf_ptr++] = 0; + } + /* digest first padding block */ + Transform(ctx, ctx->buffer, SIZE512); + ctx->buf_ptr = 0; + } + while (ctx->buf_ptr < SIZE512-LENGTHFIELDLEN) { + ctx->buffer[(int)ctx->buf_ptr++] = 0; + } + + /* length padding */ + ctx->block_counter1++; + if (ctx->block_counter1 == 0) ctx->block_counter2++; + ctx->buf_ptr = SIZE512; + + while (ctx->buf_ptr > SIZE512-(int)sizeof(uint32_t)) { + ctx->buffer[(int)--ctx->buf_ptr] = (uint8_t)ctx->block_counter1; + ctx->block_counter1 >>= 8; + } + while (ctx->buf_ptr > SIZE512-LENGTHFIELDLEN) { + ctx->buffer[(int)--ctx->buf_ptr] = (uint8_t)ctx->block_counter2; + ctx->block_counter2 >>= 8; + } + /* digest final padding block */ + Transform(ctx, ctx->buffer, SIZE512); + /* perform output transformation */ + OutputTransformation(ctx); + + /* store hash result in output */ + for (i = SIZE512-hashbytelen; i < SIZE512; i++,j++) { + output[j] = s[i]; + } + + /* zeroise relevant variables and deallocate memory */ + for (i = 0; i < COLS512; i++) { + ctx->chaining[i] = 0; + } + for (i = 0; i < SIZE512; i++) { + ctx->buffer[i] = 0; + } +} + +/* hash bit sequence */ +void groestl(const BitSequence* data, + DataLength databitlen, + BitSequence* hashval) { + + groestlHashState context; + + /* initialise */ + Init(&context); + + + /* process message */ + Update(&context, data, databitlen); + + /* finalise */ + Final(&context, hashval); +} +/* +static int crypto_hash(unsigned char *out, + const unsigned char *in, + unsigned long long len) +{ + groestl(in, 8*len, out); + return 0; +} + +*/ diff --git a/webassembly/aeon/groestl.h b/webassembly/aeon/groestl.h new file mode 100644 index 0000000..29287fc --- /dev/null +++ b/webassembly/aeon/groestl.h @@ -0,0 +1,16 @@ +#ifndef GROESTL_H +#define GROESTL_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern void groestl(const unsigned char *input, + unsigned long long len, + unsigned char *output); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/webassembly/aeon/groestl_tables.h b/webassembly/aeon/groestl_tables.h new file mode 100644 index 0000000..a23295c --- /dev/null +++ b/webassembly/aeon/groestl_tables.h @@ -0,0 +1,38 @@ +#ifndef __tables_h +#define __tables_h + + +const uint32_t T[512] = {0xa5f432c6, 0xc6a597f4, 0x84976ff8, 0xf884eb97, 0x99b05eee, 0xee99c7b0, 0x8d8c7af6, 0xf68df78c, 0xd17e8ff, 0xff0de517, 0xbddc0ad6, 0xd6bdb7dc, 0xb1c816de, 0xdeb1a7c8, 0x54fc6d91, 0x915439fc +, 0x50f09060, 0x6050c0f0, 0x3050702, 0x2030405, 0xa9e02ece, 0xcea987e0, 0x7d87d156, 0x567dac87, 0x192bcce7, 0xe719d52b, 0x62a613b5, 0xb56271a6, 0xe6317c4d, 0x4de69a31, 0x9ab559ec, 0xec9ac3b5 +, 0x45cf408f, 0x8f4505cf, 0x9dbca31f, 0x1f9d3ebc, 0x40c04989, 0x894009c0, 0x879268fa, 0xfa87ef92, 0x153fd0ef, 0xef15c53f, 0xeb2694b2, 0xb2eb7f26, 0xc940ce8e, 0x8ec90740, 0xb1de6fb, 0xfb0bed1d +, 0xec2f6e41, 0x41ec822f, 0x67a91ab3, 0xb3677da9, 0xfd1c435f, 0x5ffdbe1c, 0xea256045, 0x45ea8a25, 0xbfdaf923, 0x23bf46da, 0xf7025153, 0x53f7a602, 0x96a145e4, 0xe496d3a1, 0x5bed769b, 0x9b5b2ded +, 0xc25d2875, 0x75c2ea5d, 0x1c24c5e1, 0xe11cd924, 0xaee9d43d, 0x3dae7ae9, 0x6abef24c, 0x4c6a98be, 0x5aee826c, 0x6c5ad8ee, 0x41c3bd7e, 0x7e41fcc3, 0x206f3f5, 0xf502f106, 0x4fd15283, 0x834f1dd1 +, 0x5ce48c68, 0x685cd0e4, 0xf4075651, 0x51f4a207, 0x345c8dd1, 0xd134b95c, 0x818e1f9, 0xf908e918, 0x93ae4ce2, 0xe293dfae, 0x73953eab, 0xab734d95, 0x53f59762, 0x6253c4f5, 0x3f416b2a, 0x2a3f5441 +, 0xc141c08, 0x80c1014, 0x52f66395, 0x955231f6, 0x65afe946, 0x46658caf, 0x5ee27f9d, 0x9d5e21e2, 0x28784830, 0x30286078, 0xa1f8cf37, 0x37a16ef8, 0xf111b0a, 0xa0f1411, 0xb5c4eb2f, 0x2fb55ec4 +, 0x91b150e, 0xe091c1b, 0x365a7e24, 0x2436485a, 0x9bb6ad1b, 0x1b9b36b6, 0x3d4798df, 0xdf3da547, 0x266aa7cd, 0xcd26816a, 0x69bbf54e, 0x4e699cbb, 0xcd4c337f, 0x7fcdfe4c, 0x9fba50ea, 0xea9fcfba +, 0x1b2d3f12, 0x121b242d, 0x9eb9a41d, 0x1d9e3ab9, 0x749cc458, 0x5874b09c, 0x2e724634, 0x342e6872, 0x2d774136, 0x362d6c77, 0xb2cd11dc, 0xdcb2a3cd, 0xee299db4, 0xb4ee7329, 0xfb164d5b, 0x5bfbb616 +, 0xf601a5a4, 0xa4f65301, 0x4dd7a176, 0x764decd7, 0x61a314b7, 0xb76175a3, 0xce49347d, 0x7dcefa49, 0x7b8ddf52, 0x527ba48d, 0x3e429fdd, 0xdd3ea142, 0x7193cd5e, 0x5e71bc93, 0x97a2b113, 0x139726a2 +, 0xf504a2a6, 0xa6f55704, 0x68b801b9, 0xb96869b8, 0x0, 0x0, 0x2c74b5c1, 0xc12c9974, 0x60a0e040, 0x406080a0, 0x1f21c2e3, 0xe31fdd21, 0xc8433a79, 0x79c8f243, 0xed2c9ab6, 0xb6ed772c +, 0xbed90dd4, 0xd4beb3d9, 0x46ca478d, 0x8d4601ca, 0xd9701767, 0x67d9ce70, 0x4bddaf72, 0x724be4dd, 0xde79ed94, 0x94de3379, 0xd467ff98, 0x98d42b67, 0xe82393b0, 0xb0e87b23, 0x4ade5b85, 0x854a11de +, 0x6bbd06bb, 0xbb6b6dbd, 0x2a7ebbc5, 0xc52a917e, 0xe5347b4f, 0x4fe59e34, 0x163ad7ed, 0xed16c13a, 0xc554d286, 0x86c51754, 0xd762f89a, 0x9ad72f62, 0x55ff9966, 0x6655ccff, 0x94a7b611, 0x119422a7 +, 0xcf4ac08a, 0x8acf0f4a, 0x1030d9e9, 0xe910c930, 0x60a0e04, 0x406080a, 0x819866fe, 0xfe81e798, 0xf00baba0, 0xa0f05b0b, 0x44ccb478, 0x7844f0cc, 0xbad5f025, 0x25ba4ad5, 0xe33e754b, 0x4be3963e +, 0xf30eaca2, 0xa2f35f0e, 0xfe19445d, 0x5dfeba19, 0xc05bdb80, 0x80c01b5b, 0x8a858005, 0x58a0a85, 0xadecd33f, 0x3fad7eec, 0xbcdffe21, 0x21bc42df, 0x48d8a870, 0x7048e0d8, 0x40cfdf1, 0xf104f90c +, 0xdf7a1963, 0x63dfc67a, 0xc1582f77, 0x77c1ee58, 0x759f30af, 0xaf75459f, 0x63a5e742, 0x426384a5, 0x30507020, 0x20304050, 0x1a2ecbe5, 0xe51ad12e, 0xe12effd, 0xfd0ee112, 0x6db708bf, 0xbf6d65b7 +, 0x4cd45581, 0x814c19d4, 0x143c2418, 0x1814303c, 0x355f7926, 0x26354c5f, 0x2f71b2c3, 0xc32f9d71, 0xe13886be, 0xbee16738, 0xa2fdc835, 0x35a26afd, 0xcc4fc788, 0x88cc0b4f, 0x394b652e, 0x2e395c4b +, 0x57f96a93, 0x93573df9, 0xf20d5855, 0x55f2aa0d, 0x829d61fc, 0xfc82e39d, 0x47c9b37a, 0x7a47f4c9, 0xacef27c8, 0xc8ac8bef, 0xe73288ba, 0xbae76f32, 0x2b7d4f32, 0x322b647d, 0x95a442e6, 0xe695d7a4 +, 0xa0fb3bc0, 0xc0a09bfb, 0x98b3aa19, 0x199832b3, 0xd168f69e, 0x9ed12768, 0x7f8122a3, 0xa37f5d81, 0x66aaee44, 0x446688aa, 0x7e82d654, 0x547ea882, 0xabe6dd3b, 0x3bab76e6, 0x839e950b, 0xb83169e +, 0xca45c98c, 0x8cca0345, 0x297bbcc7, 0xc729957b, 0xd36e056b, 0x6bd3d66e, 0x3c446c28, 0x283c5044, 0x798b2ca7, 0xa779558b, 0xe23d81bc, 0xbce2633d, 0x1d273116, 0x161d2c27, 0x769a37ad, 0xad76419a +, 0x3b4d96db, 0xdb3bad4d, 0x56fa9e64, 0x6456c8fa, 0x4ed2a674, 0x744ee8d2, 0x1e223614, 0x141e2822, 0xdb76e492, 0x92db3f76, 0xa1e120c, 0xc0a181e, 0x6cb4fc48, 0x486c90b4, 0xe4378fb8, 0xb8e46b37 +, 0x5de7789f, 0x9f5d25e7, 0x6eb20fbd, 0xbd6e61b2, 0xef2a6943, 0x43ef862a, 0xa6f135c4, 0xc4a693f1, 0xa8e3da39, 0x39a872e3, 0xa4f7c631, 0x31a462f7, 0x37598ad3, 0xd337bd59, 0x8b8674f2, 0xf28bff86 +, 0x325683d5, 0xd532b156, 0x43c54e8b, 0x8b430dc5, 0x59eb856e, 0x6e59dceb, 0xb7c218da, 0xdab7afc2, 0x8c8f8e01, 0x18c028f, 0x64ac1db1, 0xb16479ac, 0xd26df19c, 0x9cd2236d, 0xe03b7249, 0x49e0923b +, 0xb4c71fd8, 0xd8b4abc7, 0xfa15b9ac, 0xacfa4315, 0x709faf3, 0xf307fd09, 0x256fa0cf, 0xcf25856f, 0xafea20ca, 0xcaaf8fea, 0x8e897df4, 0xf48ef389, 0xe9206747, 0x47e98e20, 0x18283810, 0x10182028 +, 0xd5640b6f, 0x6fd5de64, 0x888373f0, 0xf088fb83, 0x6fb1fb4a, 0x4a6f94b1, 0x7296ca5c, 0x5c72b896, 0x246c5438, 0x3824706c, 0xf1085f57, 0x57f1ae08, 0xc7522173, 0x73c7e652, 0x51f36497, 0x975135f3 +, 0x2365aecb, 0xcb238d65, 0x7c8425a1, 0xa17c5984, 0x9cbf57e8, 0xe89ccbbf, 0x21635d3e, 0x3e217c63, 0xdd7cea96, 0x96dd377c, 0xdc7f1e61, 0x61dcc27f, 0x86919c0d, 0xd861a91, 0x85949b0f, 0xf851e94 +, 0x90ab4be0, 0xe090dbab, 0x42c6ba7c, 0x7c42f8c6, 0xc4572671, 0x71c4e257, 0xaae529cc, 0xccaa83e5, 0xd873e390, 0x90d83b73, 0x50f0906, 0x6050c0f, 0x103f4f7, 0xf701f503, 0x12362a1c, 0x1c123836 +, 0xa3fe3cc2, 0xc2a39ffe, 0x5fe18b6a, 0x6a5fd4e1, 0xf910beae, 0xaef94710, 0xd06b0269, 0x69d0d26b, 0x91a8bf17, 0x17912ea8, 0x58e87199, 0x995829e8, 0x2769533a, 0x3a277469, 0xb9d0f727, 0x27b94ed0 +, 0x384891d9, 0xd938a948, 0x1335deeb, 0xeb13cd35, 0xb3cee52b, 0x2bb356ce, 0x33557722, 0x22334455, 0xbbd604d2, 0xd2bbbfd6, 0x709039a9, 0xa9704990, 0x89808707, 0x7890e80, 0xa7f2c133, 0x33a766f2 +, 0xb6c1ec2d, 0x2db65ac1, 0x22665a3c, 0x3c227866, 0x92adb815, 0x15922aad, 0x2060a9c9, 0xc9208960, 0x49db5c87, 0x874915db, 0xff1ab0aa, 0xaaff4f1a, 0x7888d850, 0x5078a088, 0x7a8e2ba5, 0xa57a518e +, 0x8f8a8903, 0x38f068a, 0xf8134a59, 0x59f8b213, 0x809b9209, 0x980129b, 0x1739231a, 0x1a173439, 0xda751065, 0x65daca75, 0x315384d7, 0xd731b553, 0xc651d584, 0x84c61351, 0xb8d303d0, 0xd0b8bbd3 +, 0xc35edc82, 0x82c31f5e, 0xb0cbe229, 0x29b052cb, 0x7799c35a, 0x5a77b499, 0x11332d1e, 0x1e113c33, 0xcb463d7b, 0x7bcbf646, 0xfc1fb7a8, 0xa8fc4b1f, 0xd6610c6d, 0x6dd6da61, 0x3a4e622c, 0x2c3a584e}; + +#endif /* __tables_h */ diff --git a/webassembly/aeon/html_template/shell_minimal.html b/webassembly/aeon/html_template/shell_minimal.html new file mode 100644 index 0000000..75f1b81 --- /dev/null +++ b/webassembly/aeon/html_template/shell_minimal.html @@ -0,0 +1,146 @@ + + + + + + Emscripten-Generated Code + + + +
+
emscripten
+
Downloading...
+
+ +
+
+ +
+
+
+ Resize canvas + Lock/hide mouse pointer +     + +
+ +
+ +
+ + {{{ SCRIPT }}} + + \ No newline at end of file diff --git a/webassembly/aeon/int-util.h b/webassembly/aeon/int-util.h new file mode 100644 index 0000000..3428880 --- /dev/null +++ b/webassembly/aeon/int-util.h @@ -0,0 +1,245 @@ +// Copyright (c) 2014-2017, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#pragma once + +#include +#include +#include +#include +#include + +#if defined(__ANDROID__) +#include +#endif + +#if defined(_MSC_VER) +#include + +static inline uint32_t rol32(uint32_t x, int r) { + static_assert(sizeof(uint32_t) == sizeof(unsigned int), "this code assumes 32-bit integers"); + return _rotl(x, r); +} + +static inline uint64_t rol64(uint64_t x, int r) { + return _rotl64(x, r); +} + +#else + +static inline uint32_t rol32(uint32_t x, int r) { + return (x << (r & 31)) | (x >> (-r & 31)); +} + +static inline uint64_t rol64(uint64_t x, int r) { + return (x << (r & 63)) | (x >> (-r & 63)); +} + +#endif + +static inline uint64_t hi_dword(uint64_t val) { + return val >> 32; +} + +static inline uint64_t lo_dword(uint64_t val) { + return val & 0xFFFFFFFF; +} + +static inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) { + // multiplier = ab = a * 2^32 + b + // multiplicand = cd = c * 2^32 + d + // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d + uint64_t a = hi_dword(multiplier); + uint64_t b = lo_dword(multiplier); + uint64_t c = hi_dword(multiplicand); + uint64_t d = lo_dword(multiplicand); + + uint64_t ac = a * c; + uint64_t ad = a * d; + uint64_t bc = b * c; + uint64_t bd = b * d; + + uint64_t adbc = ad + bc; + uint64_t adbc_carry = adbc < ad ? 1 : 0; + + // multiplier * multiplicand = product_hi * 2^64 + product_lo + uint64_t product_lo = bd + (adbc << 32); + uint64_t product_lo_carry = product_lo < bd ? 1 : 0; + *product_hi = ac + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry; + assert(ac <= *product_hi); + + return product_lo; +} + +static inline uint64_t div_with_reminder(uint64_t dividend, uint32_t divisor, uint32_t* remainder) { + dividend |= ((uint64_t)*remainder) << 32; + *remainder = dividend % divisor; + return dividend / divisor; +} + +// Long division with 2^32 base +static inline uint32_t div128_32(uint64_t dividend_hi, uint64_t dividend_lo, uint32_t divisor, uint64_t* quotient_hi, uint64_t* quotient_lo) { + uint64_t dividend_dwords[4]; + uint32_t remainder = 0; + + dividend_dwords[3] = hi_dword(dividend_hi); + dividend_dwords[2] = lo_dword(dividend_hi); + dividend_dwords[1] = hi_dword(dividend_lo); + dividend_dwords[0] = lo_dword(dividend_lo); + + *quotient_hi = div_with_reminder(dividend_dwords[3], divisor, &remainder) << 32; + *quotient_hi |= div_with_reminder(dividend_dwords[2], divisor, &remainder); + *quotient_lo = div_with_reminder(dividend_dwords[1], divisor, &remainder) << 32; + *quotient_lo |= div_with_reminder(dividend_dwords[0], divisor, &remainder); + + return remainder; +} + +#define IDENT32(x) ((uint32_t) (x)) +#define IDENT64(x) ((uint64_t) (x)) + +#define SWAP32(x) ((((uint32_t) (x) & 0x000000ff) << 24) | \ + (((uint32_t) (x) & 0x0000ff00) << 8) | \ + (((uint32_t) (x) & 0x00ff0000) >> 8) | \ + (((uint32_t) (x) & 0xff000000) >> 24)) +#define SWAP64(x) ((((uint64_t) (x) & 0x00000000000000ff) << 56) | \ + (((uint64_t) (x) & 0x000000000000ff00) << 40) | \ + (((uint64_t) (x) & 0x0000000000ff0000) << 24) | \ + (((uint64_t) (x) & 0x00000000ff000000) << 8) | \ + (((uint64_t) (x) & 0x000000ff00000000) >> 8) | \ + (((uint64_t) (x) & 0x0000ff0000000000) >> 24) | \ + (((uint64_t) (x) & 0x00ff000000000000) >> 40) | \ + (((uint64_t) (x) & 0xff00000000000000) >> 56)) + +static inline uint32_t ident32(uint32_t x) { return x; } +static inline uint64_t ident64(uint64_t x) { return x; } + +#ifndef __OpenBSD__ +# if defined(__ANDROID__) && defined(__swap32) && !defined(swap32) +# define swap32 __swap32 +# elif !defined(swap32) +static inline uint32_t swap32(uint32_t x) { + x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >> 8); + return (x << 16) | (x >> 16); +} +# endif +# if defined(__ANDROID__) && defined(__swap64) && !defined(swap64) +# define swap64 __swap64 +# elif !defined(swap64) +static inline uint64_t swap64(uint64_t x) { + x = ((x & 0x00ff00ff00ff00ff) << 8) | ((x & 0xff00ff00ff00ff00) >> 8); + x = ((x & 0x0000ffff0000ffff) << 16) | ((x & 0xffff0000ffff0000) >> 16); + return (x << 32) | (x >> 32); +} +# endif +#endif /* __OpenBSD__ */ + +#if defined(__GNUC__) +#define UNUSED __attribute__((unused)) +#else +#define UNUSED +#endif +static inline void mem_inplace_ident(void *mem UNUSED, size_t n UNUSED) { } +#undef UNUSED + +static inline void mem_inplace_swap32(void *mem, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + ((uint32_t *) mem)[i] = swap32(((const uint32_t *) mem)[i]); + } +} +static inline void mem_inplace_swap64(void *mem, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + ((uint64_t *) mem)[i] = swap64(((const uint64_t *) mem)[i]); + } +} + +static inline void memcpy_ident32(void *dst, const void *src, size_t n) { + memcpy(dst, src, 4 * n); +} +static inline void memcpy_ident64(void *dst, const void *src, size_t n) { + memcpy(dst, src, 8 * n); +} + +static inline void memcpy_swap32(void *dst, const void *src, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + ((uint32_t *) dst)[i] = swap32(((const uint32_t *) src)[i]); + } +} +static inline void memcpy_swap64(void *dst, const void *src, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + ((uint64_t *) dst)[i] = swap64(((const uint64_t *) src)[i]); + } +} + +#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN) +static_assert(false, "BYTE_ORDER is undefined. Perhaps, GNU extensions are not enabled"); +#endif + +#if BYTE_ORDER == LITTLE_ENDIAN +#define SWAP32LE IDENT32 +#define SWAP32BE SWAP32 +#define swap32le ident32 +#define swap32be swap32 +#define mem_inplace_swap32le mem_inplace_ident +#define mem_inplace_swap32be mem_inplace_swap32 +#define memcpy_swap32le memcpy_ident32 +#define memcpy_swap32be memcpy_swap32 +#define SWAP64LE IDENT64 +#define SWAP64BE SWAP64 +#define swap64le ident64 +#define swap64be swap64 +#define mem_inplace_swap64le mem_inplace_ident +#define mem_inplace_swap64be mem_inplace_swap64 +#define memcpy_swap64le memcpy_ident64 +#define memcpy_swap64be memcpy_swap64 +#endif + +#if BYTE_ORDER == BIG_ENDIAN +#define SWAP32BE IDENT32 +#define SWAP32LE SWAP32 +#define swap32be ident32 +#define swap32le swap32 +#define mem_inplace_swap32be mem_inplace_ident +#define mem_inplace_swap32le mem_inplace_swap32 +#define memcpy_swap32be memcpy_ident32 +#define memcpy_swap32le memcpy_swap32 +#define SWAP64BE IDENT64 +#define SWAP64LE SWAP64 +#define swap64be ident64 +#define swap64le swap64 +#define mem_inplace_swap64be mem_inplace_ident +#define mem_inplace_swap64le mem_inplace_swap64 +#define memcpy_swap64be memcpy_ident64 +#define memcpy_swap64le memcpy_swap64 +#endif diff --git a/webassembly/aeon/jh.h b/webassembly/aeon/jh.h new file mode 100644 index 0000000..959ba05 --- /dev/null +++ b/webassembly/aeon/jh.h @@ -0,0 +1,16 @@ +#ifndef JH_H +#define JH_H +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void jh(unsigned bit_len, const uint8_t input[], + size_t input_bit_length, uint8_t output[]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/webassembly/aeon/jh_ansi_opt64.c b/webassembly/aeon/jh_ansi_opt64.c new file mode 100644 index 0000000..7aa0310 --- /dev/null +++ b/webassembly/aeon/jh_ansi_opt64.c @@ -0,0 +1,377 @@ +/*This program gives the 64-bit optimized bitslice implementation of JH using ANSI C + + -------------------------------- + Performance + + Microprocessor: Intel CORE 2 processor (Core 2 Duo Mobile T6600 2.2GHz) + Operating System: 64-bit Ubuntu 10.04 (Linux kernel 2.6.32-22-generic) + Speed for long message: + 1) 45.8 cycles/byte compiler: Intel C++ Compiler 11.1 compilation option: icc -O2 + 2) 56.8 cycles/byte compiler: gcc 4.4.3 compilation option: gcc -O3 + + -------------------------------- + Last Modified: January 16, 2011 +*/ + + + +#include +#include +#include + +typedef unsigned long long uint64; + +typedef unsigned char BitSequence; +typedef unsigned long long DataLength; +typedef enum {SUCCESS = 0, FAIL = 1, BAD_HASHLEN = 2} HashReturn; + +/*define data alignment for different C compilers*/ +#if defined(__GNUC__) + #define DATA_ALIGN16(x) x __attribute__ ((aligned(16))) +#else + #define DATA_ALIGN16(x) __declspec(align(16)) x +#endif + + +typedef struct { + int hashbitlen; /*the message digest size*/ + unsigned long long databitlen; /*the message size in bits*/ + unsigned long long datasize_in_buffer; /*the size of the message remained in buffer; assumed to be multiple of 8bits except for the last partial block at the end of the message*/ + DATA_ALIGN16(uint64 x[8][2]); /*the 1024-bit state, ( x[i][0] || x[i][1] ) is the ith row of the state in the pseudocode*/ + unsigned char buffer[64]; /*the 512-bit message block to be hashed;*/ +} hashState; + + +/*The initial hash value H(0)*/ +static const unsigned char JH224_H0[128]={0x2d,0xfe,0xdd,0x62,0xf9,0x9a,0x98,0xac,0xae,0x7c,0xac,0xd6,0x19,0xd6,0x34,0xe7,0xa4,0x83,0x10,0x5,0xbc,0x30,0x12,0x16,0xb8,0x60,0x38,0xc6,0xc9,0x66,0x14,0x94,0x66,0xd9,0x89,0x9f,0x25,0x80,0x70,0x6f,0xce,0x9e,0xa3,0x1b,0x1d,0x9b,0x1a,0xdc,0x11,0xe8,0x32,0x5f,0x7b,0x36,0x6e,0x10,0xf9,0x94,0x85,0x7f,0x2,0xfa,0x6,0xc1,0x1b,0x4f,0x1b,0x5c,0xd8,0xc8,0x40,0xb3,0x97,0xf6,0xa1,0x7f,0x6e,0x73,0x80,0x99,0xdc,0xdf,0x93,0xa5,0xad,0xea,0xa3,0xd3,0xa4,0x31,0xe8,0xde,0xc9,0x53,0x9a,0x68,0x22,0xb4,0xa9,0x8a,0xec,0x86,0xa1,0xe4,0xd5,0x74,0xac,0x95,0x9c,0xe5,0x6c,0xf0,0x15,0x96,0xd,0xea,0xb5,0xab,0x2b,0xbf,0x96,0x11,0xdc,0xf0,0xdd,0x64,0xea,0x6e}; +static const unsigned char JH256_H0[128]={0xeb,0x98,0xa3,0x41,0x2c,0x20,0xd3,0xeb,0x92,0xcd,0xbe,0x7b,0x9c,0xb2,0x45,0xc1,0x1c,0x93,0x51,0x91,0x60,0xd4,0xc7,0xfa,0x26,0x0,0x82,0xd6,0x7e,0x50,0x8a,0x3,0xa4,0x23,0x9e,0x26,0x77,0x26,0xb9,0x45,0xe0,0xfb,0x1a,0x48,0xd4,0x1a,0x94,0x77,0xcd,0xb5,0xab,0x26,0x2,0x6b,0x17,0x7a,0x56,0xf0,0x24,0x42,0xf,0xff,0x2f,0xa8,0x71,0xa3,0x96,0x89,0x7f,0x2e,0x4d,0x75,0x1d,0x14,0x49,0x8,0xf7,0x7d,0xe2,0x62,0x27,0x76,0x95,0xf7,0x76,0x24,0x8f,0x94,0x87,0xd5,0xb6,0x57,0x47,0x80,0x29,0x6c,0x5c,0x5e,0x27,0x2d,0xac,0x8e,0xd,0x6c,0x51,0x84,0x50,0xc6,0x57,0x5,0x7a,0xf,0x7b,0xe4,0xd3,0x67,0x70,0x24,0x12,0xea,0x89,0xe3,0xab,0x13,0xd3,0x1c,0xd7,0x69}; +static const unsigned char JH384_H0[128]={0x48,0x1e,0x3b,0xc6,0xd8,0x13,0x39,0x8a,0x6d,0x3b,0x5e,0x89,0x4a,0xde,0x87,0x9b,0x63,0xfa,0xea,0x68,0xd4,0x80,0xad,0x2e,0x33,0x2c,0xcb,0x21,0x48,0xf,0x82,0x67,0x98,0xae,0xc8,0x4d,0x90,0x82,0xb9,0x28,0xd4,0x55,0xea,0x30,0x41,0x11,0x42,0x49,0x36,0xf5,0x55,0xb2,0x92,0x48,0x47,0xec,0xc7,0x25,0xa,0x93,0xba,0xf4,0x3c,0xe1,0x56,0x9b,0x7f,0x8a,0x27,0xdb,0x45,0x4c,0x9e,0xfc,0xbd,0x49,0x63,0x97,0xaf,0xe,0x58,0x9f,0xc2,0x7d,0x26,0xaa,0x80,0xcd,0x80,0xc0,0x8b,0x8c,0x9d,0xeb,0x2e,0xda,0x8a,0x79,0x81,0xe8,0xf8,0xd5,0x37,0x3a,0xf4,0x39,0x67,0xad,0xdd,0xd1,0x7a,0x71,0xa9,0xb4,0xd3,0xbd,0xa4,0x75,0xd3,0x94,0x97,0x6c,0x3f,0xba,0x98,0x42,0x73,0x7f}; +static const unsigned char JH512_H0[128]={0x6f,0xd1,0x4b,0x96,0x3e,0x0,0xaa,0x17,0x63,0x6a,0x2e,0x5,0x7a,0x15,0xd5,0x43,0x8a,0x22,0x5e,0x8d,0xc,0x97,0xef,0xb,0xe9,0x34,0x12,0x59,0xf2,0xb3,0xc3,0x61,0x89,0x1d,0xa0,0xc1,0x53,0x6f,0x80,0x1e,0x2a,0xa9,0x5,0x6b,0xea,0x2b,0x6d,0x80,0x58,0x8e,0xcc,0xdb,0x20,0x75,0xba,0xa6,0xa9,0xf,0x3a,0x76,0xba,0xf8,0x3b,0xf7,0x1,0x69,0xe6,0x5,0x41,0xe3,0x4a,0x69,0x46,0xb5,0x8a,0x8e,0x2e,0x6f,0xe6,0x5a,0x10,0x47,0xa7,0xd0,0xc1,0x84,0x3c,0x24,0x3b,0x6e,0x71,0xb1,0x2d,0x5a,0xc1,0x99,0xcf,0x57,0xf6,0xec,0x9d,0xb1,0xf8,0x56,0xa7,0x6,0x88,0x7c,0x57,0x16,0xb1,0x56,0xe3,0xc2,0xfc,0xdf,0xe6,0x85,0x17,0xfb,0x54,0x5a,0x46,0x78,0xcc,0x8c,0xdd,0x4b}; + +/*42 round constants, each round constant is 32-byte (256-bit)*/ +static const unsigned char E8_bitslice_roundconstant[42][32]={ +{0x72,0xd5,0xde,0xa2,0xdf,0x15,0xf8,0x67,0x7b,0x84,0x15,0xa,0xb7,0x23,0x15,0x57,0x81,0xab,0xd6,0x90,0x4d,0x5a,0x87,0xf6,0x4e,0x9f,0x4f,0xc5,0xc3,0xd1,0x2b,0x40}, +{0xea,0x98,0x3a,0xe0,0x5c,0x45,0xfa,0x9c,0x3,0xc5,0xd2,0x99,0x66,0xb2,0x99,0x9a,0x66,0x2,0x96,0xb4,0xf2,0xbb,0x53,0x8a,0xb5,0x56,0x14,0x1a,0x88,0xdb,0xa2,0x31}, +{0x3,0xa3,0x5a,0x5c,0x9a,0x19,0xe,0xdb,0x40,0x3f,0xb2,0xa,0x87,0xc1,0x44,0x10,0x1c,0x5,0x19,0x80,0x84,0x9e,0x95,0x1d,0x6f,0x33,0xeb,0xad,0x5e,0xe7,0xcd,0xdc}, +{0x10,0xba,0x13,0x92,0x2,0xbf,0x6b,0x41,0xdc,0x78,0x65,0x15,0xf7,0xbb,0x27,0xd0,0xa,0x2c,0x81,0x39,0x37,0xaa,0x78,0x50,0x3f,0x1a,0xbf,0xd2,0x41,0x0,0x91,0xd3}, +{0x42,0x2d,0x5a,0xd,0xf6,0xcc,0x7e,0x90,0xdd,0x62,0x9f,0x9c,0x92,0xc0,0x97,0xce,0x18,0x5c,0xa7,0xb,0xc7,0x2b,0x44,0xac,0xd1,0xdf,0x65,0xd6,0x63,0xc6,0xfc,0x23}, +{0x97,0x6e,0x6c,0x3,0x9e,0xe0,0xb8,0x1a,0x21,0x5,0x45,0x7e,0x44,0x6c,0xec,0xa8,0xee,0xf1,0x3,0xbb,0x5d,0x8e,0x61,0xfa,0xfd,0x96,0x97,0xb2,0x94,0x83,0x81,0x97}, +{0x4a,0x8e,0x85,0x37,0xdb,0x3,0x30,0x2f,0x2a,0x67,0x8d,0x2d,0xfb,0x9f,0x6a,0x95,0x8a,0xfe,0x73,0x81,0xf8,0xb8,0x69,0x6c,0x8a,0xc7,0x72,0x46,0xc0,0x7f,0x42,0x14}, +{0xc5,0xf4,0x15,0x8f,0xbd,0xc7,0x5e,0xc4,0x75,0x44,0x6f,0xa7,0x8f,0x11,0xbb,0x80,0x52,0xde,0x75,0xb7,0xae,0xe4,0x88,0xbc,0x82,0xb8,0x0,0x1e,0x98,0xa6,0xa3,0xf4}, +{0x8e,0xf4,0x8f,0x33,0xa9,0xa3,0x63,0x15,0xaa,0x5f,0x56,0x24,0xd5,0xb7,0xf9,0x89,0xb6,0xf1,0xed,0x20,0x7c,0x5a,0xe0,0xfd,0x36,0xca,0xe9,0x5a,0x6,0x42,0x2c,0x36}, +{0xce,0x29,0x35,0x43,0x4e,0xfe,0x98,0x3d,0x53,0x3a,0xf9,0x74,0x73,0x9a,0x4b,0xa7,0xd0,0xf5,0x1f,0x59,0x6f,0x4e,0x81,0x86,0xe,0x9d,0xad,0x81,0xaf,0xd8,0x5a,0x9f}, +{0xa7,0x5,0x6,0x67,0xee,0x34,0x62,0x6a,0x8b,0xb,0x28,0xbe,0x6e,0xb9,0x17,0x27,0x47,0x74,0x7,0x26,0xc6,0x80,0x10,0x3f,0xe0,0xa0,0x7e,0x6f,0xc6,0x7e,0x48,0x7b}, +{0xd,0x55,0xa,0xa5,0x4a,0xf8,0xa4,0xc0,0x91,0xe3,0xe7,0x9f,0x97,0x8e,0xf1,0x9e,0x86,0x76,0x72,0x81,0x50,0x60,0x8d,0xd4,0x7e,0x9e,0x5a,0x41,0xf3,0xe5,0xb0,0x62}, +{0xfc,0x9f,0x1f,0xec,0x40,0x54,0x20,0x7a,0xe3,0xe4,0x1a,0x0,0xce,0xf4,0xc9,0x84,0x4f,0xd7,0x94,0xf5,0x9d,0xfa,0x95,0xd8,0x55,0x2e,0x7e,0x11,0x24,0xc3,0x54,0xa5}, +{0x5b,0xdf,0x72,0x28,0xbd,0xfe,0x6e,0x28,0x78,0xf5,0x7f,0xe2,0xf,0xa5,0xc4,0xb2,0x5,0x89,0x7c,0xef,0xee,0x49,0xd3,0x2e,0x44,0x7e,0x93,0x85,0xeb,0x28,0x59,0x7f}, +{0x70,0x5f,0x69,0x37,0xb3,0x24,0x31,0x4a,0x5e,0x86,0x28,0xf1,0x1d,0xd6,0xe4,0x65,0xc7,0x1b,0x77,0x4,0x51,0xb9,0x20,0xe7,0x74,0xfe,0x43,0xe8,0x23,0xd4,0x87,0x8a}, +{0x7d,0x29,0xe8,0xa3,0x92,0x76,0x94,0xf2,0xdd,0xcb,0x7a,0x9,0x9b,0x30,0xd9,0xc1,0x1d,0x1b,0x30,0xfb,0x5b,0xdc,0x1b,0xe0,0xda,0x24,0x49,0x4f,0xf2,0x9c,0x82,0xbf}, +{0xa4,0xe7,0xba,0x31,0xb4,0x70,0xbf,0xff,0xd,0x32,0x44,0x5,0xde,0xf8,0xbc,0x48,0x3b,0xae,0xfc,0x32,0x53,0xbb,0xd3,0x39,0x45,0x9f,0xc3,0xc1,0xe0,0x29,0x8b,0xa0}, +{0xe5,0xc9,0x5,0xfd,0xf7,0xae,0x9,0xf,0x94,0x70,0x34,0x12,0x42,0x90,0xf1,0x34,0xa2,0x71,0xb7,0x1,0xe3,0x44,0xed,0x95,0xe9,0x3b,0x8e,0x36,0x4f,0x2f,0x98,0x4a}, +{0x88,0x40,0x1d,0x63,0xa0,0x6c,0xf6,0x15,0x47,0xc1,0x44,0x4b,0x87,0x52,0xaf,0xff,0x7e,0xbb,0x4a,0xf1,0xe2,0xa,0xc6,0x30,0x46,0x70,0xb6,0xc5,0xcc,0x6e,0x8c,0xe6}, +{0xa4,0xd5,0xa4,0x56,0xbd,0x4f,0xca,0x0,0xda,0x9d,0x84,0x4b,0xc8,0x3e,0x18,0xae,0x73,0x57,0xce,0x45,0x30,0x64,0xd1,0xad,0xe8,0xa6,0xce,0x68,0x14,0x5c,0x25,0x67}, +{0xa3,0xda,0x8c,0xf2,0xcb,0xe,0xe1,0x16,0x33,0xe9,0x6,0x58,0x9a,0x94,0x99,0x9a,0x1f,0x60,0xb2,0x20,0xc2,0x6f,0x84,0x7b,0xd1,0xce,0xac,0x7f,0xa0,0xd1,0x85,0x18}, +{0x32,0x59,0x5b,0xa1,0x8d,0xdd,0x19,0xd3,0x50,0x9a,0x1c,0xc0,0xaa,0xa5,0xb4,0x46,0x9f,0x3d,0x63,0x67,0xe4,0x4,0x6b,0xba,0xf6,0xca,0x19,0xab,0xb,0x56,0xee,0x7e}, +{0x1f,0xb1,0x79,0xea,0xa9,0x28,0x21,0x74,0xe9,0xbd,0xf7,0x35,0x3b,0x36,0x51,0xee,0x1d,0x57,0xac,0x5a,0x75,0x50,0xd3,0x76,0x3a,0x46,0xc2,0xfe,0xa3,0x7d,0x70,0x1}, +{0xf7,0x35,0xc1,0xaf,0x98,0xa4,0xd8,0x42,0x78,0xed,0xec,0x20,0x9e,0x6b,0x67,0x79,0x41,0x83,0x63,0x15,0xea,0x3a,0xdb,0xa8,0xfa,0xc3,0x3b,0x4d,0x32,0x83,0x2c,0x83}, +{0xa7,0x40,0x3b,0x1f,0x1c,0x27,0x47,0xf3,0x59,0x40,0xf0,0x34,0xb7,0x2d,0x76,0x9a,0xe7,0x3e,0x4e,0x6c,0xd2,0x21,0x4f,0xfd,0xb8,0xfd,0x8d,0x39,0xdc,0x57,0x59,0xef}, +{0x8d,0x9b,0xc,0x49,0x2b,0x49,0xeb,0xda,0x5b,0xa2,0xd7,0x49,0x68,0xf3,0x70,0xd,0x7d,0x3b,0xae,0xd0,0x7a,0x8d,0x55,0x84,0xf5,0xa5,0xe9,0xf0,0xe4,0xf8,0x8e,0x65}, +{0xa0,0xb8,0xa2,0xf4,0x36,0x10,0x3b,0x53,0xc,0xa8,0x7,0x9e,0x75,0x3e,0xec,0x5a,0x91,0x68,0x94,0x92,0x56,0xe8,0x88,0x4f,0x5b,0xb0,0x5c,0x55,0xf8,0xba,0xbc,0x4c}, +{0xe3,0xbb,0x3b,0x99,0xf3,0x87,0x94,0x7b,0x75,0xda,0xf4,0xd6,0x72,0x6b,0x1c,0x5d,0x64,0xae,0xac,0x28,0xdc,0x34,0xb3,0x6d,0x6c,0x34,0xa5,0x50,0xb8,0x28,0xdb,0x71}, +{0xf8,0x61,0xe2,0xf2,0x10,0x8d,0x51,0x2a,0xe3,0xdb,0x64,0x33,0x59,0xdd,0x75,0xfc,0x1c,0xac,0xbc,0xf1,0x43,0xce,0x3f,0xa2,0x67,0xbb,0xd1,0x3c,0x2,0xe8,0x43,0xb0}, +{0x33,0xa,0x5b,0xca,0x88,0x29,0xa1,0x75,0x7f,0x34,0x19,0x4d,0xb4,0x16,0x53,0x5c,0x92,0x3b,0x94,0xc3,0xe,0x79,0x4d,0x1e,0x79,0x74,0x75,0xd7,0xb6,0xee,0xaf,0x3f}, +{0xea,0xa8,0xd4,0xf7,0xbe,0x1a,0x39,0x21,0x5c,0xf4,0x7e,0x9,0x4c,0x23,0x27,0x51,0x26,0xa3,0x24,0x53,0xba,0x32,0x3c,0xd2,0x44,0xa3,0x17,0x4a,0x6d,0xa6,0xd5,0xad}, +{0xb5,0x1d,0x3e,0xa6,0xaf,0xf2,0xc9,0x8,0x83,0x59,0x3d,0x98,0x91,0x6b,0x3c,0x56,0x4c,0xf8,0x7c,0xa1,0x72,0x86,0x60,0x4d,0x46,0xe2,0x3e,0xcc,0x8,0x6e,0xc7,0xf6}, +{0x2f,0x98,0x33,0xb3,0xb1,0xbc,0x76,0x5e,0x2b,0xd6,0x66,0xa5,0xef,0xc4,0xe6,0x2a,0x6,0xf4,0xb6,0xe8,0xbe,0xc1,0xd4,0x36,0x74,0xee,0x82,0x15,0xbc,0xef,0x21,0x63}, +{0xfd,0xc1,0x4e,0xd,0xf4,0x53,0xc9,0x69,0xa7,0x7d,0x5a,0xc4,0x6,0x58,0x58,0x26,0x7e,0xc1,0x14,0x16,0x6,0xe0,0xfa,0x16,0x7e,0x90,0xaf,0x3d,0x28,0x63,0x9d,0x3f}, +{0xd2,0xc9,0xf2,0xe3,0x0,0x9b,0xd2,0xc,0x5f,0xaa,0xce,0x30,0xb7,0xd4,0xc,0x30,0x74,0x2a,0x51,0x16,0xf2,0xe0,0x32,0x98,0xd,0xeb,0x30,0xd8,0xe3,0xce,0xf8,0x9a}, +{0x4b,0xc5,0x9e,0x7b,0xb5,0xf1,0x79,0x92,0xff,0x51,0xe6,0x6e,0x4,0x86,0x68,0xd3,0x9b,0x23,0x4d,0x57,0xe6,0x96,0x67,0x31,0xcc,0xe6,0xa6,0xf3,0x17,0xa,0x75,0x5}, +{0xb1,0x76,0x81,0xd9,0x13,0x32,0x6c,0xce,0x3c,0x17,0x52,0x84,0xf8,0x5,0xa2,0x62,0xf4,0x2b,0xcb,0xb3,0x78,0x47,0x15,0x47,0xff,0x46,0x54,0x82,0x23,0x93,0x6a,0x48}, +{0x38,0xdf,0x58,0x7,0x4e,0x5e,0x65,0x65,0xf2,0xfc,0x7c,0x89,0xfc,0x86,0x50,0x8e,0x31,0x70,0x2e,0x44,0xd0,0xb,0xca,0x86,0xf0,0x40,0x9,0xa2,0x30,0x78,0x47,0x4e}, +{0x65,0xa0,0xee,0x39,0xd1,0xf7,0x38,0x83,0xf7,0x5e,0xe9,0x37,0xe4,0x2c,0x3a,0xbd,0x21,0x97,0xb2,0x26,0x1,0x13,0xf8,0x6f,0xa3,0x44,0xed,0xd1,0xef,0x9f,0xde,0xe7}, +{0x8b,0xa0,0xdf,0x15,0x76,0x25,0x92,0xd9,0x3c,0x85,0xf7,0xf6,0x12,0xdc,0x42,0xbe,0xd8,0xa7,0xec,0x7c,0xab,0x27,0xb0,0x7e,0x53,0x8d,0x7d,0xda,0xaa,0x3e,0xa8,0xde}, +{0xaa,0x25,0xce,0x93,0xbd,0x2,0x69,0xd8,0x5a,0xf6,0x43,0xfd,0x1a,0x73,0x8,0xf9,0xc0,0x5f,0xef,0xda,0x17,0x4a,0x19,0xa5,0x97,0x4d,0x66,0x33,0x4c,0xfd,0x21,0x6a}, +{0x35,0xb4,0x98,0x31,0xdb,0x41,0x15,0x70,0xea,0x1e,0xf,0xbb,0xed,0xcd,0x54,0x9b,0x9a,0xd0,0x63,0xa1,0x51,0x97,0x40,0x72,0xf6,0x75,0x9d,0xbf,0x91,0x47,0x6f,0xe2}}; + + +static void E8(hashState *state); /*The bijective function E8, in bitslice form*/ +static void F8(hashState *state); /*The compression function F8 */ + +/*The API functions*/ +static HashReturn Init(hashState *state, int hashbitlen); +static HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen); +static HashReturn Final(hashState *state, BitSequence *hashval); +static HashReturn Hash(int hashbitlen, const BitSequence *data,DataLength databitlen, BitSequence *hashval); + +/*swapping bit 2i with bit 2i+1 of 64-bit x*/ +#define SWAP1(x) (x) = ((((x) & 0x5555555555555555ULL) << 1) | (((x) & 0xaaaaaaaaaaaaaaaaULL) >> 1)); +/*swapping bits 4i||4i+1 with bits 4i+2||4i+3 of 64-bit x*/ +#define SWAP2(x) (x) = ((((x) & 0x3333333333333333ULL) << 2) | (((x) & 0xccccccccccccccccULL) >> 2)); +/*swapping bits 8i||8i+1||8i+2||8i+3 with bits 8i+4||8i+5||8i+6||8i+7 of 64-bit x*/ +#define SWAP4(x) (x) = ((((x) & 0x0f0f0f0f0f0f0f0fULL) << 4) | (((x) & 0xf0f0f0f0f0f0f0f0ULL) >> 4)); +/*swapping bits 16i||16i+1||......||16i+7 with bits 16i+8||16i+9||......||16i+15 of 64-bit x*/ +#define SWAP8(x) (x) = ((((x) & 0x00ff00ff00ff00ffULL) << 8) | (((x) & 0xff00ff00ff00ff00ULL) >> 8)); +/*swapping bits 32i||32i+1||......||32i+15 with bits 32i+16||32i+17||......||32i+31 of 64-bit x*/ +#define SWAP16(x) (x) = ((((x) & 0x0000ffff0000ffffULL) << 16) | (((x) & 0xffff0000ffff0000ULL) >> 16)); +/*swapping bits 64i||64i+1||......||64i+31 with bits 64i+32||64i+33||......||64i+63 of 64-bit x*/ +#define SWAP32(x) (x) = (((x) << 32) | ((x) >> 32)); + +/*The MDS transform*/ +#define L(m0,m1,m2,m3,m4,m5,m6,m7) \ + (m4) ^= (m1); \ + (m5) ^= (m2); \ + (m6) ^= (m0) ^ (m3); \ + (m7) ^= (m0); \ + (m0) ^= (m5); \ + (m1) ^= (m6); \ + (m2) ^= (m4) ^ (m7); \ + (m3) ^= (m4); + +/*Two Sboxes are computed in parallel, each Sbox implements S0 and S1, selected by a constant bit*/ +/*The reason to compute two Sboxes in parallel is to try to fully utilize the parallel processing power*/ +#define SS(m0,m1,m2,m3,m4,m5,m6,m7,cc0,cc1) \ + m3 = ~(m3); \ + m7 = ~(m7); \ + m0 ^= ((~(m2)) & (cc0)); \ + m4 ^= ((~(m6)) & (cc1)); \ + temp0 = (cc0) ^ ((m0) & (m1));\ + temp1 = (cc1) ^ ((m4) & (m5));\ + m0 ^= ((m2) & (m3)); \ + m4 ^= ((m6) & (m7)); \ + m3 ^= ((~(m1)) & (m2)); \ + m7 ^= ((~(m5)) & (m6)); \ + m1 ^= ((m0) & (m2)); \ + m5 ^= ((m4) & (m6)); \ + m2 ^= ((m0) & (~(m3))); \ + m6 ^= ((m4) & (~(m7))); \ + m0 ^= ((m1) | (m3)); \ + m4 ^= ((m5) | (m7)); \ + m3 ^= ((m1) & (m2)); \ + m7 ^= ((m5) & (m6)); \ + m1 ^= (temp0 & (m0)); \ + m5 ^= (temp1 & (m4)); \ + m2 ^= temp0; \ + m6 ^= temp1; + +/*The bijective function E8, in bitslice form*/ +static void E8(hashState *state) +{ + uint64 i,roundnumber,temp0,temp1; + + for (roundnumber = 0; roundnumber < 42; roundnumber = roundnumber+7) { + /*round 7*roundnumber+0: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+0])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+0])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP1(state->x[1][i]); SWAP1(state->x[3][i]); SWAP1(state->x[5][i]); SWAP1(state->x[7][i]); + } + + /*round 7*roundnumber+1: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+1])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+1])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP2(state->x[1][i]); SWAP2(state->x[3][i]); SWAP2(state->x[5][i]); SWAP2(state->x[7][i]); + } + + /*round 7*roundnumber+2: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+2])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+2])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP4(state->x[1][i]); SWAP4(state->x[3][i]); SWAP4(state->x[5][i]); SWAP4(state->x[7][i]); + } + + /*round 7*roundnumber+3: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+3])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+3])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP8(state->x[1][i]); SWAP8(state->x[3][i]); SWAP8(state->x[5][i]); SWAP8(state->x[7][i]); + } + + /*round 7*roundnumber+4: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+4])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+4])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP16(state->x[1][i]); SWAP16(state->x[3][i]); SWAP16(state->x[5][i]); SWAP16(state->x[7][i]); + } + + /*round 7*roundnumber+5: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+5])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+5])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP32(state->x[1][i]); SWAP32(state->x[3][i]); SWAP32(state->x[5][i]); SWAP32(state->x[7][i]); + } + + /*round 7*roundnumber+6: Sbox and MDS layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+6])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+6])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + } + /*round 7*roundnumber+6: swapping layer*/ + for (i = 1; i < 8; i = i+2) { + temp0 = state->x[i][0]; state->x[i][0] = state->x[i][1]; state->x[i][1] = temp0; + } + } + +} + +/*The compression function F8 */ +static void F8(hashState *state) +{ + uint64 i; + + /*xor the 512-bit message with the fist half of the 1024-bit hash state*/ + for (i = 0; i < 8; i++) state->x[i >> 1][i & 1] ^= ((uint64*)state->buffer)[i]; + + /*the bijective function E8 */ + E8(state); + + /*xor the 512-bit message with the second half of the 1024-bit hash state*/ + for (i = 0; i < 8; i++) state->x[(8+i) >> 1][(8+i) & 1] ^= ((uint64*)state->buffer)[i]; +} + +/*before hashing a message, initialize the hash state as H0 */ +static HashReturn Init(hashState *state, int hashbitlen) +{ + state->databitlen = 0; + state->datasize_in_buffer = 0; + + /*initialize the initial hash value of JH*/ + state->hashbitlen = hashbitlen; + + /*load the intital hash value into state*/ + switch (hashbitlen) + { + case 224: memcpy(state->x,JH224_H0,128); break; + case 256: memcpy(state->x,JH256_H0,128); break; + case 384: memcpy(state->x,JH384_H0,128); break; + case 512: memcpy(state->x,JH512_H0,128); break; + } + + return(SUCCESS); +} + + +/*hash each 512-bit message block, except the last partial block*/ +static HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen) +{ + DataLength index; /*the starting address of the data to be compressed*/ + + state->databitlen += databitlen; + index = 0; + + /*if there is remaining data in the buffer, fill it to a full message block first*/ + /*we assume that the size of the data in the buffer is the multiple of 8 bits if it is not at the end of a message*/ + + /*There is data in the buffer, but the incoming data is insufficient for a full block*/ + if ( (state->datasize_in_buffer > 0 ) && (( state->datasize_in_buffer + databitlen) < 512) ) { + if ( (databitlen & 7) == 0 ) { + memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3)) ; + } + else memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3)+1) ; + state->datasize_in_buffer += databitlen; + databitlen = 0; + } + + /*There is data in the buffer, and the incoming data is sufficient for a full block*/ + if ( (state->datasize_in_buffer > 0 ) && (( state->datasize_in_buffer + databitlen) >= 512) ) { + memcpy( state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3) ) ; + index = 64-(state->datasize_in_buffer >> 3); + databitlen = databitlen - (512 - state->datasize_in_buffer); + F8(state); + state->datasize_in_buffer = 0; + } + + /*hash the remaining full message blocks*/ + for ( ; databitlen >= 512; index = index+64, databitlen = databitlen - 512) { + memcpy(state->buffer, data+index, 64); + F8(state); + } + + /*store the partial block into buffer, assume that -- if part of the last byte is not part of the message, then that part consists of 0 bits*/ + if ( databitlen > 0) { + if ((databitlen & 7) == 0) + memcpy(state->buffer, data+index, (databitlen & 0x1ff) >> 3); + else + memcpy(state->buffer, data+index, ((databitlen & 0x1ff) >> 3)+1); + state->datasize_in_buffer = databitlen; + } + + return(SUCCESS); +} + +/*pad the message, process the padded block(s), truncate the hash value H to obtain the message digest*/ +static HashReturn Final(hashState *state, BitSequence *hashval) +{ + unsigned int i; + + if ( (state->databitlen & 0x1ff) == 0 ) { + /*pad the message when databitlen is multiple of 512 bits, then process the padded block*/ + memset(state->buffer, 0, 64); + state->buffer[0] = 0x80; + state->buffer[63] = state->databitlen & 0xff; + state->buffer[62] = (state->databitlen >> 8) & 0xff; + state->buffer[61] = (state->databitlen >> 16) & 0xff; + state->buffer[60] = (state->databitlen >> 24) & 0xff; + state->buffer[59] = (state->databitlen >> 32) & 0xff; + state->buffer[58] = (state->databitlen >> 40) & 0xff; + state->buffer[57] = (state->databitlen >> 48) & 0xff; + state->buffer[56] = (state->databitlen >> 56) & 0xff; + F8(state); + } + else { + /*set the rest of the bytes in the buffer to 0*/ + if ( (state->datasize_in_buffer & 7) == 0) + for (i = (state->databitlen & 0x1ff) >> 3; i < 64; i++) state->buffer[i] = 0; + else + for (i = ((state->databitlen & 0x1ff) >> 3)+1; i < 64; i++) state->buffer[i] = 0; + + /*pad and process the partial block when databitlen is not multiple of 512 bits, then hash the padded blocks*/ + state->buffer[((state->databitlen & 0x1ff) >> 3)] |= 1 << (7- (state->databitlen & 7)); + + F8(state); + memset(state->buffer, 0, 64); + state->buffer[63] = state->databitlen & 0xff; + state->buffer[62] = (state->databitlen >> 8) & 0xff; + state->buffer[61] = (state->databitlen >> 16) & 0xff; + state->buffer[60] = (state->databitlen >> 24) & 0xff; + state->buffer[59] = (state->databitlen >> 32) & 0xff; + state->buffer[58] = (state->databitlen >> 40) & 0xff; + state->buffer[57] = (state->databitlen >> 48) & 0xff; + state->buffer[56] = (state->databitlen >> 56) & 0xff; + F8(state); + } + + /*truncating the final hash value to generate the message digest*/ + switch(state->hashbitlen) { + case 224: memcpy(hashval,(unsigned char*)state->x+64+36,28); break; + case 256: memcpy(hashval,(unsigned char*)state->x+64+32,32); break; + case 384: memcpy(hashval,(unsigned char*)state->x+64+16,48); break; + case 512: memcpy(hashval,(unsigned char*)state->x+64,64); break; + } + + return(SUCCESS); +} + +/* hash a message, + three inputs: message digest size in bits (hashbitlen); message (data); message length in bits (databitlen) + one output: message digest (hashval) +*/ +static HashReturn Hash(int hashbitlen, const BitSequence *data,DataLength databitlen, BitSequence *hashval) +{ + hashState state; + + if ( hashbitlen == 224 || hashbitlen == 256 || hashbitlen == 384 || hashbitlen == 512 ) { + Init(&state, hashbitlen); + Update(&state, data, databitlen); + Final(&state, hashval); + return SUCCESS; + } + else + return(BAD_HASHLEN); +} + +void jh(unsigned bit_len, const uint8_t input[], size_t input_bit_length, uint8_t output[]) +{ + HashReturn ret = Hash(bit_len, input, input_bit_length, output); + assert(ret == SUCCESS); +} diff --git a/webassembly/aeon/keccak.c b/webassembly/aeon/keccak.c new file mode 100644 index 0000000..45aa4f9 --- /dev/null +++ b/webassembly/aeon/keccak.c @@ -0,0 +1,129 @@ +// keccak.c +// 19-Nov-11 Markku-Juhani O. Saarinen +// A baseline Keccak (3rd round) implementation. + +#include +#include +#include "keccak.h" + +#define HASH_DATA_AREA 136 +#define KECCAK_ROUNDS 24 + +#ifndef ROTL64 +#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) +#endif + +const uint64_t keccakf_rndc[24] = +{ + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 +}; + +const int keccakf_rotc[24] = +{ + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 +}; + +const int keccakf_piln[24] = +{ + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 +}; + +// update the state with given number of rounds + +void keccakf(uint64_t st[25], int rounds) +{ + int i, j, round; + uint64_t t, bc[5]; + + for (round = 0; round < rounds; ++round) { + + // Theta + bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20]; + bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21]; + bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22]; + bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23]; + bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24]; + + for (i = 0; i < 5; ++i) { + t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); + st[i ] ^= t; + st[i + 5] ^= t; + st[i + 10] ^= t; + st[i + 15] ^= t; + st[i + 20] ^= t; + } + + // Rho Pi + t = st[1]; + for (i = 0; i < 24; ++i) { + bc[0] = st[keccakf_piln[i]]; + st[keccakf_piln[i]] = ROTL64(t, keccakf_rotc[i]); + t = bc[0]; + } + + // Chi + for (j = 0; j < 25; j += 5) { + bc[0] = st[j ]; + bc[1] = st[j + 1]; + bc[2] = st[j + 2]; + bc[3] = st[j + 3]; + bc[4] = st[j + 4]; + st[j ] ^= (~bc[1]) & bc[2]; + st[j + 1] ^= (~bc[2]) & bc[3]; + st[j + 2] ^= (~bc[3]) & bc[4]; + st[j + 3] ^= (~bc[4]) & bc[0]; + st[j + 4] ^= (~bc[0]) & bc[1]; + } + + // Iota + st[0] ^= keccakf_rndc[round]; + } +} + +// compute a keccak hash (md) of given byte length from "in" +typedef uint64_t state_t[25]; + +void keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen) +{ + state_t st; + uint8_t temp[144]; + int i, rsiz, rsizw; + + rsiz = sizeof(state_t) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen; + rsizw = rsiz / 8; + + memset(st, 0, sizeof(st)); + + for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) { + for (i = 0; i < rsizw; i++) + st[i] ^= ((uint64_t *) in)[i]; + keccakf(st, KECCAK_ROUNDS); + } + + // last block and padding + memcpy(temp, in, inlen); + temp[inlen++] = 1; + memset(temp + inlen, 0, rsiz - inlen); + temp[rsiz - 1] |= 0x80; + + for (i = 0; i < rsizw; i++) + st[i] ^= ((uint64_t *) temp)[i]; + + keccakf(st, KECCAK_ROUNDS); + + memcpy(md, st, mdlen); +} + +void keccak1600(const uint8_t *in, int inlen, uint8_t *md) +{ + keccak(in, inlen, md, sizeof(state_t)); +} diff --git a/webassembly/aeon/keccak.h b/webassembly/aeon/keccak.h new file mode 100644 index 0000000..0b22d04 --- /dev/null +++ b/webassembly/aeon/keccak.h @@ -0,0 +1,23 @@ +// keccak.h +// 19-Nov-11 Markku-Juhani O. Saarinen + +#ifndef KECCAK_H +#define KECCAK_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen); + +void keccakf(uint64_t st[25], int norounds); + +void keccak1600(const uint8_t *in, int inlen, uint8_t *md); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/webassembly/aeon/license.txt b/webassembly/aeon/license.txt new file mode 100644 index 0000000..50fac93 --- /dev/null +++ b/webassembly/aeon/license.txt @@ -0,0 +1,39 @@ +code is based on + +https://github.com/noahdesu/xmonarch + +which is based on the monero code. + + + +Copyright (c) 2014-2018, The Monero Project + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Parts of the project are originally copyright (c) 2012-2013 The Cryptonote +developers diff --git a/webassembly/aeon/main.c b/webassembly/aeon/main.c new file mode 100644 index 0000000..e7fb7d5 --- /dev/null +++ b/webassembly/aeon/main.c @@ -0,0 +1,53 @@ +#include +#include +#include "cryptonight.h" + +#include +#include +#include +#include "jh.h" + +#include + +char* tohex(unsigned char * in) +{ + size_t size = 32; + + char output[(size * 2) + 1]; + + char *ptr = &output[0]; + + int i; + + for (i = 0; i < size; i++) + { + ptr += sprintf (ptr, "%02x",in[i]); + } + + return &output[0]; +} + + +char* hash_cn(char* hex, char* nonce) +{ + unsigned char inp[76]; + + char *pos = hex; + for( size_t i = 0; i < 76; i++) { sscanf(pos, "%2hhx", &inp[i]); pos += 2; } + + pos = nonce; + + for(size_t i = 39; i < 43; i++) { sscanf(pos, "%2hhx", &inp[i]); pos += 2; } + + unsigned char hash[76]; + cryptonight(hash, inp, 76); + + + return tohex(hash); +} + + +int main (void) +{ + return 0; +} diff --git a/webassembly/aeon/oaes_config.h b/webassembly/aeon/oaes_config.h new file mode 100644 index 0000000..3fc0e1b --- /dev/null +++ b/webassembly/aeon/oaes_config.h @@ -0,0 +1,50 @@ +/* + * --------------------------------------------------------------------------- + * OpenAES License + * --------------------------------------------------------------------------- + * Copyright (c) 2012, Nabil S. Al Ramli, www.nalramli.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * --------------------------------------------------------------------------- + */ + +#ifndef _OAES_CONFIG_H +#define _OAES_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#ifndef OAES_HAVE_ISAAC +//#define OAES_HAVE_ISAAC 1 +//#endif // OAES_HAVE_ISAAC + +//#ifndef OAES_DEBUG +//#define OAES_DEBUG 0 +//#endif // OAES_DEBUG + +#ifdef __cplusplus +} +#endif + +#endif // _OAES_CONFIG_H diff --git a/webassembly/aeon/oaes_lib.c b/webassembly/aeon/oaes_lib.c new file mode 100644 index 0000000..d213823 --- /dev/null +++ b/webassembly/aeon/oaes_lib.c @@ -0,0 +1,1414 @@ +/* + * --------------------------------------------------------------------------- + * OpenAES License + * --------------------------------------------------------------------------- + * Copyright (c) 2012, Nabil S. Al Ramli, www.nalramli.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * --------------------------------------------------------------------------- + */ +//static const char _NR[] = { +// 0x4e,0x61,0x62,0x69,0x6c,0x20,0x53,0x2e,0x20, +// 0x41,0x6c,0x20,0x52,0x61,0x6d,0x6c,0x69,0x00 }; + +#include +#include +#include +#if !((defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__APPLE__)) +#include +#endif +#include +#include +#include + +#ifdef WIN32 +#include +#else +#include +#include +#endif + +#include "oaes_config.h" +#include "oaes_lib.h" + +#ifdef OAES_HAVE_ISAAC +#include "rand.h" +#endif // OAES_HAVE_ISAAC + +#define OAES_RKEY_LEN 4 +#define OAES_COL_LEN 4 +#define OAES_ROUND_BASE 7 + +// the block is padded +#define OAES_FLAG_PAD 0x01 + +#ifndef min +# define min(a,b) (((a)<(b)) ? (a) : (b)) +#endif /* min */ + +// "OAES<8-bit header version><8-bit type><16-bit options><8-bit flags><56-bit reserved>" +static uint8_t oaes_header[OAES_BLOCK_SIZE] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ 0x4f, 0x41, 0x45, 0x53, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static uint8_t oaes_gf_8[] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; + +static uint8_t oaes_sub_byte_value[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76 }, + /*1*/ { 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0 }, + /*2*/ { 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15 }, + /*3*/ { 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75 }, + /*4*/ { 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84 }, + /*5*/ { 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf }, + /*6*/ { 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8 }, + /*7*/ { 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2 }, + /*8*/ { 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73 }, + /*9*/ { 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb }, + /*a*/ { 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79 }, + /*b*/ { 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08 }, + /*c*/ { 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a }, + /*d*/ { 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e }, + /*e*/ { 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf }, + /*f*/ { 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }, +}; + +static uint8_t oaes_inv_sub_byte_value[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb }, + /*1*/ { 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb }, + /*2*/ { 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e }, + /*3*/ { 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 }, + /*4*/ { 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 }, + /*5*/ { 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 }, + /*6*/ { 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 }, + /*7*/ { 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b }, + /*8*/ { 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 }, + /*9*/ { 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e }, + /*a*/ { 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b }, + /*b*/ { 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 }, + /*c*/ { 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f }, + /*d*/ { 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef }, + /*e*/ { 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 }, + /*f*/ { 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }, +}; + +static uint8_t oaes_gf_mul_2[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e }, + /*1*/ { 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e }, + /*2*/ { 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e }, + /*3*/ { 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e }, + /*4*/ { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e }, + /*5*/ { 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe }, + /*6*/ { 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde }, + /*7*/ { 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe }, + /*8*/ { 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05 }, + /*9*/ { 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25 }, + /*a*/ { 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45 }, + /*b*/ { 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65 }, + /*c*/ { 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85 }, + /*d*/ { 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5 }, + /*e*/ { 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5 }, + /*f*/ { 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5 }, +}; + +static uint8_t oaes_gf_mul_3[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11 }, + /*1*/ { 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21 }, + /*2*/ { 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71 }, + /*3*/ { 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41 }, + /*4*/ { 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1 }, + /*5*/ { 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1 }, + /*6*/ { 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1 }, + /*7*/ { 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81 }, + /*8*/ { 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a }, + /*9*/ { 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba }, + /*a*/ { 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea }, + /*b*/ { 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda }, + /*c*/ { 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a }, + /*d*/ { 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a }, + /*e*/ { 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a }, + /*f*/ { 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a }, +}; + +static uint8_t oaes_gf_mul_9[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77 }, + /*1*/ { 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7 }, + /*2*/ { 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c }, + /*3*/ { 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc }, + /*4*/ { 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01 }, + /*5*/ { 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91 }, + /*6*/ { 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a }, + /*7*/ { 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa }, + /*8*/ { 0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b }, + /*9*/ { 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b }, + /*a*/ { 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0 }, + /*b*/ { 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30 }, + /*c*/ { 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed }, + /*d*/ { 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d }, + /*e*/ { 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6 }, + /*f*/ { 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46 }, +}; + +static uint8_t oaes_gf_mul_b[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69 }, + /*1*/ { 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9 }, + /*2*/ { 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12 }, + /*3*/ { 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2 }, + /*4*/ { 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f }, + /*5*/ { 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f }, + /*6*/ { 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4 }, + /*7*/ { 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54 }, + /*8*/ { 0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e }, + /*9*/ { 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e }, + /*a*/ { 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5 }, + /*b*/ { 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55 }, + /*c*/ { 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68 }, + /*d*/ { 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8 }, + /*e*/ { 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13 }, + /*f*/ { 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3 }, +}; + +static uint8_t oaes_gf_mul_d[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b }, + /*1*/ { 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b }, + /*2*/ { 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0 }, + /*3*/ { 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20 }, + /*4*/ { 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26 }, + /*5*/ { 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6 }, + /*6*/ { 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d }, + /*7*/ { 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d }, + /*8*/ { 0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91 }, + /*9*/ { 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41 }, + /*a*/ { 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a }, + /*b*/ { 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa }, + /*c*/ { 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc }, + /*d*/ { 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c }, + /*e*/ { 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47 }, + /*f*/ { 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97 }, +}; + +static uint8_t oaes_gf_mul_e[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a }, + /*1*/ { 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba }, + /*2*/ { 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81 }, + /*3*/ { 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61 }, + /*4*/ { 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7 }, + /*5*/ { 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17 }, + /*6*/ { 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c }, + /*7*/ { 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc }, + /*8*/ { 0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b }, + /*9*/ { 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb }, + /*a*/ { 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0 }, + /*b*/ { 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20 }, + /*c*/ { 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6 }, + /*d*/ { 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56 }, + /*e*/ { 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d }, + /*f*/ { 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d }, +}; + +static OAES_RET oaes_sub_byte( uint8_t * byte ) +{ + size_t _x, _y; + + if(NULL == byte) + return OAES_RET_ARG1; + + _y = ((_x = *byte) >> 4) & 0x0f; + _x &= 0x0f; + *byte = oaes_sub_byte_value[_y][_x]; + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_inv_sub_byte( uint8_t * byte ) +{ + size_t _x, _y; + + if( NULL == byte ) + return OAES_RET_ARG1; + + _x = _y = *byte; + _x &= 0x0f; + _y &= 0xf0; + _y >>= 4; + *byte = oaes_inv_sub_byte_value[_y][_x]; + + return OAES_RET_SUCCESS; +} +/* +static OAES_RET oaes_word_rot_right( uint8_t word[OAES_COL_LEN] ) +{ + uint8_t _temp[OAES_COL_LEN]; + + if( NULL == word ) + return OAES_RET_ARG1; + + memcpy( _temp + 1, word, OAES_COL_LEN - 1 ); + _temp[0] = word[OAES_COL_LEN - 1]; + memcpy( word, _temp, OAES_COL_LEN ); + + return OAES_RET_SUCCESS; +} +*/ + +static OAES_RET oaes_word_rot_left( uint8_t word[OAES_COL_LEN] ) +{ + uint8_t _temp[OAES_COL_LEN]; + + if( NULL == word ) + return OAES_RET_ARG1; + + memcpy( _temp, word + 1, OAES_COL_LEN - 1 ); + _temp[OAES_COL_LEN - 1] = word[0]; + memcpy( word, _temp, OAES_COL_LEN ); + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_shift_rows( uint8_t block[OAES_BLOCK_SIZE] ) +{ + if(NULL == block) + return OAES_RET_ARG1; + + uint8_t _temp[] = { block[0x03], block[0x02], block[0x01], block[0x06], block[0x0b] }; + + block[0x0b] = block[0x07]; + block[0x01] = block[0x05]; + block[0x02] = block[0x0a]; + block[0x03] = block[0x0f]; + block[0x05] = block[0x09]; + block[0x06] = block[0x0e]; + block[0x07] = _temp[0]; + block[0x09] = block[0x0d]; + block[0x0a] = _temp[1]; + block[0x0d] = _temp[2]; + block[0x0e] = _temp[3]; + block[0x0f] = _temp[4]; + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_inv_shift_rows( uint8_t block[OAES_BLOCK_SIZE] ) +{ + uint8_t _temp[OAES_BLOCK_SIZE]; + + if( NULL == block ) + return OAES_RET_ARG1; + + _temp[0x00] = block[0x00]; + _temp[0x01] = block[0x0d]; + _temp[0x02] = block[0x0a]; + _temp[0x03] = block[0x07]; + _temp[0x04] = block[0x04]; + _temp[0x05] = block[0x01]; + _temp[0x06] = block[0x0e]; + _temp[0x07] = block[0x0b]; + _temp[0x08] = block[0x08]; + _temp[0x09] = block[0x05]; + _temp[0x0a] = block[0x02]; + _temp[0x0b] = block[0x0f]; + _temp[0x0c] = block[0x0c]; + _temp[0x0d] = block[0x09]; + _temp[0x0e] = block[0x06]; + _temp[0x0f] = block[0x03]; + memcpy( block, _temp, OAES_BLOCK_SIZE ); + + return OAES_RET_SUCCESS; +} + +static uint8_t oaes_gf_mul(uint8_t left, uint8_t right) +{ + size_t _x, _y; + + _y = ((_x = left) >> 4) & 0x0f; + _x &= 0x0f; + + switch( right ) + { + case 0x02: + return oaes_gf_mul_2[_y][_x]; + break; + case 0x03: + return oaes_gf_mul_3[_y][_x]; + break; + case 0x09: + return oaes_gf_mul_9[_y][_x]; + break; + case 0x0b: + return oaes_gf_mul_b[_y][_x]; + break; + case 0x0d: + return oaes_gf_mul_d[_y][_x]; + break; + case 0x0e: + return oaes_gf_mul_e[_y][_x]; + break; + default: + return left; + break; + } +} + +static OAES_RET oaes_mix_cols( uint8_t word[OAES_COL_LEN] ) +{ + uint8_t _temp[OAES_COL_LEN]; + + if(NULL == word) + return OAES_RET_ARG1; + + _temp[0] = oaes_gf_mul(word[0], 0x02) ^ oaes_gf_mul( word[1], 0x03 ) ^ + word[2] ^ word[3]; + _temp[1] = word[0] ^ oaes_gf_mul( word[1], 0x02 ) ^ + oaes_gf_mul( word[2], 0x03 ) ^ word[3]; + _temp[2] = word[0] ^ word[1] ^ + oaes_gf_mul( word[2], 0x02 ) ^ oaes_gf_mul( word[3], 0x03 ); + _temp[3] = oaes_gf_mul( word[0], 0x03 ) ^ word[1] ^ + word[2] ^ oaes_gf_mul( word[3], 0x02 ); + memcpy( word, _temp, OAES_COL_LEN ); + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_inv_mix_cols( uint8_t word[OAES_COL_LEN] ) +{ + uint8_t _temp[OAES_COL_LEN]; + + if( NULL == word ) + return OAES_RET_ARG1; + + _temp[0] = oaes_gf_mul( word[0], 0x0e ) ^ oaes_gf_mul( word[1], 0x0b ) ^ + oaes_gf_mul( word[2], 0x0d ) ^ oaes_gf_mul( word[3], 0x09 ); + _temp[1] = oaes_gf_mul( word[0], 0x09 ) ^ oaes_gf_mul( word[1], 0x0e ) ^ + oaes_gf_mul( word[2], 0x0b ) ^ oaes_gf_mul( word[3], 0x0d ); + _temp[2] = oaes_gf_mul( word[0], 0x0d ) ^ oaes_gf_mul( word[1], 0x09 ) ^ + oaes_gf_mul( word[2], 0x0e ) ^ oaes_gf_mul( word[3], 0x0b ); + _temp[3] = oaes_gf_mul( word[0], 0x0b ) ^ oaes_gf_mul( word[1], 0x0d ) ^ + oaes_gf_mul( word[2], 0x09 ) ^ oaes_gf_mul( word[3], 0x0e ); + memcpy( word, _temp, OAES_COL_LEN ); + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_sprintf( + char * buf, size_t * buf_len, const uint8_t * data, size_t data_len ) +{ + size_t _i, _buf_len_in; + char _temp[4]; + + if( NULL == buf_len ) + return OAES_RET_ARG2; + + _buf_len_in = *buf_len; + *buf_len = data_len * 3 + data_len / OAES_BLOCK_SIZE + 1; + + if( NULL == buf ) + return OAES_RET_SUCCESS; + + if( *buf_len > _buf_len_in ) + return OAES_RET_BUF; + + if( NULL == data ) + return OAES_RET_ARG3; + + strcpy( buf, "" ); + + for( _i = 0; _i < data_len; _i++ ) + { + sprintf( _temp, "%02x ", data[_i] ); + strcat( buf, _temp ); + if( _i && 0 == ( _i + 1 ) % OAES_BLOCK_SIZE ) + strcat( buf, "\n" ); + } + + return OAES_RET_SUCCESS; +} + +#ifdef OAES_HAVE_ISAAC +static void oaes_get_seed( char buf[RANDSIZ + 1] ) +{ + struct timeb timer; + struct tm *gmTimer; + char * _test = NULL; + + ftime (&timer); + gmTimer = gmtime( &timer.time ); + _test = (char *) calloc( sizeof( char ), timer.millitm ); + sprintf( buf, "%04d%02d%02d%02d%02d%02d%03d%p%d", + gmTimer->tm_year + 1900, gmTimer->tm_mon + 1, gmTimer->tm_mday, + gmTimer->tm_hour, gmTimer->tm_min, gmTimer->tm_sec, timer.millitm, + _test + timer.millitm, getpid() ); + + if( _test ) + free( _test ); +} +#else +static uint32_t oaes_get_seed(void) +{ + struct timeb timer; + struct tm *gmTimer; + char * _test = NULL; + uint32_t _ret = 0; + + ftime (&timer); + gmTimer = gmtime( &timer.time ); + _test = (char *) calloc( sizeof( char ), timer.millitm ); + _ret = gmTimer->tm_year + 1900 + gmTimer->tm_mon + 1 + gmTimer->tm_mday + + gmTimer->tm_hour + gmTimer->tm_min + gmTimer->tm_sec + timer.millitm + + (uintptr_t) ( _test + timer.millitm ) + getpid(); + + if( _test ) + free( _test ); + + return _ret; +} +#endif // OAES_HAVE_ISAAC + +static OAES_RET oaes_key_destroy( oaes_key ** key ) +{ + if( NULL == *key ) + return OAES_RET_SUCCESS; + + if( (*key)->data ) + { + free( (*key)->data ); + (*key)->data = NULL; + } + + if( (*key)->exp_data ) + { + free( (*key)->exp_data ); + (*key)->exp_data = NULL; + } + + (*key)->data_len = 0; + (*key)->exp_data_len = 0; + (*key)->num_keys = 0; + (*key)->key_base = 0; + free( *key ); + *key = NULL; + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_key_expand( OAES_CTX * ctx ) +{ + size_t _i, _j; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + // First, all these macros confuse me - so I'll make them simpler + //_ctx->key->key_base = _ctx->key->data_len / OAES_RKEY_LEN; 32 / 4 + _ctx->key->key_base = 8; + //_ctx->key->num_keys = _ctx->key->key_base + OAES_ROUND_BASE; 8 + 7 + _ctx->key->num_keys = 15; + + //_ctx->key->exp_data_len = _ctx->key->num_keys * OAES_RKEY_LEN * OAES_COL_LEN; 15 * 4 * 4 + _ctx->key->exp_data_len = 240; + + _ctx->key->exp_data = (uint8_t *)calloc( _ctx->key->exp_data_len, sizeof( uint8_t )); + + // the first _ctx->key->data_len are a direct copy + memcpy( _ctx->key->exp_data, _ctx->key->data, _ctx->key->data_len ); + + // apply ExpandKey algorithm for remainder + //for( _i = _ctx->key->key_base; _i < _ctx->key->num_keys * OAES_RKEY_LEN; _i++ ) + for(_i = 8; _i < 60; _i++) + { + uint8_t _temp[OAES_COL_LEN]; + + memcpy( _temp, _ctx->key->exp_data + ( _i - 1 ) * OAES_RKEY_LEN, OAES_COL_LEN ); + + // transform key column + if( 0 == _i % 8 ) + { + oaes_word_rot_left( _temp ); + + for( _j = 0; _j < OAES_COL_LEN; _j++ ) + oaes_sub_byte( _temp + _j ); + + _temp[0] = _temp[0] ^ oaes_gf_8[ _i / _ctx->key->key_base - 1 ]; + } + else if( 4 == _i % _ctx->key->key_base ) + { + for( _j = 0; _j < OAES_COL_LEN; _j++ ) + oaes_sub_byte( _temp + _j ); + } + + for( _j = 0; _j < OAES_COL_LEN; _j++ ) + { + _ctx->key->exp_data[ _i * OAES_RKEY_LEN + _j ] = + _ctx->key->exp_data[ ( _i - _ctx->key->key_base ) * + OAES_RKEY_LEN + _j ] ^ _temp[_j]; + } + } + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_key_gen( OAES_CTX * ctx, size_t key_size ) +{ + size_t _i; + oaes_key * _key = NULL; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + OAES_RET _rc = OAES_RET_SUCCESS; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + _key = (oaes_key *) calloc( sizeof( oaes_key ), 1 ); + + if( NULL == _key ) + return OAES_RET_MEM; + + if( _ctx->key ) + oaes_key_destroy( &(_ctx->key) ); + + _key->data_len = key_size; + _key->data = (uint8_t *) calloc( key_size, sizeof( uint8_t )); + + if( NULL == _key->data ) + return OAES_RET_MEM; + + for( _i = 0; _i < key_size; _i++ ) +#ifdef OAES_HAVE_ISAAC + _key->data[_i] = (uint8_t) rand( _ctx->rctx ); +#else + _key->data[_i] = (uint8_t) rand(); +#endif // OAES_HAVE_ISAAC + + _ctx->key = _key; + _rc = _rc || oaes_key_expand( ctx ); + + if( _rc != OAES_RET_SUCCESS ) + { + oaes_key_destroy( &(_ctx->key) ); + return _rc; + } + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_key_gen_128( OAES_CTX * ctx ) +{ + return oaes_key_gen( ctx, 16 ); +} + +OAES_RET oaes_key_gen_192( OAES_CTX * ctx ) +{ + return oaes_key_gen( ctx, 24 ); +} + +OAES_RET oaes_key_gen_256( OAES_CTX * ctx ) +{ + return oaes_key_gen( ctx, 32 ); +} + +OAES_RET oaes_key_export( OAES_CTX * ctx, + uint8_t * data, size_t * data_len ) +{ + size_t _data_len_in; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + + if( NULL == data_len ) + return OAES_RET_ARG3; + + _data_len_in = *data_len; + // data + header + *data_len = _ctx->key->data_len + OAES_BLOCK_SIZE; + + if( NULL == data ) + return OAES_RET_SUCCESS; + + if( _data_len_in < *data_len ) + return OAES_RET_BUF; + + // header + memcpy( data, oaes_header, OAES_BLOCK_SIZE ); + data[5] = 0x01; + data[7] = _ctx->key->data_len; + memcpy( data + OAES_BLOCK_SIZE, _ctx->key->data, _ctx->key->data_len ); + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_key_export_data( OAES_CTX * ctx, + uint8_t * data, size_t * data_len ) +{ + size_t _data_len_in; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + + if( NULL == data_len ) + return OAES_RET_ARG3; + + _data_len_in = *data_len; + *data_len = _ctx->key->data_len; + + if( NULL == data ) + return OAES_RET_SUCCESS; + + if( _data_len_in < *data_len ) + return OAES_RET_BUF; + + memcpy( data, _ctx->key->data, *data_len ); + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_key_import( OAES_CTX * ctx, + const uint8_t * data, size_t data_len ) +{ + oaes_ctx * _ctx = (oaes_ctx *) ctx; + OAES_RET _rc = OAES_RET_SUCCESS; + int _key_length; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == data ) + return OAES_RET_ARG2; + + switch( data_len ) + { + case 16 + OAES_BLOCK_SIZE: + case 24 + OAES_BLOCK_SIZE: + case 32 + OAES_BLOCK_SIZE: + break; + default: + return OAES_RET_ARG3; + } + + // header + if( 0 != memcmp( data, oaes_header, 4 ) ) + return OAES_RET_HEADER; + + // header version + switch( data[4] ) + { + case 0x01: + break; + default: + return OAES_RET_HEADER; + } + + // header type + switch( data[5] ) + { + case 0x01: + break; + default: + return OAES_RET_HEADER; + } + + // options + _key_length = data[7]; + switch( _key_length ) + { + case 16: + case 24: + case 32: + break; + default: + return OAES_RET_HEADER; + } + + if( (int)data_len != _key_length + OAES_BLOCK_SIZE ) + return OAES_RET_ARG3; + + if( _ctx->key ) + oaes_key_destroy( &(_ctx->key) ); + + _ctx->key = (oaes_key *) calloc( sizeof( oaes_key ), 1 ); + + if( NULL == _ctx->key ) + return OAES_RET_MEM; + + _ctx->key->data_len = _key_length; + _ctx->key->data = (uint8_t *) + calloc( _key_length, sizeof( uint8_t )); + + if( NULL == _ctx->key->data ) + { + oaes_key_destroy( &(_ctx->key) ); + return OAES_RET_MEM; + } + + memcpy( _ctx->key->data, data + OAES_BLOCK_SIZE, _key_length ); + _rc = _rc || oaes_key_expand( ctx ); + + if( _rc != OAES_RET_SUCCESS ) + { + oaes_key_destroy( &(_ctx->key) ); + return _rc; + } + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_key_import_data( OAES_CTX * ctx, + const uint8_t * data, size_t data_len ) +{ + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + _ctx->key = (oaes_key *) calloc( sizeof( oaes_key ), 1 ); + + _ctx->key->data_len = data_len; + _ctx->key->data = (uint8_t *)calloc( data_len, sizeof( uint8_t )); + + memcpy( _ctx->key->data, data, data_len ); + oaes_key_expand( ctx ); + + return OAES_RET_SUCCESS; +} + +OAES_CTX * oaes_alloc(void) +{ + oaes_ctx * _ctx = (oaes_ctx *) calloc( sizeof( oaes_ctx ), 1 ); + + if( NULL == _ctx ) + return NULL; + +#ifdef OAES_HAVE_ISAAC + { + ub4 _i = 0; + char _seed[RANDSIZ + 1]; + + _ctx->rctx = (randctx *) calloc( sizeof( randctx ), 1 ); + + if( NULL == _ctx->rctx ) + { + free( _ctx ); + return NULL; + } + + oaes_get_seed( _seed ); + memset( _ctx->rctx->randrsl, 0, RANDSIZ ); + memcpy( _ctx->rctx->randrsl, _seed, RANDSIZ ); + randinit( _ctx->rctx, TRUE); + } +#else + srand( oaes_get_seed() ); +#endif // OAES_HAVE_ISAAC + + _ctx->key = NULL; + oaes_set_option( _ctx, OAES_OPTION_CBC, NULL ); + +#ifdef OAES_DEBUG + _ctx->step_cb = NULL; + oaes_set_option( _ctx, OAES_OPTION_STEP_OFF, NULL ); +#endif // OAES_DEBUG + + return (OAES_CTX *) _ctx; +} + +OAES_RET oaes_free( OAES_CTX ** ctx ) +{ + oaes_ctx ** _ctx = (oaes_ctx **) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == *_ctx ) + return OAES_RET_SUCCESS; + + if( (*_ctx)->key ) + oaes_key_destroy( &((*_ctx)->key) ); + +#ifdef OAES_HAVE_ISAAC + if( (*_ctx)->rctx ) + { + free( (*_ctx)->rctx ); + (*_ctx)->rctx = NULL; + } +#endif // OAES_HAVE_ISAAC + + free( *_ctx ); + *_ctx = NULL; + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_set_option( OAES_CTX * ctx, + OAES_OPTION option, const void * value ) +{ + size_t _i; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + switch( option ) + { + case OAES_OPTION_ECB: + _ctx->options &= ~OAES_OPTION_CBC; + memset( _ctx->iv, 0, OAES_BLOCK_SIZE ); + break; + + case OAES_OPTION_CBC: + _ctx->options &= ~OAES_OPTION_ECB; + if( value ) + memcpy( _ctx->iv, value, OAES_BLOCK_SIZE ); + else + { + for( _i = 0; _i < OAES_BLOCK_SIZE; _i++ ) +#ifdef OAES_HAVE_ISAAC + _ctx->iv[_i] = (uint8_t) rand( _ctx->rctx ); +#else + _ctx->iv[_i] = (uint8_t) rand(); +#endif // OAES_HAVE_ISAAC + } + break; + +#ifdef OAES_DEBUG + + case OAES_OPTION_STEP_ON: + if( value ) + { + _ctx->options &= ~OAES_OPTION_STEP_OFF; + _ctx->step_cb = value; + } + else + { + _ctx->options &= ~OAES_OPTION_STEP_ON; + _ctx->options |= OAES_OPTION_STEP_OFF; + _ctx->step_cb = NULL; + return OAES_RET_ARG3; + } + break; + + case OAES_OPTION_STEP_OFF: + _ctx->options &= ~OAES_OPTION_STEP_ON; + _ctx->step_cb = NULL; + break; + +#endif // OAES_DEBUG + + default: + return OAES_RET_ARG2; + } + + _ctx->options |= option; + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_encrypt_block( + OAES_CTX * ctx, uint8_t * c, size_t c_len ) +{ + size_t _i, _j; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == c ) + return OAES_RET_ARG2; + + if( c_len != OAES_BLOCK_SIZE ) + return OAES_RET_ARG3; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "input", 1, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(State, K0) + for( _i = 0; _i < c_len; _i++ ) + c[_i] = c[_i] ^ _ctx->key->exp_data[_i]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data, "k_sch", 1, NULL ); + _ctx->step_cb( c, "k_add", 1, NULL ); + } +#endif // OAES_DEBUG + + // for round = 1 step 1 to Nr–1 + for( _i = 1; _i < _ctx->key->num_keys - 1; _i++ ) + { + // SubBytes(state) + for( _j = 0; _j < c_len; _j++ ) + oaes_sub_byte( c + _j ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "s_box", _i, NULL ); +#endif // OAES_DEBUG + + // ShiftRows(state) + oaes_shift_rows( c ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "s_row", _i, NULL ); +#endif // OAES_DEBUG + + // MixColumns(state) + oaes_mix_cols( c ); + oaes_mix_cols( c + 4 ); + oaes_mix_cols( c + 8 ); + oaes_mix_cols( c + 12 ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "m_col", _i, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(state, w[round*Nb, (round+1)*Nb-1]) + for( _j = 0; _j < c_len; _j++ ) + c[_j] = c[_j] ^ + _ctx->key->exp_data[_i * OAES_RKEY_LEN * OAES_COL_LEN + _j]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data + _i * OAES_RKEY_LEN * OAES_COL_LEN, + "k_sch", _i, NULL ); + _ctx->step_cb( c, "k_add", _i, NULL ); + } +#endif // OAES_DEBUG + + } + + // SubBytes(state) + for( _i = 0; _i < c_len; _i++ ) + oaes_sub_byte( c + _i ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "s_box", _ctx->key->num_keys - 1, NULL ); +#endif // OAES_DEBUG + + // ShiftRows(state) + oaes_shift_rows( c ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "s_row", _ctx->key->num_keys - 1, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) + for( _i = 0; _i < c_len; _i++ ) + c[_i] = c[_i] ^ _ctx->key->exp_data[ + ( _ctx->key->num_keys - 1 ) * OAES_RKEY_LEN * OAES_COL_LEN + _i ]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data + + ( _ctx->key->num_keys - 1 ) * OAES_RKEY_LEN * OAES_COL_LEN, + "k_sch", _ctx->key->num_keys - 1, NULL ); + _ctx->step_cb( c, "output", _ctx->key->num_keys - 1, NULL ); + } +#endif // OAES_DEBUG + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_decrypt_block( + OAES_CTX * ctx, uint8_t * c, size_t c_len ) +{ + size_t _i, _j; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == c ) + return OAES_RET_ARG2; + + if( c_len != OAES_BLOCK_SIZE ) + return OAES_RET_ARG3; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "iinput", _ctx->key->num_keys - 1, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) + for( _i = 0; _i < c_len; _i++ ) + c[_i] = c[_i] ^ _ctx->key->exp_data[ + ( _ctx->key->num_keys - 1 ) * OAES_RKEY_LEN * OAES_COL_LEN + _i ]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data + + ( _ctx->key->num_keys - 1 ) * OAES_RKEY_LEN * OAES_COL_LEN, + "ik_sch", _ctx->key->num_keys - 1, NULL ); + _ctx->step_cb( c, "ik_add", _ctx->key->num_keys - 1, NULL ); + } +#endif // OAES_DEBUG + + for( _i = _ctx->key->num_keys - 2; _i > 0; _i-- ) + { + // InvShiftRows(state) + oaes_inv_shift_rows( c ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "is_row", _i, NULL ); +#endif // OAES_DEBUG + + // InvSubBytes(state) + for( _j = 0; _j < c_len; _j++ ) + oaes_inv_sub_byte( c + _j ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "is_box", _i, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(state, w[round*Nb, (round+1)*Nb-1]) + for( _j = 0; _j < c_len; _j++ ) + c[_j] = c[_j] ^ + _ctx->key->exp_data[_i * OAES_RKEY_LEN * OAES_COL_LEN + _j]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data + _i * OAES_RKEY_LEN * OAES_COL_LEN, + "ik_sch", _i, NULL ); + _ctx->step_cb( c, "ik_add", _i, NULL ); + } +#endif // OAES_DEBUG + + // InvMixColums(state) + oaes_inv_mix_cols( c ); + oaes_inv_mix_cols( c + 4 ); + oaes_inv_mix_cols( c + 8 ); + oaes_inv_mix_cols( c + 12 ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "im_col", _i, NULL ); +#endif // OAES_DEBUG + + } + + // InvShiftRows(state) + oaes_inv_shift_rows( c ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "is_row", 1, NULL ); +#endif // OAES_DEBUG + + // InvSubBytes(state) + for( _i = 0; _i < c_len; _i++ ) + oaes_inv_sub_byte( c + _i ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "is_box", 1, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(state, w[0, Nb-1]) + for( _i = 0; _i < c_len; _i++ ) + c[_i] = c[_i] ^ _ctx->key->exp_data[_i]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data, "ik_sch", 1, NULL ); + _ctx->step_cb( c, "ioutput", 1, NULL ); + } +#endif // OAES_DEBUG + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_encrypt( OAES_CTX * ctx, + const uint8_t * m, size_t m_len, uint8_t * c, size_t * c_len ) +{ + size_t _i, _j, _c_len_in, _c_data_len; + size_t _pad_len = m_len % OAES_BLOCK_SIZE == 0 ? + 0 : OAES_BLOCK_SIZE - m_len % OAES_BLOCK_SIZE; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + OAES_RET _rc = OAES_RET_SUCCESS; + uint8_t _flags = _pad_len ? OAES_FLAG_PAD : 0; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == m ) + return OAES_RET_ARG2; + + if( NULL == c_len ) + return OAES_RET_ARG5; + + _c_len_in = *c_len; + // data + pad + _c_data_len = m_len + _pad_len; + // header + iv + data + pad + *c_len = 2 * OAES_BLOCK_SIZE + m_len + _pad_len; + + if( NULL == c ) + return OAES_RET_SUCCESS; + + if( _c_len_in < *c_len ) + return OAES_RET_BUF; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + + // header + memcpy(c, oaes_header, OAES_BLOCK_SIZE ); + memcpy(c + 6, &_ctx->options, sizeof(_ctx->options)); + memcpy(c + 8, &_flags, sizeof(_flags)); + // iv + memcpy(c + OAES_BLOCK_SIZE, _ctx->iv, OAES_BLOCK_SIZE ); + // data + memcpy(c + 2 * OAES_BLOCK_SIZE, m, m_len ); + + for( _i = 0; _i < _c_data_len; _i += OAES_BLOCK_SIZE ) + { + uint8_t _block[OAES_BLOCK_SIZE]; + size_t _block_size = min( m_len - _i, OAES_BLOCK_SIZE ); + + memcpy( _block, c + 2 * OAES_BLOCK_SIZE + _i, _block_size ); + + // insert pad + for( _j = 0; _j < OAES_BLOCK_SIZE - _block_size; _j++ ) + _block[ _block_size + _j ] = _j + 1; + + // CBC + if( _ctx->options & OAES_OPTION_CBC ) + { + for( _j = 0; _j < OAES_BLOCK_SIZE; _j++ ) + _block[_j] = _block[_j] ^ _ctx->iv[_j]; + } + + _rc = _rc || + oaes_encrypt_block( ctx, _block, OAES_BLOCK_SIZE ); + memcpy( c + 2 * OAES_BLOCK_SIZE + _i, _block, OAES_BLOCK_SIZE ); + + if( _ctx->options & OAES_OPTION_CBC ) + memcpy( _ctx->iv, _block, OAES_BLOCK_SIZE ); + } + + return _rc; +} + +OAES_RET oaes_decrypt( OAES_CTX * ctx, + const uint8_t * c, size_t c_len, uint8_t * m, size_t * m_len ) +{ + size_t _i, _j, _m_len_in; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + OAES_RET _rc = OAES_RET_SUCCESS; + uint8_t _iv[OAES_BLOCK_SIZE]; + uint8_t _flags; + OAES_OPTION _options; + + if( NULL == ctx ) + return OAES_RET_ARG1; + + if( NULL == c ) + return OAES_RET_ARG2; + + if( c_len % OAES_BLOCK_SIZE ) + return OAES_RET_ARG3; + + if( NULL == m_len ) + return OAES_RET_ARG5; + + _m_len_in = *m_len; + *m_len = c_len - 2 * OAES_BLOCK_SIZE; + + if( NULL == m ) + return OAES_RET_SUCCESS; + + if( _m_len_in < *m_len ) + return OAES_RET_BUF; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + + // header + if( 0 != memcmp( c, oaes_header, 4 ) ) + return OAES_RET_HEADER; + + // header version + switch( c[4] ) + { + case 0x01: + break; + default: + return OAES_RET_HEADER; + } + + // header type + switch( c[5] ) + { + case 0x02: + break; + default: + return OAES_RET_HEADER; + } + + // options + memcpy(&_options, c + 6, sizeof(_options)); + // validate that all options are valid + if( _options & ~( + OAES_OPTION_ECB + | OAES_OPTION_CBC +#ifdef OAES_DEBUG + | OAES_OPTION_STEP_ON + | OAES_OPTION_STEP_OFF +#endif // OAES_DEBUG + ) ) + return OAES_RET_HEADER; + if( ( _options & OAES_OPTION_ECB ) && + ( _options & OAES_OPTION_CBC ) ) + return OAES_RET_HEADER; + if( _options == OAES_OPTION_NONE ) + return OAES_RET_HEADER; + + // flags + memcpy(&_flags, c + 8, sizeof(_flags)); + // validate that all flags are valid + if( _flags & ~( + OAES_FLAG_PAD + ) ) + return OAES_RET_HEADER; + + // iv + memcpy( _iv, c + OAES_BLOCK_SIZE, OAES_BLOCK_SIZE); + // data + pad + memcpy( m, c + 2 * OAES_BLOCK_SIZE, *m_len ); + + for( _i = 0; _i < *m_len; _i += OAES_BLOCK_SIZE ) + { + if( ( _options & OAES_OPTION_CBC ) && _i > 0 ) + memcpy( _iv, c + OAES_BLOCK_SIZE + _i, OAES_BLOCK_SIZE ); + + _rc = _rc || + oaes_decrypt_block( ctx, m + _i, min( *m_len - _i, OAES_BLOCK_SIZE ) ); + + // CBC + if( _options & OAES_OPTION_CBC ) + { + for( _j = 0; _j < OAES_BLOCK_SIZE; _j++ ) + m[ _i + _j ] = m[ _i + _j ] ^ _iv[_j]; + } + } + + // remove pad + if( _flags & OAES_FLAG_PAD ) + { + int _is_pad = 1; + size_t _temp = (size_t) m[*m_len - 1]; + + if( _temp <= 0x00 || _temp > 0x0f ) + return OAES_RET_HEADER; + for( _i = 0; _i < _temp; _i++ ) + if( m[*m_len - 1 - _i] != _temp - _i ) + _is_pad = 0; + if( _is_pad ) + { + memset( m + *m_len - _temp, 0, _temp ); + *m_len -= _temp; + } + else + return OAES_RET_HEADER; + } + + return OAES_RET_SUCCESS; +} + + +OAES_API OAES_RET oaes_encryption_round( const uint8_t * key, uint8_t * c ) +{ + size_t _i; + + if(NULL == key) + return OAES_RET_ARG1; + + if(NULL == c) + return OAES_RET_ARG2; + + // SubBytes(state) + for( _i = 0; _i < OAES_BLOCK_SIZE; _i++ ) + oaes_sub_byte( c + _i ); + + // ShiftRows(state) + oaes_shift_rows( c ); + + // MixColumns(state) + oaes_mix_cols( c ); + oaes_mix_cols( c + 4 ); + oaes_mix_cols( c + 8 ); + oaes_mix_cols( c + 12 ); + + // AddRoundKey(State, key) + for( _i = 0; _i < OAES_BLOCK_SIZE; _i++ ) + c[_i] ^= key[_i]; + + return OAES_RET_SUCCESS; +} + +OAES_API OAES_RET oaes_pseudo_encrypt_ecb( OAES_CTX * ctx, uint8_t * c ) +{ + size_t _i; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if(NULL == _ctx) + return OAES_RET_ARG1; + + if(NULL == c) + return OAES_RET_ARG2; + + if(NULL == _ctx->key) + return OAES_RET_NOKEY; + + for ( _i = 0; _i < 10; ++_i ) + { + oaes_encryption_round( &_ctx->key->exp_data[_i * OAES_RKEY_LEN * OAES_COL_LEN], c ); + } + + return OAES_RET_SUCCESS; +} diff --git a/webassembly/aeon/oaes_lib.h b/webassembly/aeon/oaes_lib.h new file mode 100644 index 0000000..a22bbf4 --- /dev/null +++ b/webassembly/aeon/oaes_lib.h @@ -0,0 +1,214 @@ +/* + * --------------------------------------------------------------------------- + * OpenAES License + * --------------------------------------------------------------------------- + * Copyright (c) 2012, Nabil S. Al Ramli, www.nalramli.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * --------------------------------------------------------------------------- + */ + +#ifndef _OAES_LIB_H +#define _OAES_LIB_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +# ifdef OAES_SHARED +# ifdef oaes_lib_EXPORTS +# define OAES_API __declspec(dllexport) +# else +# define OAES_API __declspec(dllimport) +# endif +# else +# define OAES_API +# endif +#else +# define OAES_API +#endif // WIN32 + +#define OAES_VERSION "0.8.1" +#define OAES_BLOCK_SIZE 16 + +typedef void OAES_CTX; + +typedef enum +{ + OAES_RET_FIRST = 0, + OAES_RET_SUCCESS = 0, + OAES_RET_UNKNOWN, + OAES_RET_ARG1, + OAES_RET_ARG2, + OAES_RET_ARG3, + OAES_RET_ARG4, + OAES_RET_ARG5, + OAES_RET_NOKEY, + OAES_RET_MEM, + OAES_RET_BUF, + OAES_RET_HEADER, + OAES_RET_COUNT +} OAES_RET; + +/* + * oaes_set_option() takes one of these values for its [option] parameter + * some options accept either an optional or a required [value] parameter + */ +// no option +#define OAES_OPTION_NONE 0 +// enable ECB mode, disable CBC mode +#define OAES_OPTION_ECB 1 +// enable CBC mode, disable ECB mode +// value is optional, may pass uint8_t iv[OAES_BLOCK_SIZE] to specify +// the value of the initialization vector, iv +#define OAES_OPTION_CBC 2 + +#ifdef OAES_DEBUG +typedef int ( * oaes_step_cb ) ( + const uint8_t state[OAES_BLOCK_SIZE], + const char * step_name, + int step_count, + void * user_data ); +// enable state stepping mode +// value is required, must pass oaes_step_cb to receive the state at each step +#define OAES_OPTION_STEP_ON 4 +// disable state stepping mode +#define OAES_OPTION_STEP_OFF 8 +#endif // OAES_DEBUG + +typedef uint16_t OAES_OPTION; + +typedef struct _oaes_key +{ + size_t data_len; + uint8_t *data; + size_t exp_data_len; + uint8_t *exp_data; + size_t num_keys; + size_t key_base; +} oaes_key; + +typedef struct _oaes_ctx +{ +#ifdef OAES_HAVE_ISAAC + randctx * rctx; +#endif // OAES_HAVE_ISAAC + +#ifdef OAES_DEBUG + oaes_step_cb step_cb; +#endif // OAES_DEBUG + + oaes_key * key; + OAES_OPTION options; + uint8_t iv[OAES_BLOCK_SIZE]; +} oaes_ctx; +/* + * // usage: + * + * OAES_CTX * ctx = oaes_alloc(); + * . + * . + * . + * { + * oaes_gen_key_xxx( ctx ); + * { + * oaes_key_export( ctx, _buf, &_buf_len ); + * // or + * oaes_key_export_data( ctx, _buf, &_buf_len );\ + * } + * } + * // or + * { + * oaes_key_import( ctx, _buf, _buf_len ); + * // or + * oaes_key_import_data( ctx, _buf, _buf_len ); + * } + * . + * . + * . + * oaes_encrypt( ctx, m, m_len, c, &c_len ); + * . + * . + * . + * oaes_decrypt( ctx, c, c_len, m, &m_len ); + * . + * . + * . + * oaes_free( &ctx ); + */ + +OAES_API OAES_CTX * oaes_alloc(void); + +OAES_API OAES_RET oaes_free( OAES_CTX ** ctx ); + +OAES_API OAES_RET oaes_set_option( OAES_CTX * ctx, + OAES_OPTION option, const void * value ); + +OAES_API OAES_RET oaes_key_gen_128( OAES_CTX * ctx ); + +OAES_API OAES_RET oaes_key_gen_192( OAES_CTX * ctx ); + +OAES_API OAES_RET oaes_key_gen_256( OAES_CTX * ctx ); + +// export key with header information +// set data == NULL to get the required data_len +OAES_API OAES_RET oaes_key_export( OAES_CTX * ctx, + uint8_t * data, size_t * data_len ); + +// directly export the data from key +// set data == NULL to get the required data_len +OAES_API OAES_RET oaes_key_export_data( OAES_CTX * ctx, + uint8_t * data, size_t * data_len ); + +// import key with header information +OAES_API OAES_RET oaes_key_import( OAES_CTX * ctx, + const uint8_t * data, size_t data_len ); + +// directly import data into key +OAES_API OAES_RET oaes_key_import_data( OAES_CTX * ctx, + const uint8_t * data, size_t data_len ); + +// set c == NULL to get the required c_len +OAES_API OAES_RET oaes_encrypt( OAES_CTX * ctx, + const uint8_t * m, size_t m_len, uint8_t * c, size_t * c_len ); + +// set m == NULL to get the required m_len +OAES_API OAES_RET oaes_decrypt( OAES_CTX * ctx, + const uint8_t * c, size_t c_len, uint8_t * m, size_t * m_len ); + +// set buf == NULL to get the required buf_len +OAES_API OAES_RET oaes_sprintf( + char * buf, size_t * buf_len, const uint8_t * data, size_t data_len ); + +OAES_API OAES_RET oaes_encryption_round( const uint8_t * key, uint8_t * c ); + +OAES_API OAES_RET oaes_pseudo_encrypt_ecb( OAES_CTX * ctx, uint8_t * c ); + +#ifdef __cplusplus +} +#endif + +#endif // _OAES_LIB_H diff --git a/webassembly/aeon/skein.c b/webassembly/aeon/skein.c new file mode 100644 index 0000000..4368d15 --- /dev/null +++ b/webassembly/aeon/skein.c @@ -0,0 +1,2047 @@ +/*********************************************************************** +** +** Implementation of the Skein hash function. +** +** Source code author: Doug Whiting, 2008. +** +** This algorithm and source code is released to the public domain. +** +************************************************************************/ + +#define SKEIN_PORT_CODE /* instantiate any code in skein_port.h */ + +#include /* get size_t definition */ +#include /* get the memcpy/memset functions */ +#include "skein_port.h" + +typedef enum +{ + SKEIN_SUCCESS = 0, /* return codes from Skein calls */ + SKEIN_FAIL = 1, + SKEIN_BAD_HASHLEN = 2 +} +SkeinHashReturn; + +typedef size_t SkeinDataLength; /* bit count type */ +typedef u08b_t SkeinBitSequence; /* bit stream type */ + +#define DISABLE_UNUSED 0 + +#ifndef SKEIN_256_NIST_MAX_HASHBITS +#define SKEIN_256_NIST_MAX_HASHBITS (0) +#endif + +#ifndef SKEIN_512_NIST_MAX_HASHBITS +#define SKEIN_512_NIST_MAX_HASHBITS (512) +#endif + +#define SKEIN_MODIFIER_WORDS ( 2) /* number of modifier (tweak) words */ + +#define SKEIN_256_STATE_WORDS ( 4) +#define SKEIN_512_STATE_WORDS ( 8) +#define SKEIN1024_STATE_WORDS (16) +#define SKEIN_MAX_STATE_WORDS (16) + +#define SKEIN_256_STATE_BYTES ( 8*SKEIN_256_STATE_WORDS) +#define SKEIN_512_STATE_BYTES ( 8*SKEIN_512_STATE_WORDS) +#define SKEIN1024_STATE_BYTES ( 8*SKEIN1024_STATE_WORDS) + +#define SKEIN_256_STATE_BITS (64*SKEIN_256_STATE_WORDS) +#define SKEIN_512_STATE_BITS (64*SKEIN_512_STATE_WORDS) +#define SKEIN1024_STATE_BITS (64*SKEIN1024_STATE_WORDS) + +#define SKEIN_256_BLOCK_BYTES ( 8*SKEIN_256_STATE_WORDS) +#define SKEIN_512_BLOCK_BYTES ( 8*SKEIN_512_STATE_WORDS) +#define SKEIN1024_BLOCK_BYTES ( 8*SKEIN1024_STATE_WORDS) + +#define SKEIN_RND_SPECIAL (1000u) +#define SKEIN_RND_KEY_INITIAL (SKEIN_RND_SPECIAL+0u) +#define SKEIN_RND_KEY_INJECT (SKEIN_RND_SPECIAL+1u) +#define SKEIN_RND_FEED_FWD (SKEIN_RND_SPECIAL+2u) + +typedef struct +{ + size_t hashBitLen; /* size of hash result, in bits */ + size_t bCnt; /* current byte count in buffer b[] */ + u64b_t T[SKEIN_MODIFIER_WORDS]; /* tweak words: T[0]=byte cnt, T[1]=flags */ +} Skein_Ctxt_Hdr_t; + +typedef struct /* 256-bit Skein hash context structure */ +{ + Skein_Ctxt_Hdr_t h; /* common header context variables */ + u64b_t X[SKEIN_256_STATE_WORDS]; /* chaining variables */ + u08b_t b[SKEIN_256_BLOCK_BYTES]; /* partial block buffer (8-byte aligned) */ +} Skein_256_Ctxt_t; + +typedef struct /* 512-bit Skein hash context structure */ +{ + Skein_Ctxt_Hdr_t h; /* common header context variables */ + u64b_t X[SKEIN_512_STATE_WORDS]; /* chaining variables */ + u08b_t b[SKEIN_512_BLOCK_BYTES]; /* partial block buffer (8-byte aligned) */ +} Skein_512_Ctxt_t; + +typedef struct /* 1024-bit Skein hash context structure */ +{ + Skein_Ctxt_Hdr_t h; /* common header context variables */ + u64b_t X[SKEIN1024_STATE_WORDS]; /* chaining variables */ + u08b_t b[SKEIN1024_BLOCK_BYTES]; /* partial block buffer (8-byte aligned) */ +} Skein1024_Ctxt_t; + +/* Skein APIs for (incremental) "straight hashing" */ +#if SKEIN_256_NIST_MAX_HASH_BITS +static int Skein_256_Init (Skein_256_Ctxt_t *ctx, size_t hashBitLen); +#endif +static int Skein_512_Init (Skein_512_Ctxt_t *ctx, size_t hashBitLen); +static int Skein1024_Init (Skein1024_Ctxt_t *ctx, size_t hashBitLen); + +static int Skein_256_Update(Skein_256_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt); +static int Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt); +static int Skein1024_Update(Skein1024_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt); + +static int Skein_256_Final (Skein_256_Ctxt_t *ctx, u08b_t * hashVal); +static int Skein_512_Final (Skein_512_Ctxt_t *ctx, u08b_t * hashVal); +static int Skein1024_Final (Skein1024_Ctxt_t *ctx, u08b_t * hashVal); + +/* +** Skein APIs for "extended" initialization: MAC keys, tree hashing. +** After an InitExt() call, just use Update/Final calls as with Init(). +** +** Notes: Same parameters as _Init() calls, plus treeInfo/key/keyBytes. +** When keyBytes == 0 and treeInfo == SKEIN_SEQUENTIAL, +** the results of InitExt() are identical to calling Init(). +** The function Init() may be called once to "precompute" the IV for +** a given hashBitLen value, then by saving a copy of the context +** the IV computation may be avoided in later calls. +** Similarly, the function InitExt() may be called once per MAC key +** to precompute the MAC IV, then a copy of the context saved and +** reused for each new MAC computation. +**/ +#if 0 +static int Skein_256_InitExt(Skein_256_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes); +static int Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes); +static int Skein1024_InitExt(Skein1024_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes); +#endif + +/* +** Skein APIs for MAC and tree hash: +** Final_Pad: pad, do final block, but no OUTPUT type +** Output: do just the output stage +*/ +#if 0 +static int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, u08b_t * hashVal); +static int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t * hashVal); +static int Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, u08b_t * hashVal); +#endif + +#ifndef SKEIN_TREE_HASH +#define SKEIN_TREE_HASH (1) +#endif +#if 0 +#if SKEIN_TREE_HASH +static int Skein_256_Output (Skein_256_Ctxt_t *ctx, u08b_t * hashVal); +static int Skein_512_Output (Skein_512_Ctxt_t *ctx, u08b_t * hashVal); +static int Skein1024_Output (Skein1024_Ctxt_t *ctx, u08b_t * hashVal); +#endif +#endif + +/***************************************************************** +** "Internal" Skein definitions +** -- not needed for sequential hashing API, but will be +** helpful for other uses of Skein (e.g., tree hash mode). +** -- included here so that they can be shared between +** reference and optimized code. +******************************************************************/ + +/* tweak word T[1]: bit field starting positions */ +#define SKEIN_T1_BIT(BIT) ((BIT) - 64) /* offset 64 because it's the second word */ + +#define SKEIN_T1_POS_TREE_LVL SKEIN_T1_BIT(112) /* bits 112..118: level in hash tree */ +#define SKEIN_T1_POS_BIT_PAD SKEIN_T1_BIT(119) /* bit 119 : partial final input byte */ +#define SKEIN_T1_POS_BLK_TYPE SKEIN_T1_BIT(120) /* bits 120..125: type field */ +#define SKEIN_T1_POS_FIRST SKEIN_T1_BIT(126) /* bits 126 : first block flag */ +#define SKEIN_T1_POS_FINAL SKEIN_T1_BIT(127) /* bit 127 : final block flag */ + +/* tweak word T[1]: flag bit definition(s) */ +#define SKEIN_T1_FLAG_FIRST (((u64b_t) 1 ) << SKEIN_T1_POS_FIRST) +#define SKEIN_T1_FLAG_FINAL (((u64b_t) 1 ) << SKEIN_T1_POS_FINAL) +#define SKEIN_T1_FLAG_BIT_PAD (((u64b_t) 1 ) << SKEIN_T1_POS_BIT_PAD) + +/* tweak word T[1]: tree level bit field mask */ +#define SKEIN_T1_TREE_LVL_MASK (((u64b_t)0x7F) << SKEIN_T1_POS_TREE_LVL) +#define SKEIN_T1_TREE_LEVEL(n) (((u64b_t) (n)) << SKEIN_T1_POS_TREE_LVL) + +/* tweak word T[1]: block type field */ +#define SKEIN_BLK_TYPE_KEY ( 0) /* key, for MAC and KDF */ +#define SKEIN_BLK_TYPE_CFG ( 4) /* configuration block */ +#define SKEIN_BLK_TYPE_PERS ( 8) /* personalization string */ +#define SKEIN_BLK_TYPE_PK (12) /* public key (for digital signature hashing) */ +#define SKEIN_BLK_TYPE_KDF (16) /* key identifier for KDF */ +#define SKEIN_BLK_TYPE_NONCE (20) /* nonce for PRNG */ +#define SKEIN_BLK_TYPE_MSG (48) /* message processing */ +#define SKEIN_BLK_TYPE_OUT (63) /* output stage */ +#define SKEIN_BLK_TYPE_MASK (63) /* bit field mask */ + +#define SKEIN_T1_BLK_TYPE(T) (((u64b_t) (SKEIN_BLK_TYPE_##T)) << SKEIN_T1_POS_BLK_TYPE) +#define SKEIN_T1_BLK_TYPE_KEY SKEIN_T1_BLK_TYPE(KEY) /* key, for MAC and KDF */ +#define SKEIN_T1_BLK_TYPE_CFG SKEIN_T1_BLK_TYPE(CFG) /* configuration block */ +#define SKEIN_T1_BLK_TYPE_PERS SKEIN_T1_BLK_TYPE(PERS) /* personalization string */ +#define SKEIN_T1_BLK_TYPE_PK SKEIN_T1_BLK_TYPE(PK) /* public key (for digital signature hashing) */ +#define SKEIN_T1_BLK_TYPE_KDF SKEIN_T1_BLK_TYPE(KDF) /* key identifier for KDF */ +#define SKEIN_T1_BLK_TYPE_NONCE SKEIN_T1_BLK_TYPE(NONCE)/* nonce for PRNG */ +#define SKEIN_T1_BLK_TYPE_MSG SKEIN_T1_BLK_TYPE(MSG) /* message processing */ +#define SKEIN_T1_BLK_TYPE_OUT SKEIN_T1_BLK_TYPE(OUT) /* output stage */ +#define SKEIN_T1_BLK_TYPE_MASK SKEIN_T1_BLK_TYPE(MASK) /* field bit mask */ + +#define SKEIN_T1_BLK_TYPE_CFG_FINAL (SKEIN_T1_BLK_TYPE_CFG | SKEIN_T1_FLAG_FINAL) +#define SKEIN_T1_BLK_TYPE_OUT_FINAL (SKEIN_T1_BLK_TYPE_OUT | SKEIN_T1_FLAG_FINAL) + +#define SKEIN_VERSION (1) + +#ifndef SKEIN_ID_STRING_LE /* allow compile-time personalization */ +#define SKEIN_ID_STRING_LE (0x33414853) /* "SHA3" (little-endian)*/ +#endif + +#define SKEIN_MK_64(hi32,lo32) ((lo32) + (((u64b_t) (hi32)) << 32)) +#define SKEIN_SCHEMA_VER SKEIN_MK_64(SKEIN_VERSION,SKEIN_ID_STRING_LE) +#define SKEIN_KS_PARITY SKEIN_MK_64(0x1BD11BDA,0xA9FC1A22) + +#define SKEIN_CFG_STR_LEN (4*8) + +/* bit field definitions in config block treeInfo word */ +#define SKEIN_CFG_TREE_LEAF_SIZE_POS ( 0) +#define SKEIN_CFG_TREE_NODE_SIZE_POS ( 8) +#define SKEIN_CFG_TREE_MAX_LEVEL_POS (16) + +#define SKEIN_CFG_TREE_LEAF_SIZE_MSK (((u64b_t) 0xFF) << SKEIN_CFG_TREE_LEAF_SIZE_POS) +#define SKEIN_CFG_TREE_NODE_SIZE_MSK (((u64b_t) 0xFF) << SKEIN_CFG_TREE_NODE_SIZE_POS) +#define SKEIN_CFG_TREE_MAX_LEVEL_MSK (((u64b_t) 0xFF) << SKEIN_CFG_TREE_MAX_LEVEL_POS) + +#define SKEIN_CFG_TREE_INFO(leaf,node,maxLvl) \ + ( (((u64b_t)(leaf )) << SKEIN_CFG_TREE_LEAF_SIZE_POS) | \ + (((u64b_t)(node )) << SKEIN_CFG_TREE_NODE_SIZE_POS) | \ + (((u64b_t)(maxLvl)) << SKEIN_CFG_TREE_MAX_LEVEL_POS) ) + +#define SKEIN_CFG_TREE_INFO_SEQUENTIAL SKEIN_CFG_TREE_INFO(0,0,0) /* use as treeInfo in InitExt() call for sequential processing */ + +/* +** Skein macros for getting/setting tweak words, etc. +** These are useful for partial input bytes, hash tree init/update, etc. +**/ +#define Skein_Get_Tweak(ctxPtr,TWK_NUM) ((ctxPtr)->h.T[TWK_NUM]) +#define Skein_Set_Tweak(ctxPtr,TWK_NUM,tVal) {(ctxPtr)->h.T[TWK_NUM] = (tVal);} + +#define Skein_Get_T0(ctxPtr) Skein_Get_Tweak(ctxPtr,0) +#define Skein_Get_T1(ctxPtr) Skein_Get_Tweak(ctxPtr,1) +#define Skein_Set_T0(ctxPtr,T0) Skein_Set_Tweak(ctxPtr,0,T0) +#define Skein_Set_T1(ctxPtr,T1) Skein_Set_Tweak(ctxPtr,1,T1) + +/* set both tweak words at once */ +#define Skein_Set_T0_T1(ctxPtr,T0,T1) \ +{ \ + Skein_Set_T0(ctxPtr,(T0)); \ + Skein_Set_T1(ctxPtr,(T1)); \ +} + +#define Skein_Set_Type(ctxPtr,BLK_TYPE) \ + Skein_Set_T1(ctxPtr,SKEIN_T1_BLK_TYPE_##BLK_TYPE) + +/* set up for starting with a new type: h.T[0]=0; h.T[1] = NEW_TYPE; h.bCnt=0; */ +#define Skein_Start_New_Type(ctxPtr,BLK_TYPE) \ +{ Skein_Set_T0_T1(ctxPtr,0,SKEIN_T1_FLAG_FIRST | SKEIN_T1_BLK_TYPE_##BLK_TYPE); (ctxPtr)->h.bCnt=0; } + +#define Skein_Clear_First_Flag(hdr) { (hdr).T[1] &= ~SKEIN_T1_FLAG_FIRST; } +#define Skein_Set_Bit_Pad_Flag(hdr) { (hdr).T[1] |= SKEIN_T1_FLAG_BIT_PAD; } + +#define Skein_Set_Tree_Level(hdr,height) { (hdr).T[1] |= SKEIN_T1_TREE_LEVEL(height);} + +/***************************************************************** +** "Internal" Skein definitions for debugging and error checking +******************************************************************/ +#define Skein_Show_Block(bits,ctx,X,blkPtr,wPtr,ksEvenPtr,ksOddPtr) +#define Skein_Show_Round(bits,ctx,r,X) +#define Skein_Show_R_Ptr(bits,ctx,r,X_ptr) +#define Skein_Show_Final(bits,ctx,cnt,outPtr) +#define Skein_Show_Key(bits,ctx,key,keyBytes) + + +#ifndef SKEIN_ERR_CHECK /* run-time checks (e.g., bad params, uninitialized context)? */ +#define Skein_Assert(x,retCode)/* default: ignore all Asserts, for performance */ +#define Skein_assert(x) +#elif defined(SKEIN_ASSERT) +#include +#define Skein_Assert(x,retCode) assert(x) +#define Skein_assert(x) assert(x) +#else +#include +#define Skein_Assert(x,retCode) { if (!(x)) return retCode; } /* caller error */ +#define Skein_assert(x) assert(x) /* internal error */ +#endif + +/***************************************************************** +** Skein block function constants (shared across Ref and Opt code) +******************************************************************/ +enum +{ + /* Skein_256 round rotation constants */ + R_256_0_0=14, R_256_0_1=16, + R_256_1_0=52, R_256_1_1=57, + R_256_2_0=23, R_256_2_1=40, + R_256_3_0= 5, R_256_3_1=37, + R_256_4_0=25, R_256_4_1=33, + R_256_5_0=46, R_256_5_1=12, + R_256_6_0=58, R_256_6_1=22, + R_256_7_0=32, R_256_7_1=32, + + /* Skein_512 round rotation constants */ + R_512_0_0=46, R_512_0_1=36, R_512_0_2=19, R_512_0_3=37, + R_512_1_0=33, R_512_1_1=27, R_512_1_2=14, R_512_1_3=42, + R_512_2_0=17, R_512_2_1=49, R_512_2_2=36, R_512_2_3=39, + R_512_3_0=44, R_512_3_1= 9, R_512_3_2=54, R_512_3_3=56, + R_512_4_0=39, R_512_4_1=30, R_512_4_2=34, R_512_4_3=24, + R_512_5_0=13, R_512_5_1=50, R_512_5_2=10, R_512_5_3=17, + R_512_6_0=25, R_512_6_1=29, R_512_6_2=39, R_512_6_3=43, + R_512_7_0= 8, R_512_7_1=35, R_512_7_2=56, R_512_7_3=22, + + /* Skein1024 round rotation constants */ + R1024_0_0=24, R1024_0_1=13, R1024_0_2= 8, R1024_0_3=47, R1024_0_4= 8, R1024_0_5=17, R1024_0_6=22, R1024_0_7=37, + R1024_1_0=38, R1024_1_1=19, R1024_1_2=10, R1024_1_3=55, R1024_1_4=49, R1024_1_5=18, R1024_1_6=23, R1024_1_7=52, + R1024_2_0=33, R1024_2_1= 4, R1024_2_2=51, R1024_2_3=13, R1024_2_4=34, R1024_2_5=41, R1024_2_6=59, R1024_2_7=17, + R1024_3_0= 5, R1024_3_1=20, R1024_3_2=48, R1024_3_3=41, R1024_3_4=47, R1024_3_5=28, R1024_3_6=16, R1024_3_7=25, + R1024_4_0=41, R1024_4_1= 9, R1024_4_2=37, R1024_4_3=31, R1024_4_4=12, R1024_4_5=47, R1024_4_6=44, R1024_4_7=30, + R1024_5_0=16, R1024_5_1=34, R1024_5_2=56, R1024_5_3=51, R1024_5_4= 4, R1024_5_5=53, R1024_5_6=42, R1024_5_7=41, + R1024_6_0=31, R1024_6_1=44, R1024_6_2=47, R1024_6_3=46, R1024_6_4=19, R1024_6_5=42, R1024_6_6=44, R1024_6_7=25, + R1024_7_0= 9, R1024_7_1=48, R1024_7_2=35, R1024_7_3=52, R1024_7_4=23, R1024_7_5=31, R1024_7_6=37, R1024_7_7=20 +}; + +#ifndef SKEIN_ROUNDS +#define SKEIN_256_ROUNDS_TOTAL (72) /* number of rounds for the different block sizes */ +#define SKEIN_512_ROUNDS_TOTAL (72) +#define SKEIN1024_ROUNDS_TOTAL (80) +#else /* allow command-line define in range 8*(5..14) */ +#define SKEIN_256_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS/100) + 5) % 10) + 5)) +#define SKEIN_512_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS/ 10) + 5) % 10) + 5)) +#define SKEIN1024_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS ) + 5) % 10) + 5)) +#endif + + +/* +***************** Pre-computed Skein IVs ******************* +** +** NOTE: these values are not "magic" constants, but +** are generated using the Threefish block function. +** They are pre-computed here only for speed; i.e., to +** avoid the need for a Threefish call during Init(). +** +** The IV for any fixed hash length may be pre-computed. +** Only the most common values are included here. +** +************************************************************ +**/ + +#define MK_64 SKEIN_MK_64 + +/* blkSize = 256 bits. hashSize = 128 bits */ +const u64b_t SKEIN_256_IV_128[] = + { + MK_64(0xE1111906,0x964D7260), + MK_64(0x883DAAA7,0x7C8D811C), + MK_64(0x10080DF4,0x91960F7A), + MK_64(0xCCF7DDE5,0xB45BC1C2) + }; + +/* blkSize = 256 bits. hashSize = 160 bits */ +const u64b_t SKEIN_256_IV_160[] = + { + MK_64(0x14202314,0x72825E98), + MK_64(0x2AC4E9A2,0x5A77E590), + MK_64(0xD47A5856,0x8838D63E), + MK_64(0x2DD2E496,0x8586AB7D) + }; + +/* blkSize = 256 bits. hashSize = 224 bits */ +const u64b_t SKEIN_256_IV_224[] = + { + MK_64(0xC6098A8C,0x9AE5EA0B), + MK_64(0x876D5686,0x08C5191C), + MK_64(0x99CB88D7,0xD7F53884), + MK_64(0x384BDDB1,0xAEDDB5DE) + }; + +/* blkSize = 256 bits. hashSize = 256 bits */ +const u64b_t SKEIN_256_IV_256[] = + { + MK_64(0xFC9DA860,0xD048B449), + MK_64(0x2FCA6647,0x9FA7D833), + MK_64(0xB33BC389,0x6656840F), + MK_64(0x6A54E920,0xFDE8DA69) + }; + +/* blkSize = 512 bits. hashSize = 128 bits */ +const u64b_t SKEIN_512_IV_128[] = + { + MK_64(0xA8BC7BF3,0x6FBF9F52), + MK_64(0x1E9872CE,0xBD1AF0AA), + MK_64(0x309B1790,0xB32190D3), + MK_64(0xBCFBB854,0x3F94805C), + MK_64(0x0DA61BCD,0x6E31B11B), + MK_64(0x1A18EBEA,0xD46A32E3), + MK_64(0xA2CC5B18,0xCE84AA82), + MK_64(0x6982AB28,0x9D46982D) + }; + +/* blkSize = 512 bits. hashSize = 160 bits */ +const u64b_t SKEIN_512_IV_160[] = + { + MK_64(0x28B81A2A,0xE013BD91), + MK_64(0xC2F11668,0xB5BDF78F), + MK_64(0x1760D8F3,0xF6A56F12), + MK_64(0x4FB74758,0x8239904F), + MK_64(0x21EDE07F,0x7EAF5056), + MK_64(0xD908922E,0x63ED70B8), + MK_64(0xB8EC76FF,0xECCB52FA), + MK_64(0x01A47BB8,0xA3F27A6E) + }; + +/* blkSize = 512 bits. hashSize = 224 bits */ +const u64b_t SKEIN_512_IV_224[] = + { + MK_64(0xCCD06162,0x48677224), + MK_64(0xCBA65CF3,0xA92339EF), + MK_64(0x8CCD69D6,0x52FF4B64), + MK_64(0x398AED7B,0x3AB890B4), + MK_64(0x0F59D1B1,0x457D2BD0), + MK_64(0x6776FE65,0x75D4EB3D), + MK_64(0x99FBC70E,0x997413E9), + MK_64(0x9E2CFCCF,0xE1C41EF7) + }; + +/* blkSize = 512 bits. hashSize = 256 bits */ +const u64b_t SKEIN_512_IV_256[] = + { + MK_64(0xCCD044A1,0x2FDB3E13), + MK_64(0xE8359030,0x1A79A9EB), + MK_64(0x55AEA061,0x4F816E6F), + MK_64(0x2A2767A4,0xAE9B94DB), + MK_64(0xEC06025E,0x74DD7683), + MK_64(0xE7A436CD,0xC4746251), + MK_64(0xC36FBAF9,0x393AD185), + MK_64(0x3EEDBA18,0x33EDFC13) + }; + +/* blkSize = 512 bits. hashSize = 384 bits */ +const u64b_t SKEIN_512_IV_384[] = + { + MK_64(0xA3F6C6BF,0x3A75EF5F), + MK_64(0xB0FEF9CC,0xFD84FAA4), + MK_64(0x9D77DD66,0x3D770CFE), + MK_64(0xD798CBF3,0xB468FDDA), + MK_64(0x1BC4A666,0x8A0E4465), + MK_64(0x7ED7D434,0xE5807407), + MK_64(0x548FC1AC,0xD4EC44D6), + MK_64(0x266E1754,0x6AA18FF8) + }; + +/* blkSize = 512 bits. hashSize = 512 bits */ +const u64b_t SKEIN_512_IV_512[] = + { + MK_64(0x4903ADFF,0x749C51CE), + MK_64(0x0D95DE39,0x9746DF03), + MK_64(0x8FD19341,0x27C79BCE), + MK_64(0x9A255629,0xFF352CB1), + MK_64(0x5DB62599,0xDF6CA7B0), + MK_64(0xEABE394C,0xA9D5C3F4), + MK_64(0x991112C7,0x1A75B523), + MK_64(0xAE18A40B,0x660FCC33) + }; + +/* blkSize = 1024 bits. hashSize = 384 bits */ +const u64b_t SKEIN1024_IV_384[] = + { + MK_64(0x5102B6B8,0xC1894A35), + MK_64(0xFEEBC9E3,0xFE8AF11A), + MK_64(0x0C807F06,0xE32BED71), + MK_64(0x60C13A52,0xB41A91F6), + MK_64(0x9716D35D,0xD4917C38), + MK_64(0xE780DF12,0x6FD31D3A), + MK_64(0x797846B6,0xC898303A), + MK_64(0xB172C2A8,0xB3572A3B), + MK_64(0xC9BC8203,0xA6104A6C), + MK_64(0x65909338,0xD75624F4), + MK_64(0x94BCC568,0x4B3F81A0), + MK_64(0x3EBBF51E,0x10ECFD46), + MK_64(0x2DF50F0B,0xEEB08542), + MK_64(0x3B5A6530,0x0DBC6516), + MK_64(0x484B9CD2,0x167BBCE1), + MK_64(0x2D136947,0xD4CBAFEA) + }; + +/* blkSize = 1024 bits. hashSize = 512 bits */ +const u64b_t SKEIN1024_IV_512[] = + { + MK_64(0xCAEC0E5D,0x7C1B1B18), + MK_64(0xA01B0E04,0x5F03E802), + MK_64(0x33840451,0xED912885), + MK_64(0x374AFB04,0xEAEC2E1C), + MK_64(0xDF25A0E2,0x813581F7), + MK_64(0xE4004093,0x8B12F9D2), + MK_64(0xA662D539,0xC2ED39B6), + MK_64(0xFA8B85CF,0x45D8C75A), + MK_64(0x8316ED8E,0x29EDE796), + MK_64(0x053289C0,0x2E9F91B8), + MK_64(0xC3F8EF1D,0x6D518B73), + MK_64(0xBDCEC3C4,0xD5EF332E), + MK_64(0x549A7E52,0x22974487), + MK_64(0x67070872,0x5B749816), + MK_64(0xB9CD28FB,0xF0581BD1), + MK_64(0x0E2940B8,0x15804974) + }; + +/* blkSize = 1024 bits. hashSize = 1024 bits */ +const u64b_t SKEIN1024_IV_1024[] = + { + MK_64(0xD593DA07,0x41E72355), + MK_64(0x15B5E511,0xAC73E00C), + MK_64(0x5180E5AE,0xBAF2C4F0), + MK_64(0x03BD41D3,0xFCBCAFAF), + MK_64(0x1CAEC6FD,0x1983A898), + MK_64(0x6E510B8B,0xCDD0589F), + MK_64(0x77E2BDFD,0xC6394ADA), + MK_64(0xC11E1DB5,0x24DCB0A3), + MK_64(0xD6D14AF9,0xC6329AB5), + MK_64(0x6A9B0BFC,0x6EB67E0D), + MK_64(0x9243C60D,0xCCFF1332), + MK_64(0x1A1F1DDE,0x743F02D4), + MK_64(0x0996753C,0x10ED0BB8), + MK_64(0x6572DD22,0xF2B4969A), + MK_64(0x61FD3062,0xD00A579A), + MK_64(0x1DE0536E,0x8682E539) + }; + + +#ifndef SKEIN_USE_ASM +#define SKEIN_USE_ASM (0) /* default is all C code (no ASM) */ +#endif + +#ifndef SKEIN_LOOP +#define SKEIN_LOOP 001 /* default: unroll 256 and 512, but not 1024 */ +#endif + +#define BLK_BITS (WCNT*64) /* some useful definitions for code here */ +#define KW_TWK_BASE (0) +#define KW_KEY_BASE (3) +#define ks (kw + KW_KEY_BASE) +#define ts (kw + KW_TWK_BASE) + +#ifdef SKEIN_DEBUG +#define DebugSaveTweak(ctx) { ctx->h.T[0] = ts[0]; ctx->h.T[1] = ts[1]; } +#else +#define DebugSaveTweak(ctx) +#endif + +/***************************** Skein_256 ******************************/ +#if !(SKEIN_USE_ASM & 256) +static void Skein_256_Process_Block(Skein_256_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd) + { /* do it in C */ + enum + { + WCNT = SKEIN_256_STATE_WORDS + }; +#undef RCNT +#define RCNT (SKEIN_256_ROUNDS_TOTAL/8) + +#ifdef SKEIN_LOOP /* configure how much to unroll the loop */ +#define SKEIN_UNROLL_256 (((SKEIN_LOOP)/100)%10) +#else +#define SKEIN_UNROLL_256 (0) +#endif + +#if SKEIN_UNROLL_256 +#if (RCNT % SKEIN_UNROLL_256) +#error "Invalid SKEIN_UNROLL_256" /* sanity check on unroll count */ +#endif + size_t r; + u64b_t kw[WCNT+4+RCNT*2]; /* key schedule words : chaining vars + tweak + "rotation"*/ +#else + u64b_t kw[WCNT+4]; /* key schedule words : chaining vars + tweak */ +#endif + u64b_t X0,X1,X2,X3; /* local copy of context vars, for speed */ + u64b_t w [WCNT]; /* local copy of input block */ +#ifdef SKEIN_DEBUG + const u64b_t *Xptr[4]; /* use for debugging (help compiler put Xn in registers) */ + Xptr[0] = &X0; Xptr[1] = &X1; Xptr[2] = &X2; Xptr[3] = &X3; +#endif + Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ + ts[0] = ctx->h.T[0]; + ts[1] = ctx->h.T[1]; + do { + /* this implementation only supports 2**64 input bytes (no carry out here) */ + ts[0] += byteCntAdd; /* update processed length */ + + /* precompute the key schedule for this block */ + ks[0] = ctx->X[0]; + ks[1] = ctx->X[1]; + ks[2] = ctx->X[2]; + ks[3] = ctx->X[3]; + ks[4] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ SKEIN_KS_PARITY; + + ts[2] = ts[0] ^ ts[1]; + + Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */ + DebugSaveTweak(ctx); + Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts); + + X0 = w[0] + ks[0]; /* do the first full key injection */ + X1 = w[1] + ks[1] + ts[0]; + X2 = w[2] + ks[2] + ts[1]; + X3 = w[3] + ks[3]; + + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr); /* show starting state values */ + + blkPtr += SKEIN_256_BLOCK_BYTES; + + /* run the rounds */ + +#define Round256(p0,p1,p2,p3,ROT,rNum) \ + X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \ + X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \ + +#if SKEIN_UNROLL_256 == 0 +#define R256(p0,p1,p2,p3,ROT,rNum) /* fully unrolled */ \ + Round256(p0,p1,p2,p3,ROT,rNum) \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rNum,Xptr); + +#define I256(R) \ + X0 += ks[((R)+1) % 5]; /* inject the key schedule value */ \ + X1 += ks[((R)+2) % 5] + ts[((R)+1) % 3]; \ + X2 += ks[((R)+3) % 5] + ts[((R)+2) % 3]; \ + X3 += ks[((R)+4) % 5] + (R)+1; \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); +#else /* looping version */ +#define R256(p0,p1,p2,p3,ROT,rNum) \ + Round256(p0,p1,p2,p3,ROT,rNum) \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rNum,Xptr); + +#define I256(R) \ + X0 += ks[r+(R)+0]; /* inject the key schedule value */ \ + X1 += ks[r+(R)+1] + ts[r+(R)+0]; \ + X2 += ks[r+(R)+2] + ts[r+(R)+1]; \ + X3 += ks[r+(R)+3] + r+(R) ; \ + ks[r + (R)+4 ] = ks[r+(R)-1]; /* rotate key schedule */\ + ts[r + (R)+2 ] = ts[r+(R)-1]; \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); + + for (r=1;r < 2*RCNT;r+=2*SKEIN_UNROLL_256) /* loop thru it */ +#endif + { +#define R256_8_rounds(R) \ + R256(0,1,2,3,R_256_0,8*(R) + 1); \ + R256(0,3,2,1,R_256_1,8*(R) + 2); \ + R256(0,1,2,3,R_256_2,8*(R) + 3); \ + R256(0,3,2,1,R_256_3,8*(R) + 4); \ + I256(2*(R)); \ + R256(0,1,2,3,R_256_4,8*(R) + 5); \ + R256(0,3,2,1,R_256_5,8*(R) + 6); \ + R256(0,1,2,3,R_256_6,8*(R) + 7); \ + R256(0,3,2,1,R_256_7,8*(R) + 8); \ + I256(2*(R)+1); + + R256_8_rounds( 0); + +#define R256_Unroll_R(NN) ((SKEIN_UNROLL_256 == 0 && SKEIN_256_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_256 > (NN))) + + #if R256_Unroll_R( 1) + R256_8_rounds( 1); + #endif + #if R256_Unroll_R( 2) + R256_8_rounds( 2); + #endif + #if R256_Unroll_R( 3) + R256_8_rounds( 3); + #endif + #if R256_Unroll_R( 4) + R256_8_rounds( 4); + #endif + #if R256_Unroll_R( 5) + R256_8_rounds( 5); + #endif + #if R256_Unroll_R( 6) + R256_8_rounds( 6); + #endif + #if R256_Unroll_R( 7) + R256_8_rounds( 7); + #endif + #if R256_Unroll_R( 8) + R256_8_rounds( 8); + #endif + #if R256_Unroll_R( 9) + R256_8_rounds( 9); + #endif + #if R256_Unroll_R(10) + R256_8_rounds(10); + #endif + #if R256_Unroll_R(11) + R256_8_rounds(11); + #endif + #if R256_Unroll_R(12) + R256_8_rounds(12); + #endif + #if R256_Unroll_R(13) + R256_8_rounds(13); + #endif + #if R256_Unroll_R(14) + R256_8_rounds(14); + #endif + #if (SKEIN_UNROLL_256 > 14) +#error "need more unrolling in Skein_256_Process_Block" + #endif + } + /* do the final "feedforward" xor, update context chaining vars */ + ctx->X[0] = X0 ^ w[0]; + ctx->X[1] = X1 ^ w[1]; + ctx->X[2] = X2 ^ w[2]; + ctx->X[3] = X3 ^ w[3]; + + Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X); + + ts[1] &= ~SKEIN_T1_FLAG_FIRST; + } + while (--blkCnt); + ctx->h.T[0] = ts[0]; + ctx->h.T[1] = ts[1]; + } + +#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) +static size_t Skein_256_Process_Block_CodeSize(void) + { + return ((u08b_t *) Skein_256_Process_Block_CodeSize) - + ((u08b_t *) Skein_256_Process_Block); + } +static uint_t Skein_256_Unroll_Cnt(void) + { + return SKEIN_UNROLL_256; + } +#endif +#endif + +/***************************** Skein_512 ******************************/ +#if !(SKEIN_USE_ASM & 512) +static void Skein_512_Process_Block(Skein_512_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd) + { /* do it in C */ + enum + { + WCNT = SKEIN_512_STATE_WORDS + }; +#undef RCNT +#define RCNT (SKEIN_512_ROUNDS_TOTAL/8) + +#ifdef SKEIN_LOOP /* configure how much to unroll the loop */ +#define SKEIN_UNROLL_512 (((SKEIN_LOOP)/10)%10) +#else +#define SKEIN_UNROLL_512 (0) +#endif + +#if SKEIN_UNROLL_512 +#if (RCNT % SKEIN_UNROLL_512) +#error "Invalid SKEIN_UNROLL_512" /* sanity check on unroll count */ +#endif + size_t r; + u64b_t kw[WCNT+4+RCNT*2]; /* key schedule words : chaining vars + tweak + "rotation"*/ +#else + u64b_t kw[WCNT+4]; /* key schedule words : chaining vars + tweak */ +#endif + u64b_t X0,X1,X2,X3,X4,X5,X6,X7; /* local copy of vars, for speed */ + u64b_t w [WCNT]; /* local copy of input block */ +#ifdef SKEIN_DEBUG + const u64b_t *Xptr[8]; /* use for debugging (help compiler put Xn in registers) */ + Xptr[0] = &X0; Xptr[1] = &X1; Xptr[2] = &X2; Xptr[3] = &X3; + Xptr[4] = &X4; Xptr[5] = &X5; Xptr[6] = &X6; Xptr[7] = &X7; +#endif + + Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ + ts[0] = ctx->h.T[0]; + ts[1] = ctx->h.T[1]; + do { + /* this implementation only supports 2**64 input bytes (no carry out here) */ + ts[0] += byteCntAdd; /* update processed length */ + + /* precompute the key schedule for this block */ + ks[0] = ctx->X[0]; + ks[1] = ctx->X[1]; + ks[2] = ctx->X[2]; + ks[3] = ctx->X[3]; + ks[4] = ctx->X[4]; + ks[5] = ctx->X[5]; + ks[6] = ctx->X[6]; + ks[7] = ctx->X[7]; + ks[8] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ + ks[4] ^ ks[5] ^ ks[6] ^ ks[7] ^ SKEIN_KS_PARITY; + + ts[2] = ts[0] ^ ts[1]; + + Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */ + DebugSaveTweak(ctx); + Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts); + + X0 = w[0] + ks[0]; /* do the first full key injection */ + X1 = w[1] + ks[1]; + X2 = w[2] + ks[2]; + X3 = w[3] + ks[3]; + X4 = w[4] + ks[4]; + X5 = w[5] + ks[5] + ts[0]; + X6 = w[6] + ks[6] + ts[1]; + X7 = w[7] + ks[7]; + + blkPtr += SKEIN_512_BLOCK_BYTES; + + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr); + /* run the rounds */ +#define Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ + X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \ + X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \ + X##p4 += X##p5; X##p5 = RotL_64(X##p5,ROT##_2); X##p5 ^= X##p4; \ + X##p6 += X##p7; X##p7 = RotL_64(X##p7,ROT##_3); X##p7 ^= X##p6; \ + +#if SKEIN_UNROLL_512 == 0 +#define R512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) /* unrolled */ \ + Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rNum,Xptr); + +#define I512(R) \ + X0 += ks[((R)+1) % 9]; /* inject the key schedule value */ \ + X1 += ks[((R)+2) % 9]; \ + X2 += ks[((R)+3) % 9]; \ + X3 += ks[((R)+4) % 9]; \ + X4 += ks[((R)+5) % 9]; \ + X5 += ks[((R)+6) % 9] + ts[((R)+1) % 3]; \ + X6 += ks[((R)+7) % 9] + ts[((R)+2) % 3]; \ + X7 += ks[((R)+8) % 9] + (R)+1; \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); +#else /* looping version */ +#define R512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ + Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rNum,Xptr); + +#define I512(R) \ + X0 += ks[r+(R)+0]; /* inject the key schedule value */ \ + X1 += ks[r+(R)+1]; \ + X2 += ks[r+(R)+2]; \ + X3 += ks[r+(R)+3]; \ + X4 += ks[r+(R)+4]; \ + X5 += ks[r+(R)+5] + ts[r+(R)+0]; \ + X6 += ks[r+(R)+6] + ts[r+(R)+1]; \ + X7 += ks[r+(R)+7] + r+(R) ; \ + ks[r + (R)+8] = ks[r+(R)-1]; /* rotate key schedule */ \ + ts[r + (R)+2] = ts[r+(R)-1]; \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); + + for (r=1;r < 2*RCNT;r+=2*SKEIN_UNROLL_512) /* loop thru it */ +#endif /* end of looped code definitions */ + { +#define R512_8_rounds(R) /* do 8 full rounds */ \ + R512(0,1,2,3,4,5,6,7,R_512_0,8*(R)+ 1); \ + R512(2,1,4,7,6,5,0,3,R_512_1,8*(R)+ 2); \ + R512(4,1,6,3,0,5,2,7,R_512_2,8*(R)+ 3); \ + R512(6,1,0,7,2,5,4,3,R_512_3,8*(R)+ 4); \ + I512(2*(R)); \ + R512(0,1,2,3,4,5,6,7,R_512_4,8*(R)+ 5); \ + R512(2,1,4,7,6,5,0,3,R_512_5,8*(R)+ 6); \ + R512(4,1,6,3,0,5,2,7,R_512_6,8*(R)+ 7); \ + R512(6,1,0,7,2,5,4,3,R_512_7,8*(R)+ 8); \ + I512(2*(R)+1); /* and key injection */ + + R512_8_rounds( 0); + +#define R512_Unroll_R(NN) ((SKEIN_UNROLL_512 == 0 && SKEIN_512_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_512 > (NN))) + + #if R512_Unroll_R( 1) + R512_8_rounds( 1); + #endif + #if R512_Unroll_R( 2) + R512_8_rounds( 2); + #endif + #if R512_Unroll_R( 3) + R512_8_rounds( 3); + #endif + #if R512_Unroll_R( 4) + R512_8_rounds( 4); + #endif + #if R512_Unroll_R( 5) + R512_8_rounds( 5); + #endif + #if R512_Unroll_R( 6) + R512_8_rounds( 6); + #endif + #if R512_Unroll_R( 7) + R512_8_rounds( 7); + #endif + #if R512_Unroll_R( 8) + R512_8_rounds( 8); + #endif + #if R512_Unroll_R( 9) + R512_8_rounds( 9); + #endif + #if R512_Unroll_R(10) + R512_8_rounds(10); + #endif + #if R512_Unroll_R(11) + R512_8_rounds(11); + #endif + #if R512_Unroll_R(12) + R512_8_rounds(12); + #endif + #if R512_Unroll_R(13) + R512_8_rounds(13); + #endif + #if R512_Unroll_R(14) + R512_8_rounds(14); + #endif + #if (SKEIN_UNROLL_512 > 14) +#error "need more unrolling in Skein_512_Process_Block" + #endif + } + + /* do the final "feedforward" xor, update context chaining vars */ + ctx->X[0] = X0 ^ w[0]; + ctx->X[1] = X1 ^ w[1]; + ctx->X[2] = X2 ^ w[2]; + ctx->X[3] = X3 ^ w[3]; + ctx->X[4] = X4 ^ w[4]; + ctx->X[5] = X5 ^ w[5]; + ctx->X[6] = X6 ^ w[6]; + ctx->X[7] = X7 ^ w[7]; + Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X); + + ts[1] &= ~SKEIN_T1_FLAG_FIRST; + } + while (--blkCnt); + ctx->h.T[0] = ts[0]; + ctx->h.T[1] = ts[1]; + } + +#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) +static size_t Skein_512_Process_Block_CodeSize(void) + { + return ((u08b_t *) Skein_512_Process_Block_CodeSize) - + ((u08b_t *) Skein_512_Process_Block); + } +static uint_t Skein_512_Unroll_Cnt(void) + { + return SKEIN_UNROLL_512; + } +#endif +#endif + +/***************************** Skein1024 ******************************/ +#if !(SKEIN_USE_ASM & 1024) +static void Skein1024_Process_Block(Skein1024_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd) + { /* do it in C, always looping (unrolled is bigger AND slower!) */ + enum + { + WCNT = SKEIN1024_STATE_WORDS + }; +#undef RCNT +#define RCNT (SKEIN1024_ROUNDS_TOTAL/8) + +#ifdef SKEIN_LOOP /* configure how much to unroll the loop */ +#define SKEIN_UNROLL_1024 ((SKEIN_LOOP)%10) +#else +#define SKEIN_UNROLL_1024 (0) +#endif + +#if (SKEIN_UNROLL_1024 != 0) +#if (RCNT % SKEIN_UNROLL_1024) +#error "Invalid SKEIN_UNROLL_1024" /* sanity check on unroll count */ +#endif + size_t r; + u64b_t kw[WCNT+4+RCNT*2]; /* key schedule words : chaining vars + tweak + "rotation"*/ +#else + u64b_t kw[WCNT+4]; /* key schedule words : chaining vars + tweak */ +#endif + + u64b_t X00,X01,X02,X03,X04,X05,X06,X07, /* local copy of vars, for speed */ + X08,X09,X10,X11,X12,X13,X14,X15; + u64b_t w [WCNT]; /* local copy of input block */ +#ifdef SKEIN_DEBUG + const u64b_t *Xptr[16]; /* use for debugging (help compiler put Xn in registers) */ + Xptr[ 0] = &X00; Xptr[ 1] = &X01; Xptr[ 2] = &X02; Xptr[ 3] = &X03; + Xptr[ 4] = &X04; Xptr[ 5] = &X05; Xptr[ 6] = &X06; Xptr[ 7] = &X07; + Xptr[ 8] = &X08; Xptr[ 9] = &X09; Xptr[10] = &X10; Xptr[11] = &X11; + Xptr[12] = &X12; Xptr[13] = &X13; Xptr[14] = &X14; Xptr[15] = &X15; +#endif + + Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ + ts[0] = ctx->h.T[0]; + ts[1] = ctx->h.T[1]; + do { + /* this implementation only supports 2**64 input bytes (no carry out here) */ + ts[0] += byteCntAdd; /* update processed length */ + + /* precompute the key schedule for this block */ + ks[ 0] = ctx->X[ 0]; + ks[ 1] = ctx->X[ 1]; + ks[ 2] = ctx->X[ 2]; + ks[ 3] = ctx->X[ 3]; + ks[ 4] = ctx->X[ 4]; + ks[ 5] = ctx->X[ 5]; + ks[ 6] = ctx->X[ 6]; + ks[ 7] = ctx->X[ 7]; + ks[ 8] = ctx->X[ 8]; + ks[ 9] = ctx->X[ 9]; + ks[10] = ctx->X[10]; + ks[11] = ctx->X[11]; + ks[12] = ctx->X[12]; + ks[13] = ctx->X[13]; + ks[14] = ctx->X[14]; + ks[15] = ctx->X[15]; + ks[16] = ks[ 0] ^ ks[ 1] ^ ks[ 2] ^ ks[ 3] ^ + ks[ 4] ^ ks[ 5] ^ ks[ 6] ^ ks[ 7] ^ + ks[ 8] ^ ks[ 9] ^ ks[10] ^ ks[11] ^ + ks[12] ^ ks[13] ^ ks[14] ^ ks[15] ^ SKEIN_KS_PARITY; + + ts[2] = ts[0] ^ ts[1]; + + Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */ + DebugSaveTweak(ctx); + Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts); + + X00 = w[ 0] + ks[ 0]; /* do the first full key injection */ + X01 = w[ 1] + ks[ 1]; + X02 = w[ 2] + ks[ 2]; + X03 = w[ 3] + ks[ 3]; + X04 = w[ 4] + ks[ 4]; + X05 = w[ 5] + ks[ 5]; + X06 = w[ 6] + ks[ 6]; + X07 = w[ 7] + ks[ 7]; + X08 = w[ 8] + ks[ 8]; + X09 = w[ 9] + ks[ 9]; + X10 = w[10] + ks[10]; + X11 = w[11] + ks[11]; + X12 = w[12] + ks[12]; + X13 = w[13] + ks[13] + ts[0]; + X14 = w[14] + ks[14] + ts[1]; + X15 = w[15] + ks[15]; + + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr); + +#define Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rNum) \ + X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \ + X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \ + X##p4 += X##p5; X##p5 = RotL_64(X##p5,ROT##_2); X##p5 ^= X##p4; \ + X##p6 += X##p7; X##p7 = RotL_64(X##p7,ROT##_3); X##p7 ^= X##p6; \ + X##p8 += X##p9; X##p9 = RotL_64(X##p9,ROT##_4); X##p9 ^= X##p8; \ + X##pA += X##pB; X##pB = RotL_64(X##pB,ROT##_5); X##pB ^= X##pA; \ + X##pC += X##pD; X##pD = RotL_64(X##pD,ROT##_6); X##pD ^= X##pC; \ + X##pE += X##pF; X##pF = RotL_64(X##pF,ROT##_7); X##pF ^= X##pE; \ + +#if SKEIN_UNROLL_1024 == 0 +#define R1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \ + Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rn,Xptr); + +#define I1024(R) \ + X00 += ks[((R)+ 1) % 17]; /* inject the key schedule value */ \ + X01 += ks[((R)+ 2) % 17]; \ + X02 += ks[((R)+ 3) % 17]; \ + X03 += ks[((R)+ 4) % 17]; \ + X04 += ks[((R)+ 5) % 17]; \ + X05 += ks[((R)+ 6) % 17]; \ + X06 += ks[((R)+ 7) % 17]; \ + X07 += ks[((R)+ 8) % 17]; \ + X08 += ks[((R)+ 9) % 17]; \ + X09 += ks[((R)+10) % 17]; \ + X10 += ks[((R)+11) % 17]; \ + X11 += ks[((R)+12) % 17]; \ + X12 += ks[((R)+13) % 17]; \ + X13 += ks[((R)+14) % 17] + ts[((R)+1) % 3]; \ + X14 += ks[((R)+15) % 17] + ts[((R)+2) % 3]; \ + X15 += ks[((R)+16) % 17] + (R)+1; \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); +#else /* looping version */ +#define R1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \ + Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rn,Xptr); + +#define I1024(R) \ + X00 += ks[r+(R)+ 0]; /* inject the key schedule value */ \ + X01 += ks[r+(R)+ 1]; \ + X02 += ks[r+(R)+ 2]; \ + X03 += ks[r+(R)+ 3]; \ + X04 += ks[r+(R)+ 4]; \ + X05 += ks[r+(R)+ 5]; \ + X06 += ks[r+(R)+ 6]; \ + X07 += ks[r+(R)+ 7]; \ + X08 += ks[r+(R)+ 8]; \ + X09 += ks[r+(R)+ 9]; \ + X10 += ks[r+(R)+10]; \ + X11 += ks[r+(R)+11]; \ + X12 += ks[r+(R)+12]; \ + X13 += ks[r+(R)+13] + ts[r+(R)+0]; \ + X14 += ks[r+(R)+14] + ts[r+(R)+1]; \ + X15 += ks[r+(R)+15] + r+(R) ; \ + ks[r + (R)+16] = ks[r+(R)-1]; /* rotate key schedule */ \ + ts[r + (R)+ 2] = ts[r+(R)-1]; \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); + + for (r=1;r <= 2*RCNT;r+=2*SKEIN_UNROLL_1024) /* loop thru it */ +#endif + { +#define R1024_8_rounds(R) /* do 8 full rounds */ \ + R1024(00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,R1024_0,8*(R) + 1); \ + R1024(00,09,02,13,06,11,04,15,10,07,12,03,14,05,08,01,R1024_1,8*(R) + 2); \ + R1024(00,07,02,05,04,03,06,01,12,15,14,13,08,11,10,09,R1024_2,8*(R) + 3); \ + R1024(00,15,02,11,06,13,04,09,14,01,08,05,10,03,12,07,R1024_3,8*(R) + 4); \ + I1024(2*(R)); \ + R1024(00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,R1024_4,8*(R) + 5); \ + R1024(00,09,02,13,06,11,04,15,10,07,12,03,14,05,08,01,R1024_5,8*(R) + 6); \ + R1024(00,07,02,05,04,03,06,01,12,15,14,13,08,11,10,09,R1024_6,8*(R) + 7); \ + R1024(00,15,02,11,06,13,04,09,14,01,08,05,10,03,12,07,R1024_7,8*(R) + 8); \ + I1024(2*(R)+1); + + R1024_8_rounds( 0); + +#define R1024_Unroll_R(NN) ((SKEIN_UNROLL_1024 == 0 && SKEIN1024_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_1024 > (NN))) + + #if R1024_Unroll_R( 1) + R1024_8_rounds( 1); + #endif + #if R1024_Unroll_R( 2) + R1024_8_rounds( 2); + #endif + #if R1024_Unroll_R( 3) + R1024_8_rounds( 3); + #endif + #if R1024_Unroll_R( 4) + R1024_8_rounds( 4); + #endif + #if R1024_Unroll_R( 5) + R1024_8_rounds( 5); + #endif + #if R1024_Unroll_R( 6) + R1024_8_rounds( 6); + #endif + #if R1024_Unroll_R( 7) + R1024_8_rounds( 7); + #endif + #if R1024_Unroll_R( 8) + R1024_8_rounds( 8); + #endif + #if R1024_Unroll_R( 9) + R1024_8_rounds( 9); + #endif + #if R1024_Unroll_R(10) + R1024_8_rounds(10); + #endif + #if R1024_Unroll_R(11) + R1024_8_rounds(11); + #endif + #if R1024_Unroll_R(12) + R1024_8_rounds(12); + #endif + #if R1024_Unroll_R(13) + R1024_8_rounds(13); + #endif + #if R1024_Unroll_R(14) + R1024_8_rounds(14); + #endif + #if (SKEIN_UNROLL_1024 > 14) +#error "need more unrolling in Skein_1024_Process_Block" + #endif + } + /* do the final "feedforward" xor, update context chaining vars */ + + ctx->X[ 0] = X00 ^ w[ 0]; + ctx->X[ 1] = X01 ^ w[ 1]; + ctx->X[ 2] = X02 ^ w[ 2]; + ctx->X[ 3] = X03 ^ w[ 3]; + ctx->X[ 4] = X04 ^ w[ 4]; + ctx->X[ 5] = X05 ^ w[ 5]; + ctx->X[ 6] = X06 ^ w[ 6]; + ctx->X[ 7] = X07 ^ w[ 7]; + ctx->X[ 8] = X08 ^ w[ 8]; + ctx->X[ 9] = X09 ^ w[ 9]; + ctx->X[10] = X10 ^ w[10]; + ctx->X[11] = X11 ^ w[11]; + ctx->X[12] = X12 ^ w[12]; + ctx->X[13] = X13 ^ w[13]; + ctx->X[14] = X14 ^ w[14]; + ctx->X[15] = X15 ^ w[15]; + + Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X); + + ts[1] &= ~SKEIN_T1_FLAG_FIRST; + blkPtr += SKEIN1024_BLOCK_BYTES; + } + while (--blkCnt); + ctx->h.T[0] = ts[0]; + ctx->h.T[1] = ts[1]; + } + +#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) +static size_t Skein1024_Process_Block_CodeSize(void) + { + return ((u08b_t *) Skein1024_Process_Block_CodeSize) - + ((u08b_t *) Skein1024_Process_Block); + } +static uint_t Skein1024_Unroll_Cnt(void) + { + return SKEIN_UNROLL_1024; + } +#endif +#endif + + +#if 0 +/*****************************************************************/ +/* 256-bit Skein */ +/*****************************************************************/ + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a straight hashing operation */ +static int Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen) + { + union + { + u08b_t b[SKEIN_256_STATE_BYTES]; + u64b_t w[SKEIN_256_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); + ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ + + switch (hashBitLen) + { /* use pre-computed values, where available */ +#ifndef SKEIN_NO_PRECOMP + case 256: memcpy(ctx->X,SKEIN_256_IV_256,sizeof(ctx->X)); break; + case 224: memcpy(ctx->X,SKEIN_256_IV_224,sizeof(ctx->X)); break; + case 160: memcpy(ctx->X,SKEIN_256_IV_160,sizeof(ctx->X)); break; + case 128: memcpy(ctx->X,SKEIN_256_IV_128,sizeof(ctx->X)); break; +#endif + default: + /* here if there is no precomputed IV value available */ + /* build/process the config block, type == CONFIG (could be precomputed) */ + Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */ + + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */ + cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ + cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); + memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */ + + /* compute the initial chaining values from config block */ + memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */ + Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); + break; + } + /* The chaining vars ctx->X are now initialized for the given hashBitLen. */ + /* Set up to process the data message portion of the hash (default) */ + Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type */ + + return SKEIN_SUCCESS; + } + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a MAC and/or tree hash operation */ +/* [identical to Skein_256_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */ +static int Skein_256_InitExt(Skein_256_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes) + { + union + { + u08b_t b[SKEIN_256_STATE_BYTES]; + u64b_t w[SKEIN_256_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); + Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL); + + /* compute the initial chaining values ctx->X[], based on key */ + if (keyBytes == 0) /* is there a key? */ + { + memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */ + } + else /* here to pre-process a key */ + { + Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X)); + /* do a mini-Init right here */ + ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */ + Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */ + memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */ + Skein_256_Update(ctx,key,keyBytes); /* hash the key */ + Skein_256_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */ + memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */ +#if SKEIN_NEED_SWAP + { + uint_t i; + for (i=0;iX[i] = Skein_Swap64(ctx->X[i]); + } +#endif + } + /* build/process the config block, type == CONFIG (could be precomputed for each key) */ + ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ + Skein_Start_New_Type(ctx,CFG_FINAL); + + memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */ + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); + cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ + cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ + + Skein_Show_Key(256,&ctx->h,key,keyBytes); + + /* compute the initial chaining values from config block */ + Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); + + /* The chaining vars ctx->X are now initialized */ + /* Set up to process the data message portion of the hash (default) */ + ctx->h.bCnt = 0; /* buffer b[] starts out empty */ + Skein_Start_New_Type(ctx,MSG); + + return SKEIN_SUCCESS; + } +#endif + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* process the input bytes */ +static int Skein_256_Update(Skein_256_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt) + { + size_t n; + + Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + /* process full blocks, if any */ + if (msgByteCnt + ctx->h.bCnt > SKEIN_256_BLOCK_BYTES) + { + if (ctx->h.bCnt) /* finish up any buffered message data */ + { + n = SKEIN_256_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */ + if (n) + { + Skein_assert(n < msgByteCnt); /* check on our logic here */ + memcpy(&ctx->b[ctx->h.bCnt],msg,n); + msgByteCnt -= n; + msg += n; + ctx->h.bCnt += n; + } + Skein_assert(ctx->h.bCnt == SKEIN_256_BLOCK_BYTES); + Skein_256_Process_Block(ctx,ctx->b,1,SKEIN_256_BLOCK_BYTES); + ctx->h.bCnt = 0; + } + /* now process any remaining full blocks, directly from input message data */ + if (msgByteCnt > SKEIN_256_BLOCK_BYTES) + { + n = (msgByteCnt-1) / SKEIN_256_BLOCK_BYTES; /* number of full blocks to process */ + Skein_256_Process_Block(ctx,msg,n,SKEIN_256_BLOCK_BYTES); + msgByteCnt -= n * SKEIN_256_BLOCK_BYTES; + msg += n * SKEIN_256_BLOCK_BYTES; + } + Skein_assert(ctx->h.bCnt == 0); + } + + /* copy any remaining source message data bytes into b[] */ + if (msgByteCnt) + { + Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES); + memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt); + ctx->h.bCnt += msgByteCnt; + } + + return SKEIN_SUCCESS; + } + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the result */ +static int Skein_256_Final(Skein_256_Ctxt_t *ctx, u08b_t *hashVal) + { + size_t i,n,byteCnt; + u64b_t X[SKEIN_256_STATE_WORDS]; + Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ + if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES) /* zero pad b[] if necessary */ + memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt); + + Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ + + /* now output the result */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ + + /* run Threefish in "counter mode" to generate output */ + memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ + memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ + for (i=0;i < byteCnt;i += SKEIN_256_BLOCK_BYTES) + { + ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ + Skein_Start_New_Type(ctx,OUT_FINAL); + Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ + n = byteCnt - i; /* number of output bytes left to go */ + if (n >= SKEIN_256_BLOCK_BYTES) + n = SKEIN_256_BLOCK_BYTES; + Skein_Put64_LSB_First(hashVal+i,ctx->X,n); /* "output" the ctr mode bytes */ + Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES); + memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ + } + return SKEIN_SUCCESS; + } + +#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) +static size_t Skein_256_API_CodeSize(void) + { + return ((u08b_t *) Skein_256_API_CodeSize) - + ((u08b_t *) Skein_256_Init); + } +#endif + +/*****************************************************************/ +/* 512-bit Skein */ +/*****************************************************************/ + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a straight hashing operation */ +static int Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen) + { + union + { + u08b_t b[SKEIN_512_STATE_BYTES]; + u64b_t w[SKEIN_512_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); + ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ + + switch (hashBitLen) + { /* use pre-computed values, where available */ +#ifndef SKEIN_NO_PRECOMP + case 512: memcpy(ctx->X,SKEIN_512_IV_512,sizeof(ctx->X)); break; + case 384: memcpy(ctx->X,SKEIN_512_IV_384,sizeof(ctx->X)); break; + case 256: memcpy(ctx->X,SKEIN_512_IV_256,sizeof(ctx->X)); break; + case 224: memcpy(ctx->X,SKEIN_512_IV_224,sizeof(ctx->X)); break; +#endif + default: + /* here if there is no precomputed IV value available */ + /* build/process the config block, type == CONFIG (could be precomputed) */ + Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */ + + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */ + cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ + cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); + memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */ + + /* compute the initial chaining values from config block */ + memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */ + Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); + break; + } + + /* The chaining vars ctx->X are now initialized for the given hashBitLen. */ + /* Set up to process the data message portion of the hash (default) */ + Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type */ + + return SKEIN_SUCCESS; + } + +#if 0 +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a MAC and/or tree hash operation */ +/* [identical to Skein_512_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */ +static int Skein_512_InitExt(Skein_512_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes) + { + union + { + u08b_t b[SKEIN_512_STATE_BYTES]; + u64b_t w[SKEIN_512_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); + Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL); + + /* compute the initial chaining values ctx->X[], based on key */ + if (keyBytes == 0) /* is there a key? */ + { + memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */ + } + else /* here to pre-process a key */ + { + Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X)); + /* do a mini-Init right here */ + ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */ + Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */ + memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */ + Skein_512_Update(ctx,key,keyBytes); /* hash the key */ + Skein_512_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */ + memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */ +#if SKEIN_NEED_SWAP + { + uint_t i; + for (i=0;iX[i] = Skein_Swap64(ctx->X[i]); + } +#endif + } + /* build/process the config block, type == CONFIG (could be precomputed for each key) */ + ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ + Skein_Start_New_Type(ctx,CFG_FINAL); + + memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */ + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); + cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ + cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ + + Skein_Show_Key(512,&ctx->h,key,keyBytes); + + /* compute the initial chaining values from config block */ + Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); + + /* The chaining vars ctx->X are now initialized */ + /* Set up to process the data message portion of the hash (default) */ + ctx->h.bCnt = 0; /* buffer b[] starts out empty */ + Skein_Start_New_Type(ctx,MSG); + + return SKEIN_SUCCESS; + } +#endif + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* process the input bytes */ +static int Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt) + { + size_t n; + + Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + /* process full blocks, if any */ + if (msgByteCnt + ctx->h.bCnt > SKEIN_512_BLOCK_BYTES) + { + if (ctx->h.bCnt) /* finish up any buffered message data */ + { + n = SKEIN_512_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */ + if (n) + { + Skein_assert(n < msgByteCnt); /* check on our logic here */ + memcpy(&ctx->b[ctx->h.bCnt],msg,n); + msgByteCnt -= n; + msg += n; + ctx->h.bCnt += n; + } + Skein_assert(ctx->h.bCnt == SKEIN_512_BLOCK_BYTES); + Skein_512_Process_Block(ctx,ctx->b,1,SKEIN_512_BLOCK_BYTES); + ctx->h.bCnt = 0; + } + /* now process any remaining full blocks, directly from input message data */ + if (msgByteCnt > SKEIN_512_BLOCK_BYTES) + { + n = (msgByteCnt-1) / SKEIN_512_BLOCK_BYTES; /* number of full blocks to process */ + Skein_512_Process_Block(ctx,msg,n,SKEIN_512_BLOCK_BYTES); + msgByteCnt -= n * SKEIN_512_BLOCK_BYTES; + msg += n * SKEIN_512_BLOCK_BYTES; + } + Skein_assert(ctx->h.bCnt == 0); + } + + /* copy any remaining source message data bytes into b[] */ + if (msgByteCnt) + { + Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES); + memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt); + ctx->h.bCnt += msgByteCnt; + } + + return SKEIN_SUCCESS; + } + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the result */ +static int Skein_512_Final(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) + { + size_t i,n,byteCnt; + u64b_t X[SKEIN_512_STATE_WORDS]; + Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ + if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) /* zero pad b[] if necessary */ + memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt); + + Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ + + /* now output the result */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ + + /* run Threefish in "counter mode" to generate output */ + memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ + memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ + for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++) + { + ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ + Skein_Start_New_Type(ctx,OUT_FINAL); + Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ + n = byteCnt - i*SKEIN_512_BLOCK_BYTES; /* number of output bytes left to go */ + if (n >= SKEIN_512_BLOCK_BYTES) + n = SKEIN_512_BLOCK_BYTES; + Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ + Skein_Show_Final(512,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES); + memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ + } + return SKEIN_SUCCESS; + } + +#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) +static size_t Skein_512_API_CodeSize(void) + { + return ((u08b_t *) Skein_512_API_CodeSize) - + ((u08b_t *) Skein_512_Init); + } +#endif + +/*****************************************************************/ +/* 1024-bit Skein */ +/*****************************************************************/ +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a straight hashing operation */ +static int Skein1024_Init(Skein1024_Ctxt_t *ctx, size_t hashBitLen) + { + union + { + u08b_t b[SKEIN1024_STATE_BYTES]; + u64b_t w[SKEIN1024_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); + ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ + + switch (hashBitLen) + { /* use pre-computed values, where available */ +#ifndef SKEIN_NO_PRECOMP + case 512: memcpy(ctx->X,SKEIN1024_IV_512 ,sizeof(ctx->X)); break; + case 384: memcpy(ctx->X,SKEIN1024_IV_384 ,sizeof(ctx->X)); break; + case 1024: memcpy(ctx->X,SKEIN1024_IV_1024,sizeof(ctx->X)); break; +#endif + default: + /* here if there is no precomputed IV value available */ + /* build/process the config block, type == CONFIG (could be precomputed) */ + Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */ + + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */ + cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ + cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); + memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */ + + /* compute the initial chaining values from config block */ + memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */ + Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); + break; + } + + /* The chaining vars ctx->X are now initialized for the given hashBitLen. */ + /* Set up to process the data message portion of the hash (default) */ + Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type */ + + return SKEIN_SUCCESS; + } + +#if 0 +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a MAC and/or tree hash operation */ +/* [identical to Skein1024_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */ +static int Skein1024_InitExt(Skein1024_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes) + { + union + { + u08b_t b[SKEIN1024_STATE_BYTES]; + u64b_t w[SKEIN1024_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); + Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL); + + /* compute the initial chaining values ctx->X[], based on key */ + if (keyBytes == 0) /* is there a key? */ + { + memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */ + } + else /* here to pre-process a key */ + { + Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X)); + /* do a mini-Init right here */ + ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */ + Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */ + memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */ + Skein1024_Update(ctx,key,keyBytes); /* hash the key */ + Skein1024_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */ + memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */ +#if SKEIN_NEED_SWAP + { + uint_t i; + for (i=0;iX[i] = Skein_Swap64(ctx->X[i]); + } +#endif + } + /* build/process the config block, type == CONFIG (could be precomputed for each key) */ + ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ + Skein_Start_New_Type(ctx,CFG_FINAL); + + memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */ + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); + cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ + cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ + + Skein_Show_Key(1024,&ctx->h,key,keyBytes); + + /* compute the initial chaining values from config block */ + Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); + + /* The chaining vars ctx->X are now initialized */ + /* Set up to process the data message portion of the hash (default) */ + ctx->h.bCnt = 0; /* buffer b[] starts out empty */ + Skein_Start_New_Type(ctx,MSG); + + return SKEIN_SUCCESS; + } +#endif + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* process the input bytes */ +static int Skein1024_Update(Skein1024_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt) + { + size_t n; + + Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + /* process full blocks, if any */ + if (msgByteCnt + ctx->h.bCnt > SKEIN1024_BLOCK_BYTES) + { + if (ctx->h.bCnt) /* finish up any buffered message data */ + { + n = SKEIN1024_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */ + if (n) + { + Skein_assert(n < msgByteCnt); /* check on our logic here */ + memcpy(&ctx->b[ctx->h.bCnt],msg,n); + msgByteCnt -= n; + msg += n; + ctx->h.bCnt += n; + } + Skein_assert(ctx->h.bCnt == SKEIN1024_BLOCK_BYTES); + Skein1024_Process_Block(ctx,ctx->b,1,SKEIN1024_BLOCK_BYTES); + ctx->h.bCnt = 0; + } + /* now process any remaining full blocks, directly from input message data */ + if (msgByteCnt > SKEIN1024_BLOCK_BYTES) + { + n = (msgByteCnt-1) / SKEIN1024_BLOCK_BYTES; /* number of full blocks to process */ + Skein1024_Process_Block(ctx,msg,n,SKEIN1024_BLOCK_BYTES); + msgByteCnt -= n * SKEIN1024_BLOCK_BYTES; + msg += n * SKEIN1024_BLOCK_BYTES; + } + Skein_assert(ctx->h.bCnt == 0); + } + + /* copy any remaining source message data bytes into b[] */ + if (msgByteCnt) + { + Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES); + memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt); + ctx->h.bCnt += msgByteCnt; + } + + return SKEIN_SUCCESS; + } + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the result */ +static int Skein1024_Final(Skein1024_Ctxt_t *ctx, u08b_t *hashVal) + { + size_t i,n,byteCnt; + u64b_t X[SKEIN1024_STATE_WORDS]; + Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ + if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES) /* zero pad b[] if necessary */ + memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt); + + Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ + + /* now output the result */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ + + /* run Threefish in "counter mode" to generate output */ + memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ + memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ + for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++) + { + ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ + Skein_Start_New_Type(ctx,OUT_FINAL); + Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ + n = byteCnt - i*SKEIN1024_BLOCK_BYTES; /* number of output bytes left to go */ + if (n >= SKEIN1024_BLOCK_BYTES) + n = SKEIN1024_BLOCK_BYTES; + Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ + Skein_Show_Final(1024,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES); + memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ + } + return SKEIN_SUCCESS; + } + +#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) +static size_t Skein1024_API_CodeSize(void) + { + return ((u08b_t *) Skein1024_API_CodeSize) - + ((u08b_t *) Skein1024_Init); + } +#endif + +/**************** Functions to support MAC/tree hashing ***************/ +/* (this code is identical for Optimized and Reference versions) */ + +#if 0 +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the block, no OUTPUT stage */ +static int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, u08b_t *hashVal) + { + Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ + if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES) /* zero pad b[] if necessary */ + memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt); + Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ + + Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_256_BLOCK_BYTES); /* "output" the state bytes */ + + return SKEIN_SUCCESS; + } + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the block, no OUTPUT stage */ +static int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) + { + Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ + if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) /* zero pad b[] if necessary */ + memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt); + Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ + + Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_512_BLOCK_BYTES); /* "output" the state bytes */ + + return SKEIN_SUCCESS; + } + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the block, no OUTPUT stage */ +static int Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, u08b_t *hashVal) + { + Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ + if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES) /* zero pad b[] if necessary */ + memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt); + Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ + + Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN1024_BLOCK_BYTES); /* "output" the state bytes */ + + return SKEIN_SUCCESS; + } + + +#if SKEIN_TREE_HASH +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* just do the OUTPUT stage */ +static int Skein_256_Output(Skein_256_Ctxt_t *ctx, u08b_t *hashVal) + { + size_t i,n,byteCnt; + u64b_t X[SKEIN_256_STATE_WORDS]; + Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + /* now output the result */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ + + /* run Threefish in "counter mode" to generate output */ + memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ + memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ + for (i=0;i*SKEIN_256_BLOCK_BYTES < byteCnt;i++) + { + ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ + Skein_Start_New_Type(ctx,OUT_FINAL); + Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ + n = byteCnt - i*SKEIN_256_BLOCK_BYTES; /* number of output bytes left to go */ + if (n >= SKEIN_256_BLOCK_BYTES) + n = SKEIN_256_BLOCK_BYTES; + Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ + Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES); + memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ + } + return SKEIN_SUCCESS; + } + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* just do the OUTPUT stage */ +static int Skein_512_Output(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) + { + size_t i,n,byteCnt; + u64b_t X[SKEIN_512_STATE_WORDS]; + Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + /* now output the result */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ + + /* run Threefish in "counter mode" to generate output */ + memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ + memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ + for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++) + { + ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ + Skein_Start_New_Type(ctx,OUT_FINAL); + Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ + n = byteCnt - i*SKEIN_512_BLOCK_BYTES; /* number of output bytes left to go */ + if (n >= SKEIN_512_BLOCK_BYTES) + n = SKEIN_512_BLOCK_BYTES; + Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ + Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES); + memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ + } + return SKEIN_SUCCESS; + } + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* just do the OUTPUT stage */ +static int Skein1024_Output(Skein1024_Ctxt_t *ctx, u08b_t *hashVal) + { + size_t i,n,byteCnt; + u64b_t X[SKEIN1024_STATE_WORDS]; + Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + /* now output the result */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ + + /* run Threefish in "counter mode" to generate output */ + memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ + memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ + for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++) + { + ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ + Skein_Start_New_Type(ctx,OUT_FINAL); + Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ + n = byteCnt - i*SKEIN1024_BLOCK_BYTES; /* number of output bytes left to go */ + if (n >= SKEIN1024_BLOCK_BYTES) + n = SKEIN1024_BLOCK_BYTES; + Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ + Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES); + memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ + } + return SKEIN_SUCCESS; + } +#endif +#endif + +typedef struct +{ + uint_t statebits; /* 256, 512, or 1024 */ + union + { + Skein_Ctxt_Hdr_t h; /* common header "overlay" */ + Skein_256_Ctxt_t ctx_256; + Skein_512_Ctxt_t ctx_512; + Skein1024_Ctxt_t ctx1024; + } u; +} +hashState; + +/* "incremental" hashing API */ +static SkeinHashReturn Init (hashState *state, int hashbitlen); +static SkeinHashReturn Update(hashState *state, const SkeinBitSequence *data, SkeinDataLength databitlen); +static SkeinHashReturn Final (hashState *state, SkeinBitSequence *hashval); + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* select the context size and init the context */ +static SkeinHashReturn Init(hashState *state, int hashbitlen) +{ +#if SKEIN_256_NIST_MAX_HASH_BITS + if (hashbitlen <= SKEIN_256_NIST_MAX_HASHBITS) + { + Skein_Assert(hashbitlen > 0,BAD_HASHLEN); + state->statebits = 64*SKEIN_256_STATE_WORDS; + return Skein_256_Init(&state->u.ctx_256,(size_t) hashbitlen); + } +#endif + if (hashbitlen <= SKEIN_512_NIST_MAX_HASHBITS) + { + state->statebits = 64*SKEIN_512_STATE_WORDS; + return Skein_512_Init(&state->u.ctx_512,(size_t) hashbitlen); + } + else + { + state->statebits = 64*SKEIN1024_STATE_WORDS; + return Skein1024_Init(&state->u.ctx1024,(size_t) hashbitlen); + } +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* process data to be hashed */ +static SkeinHashReturn Update(hashState *state, const SkeinBitSequence *data, SkeinDataLength databitlen) +{ + /* only the final Update() call is allowed do partial bytes, else assert an error */ + Skein_Assert((state->u.h.T[1] & SKEIN_T1_FLAG_BIT_PAD) == 0 || databitlen == 0, SKEIN_FAIL); + + Skein_Assert(state->statebits % 256 == 0 && (state->statebits-256) < 1024,SKEIN_FAIL); + if ((databitlen & 7) == 0) /* partial bytes? */ + { + switch ((state->statebits >> 8) & 3) + { + case 2: return Skein_512_Update(&state->u.ctx_512,data,databitlen >> 3); + case 1: return Skein_256_Update(&state->u.ctx_256,data,databitlen >> 3); + case 0: return Skein1024_Update(&state->u.ctx1024,data,databitlen >> 3); + default: return SKEIN_FAIL; + } + } + else + { /* handle partial final byte */ + size_t bCnt = (databitlen >> 3) + 1; /* number of bytes to handle (nonzero here!) */ + u08b_t b,mask; + + mask = (u08b_t) (1u << (7 - (databitlen & 7))); /* partial byte bit mask */ + b = (u08b_t) ((data[bCnt-1] & (0-mask)) | mask); /* apply bit padding on final byte */ + + switch ((state->statebits >> 8) & 3) + { + case 2: Skein_512_Update(&state->u.ctx_512,data,bCnt-1); /* process all but the final byte */ + Skein_512_Update(&state->u.ctx_512,&b , 1 ); /* process the (masked) partial byte */ + break; + case 1: Skein_256_Update(&state->u.ctx_256,data,bCnt-1); /* process all but the final byte */ + Skein_256_Update(&state->u.ctx_256,&b , 1 ); /* process the (masked) partial byte */ + break; + case 0: Skein1024_Update(&state->u.ctx1024,data,bCnt-1); /* process all but the final byte */ + Skein1024_Update(&state->u.ctx1024,&b , 1 ); /* process the (masked) partial byte */ + break; + default: return SKEIN_FAIL; + } + Skein_Set_Bit_Pad_Flag(state->u.h); /* set tweak flag for the final call */ + + return SKEIN_SUCCESS; + } +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize hash computation and output the result (hashbitlen bits) */ +static SkeinHashReturn Final(hashState *state, SkeinBitSequence *hashval) +{ + Skein_Assert(state->statebits % 256 == 0 && (state->statebits-256) < 1024,FAIL); + switch ((state->statebits >> 8) & 3) + { + case 2: return Skein_512_Final(&state->u.ctx_512,hashval); + case 1: return Skein_256_Final(&state->u.ctx_256,hashval); + case 0: return Skein1024_Final(&state->u.ctx1024,hashval); + default: return SKEIN_FAIL; + } +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* all-in-one hash function */ +SkeinHashReturn skein(int hashbitlen, const SkeinBitSequence *data, /* all-in-one call */ + SkeinDataLength databitlen,SkeinBitSequence *hashval) +{ + hashState state; + SkeinHashReturn r = Init(&state,hashbitlen); + if (r == SKEIN_SUCCESS) + { /* these calls do not fail when called properly */ + r = Update(&state,data,databitlen); + Final(&state,hashval); + } + return r; +} diff --git a/webassembly/aeon/skein.h b/webassembly/aeon/skein.h new file mode 100644 index 0000000..e672479 --- /dev/null +++ b/webassembly/aeon/skein.h @@ -0,0 +1,15 @@ +#ifndef SKEIN_H +#define SKEIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern int skein(int hashbitlen, const unsigned char *input, + size_t input_len, unsigned char *output); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/webassembly/aeon/skein_port.h b/webassembly/aeon/skein_port.h new file mode 100644 index 0000000..9cbefcb --- /dev/null +++ b/webassembly/aeon/skein_port.h @@ -0,0 +1,179 @@ +#ifndef _SKEIN_PORT_H_ +#define _SKEIN_PORT_H_ + +#include +#include +#include + +#ifndef RETURN_VALUES +# define RETURN_VALUES +# if defined( DLL_EXPORT ) +# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) +# define VOID_RETURN __declspec( dllexport ) void __stdcall +# define INT_RETURN __declspec( dllexport ) int __stdcall +# elif defined( __GNUC__ ) +# define VOID_RETURN __declspec( __dllexport__ ) void +# define INT_RETURN __declspec( __dllexport__ ) int +# else +# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers +# endif +# elif defined( DLL_IMPORT ) +# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) +# define VOID_RETURN __declspec( dllimport ) void __stdcall +# define INT_RETURN __declspec( dllimport ) int __stdcall +# elif defined( __GNUC__ ) +# define VOID_RETURN __declspec( __dllimport__ ) void +# define INT_RETURN __declspec( __dllimport__ ) int +# else +# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers +# endif +# elif defined( __WATCOMC__ ) +# define VOID_RETURN void __cdecl +# define INT_RETURN int __cdecl +# else +# define VOID_RETURN void +# define INT_RETURN int +# endif +#endif + +/* These defines are used to declare buffers in a way that allows + faster operations on longer variables to be used. In all these + defines 'size' must be a power of 2 and >= 8 + + dec_unit_type(size,x) declares a variable 'x' of length + 'size' bits + + dec_bufr_type(size,bsize,x) declares a buffer 'x' of length 'bsize' + bytes defined as an array of variables + each of 'size' bits (bsize must be a + multiple of size / 8) + + ptr_cast(x,size) casts a pointer to a pointer to a + varaiable of length 'size' bits +*/ + +#define ui_type(size) uint##size##_t +#define dec_unit_type(size,x) typedef ui_type(size) x +#define dec_bufr_type(size,bsize,x) typedef ui_type(size) x[bsize / (size >> 3)] +#define ptr_cast(x,size) ((ui_type(size)*)(x)) + +typedef unsigned int uint_t; /* native unsigned integer */ +typedef uint8_t u08b_t; /* 8-bit unsigned integer */ +typedef uint64_t u64b_t; /* 64-bit unsigned integer */ + +#ifndef RotL_64 +#define RotL_64(x,N) (((x) << (N)) | ((x) >> (64-(N)))) +#endif + +/* + * Skein is "natively" little-endian (unlike SHA-xxx), for optimal + * performance on x86 CPUs. The Skein code requires the following + * definitions for dealing with endianness: + * + * SKEIN_NEED_SWAP: 0 for little-endian, 1 for big-endian + * Skein_Put64_LSB_First + * Skein_Get64_LSB_First + * Skein_Swap64 + * + * If SKEIN_NEED_SWAP is defined at compile time, it is used here + * along with the portable versions of Put64/Get64/Swap64, which + * are slow in general. + * + * Otherwise, an "auto-detect" of endianness is attempted below. + * If the default handling doesn't work well, the user may insert + * platform-specific code instead (e.g., for big-endian CPUs). + * + */ +#ifndef SKEIN_NEED_SWAP /* compile-time "override" for endianness? */ + +#define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN + +/* special handler for IA64, which may be either endianness (?) */ +/* here we assume little-endian, but this may need to be changed */ +#if defined(__ia64) || defined(__ia64__) || defined(_M_IA64) +# define PLATFORM_MUST_ALIGN (1) +#ifndef PLATFORM_BYTE_ORDER +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif +#endif + +#ifndef PLATFORM_MUST_ALIGN +# define PLATFORM_MUST_ALIGN (0) +#endif + + +#if PLATFORM_BYTE_ORDER == IS_BIG_ENDIAN + /* here for big-endian CPUs */ +#define SKEIN_NEED_SWAP (1) +#elif PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN + /* here for x86 and x86-64 CPUs (and other detected little-endian CPUs) */ +#define SKEIN_NEED_SWAP (0) +#if PLATFORM_MUST_ALIGN == 0 /* ok to use "fast" versions? */ +#define Skein_Put64_LSB_First(dst08,src64,bCnt) memcpy(dst08,src64,bCnt) +#define Skein_Get64_LSB_First(dst64,src08,wCnt) memcpy(dst64,src08,8*(wCnt)) +#endif +#else +#error "Skein needs endianness setting!" +#endif + +#endif /* ifndef SKEIN_NEED_SWAP */ + +/* + ****************************************************************** + * Provide any definitions still needed. + ****************************************************************** + */ +#ifndef Skein_Swap64 /* swap for big-endian, nop for little-endian */ +#if SKEIN_NEED_SWAP +#define Skein_Swap64(w64) \ + ( (( ((u64b_t)(w64)) & 0xFF) << 56) | \ + (((((u64b_t)(w64)) >> 8) & 0xFF) << 48) | \ + (((((u64b_t)(w64)) >>16) & 0xFF) << 40) | \ + (((((u64b_t)(w64)) >>24) & 0xFF) << 32) | \ + (((((u64b_t)(w64)) >>32) & 0xFF) << 24) | \ + (((((u64b_t)(w64)) >>40) & 0xFF) << 16) | \ + (((((u64b_t)(w64)) >>48) & 0xFF) << 8) | \ + (((((u64b_t)(w64)) >>56) & 0xFF) ) ) +#else +#define Skein_Swap64(w64) (w64) +#endif +#endif /* ifndef Skein_Swap64 */ + + +#ifndef Skein_Put64_LSB_First +void Skein_Put64_LSB_First(u08b_t *dst,const u64b_t *src,size_t bCnt) +#ifdef SKEIN_PORT_CODE /* instantiate the function code here? */ + { /* this version is fully portable (big-endian or little-endian), but slow */ + size_t n; + + for (n=0;n>3] >> (8*(n&7))); + } +#else + ; /* output only the function prototype */ +#endif +#endif /* ifndef Skein_Put64_LSB_First */ + + +#ifndef Skein_Get64_LSB_First +void Skein_Get64_LSB_First(u64b_t *dst,const u08b_t *src,size_t wCnt) +#ifdef SKEIN_PORT_CODE /* instantiate the function code here? */ + { /* this version is fully portable (big-endian or little-endian), but slow */ + size_t n; + + for (n=0;n<8*wCnt;n+=8) + dst[n/8] = (((u64b_t) src[n ]) ) + + (((u64b_t) src[n+1]) << 8) + + (((u64b_t) src[n+2]) << 16) + + (((u64b_t) src[n+3]) << 24) + + (((u64b_t) src[n+4]) << 32) + + (((u64b_t) src[n+5]) << 40) + + (((u64b_t) src[n+6]) << 48) + + (((u64b_t) src[n+7]) << 56) ; + } +#else + ; /* output only the function prototype */ +#endif +#endif /* ifndef Skein_Get64_LSB_First */ + +#endif /* ifndef _SKEIN_PORT_H_ */ diff --git a/webassembly/xmr/Makefile b/webassembly/xmr/Makefile new file mode 100644 index 0000000..4adcad4 --- /dev/null +++ b/webassembly/xmr/Makefile @@ -0,0 +1,28 @@ +TARGET = prog +LIBS = -lm +CC = emcc -O3 -s SINGLE_FILE=1 -s NO_FILESYSTEM=1 -s 'EXTRA_EXPORTED_RUNTIME_METHODS=["ccall", "cwrap"]' --llvm-lto 1 -s TOTAL_MEMORY=67108864 -s WASM=1 -s "BINARYEN_TRAP_MODE='allow'" -s EXPORTED_FUNCTIONS="['_hash_cn']" --shell-file html_template/shell_minimal.html +CFLAGS = -Wall -msse2 + + +# SINGLE_FILE=1 + +# -s ASSERTIONS=1 +# -s SINGLE_FILE=1 +.PHONY: default all clean + +default: $(TARGET) +all: default + +OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c)) +HEADERS = $(wildcard *.h) + +%.o: %.c $(HEADERS) $(CC) $(CFLAGS) -c $< -o $@ + +.PRECIOUS: $(TARGET) $(OBJECTS) + +$(TARGET): $(OBJECTS) + $(CC) $(OBJECTS) -Wall $(LIBS) -o cn.html + +clean: + -rm -f *.o + -rm -f $(TARGET) diff --git a/webassembly/xmr/base64.h b/webassembly/xmr/base64.h new file mode 100644 index 0000000..e1362bd --- /dev/null +++ b/webassembly/xmr/base64.h @@ -0,0 +1,258 @@ +// https://github.com/tkislan/base64 + +#ifndef BASE64_H +#define BASE64_H + +#include + +const char kBase64Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +class Base64 { + public: + static bool Encode(const std::string &in, std::string *out) { + int i = 0, j = 0; + size_t enc_len = 0; + unsigned char a3[3]; + unsigned char a4[4]; + + out->resize(EncodedLength(in)); + + int input_len = in.size(); + std::string::const_iterator input = in.begin(); + + while (input_len--) { + a3[i++] = *(input++); + if (i == 3) { + a3_to_a4(a4, a3); + + for (i = 0; i < 4; i++) { + (*out)[enc_len++] = kBase64Alphabet[a4[i]]; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 3; j++) { + a3[j] = '\0'; + } + + a3_to_a4(a4, a3); + + for (j = 0; j < i + 1; j++) { + (*out)[enc_len++] = kBase64Alphabet[a4[j]]; + } + + while ((i++ < 3)) { + (*out)[enc_len++] = '='; + } + } + + return (enc_len == out->size()); + } + + static bool Encode(const char *input, size_t input_length, char *out, size_t out_length) { + int i = 0, j = 0; + char *out_begin = out; + unsigned char a3[3]; + unsigned char a4[4]; + + size_t encoded_length = EncodedLength(input_length); + + if (out_length < encoded_length) return false; + + while (input_length--) { + a3[i++] = *input++; + if (i == 3) { + a3_to_a4(a4, a3); + + for (i = 0; i < 4; i++) { + *out++ = kBase64Alphabet[a4[i]]; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 3; j++) { + a3[j] = '\0'; + } + + a3_to_a4(a4, a3); + + for (j = 0; j < i + 1; j++) { + *out++ = kBase64Alphabet[a4[j]]; + } + + while ((i++ < 3)) { + *out++ = '='; + } + } + + return (out == (out_begin + encoded_length)); + } + + static bool Decode(const std::string &in, std::string *out) { + int i = 0, j = 0; + size_t dec_len = 0; + unsigned char a3[3]; + unsigned char a4[4]; + + int input_len = in.size(); + std::string::const_iterator input = in.begin(); + + out->resize(DecodedLength(in)); + + while (input_len--) { + if (*input == '=') { + break; + } + + a4[i++] = *(input++); + if (i == 4) { + for (i = 0; i <4; i++) { + a4[i] = b64_lookup(a4[i]); + } + + a4_to_a3(a3,a4); + + for (i = 0; i < 3; i++) { + (*out)[dec_len++] = a3[i]; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) { + a4[j] = '\0'; + } + + for (j = 0; j < 4; j++) { + a4[j] = b64_lookup(a4[j]); + } + + a4_to_a3(a3,a4); + + for (j = 0; j < i - 1; j++) { + (*out)[dec_len++] = a3[j]; + } + } + + return (dec_len == out->size()); + } + + static bool Decode(const char *input, size_t input_length, char *out, size_t out_length) { + int i = 0, j = 0; + char *out_begin = out; + unsigned char a3[3]; + unsigned char a4[4]; + + size_t decoded_length = DecodedLength(input, input_length); + + if (out_length < decoded_length) return false; + + while (input_length--) { + if (*input == '=') { + break; + } + + a4[i++] = *(input++); + if (i == 4) { + for (i = 0; i <4; i++) { + a4[i] = b64_lookup(a4[i]); + } + + a4_to_a3(a3,a4); + + for (i = 0; i < 3; i++) { + *out++ = a3[i]; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) { + a4[j] = '\0'; + } + + for (j = 0; j < 4; j++) { + a4[j] = b64_lookup(a4[j]); + } + + a4_to_a3(a3,a4); + + for (j = 0; j < i - 1; j++) { + *out++ = a3[j]; + } + } + + return (out == (out_begin + decoded_length)); + } + + static int DecodedLength(const char *in, size_t in_length) { + int numEq = 0; + + const char *in_end = in + in_length; + while (*--in_end == '=') ++numEq; + + return ((6 * in_length) / 8) - numEq; + } + + static int DecodedLength(const std::string &in) { + int numEq = 0; + int n = in.size(); + + for (std::string::const_reverse_iterator it = in.rbegin(); *it == '='; ++it) { + ++numEq; + } + + return ((6 * n) / 8) - numEq; + } + + inline static int EncodedLength(size_t length) { + return (length + 2 - ((length + 2) % 3)) / 3 * 4; + } + + inline static int EncodedLength(const std::string &in) { + return EncodedLength(in.length()); + } + + inline static void StripPadding(std::string *in) { + while (!in->empty() && *(in->rbegin()) == '=') in->resize(in->size() - 1); + } + + private: + static inline void a3_to_a4(unsigned char * a4, unsigned char * a3) { + a4[0] = (a3[0] & 0xfc) >> 2; + a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); + a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); + a4[3] = (a3[2] & 0x3f); + } + + static inline void a4_to_a3(unsigned char * a3, unsigned char * a4) { + a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); + a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); + a3[2] = ((a4[2] & 0x3) << 6) + a4[3]; + } + + static inline unsigned char b64_lookup(unsigned char c) { + if(c >='A' && c <='Z') return c - 'A'; + if(c >='a' && c <='z') return c - 71; + if(c >='0' && c <='9') return c + 4; + if(c == '+') return 62; + if(c == '/') return 63; + return 255; + } +}; + + + +#endif // BASE64_H diff --git a/webassembly/xmr/blake.c b/webassembly/xmr/blake.c new file mode 100644 index 0000000..464a0de --- /dev/null +++ b/webassembly/xmr/blake.c @@ -0,0 +1,341 @@ +/* + * The blake256_* and blake224_* functions are largely copied from + * blake256_light.c and blake224_light.c from the BLAKE website: + * + * http://131002.net/blake/ + * + * The hmac_* functions implement HMAC-BLAKE-256 and HMAC-BLAKE-224. + * HMAC is specified by RFC 2104. + */ + +#include +#include + +typedef struct { + uint32_t h[8], s[4], t[2]; + int buflen, nullt; + uint8_t buf[64]; +} state; + +typedef struct { + state inner; + state outer; +} hmac_state; + + +#define U8TO32(p) \ + (((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | \ + ((uint32_t)((p)[2]) << 8) | ((uint32_t)((p)[3]) )) +#define U32TO8(p, v) \ + (p)[0] = (uint8_t)((v) >> 24); (p)[1] = (uint8_t)((v) >> 16); \ + (p)[2] = (uint8_t)((v) >> 8); (p)[3] = (uint8_t)((v) ); + +const uint8_t sigma[][16] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15}, + {14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3}, + {11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4}, + { 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8}, + { 9, 0, 5, 7, 2, 4,10,15,14, 1,11,12, 6, 8, 3,13}, + { 2,12, 6,10, 0,11, 8, 3, 4,13, 7, 5,15,14, 1, 9}, + {12, 5, 1,15,14,13, 4,10, 0, 7, 6, 3, 9, 2, 8,11}, + {13,11, 7,14,12, 1, 3, 9, 5, 0,15, 4, 8, 6, 2,10}, + { 6,15,14, 9,11, 3, 0, 8,12, 2,13, 7, 1, 4,10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5,15,11, 9,14, 3,12,13, 0}, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15}, + {14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3}, + {11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4}, + { 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8} +}; + +const uint32_t cst[16] = { + 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, + 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, + 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917 +}; + +static const uint8_t padding[] = { + 0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; + + +void blake256_compress(state *S, const uint8_t *block) { + uint32_t v[16], m[16], i; + +#define ROT(x,n) (((x)<<(32-n))|((x)>>(n))) +#define G(a,b,c,d,e) \ + v[a] += (m[sigma[i][e]] ^ cst[sigma[i][e+1]]) + v[b]; \ + v[d] = ROT(v[d] ^ v[a],16); \ + v[c] += v[d]; \ + v[b] = ROT(v[b] ^ v[c],12); \ + v[a] += (m[sigma[i][e+1]] ^ cst[sigma[i][e]])+v[b]; \ + v[d] = ROT(v[d] ^ v[a], 8); \ + v[c] += v[d]; \ + v[b] = ROT(v[b] ^ v[c], 7); + + for (i = 0; i < 16; ++i) m[i] = U8TO32(block + i * 4); + for (i = 0; i < 8; ++i) v[i] = S->h[i]; + v[ 8] = S->s[0] ^ 0x243F6A88; + v[ 9] = S->s[1] ^ 0x85A308D3; + v[10] = S->s[2] ^ 0x13198A2E; + v[11] = S->s[3] ^ 0x03707344; + v[12] = 0xA4093822; + v[13] = 0x299F31D0; + v[14] = 0x082EFA98; + v[15] = 0xEC4E6C89; + + if (S->nullt == 0) { + v[12] ^= S->t[0]; + v[13] ^= S->t[0]; + v[14] ^= S->t[1]; + v[15] ^= S->t[1]; + } + + for (i = 0; i < 14; ++i) { + G(0, 4, 8, 12, 0); + G(1, 5, 9, 13, 2); + G(2, 6, 10, 14, 4); + G(3, 7, 11, 15, 6); + G(3, 4, 9, 14, 14); + G(2, 7, 8, 13, 12); + G(0, 5, 10, 15, 8); + G(1, 6, 11, 12, 10); + } + + for (i = 0; i < 16; ++i) S->h[i % 8] ^= v[i]; + for (i = 0; i < 8; ++i) S->h[i] ^= S->s[i % 4]; +} + +void blake256_init(state *S) { + S->h[0] = 0x6A09E667; + S->h[1] = 0xBB67AE85; + S->h[2] = 0x3C6EF372; + S->h[3] = 0xA54FF53A; + S->h[4] = 0x510E527F; + S->h[5] = 0x9B05688C; + S->h[6] = 0x1F83D9AB; + S->h[7] = 0x5BE0CD19; + S->t[0] = S->t[1] = S->buflen = S->nullt = 0; + S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; +} + +void blake224_init(state *S) { + S->h[0] = 0xC1059ED8; + S->h[1] = 0x367CD507; + S->h[2] = 0x3070DD17; + S->h[3] = 0xF70E5939; + S->h[4] = 0xFFC00B31; + S->h[5] = 0x68581511; + S->h[6] = 0x64F98FA7; + S->h[7] = 0xBEFA4FA4; + S->t[0] = S->t[1] = S->buflen = S->nullt = 0; + S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; +} + +// datalen = number of bits +void blake256_update(state *S, const uint8_t *data, uint64_t datalen) { + int left = S->buflen >> 3; + int fill = 64 - left; + + if (left && (((datalen >> 3) & 0x3F) >= (unsigned) fill)) { + memcpy((void *) (S->buf + left), (void *) data, fill); + S->t[0] += 512; + if (S->t[0] == 0) S->t[1]++; + blake256_compress(S, S->buf); + data += fill; + datalen -= (fill << 3); + left = 0; + } + + while (datalen >= 512) { + S->t[0] += 512; + if (S->t[0] == 0) S->t[1]++; + blake256_compress(S, data); + data += 64; + datalen -= 512; + } + + if (datalen > 0) { + memcpy((void *) (S->buf + left), (void *) data, datalen >> 3); + S->buflen = (left << 3) + datalen; + } else { + S->buflen = 0; + } +} + +// datalen = number of bits +void blake224_update(state *S, const uint8_t *data, uint64_t datalen) { + blake256_update(S, data, datalen); +} + +void blake256_final_h(state *S, uint8_t *digest, uint8_t pa, uint8_t pb) { + uint8_t msglen[8]; + uint32_t lo = S->t[0] + S->buflen, hi = S->t[1]; + if (lo < (unsigned) S->buflen) hi++; + U32TO8(msglen + 0, hi); + U32TO8(msglen + 4, lo); + + if (S->buflen == 440) { /* one padding byte */ + S->t[0] -= 8; + blake256_update(S, &pa, 8); + } else { + if (S->buflen < 440) { /* enough space to fill the block */ + if (S->buflen == 0) S->nullt = 1; + S->t[0] -= 440 - S->buflen; + blake256_update(S, padding, 440 - S->buflen); + } else { /* need 2 compressions */ + S->t[0] -= 512 - S->buflen; + blake256_update(S, padding, 512 - S->buflen); + S->t[0] -= 440; + blake256_update(S, padding + 1, 440); + S->nullt = 1; + } + blake256_update(S, &pb, 8); + S->t[0] -= 8; + } + S->t[0] -= 64; + blake256_update(S, msglen, 64); + + U32TO8(digest + 0, S->h[0]); + U32TO8(digest + 4, S->h[1]); + U32TO8(digest + 8, S->h[2]); + U32TO8(digest + 12, S->h[3]); + U32TO8(digest + 16, S->h[4]); + U32TO8(digest + 20, S->h[5]); + U32TO8(digest + 24, S->h[6]); + U32TO8(digest + 28, S->h[7]); +} + +void blake256_final(state *S, uint8_t *digest) { + blake256_final_h(S, digest, 0x81, 0x01); +} + +void blake224_final(state *S, uint8_t *digest) { + blake256_final_h(S, digest, 0x80, 0x00); +} + +// inlen = number of bytes +void blake256_hash(uint8_t *out, const uint8_t *in, uint64_t inlen) { + state S; + blake256_init(&S); + blake256_update(&S, in, inlen * 8); + blake256_final(&S, out); +} + +void blake(const uint8_t *input, uint64_t len, uint8_t *output) +{ + blake256_hash(output, input, len); +} + +// inlen = number of bytes +void blake224_hash(uint8_t *out, const uint8_t *in, uint64_t inlen) { + state S; + blake224_init(&S); + blake224_update(&S, in, inlen * 8); + blake224_final(&S, out); +} + +// keylen = number of bytes +void hmac_blake256_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) { + const uint8_t *key = _key; + uint8_t keyhash[32]; + uint8_t pad[64]; + uint64_t i; + + if (keylen > 64) { + blake256_hash(keyhash, key, keylen); + key = keyhash; + keylen = 32; + } + + blake256_init(&S->inner); + memset(pad, 0x36, 64); + for (i = 0; i < keylen; ++i) { + pad[i] ^= key[i]; + } + blake256_update(&S->inner, pad, 512); + + blake256_init(&S->outer); + memset(pad, 0x5c, 64); + for (i = 0; i < keylen; ++i) { + pad[i] ^= key[i]; + } + blake256_update(&S->outer, pad, 512); + + memset(keyhash, 0, 32); +} + +// keylen = number of bytes +void hmac_blake224_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) { + const uint8_t *key = _key; + uint8_t keyhash[32]; + uint8_t pad[64]; + uint64_t i; + + if (keylen > 64) { + blake256_hash(keyhash, key, keylen); + key = keyhash; + keylen = 28; + } + + blake224_init(&S->inner); + memset(pad, 0x36, 64); + for (i = 0; i < keylen; ++i) { + pad[i] ^= key[i]; + } + blake224_update(&S->inner, pad, 512); + + blake224_init(&S->outer); + memset(pad, 0x5c, 64); + for (i = 0; i < keylen; ++i) { + pad[i] ^= key[i]; + } + blake224_update(&S->outer, pad, 512); + + memset(keyhash, 0, 32); +} + +// datalen = number of bits +void hmac_blake256_update(hmac_state *S, const uint8_t *data, uint64_t datalen) { + // update the inner state + blake256_update(&S->inner, data, datalen); +} + +// datalen = number of bits +void hmac_blake224_update(hmac_state *S, const uint8_t *data, uint64_t datalen) { + // update the inner state + blake224_update(&S->inner, data, datalen); +} + +void hmac_blake256_final(hmac_state *S, uint8_t *digest) { + uint8_t ihash[32]; + blake256_final(&S->inner, ihash); + blake256_update(&S->outer, ihash, 256); + blake256_final(&S->outer, digest); + memset(ihash, 0, 32); +} + +void hmac_blake224_final(hmac_state *S, uint8_t *digest) { + uint8_t ihash[32]; + blake224_final(&S->inner, ihash); + blake224_update(&S->outer, ihash, 224); + blake224_final(&S->outer, digest); + memset(ihash, 0, 32); +} + +// keylen = number of bytes; inlen = number of bytes +void hmac_blake256_hash(uint8_t *out, const uint8_t *key, uint64_t keylen, const uint8_t *in, uint64_t inlen) { + hmac_state S; + hmac_blake256_init(&S, key, keylen); + hmac_blake256_update(&S, in, inlen * 8); + hmac_blake256_final(&S, out); +} + +// keylen = number of bytes; inlen = number of bytes +void hmac_blake224_hash(uint8_t *out, const uint8_t *key, uint64_t keylen, const uint8_t *in, uint64_t inlen) { + hmac_state S; + hmac_blake224_init(&S, key, keylen); + hmac_blake224_update(&S, in, inlen * 8); + hmac_blake224_final(&S, out); +} diff --git a/webassembly/xmr/blake.h b/webassembly/xmr/blake.h new file mode 100644 index 0000000..8fa43f3 --- /dev/null +++ b/webassembly/xmr/blake.h @@ -0,0 +1,14 @@ +#ifndef BLAKE_H +#define BLAKE_H + +#ifdef __cplusplus +extern "C" { +#endif + +void blake(const uint8_t *input, uint64_t len, uint8_t *output); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/webassembly/xmr/cn.html b/webassembly/xmr/cn.html new file mode 100644 index 0000000..f2da5a0 --- /dev/null +++ b/webassembly/xmr/cn.html @@ -0,0 +1,152 @@ + + + + + + Emscripten-Generated Code + + + +
+
emscripten
+
Downloading...
+
+ +
+
+ +
+
+
+ Resize canvas + Lock/hide mouse pointer +     + +
+ +
+ +
+ + + + \ No newline at end of file diff --git a/webassembly/xmr/cryptonight.c b/webassembly/xmr/cryptonight.c new file mode 100644 index 0000000..6a1b9fd --- /dev/null +++ b/webassembly/xmr/cryptonight.c @@ -0,0 +1,505 @@ + +#include +#include +#include +#include "keccak.h" +#include "blake.h" +#include "skein.h" +#include "jh.h" +#include "groestl.h" +#include "oaes_lib.h" + +#define MEMORY (1 << 21) /* 2 MiB */ +#define ITER (1 << 20) +#define AES_BLOCK_SIZE 16 +#define AES_KEY_SIZE 32 /*16*/ +#define INIT_SIZE_BLK 8 +#define INIT_SIZE_BYTE (INIT_SIZE_BLK * AES_BLOCK_SIZE) // 128 + +#define VARIANT1_1(p) \ + do if (variant > 0) \ + { \ + const uint8_t tmp = ((const uint8_t*)(p))[11]; \ + static const uint32_t table = 0x75310; \ + const uint8_t index = (((tmp >> 3) & 6) | (tmp & 1)) << 1; \ + ((uint8_t*)(p))[11] = tmp ^ ((table >> index) & 0x30); \ + } while(0) + +#define VARIANT1_2(p) \ + do if (variant > 0) \ + { \ + ((uint64_t*)p)[1] ^= tweak1_2; \ + } while(0) + + + #define VARIANT1_INIT() \ + const uint64_t tweak1_2 = variant > 0 ? *(const uint64_t*)(((const uint8_t*)input)+35) ^ ctx->state.hs.w[24] : 0 + + // zeile hier drüber möglicherweise ein & vor das ctx + +void do_blake_hash(const void* input, size_t len, char* output) { + blake(input, len, (unsigned char *)output); +} + +void do_groestl_hash(const void* input, size_t len, char* output) { + groestl(input, len * 8, (uint8_t*)output); +} + +void do_jh_hash(const void* input, size_t len, char* output) { + jh(32 * 8, input, 8 * len, (uint8_t*)output); +} + +void do_skein_hash(const void* input, size_t len, char* output) { + skein(8 * 32, input, 8 * len, (uint8_t*)output); +} + +void (* const extra_hashes[4])(const void *, size_t, char *) = { + do_blake_hash, do_groestl_hash, do_jh_hash, do_skein_hash}; + +void xor_blocks_dst(const uint8_t * a, const uint8_t * b, uint8_t * dst) { + ((uint64_t*) dst)[0] = ((uint64_t*) a)[0] ^ ((uint64_t*) b)[0]; + ((uint64_t*) dst)[1] = ((uint64_t*) a)[1] ^ ((uint64_t*) b)[1]; +} + +#define likely(x) (x) + +#pragma pack(push, 1) +union hash_state { + uint8_t b[200]; + uint64_t w[25]; +}; +#pragma pack(pop) + +#pragma pack(push, 1) +union cn_slow_hash_state { + union hash_state hs; + struct { + uint8_t k[64]; + uint8_t init[INIT_SIZE_BYTE]; + }; +}; +#pragma pack(pop) + +struct cryptonight_ctx { + uint8_t long_state[MEMORY] __attribute((aligned(16))); + union cn_slow_hash_state state; + uint8_t text[INIT_SIZE_BYTE] __attribute((aligned(16))); + uint8_t a[AES_BLOCK_SIZE] __attribute__((aligned(16))); + uint8_t b[AES_BLOCK_SIZE] __attribute__((aligned(16))); + uint8_t c[AES_BLOCK_SIZE] __attribute__((aligned(16))); + oaes_ctx* aes_ctx; +}; + +const uint32_t TestTable1[256] __attribute((aligned(16))) ={ + 0xA56363C6,0x847C7CF8,0x997777EE,0x8D7B7BF6,0x0DF2F2FF,0xBD6B6BD6,0xB16F6FDE,0x54C5C591, + 0x50303060,0x03010102,0xA96767CE,0x7D2B2B56,0x19FEFEE7,0x62D7D7B5,0xE6ABAB4D,0x9A7676EC, + 0x45CACA8F,0x9D82821F,0x40C9C989,0x877D7DFA,0x15FAFAEF,0xEB5959B2,0xC947478E,0x0BF0F0FB, + 0xECADAD41,0x67D4D4B3,0xFDA2A25F,0xEAAFAF45,0xBF9C9C23,0xF7A4A453,0x967272E4,0x5BC0C09B, + 0xC2B7B775,0x1CFDFDE1,0xAE93933D,0x6A26264C,0x5A36366C,0x413F3F7E,0x02F7F7F5,0x4FCCCC83, + 0x5C343468,0xF4A5A551,0x34E5E5D1,0x08F1F1F9,0x937171E2,0x73D8D8AB,0x53313162,0x3F15152A, + 0x0C040408,0x52C7C795,0x65232346,0x5EC3C39D,0x28181830,0xA1969637,0x0F05050A,0xB59A9A2F, + 0x0907070E,0x36121224,0x9B80801B,0x3DE2E2DF,0x26EBEBCD,0x6927274E,0xCDB2B27F,0x9F7575EA, + 0x1B090912,0x9E83831D,0x742C2C58,0x2E1A1A34,0x2D1B1B36,0xB26E6EDC,0xEE5A5AB4,0xFBA0A05B, + 0xF65252A4,0x4D3B3B76,0x61D6D6B7,0xCEB3B37D,0x7B292952,0x3EE3E3DD,0x712F2F5E,0x97848413, + 0xF55353A6,0x68D1D1B9,0x00000000,0x2CEDEDC1,0x60202040,0x1FFCFCE3,0xC8B1B179,0xED5B5BB6, + 0xBE6A6AD4,0x46CBCB8D,0xD9BEBE67,0x4B393972,0xDE4A4A94,0xD44C4C98,0xE85858B0,0x4ACFCF85, + 0x6BD0D0BB,0x2AEFEFC5,0xE5AAAA4F,0x16FBFBED,0xC5434386,0xD74D4D9A,0x55333366,0x94858511, + 0xCF45458A,0x10F9F9E9,0x06020204,0x817F7FFE,0xF05050A0,0x443C3C78,0xBA9F9F25,0xE3A8A84B, + 0xF35151A2,0xFEA3A35D,0xC0404080,0x8A8F8F05,0xAD92923F,0xBC9D9D21,0x48383870,0x04F5F5F1, + 0xDFBCBC63,0xC1B6B677,0x75DADAAF,0x63212142,0x30101020,0x1AFFFFE5,0x0EF3F3FD,0x6DD2D2BF, + 0x4CCDCD81,0x140C0C18,0x35131326,0x2FECECC3,0xE15F5FBE,0xA2979735,0xCC444488,0x3917172E, + 0x57C4C493,0xF2A7A755,0x827E7EFC,0x473D3D7A,0xAC6464C8,0xE75D5DBA,0x2B191932,0x957373E6, + 0xA06060C0,0x98818119,0xD14F4F9E,0x7FDCDCA3,0x66222244,0x7E2A2A54,0xAB90903B,0x8388880B, + 0xCA46468C,0x29EEEEC7,0xD3B8B86B,0x3C141428,0x79DEDEA7,0xE25E5EBC,0x1D0B0B16,0x76DBDBAD, + 0x3BE0E0DB,0x56323264,0x4E3A3A74,0x1E0A0A14,0xDB494992,0x0A06060C,0x6C242448,0xE45C5CB8, + 0x5DC2C29F,0x6ED3D3BD,0xEFACAC43,0xA66262C4,0xA8919139,0xA4959531,0x37E4E4D3,0x8B7979F2, + 0x32E7E7D5,0x43C8C88B,0x5937376E,0xB76D6DDA,0x8C8D8D01,0x64D5D5B1,0xD24E4E9C,0xE0A9A949, + 0xB46C6CD8,0xFA5656AC,0x07F4F4F3,0x25EAEACF,0xAF6565CA,0x8E7A7AF4,0xE9AEAE47,0x18080810, + 0xD5BABA6F,0x887878F0,0x6F25254A,0x722E2E5C,0x241C1C38,0xF1A6A657,0xC7B4B473,0x51C6C697, + 0x23E8E8CB,0x7CDDDDA1,0x9C7474E8,0x211F1F3E,0xDD4B4B96,0xDCBDBD61,0x868B8B0D,0x858A8A0F, + 0x907070E0,0x423E3E7C,0xC4B5B571,0xAA6666CC,0xD8484890,0x05030306,0x01F6F6F7,0x120E0E1C, + 0xA36161C2,0x5F35356A,0xF95757AE,0xD0B9B969,0x91868617,0x58C1C199,0x271D1D3A,0xB99E9E27, + 0x38E1E1D9,0x13F8F8EB,0xB398982B,0x33111122,0xBB6969D2,0x70D9D9A9,0x898E8E07,0xA7949433, + 0xB69B9B2D,0x221E1E3C,0x92878715,0x20E9E9C9,0x49CECE87,0xFF5555AA,0x78282850,0x7ADFDFA5, + 0x8F8C8C03,0xF8A1A159,0x80898909,0x170D0D1A,0xDABFBF65,0x31E6E6D7,0xC6424284,0xB86868D0, + 0xC3414182,0xB0999929,0x772D2D5A,0x110F0F1E,0xCBB0B07B,0xFC5454A8,0xD6BBBB6D,0x3A16162C +}; + +const uint32_t TestTable2[256] __attribute((aligned(16))) ={ + 0x6363C6A5,0x7C7CF884,0x7777EE99,0x7B7BF68D,0xF2F2FF0D,0x6B6BD6BD,0x6F6FDEB1,0xC5C59154, + 0x30306050,0x01010203,0x6767CEA9,0x2B2B567D,0xFEFEE719,0xD7D7B562,0xABAB4DE6,0x7676EC9A, + 0xCACA8F45,0x82821F9D,0xC9C98940,0x7D7DFA87,0xFAFAEF15,0x5959B2EB,0x47478EC9,0xF0F0FB0B, + 0xADAD41EC,0xD4D4B367,0xA2A25FFD,0xAFAF45EA,0x9C9C23BF,0xA4A453F7,0x7272E496,0xC0C09B5B, + 0xB7B775C2,0xFDFDE11C,0x93933DAE,0x26264C6A,0x36366C5A,0x3F3F7E41,0xF7F7F502,0xCCCC834F, + 0x3434685C,0xA5A551F4,0xE5E5D134,0xF1F1F908,0x7171E293,0xD8D8AB73,0x31316253,0x15152A3F, + 0x0404080C,0xC7C79552,0x23234665,0xC3C39D5E,0x18183028,0x969637A1,0x05050A0F,0x9A9A2FB5, + 0x07070E09,0x12122436,0x80801B9B,0xE2E2DF3D,0xEBEBCD26,0x27274E69,0xB2B27FCD,0x7575EA9F, + 0x0909121B,0x83831D9E,0x2C2C5874,0x1A1A342E,0x1B1B362D,0x6E6EDCB2,0x5A5AB4EE,0xA0A05BFB, + 0x5252A4F6,0x3B3B764D,0xD6D6B761,0xB3B37DCE,0x2929527B,0xE3E3DD3E,0x2F2F5E71,0x84841397, + 0x5353A6F5,0xD1D1B968,0x00000000,0xEDEDC12C,0x20204060,0xFCFCE31F,0xB1B179C8,0x5B5BB6ED, + 0x6A6AD4BE,0xCBCB8D46,0xBEBE67D9,0x3939724B,0x4A4A94DE,0x4C4C98D4,0x5858B0E8,0xCFCF854A, + 0xD0D0BB6B,0xEFEFC52A,0xAAAA4FE5,0xFBFBED16,0x434386C5,0x4D4D9AD7,0x33336655,0x85851194, + 0x45458ACF,0xF9F9E910,0x02020406,0x7F7FFE81,0x5050A0F0,0x3C3C7844,0x9F9F25BA,0xA8A84BE3, + 0x5151A2F3,0xA3A35DFE,0x404080C0,0x8F8F058A,0x92923FAD,0x9D9D21BC,0x38387048,0xF5F5F104, + 0xBCBC63DF,0xB6B677C1,0xDADAAF75,0x21214263,0x10102030,0xFFFFE51A,0xF3F3FD0E,0xD2D2BF6D, + 0xCDCD814C,0x0C0C1814,0x13132635,0xECECC32F,0x5F5FBEE1,0x979735A2,0x444488CC,0x17172E39, + 0xC4C49357,0xA7A755F2,0x7E7EFC82,0x3D3D7A47,0x6464C8AC,0x5D5DBAE7,0x1919322B,0x7373E695, + 0x6060C0A0,0x81811998,0x4F4F9ED1,0xDCDCA37F,0x22224466,0x2A2A547E,0x90903BAB,0x88880B83, + 0x46468CCA,0xEEEEC729,0xB8B86BD3,0x1414283C,0xDEDEA779,0x5E5EBCE2,0x0B0B161D,0xDBDBAD76, + 0xE0E0DB3B,0x32326456,0x3A3A744E,0x0A0A141E,0x494992DB,0x06060C0A,0x2424486C,0x5C5CB8E4, + 0xC2C29F5D,0xD3D3BD6E,0xACAC43EF,0x6262C4A6,0x919139A8,0x959531A4,0xE4E4D337,0x7979F28B, + 0xE7E7D532,0xC8C88B43,0x37376E59,0x6D6DDAB7,0x8D8D018C,0xD5D5B164,0x4E4E9CD2,0xA9A949E0, + 0x6C6CD8B4,0x5656ACFA,0xF4F4F307,0xEAEACF25,0x6565CAAF,0x7A7AF48E,0xAEAE47E9,0x08081018, + 0xBABA6FD5,0x7878F088,0x25254A6F,0x2E2E5C72,0x1C1C3824,0xA6A657F1,0xB4B473C7,0xC6C69751, + 0xE8E8CB23,0xDDDDA17C,0x7474E89C,0x1F1F3E21,0x4B4B96DD,0xBDBD61DC,0x8B8B0D86,0x8A8A0F85, + 0x7070E090,0x3E3E7C42,0xB5B571C4,0x6666CCAA,0x484890D8,0x03030605,0xF6F6F701,0x0E0E1C12, + 0x6161C2A3,0x35356A5F,0x5757AEF9,0xB9B969D0,0x86861791,0xC1C19958,0x1D1D3A27,0x9E9E27B9, + 0xE1E1D938,0xF8F8EB13,0x98982BB3,0x11112233,0x6969D2BB,0xD9D9A970,0x8E8E0789,0x949433A7, + 0x9B9B2DB6,0x1E1E3C22,0x87871592,0xE9E9C920,0xCECE8749,0x5555AAFF,0x28285078,0xDFDFA57A, + 0x8C8C038F,0xA1A159F8,0x89890980,0x0D0D1A17,0xBFBF65DA,0xE6E6D731,0x424284C6,0x6868D0B8, + 0x414182C3,0x999929B0,0x2D2D5A77,0x0F0F1E11,0xB0B07BCB,0x5454A8FC,0xBBBB6DD6,0x16162C3A +}; + +const uint32_t TestTable3[256] __attribute((aligned(16))) ={ + 0x63C6A563,0x7CF8847C,0x77EE9977,0x7BF68D7B,0xF2FF0DF2,0x6BD6BD6B,0x6FDEB16F,0xC59154C5, + 0x30605030,0x01020301,0x67CEA967,0x2B567D2B,0xFEE719FE,0xD7B562D7,0xAB4DE6AB,0x76EC9A76, + 0xCA8F45CA,0x821F9D82,0xC98940C9,0x7DFA877D,0xFAEF15FA,0x59B2EB59,0x478EC947,0xF0FB0BF0, + 0xAD41ECAD,0xD4B367D4,0xA25FFDA2,0xAF45EAAF,0x9C23BF9C,0xA453F7A4,0x72E49672,0xC09B5BC0, + 0xB775C2B7,0xFDE11CFD,0x933DAE93,0x264C6A26,0x366C5A36,0x3F7E413F,0xF7F502F7,0xCC834FCC, + 0x34685C34,0xA551F4A5,0xE5D134E5,0xF1F908F1,0x71E29371,0xD8AB73D8,0x31625331,0x152A3F15, + 0x04080C04,0xC79552C7,0x23466523,0xC39D5EC3,0x18302818,0x9637A196,0x050A0F05,0x9A2FB59A, + 0x070E0907,0x12243612,0x801B9B80,0xE2DF3DE2,0xEBCD26EB,0x274E6927,0xB27FCDB2,0x75EA9F75, + 0x09121B09,0x831D9E83,0x2C58742C,0x1A342E1A,0x1B362D1B,0x6EDCB26E,0x5AB4EE5A,0xA05BFBA0, + 0x52A4F652,0x3B764D3B,0xD6B761D6,0xB37DCEB3,0x29527B29,0xE3DD3EE3,0x2F5E712F,0x84139784, + 0x53A6F553,0xD1B968D1,0x00000000,0xEDC12CED,0x20406020,0xFCE31FFC,0xB179C8B1,0x5BB6ED5B, + 0x6AD4BE6A,0xCB8D46CB,0xBE67D9BE,0x39724B39,0x4A94DE4A,0x4C98D44C,0x58B0E858,0xCF854ACF, + 0xD0BB6BD0,0xEFC52AEF,0xAA4FE5AA,0xFBED16FB,0x4386C543,0x4D9AD74D,0x33665533,0x85119485, + 0x458ACF45,0xF9E910F9,0x02040602,0x7FFE817F,0x50A0F050,0x3C78443C,0x9F25BA9F,0xA84BE3A8, + 0x51A2F351,0xA35DFEA3,0x4080C040,0x8F058A8F,0x923FAD92,0x9D21BC9D,0x38704838,0xF5F104F5, + 0xBC63DFBC,0xB677C1B6,0xDAAF75DA,0x21426321,0x10203010,0xFFE51AFF,0xF3FD0EF3,0xD2BF6DD2, + 0xCD814CCD,0x0C18140C,0x13263513,0xECC32FEC,0x5FBEE15F,0x9735A297,0x4488CC44,0x172E3917, + 0xC49357C4,0xA755F2A7,0x7EFC827E,0x3D7A473D,0x64C8AC64,0x5DBAE75D,0x19322B19,0x73E69573, + 0x60C0A060,0x81199881,0x4F9ED14F,0xDCA37FDC,0x22446622,0x2A547E2A,0x903BAB90,0x880B8388, + 0x468CCA46,0xEEC729EE,0xB86BD3B8,0x14283C14,0xDEA779DE,0x5EBCE25E,0x0B161D0B,0xDBAD76DB, + 0xE0DB3BE0,0x32645632,0x3A744E3A,0x0A141E0A,0x4992DB49,0x060C0A06,0x24486C24,0x5CB8E45C, + 0xC29F5DC2,0xD3BD6ED3,0xAC43EFAC,0x62C4A662,0x9139A891,0x9531A495,0xE4D337E4,0x79F28B79, + 0xE7D532E7,0xC88B43C8,0x376E5937,0x6DDAB76D,0x8D018C8D,0xD5B164D5,0x4E9CD24E,0xA949E0A9, + 0x6CD8B46C,0x56ACFA56,0xF4F307F4,0xEACF25EA,0x65CAAF65,0x7AF48E7A,0xAE47E9AE,0x08101808, + 0xBA6FD5BA,0x78F08878,0x254A6F25,0x2E5C722E,0x1C38241C,0xA657F1A6,0xB473C7B4,0xC69751C6, + 0xE8CB23E8,0xDDA17CDD,0x74E89C74,0x1F3E211F,0x4B96DD4B,0xBD61DCBD,0x8B0D868B,0x8A0F858A, + 0x70E09070,0x3E7C423E,0xB571C4B5,0x66CCAA66,0x4890D848,0x03060503,0xF6F701F6,0x0E1C120E, + 0x61C2A361,0x356A5F35,0x57AEF957,0xB969D0B9,0x86179186,0xC19958C1,0x1D3A271D,0x9E27B99E, + 0xE1D938E1,0xF8EB13F8,0x982BB398,0x11223311,0x69D2BB69,0xD9A970D9,0x8E07898E,0x9433A794, + 0x9B2DB69B,0x1E3C221E,0x87159287,0xE9C920E9,0xCE8749CE,0x55AAFF55,0x28507828,0xDFA57ADF, + 0x8C038F8C,0xA159F8A1,0x89098089,0x0D1A170D,0xBF65DABF,0xE6D731E6,0x4284C642,0x68D0B868, + 0x4182C341,0x9929B099,0x2D5A772D,0x0F1E110F,0xB07BCBB0,0x54A8FC54,0xBB6DD6BB,0x162C3A16 +}; + +const uint32_t TestTable4[256] __attribute((aligned(16))) ={ + 0xC6A56363,0xF8847C7C,0xEE997777,0xF68D7B7B,0xFF0DF2F2,0xD6BD6B6B,0xDEB16F6F,0x9154C5C5, + 0x60503030,0x02030101,0xCEA96767,0x567D2B2B,0xE719FEFE,0xB562D7D7,0x4DE6ABAB,0xEC9A7676, + 0x8F45CACA,0x1F9D8282,0x8940C9C9,0xFA877D7D,0xEF15FAFA,0xB2EB5959,0x8EC94747,0xFB0BF0F0, + 0x41ECADAD,0xB367D4D4,0x5FFDA2A2,0x45EAAFAF,0x23BF9C9C,0x53F7A4A4,0xE4967272,0x9B5BC0C0, + 0x75C2B7B7,0xE11CFDFD,0x3DAE9393,0x4C6A2626,0x6C5A3636,0x7E413F3F,0xF502F7F7,0x834FCCCC, + 0x685C3434,0x51F4A5A5,0xD134E5E5,0xF908F1F1,0xE2937171,0xAB73D8D8,0x62533131,0x2A3F1515, + 0x080C0404,0x9552C7C7,0x46652323,0x9D5EC3C3,0x30281818,0x37A19696,0x0A0F0505,0x2FB59A9A, + 0x0E090707,0x24361212,0x1B9B8080,0xDF3DE2E2,0xCD26EBEB,0x4E692727,0x7FCDB2B2,0xEA9F7575, + 0x121B0909,0x1D9E8383,0x58742C2C,0x342E1A1A,0x362D1B1B,0xDCB26E6E,0xB4EE5A5A,0x5BFBA0A0, + 0xA4F65252,0x764D3B3B,0xB761D6D6,0x7DCEB3B3,0x527B2929,0xDD3EE3E3,0x5E712F2F,0x13978484, + 0xA6F55353,0xB968D1D1,0x00000000,0xC12CEDED,0x40602020,0xE31FFCFC,0x79C8B1B1,0xB6ED5B5B, + 0xD4BE6A6A,0x8D46CBCB,0x67D9BEBE,0x724B3939,0x94DE4A4A,0x98D44C4C,0xB0E85858,0x854ACFCF, + 0xBB6BD0D0,0xC52AEFEF,0x4FE5AAAA,0xED16FBFB,0x86C54343,0x9AD74D4D,0x66553333,0x11948585, + 0x8ACF4545,0xE910F9F9,0x04060202,0xFE817F7F,0xA0F05050,0x78443C3C,0x25BA9F9F,0x4BE3A8A8, + 0xA2F35151,0x5DFEA3A3,0x80C04040,0x058A8F8F,0x3FAD9292,0x21BC9D9D,0x70483838,0xF104F5F5, + 0x63DFBCBC,0x77C1B6B6,0xAF75DADA,0x42632121,0x20301010,0xE51AFFFF,0xFD0EF3F3,0xBF6DD2D2, + 0x814CCDCD,0x18140C0C,0x26351313,0xC32FECEC,0xBEE15F5F,0x35A29797,0x88CC4444,0x2E391717, + 0x9357C4C4,0x55F2A7A7,0xFC827E7E,0x7A473D3D,0xC8AC6464,0xBAE75D5D,0x322B1919,0xE6957373, + 0xC0A06060,0x19988181,0x9ED14F4F,0xA37FDCDC,0x44662222,0x547E2A2A,0x3BAB9090,0x0B838888, + 0x8CCA4646,0xC729EEEE,0x6BD3B8B8,0x283C1414,0xA779DEDE,0xBCE25E5E,0x161D0B0B,0xAD76DBDB, + 0xDB3BE0E0,0x64563232,0x744E3A3A,0x141E0A0A,0x92DB4949,0x0C0A0606,0x486C2424,0xB8E45C5C, + 0x9F5DC2C2,0xBD6ED3D3,0x43EFACAC,0xC4A66262,0x39A89191,0x31A49595,0xD337E4E4,0xF28B7979, + 0xD532E7E7,0x8B43C8C8,0x6E593737,0xDAB76D6D,0x018C8D8D,0xB164D5D5,0x9CD24E4E,0x49E0A9A9, + 0xD8B46C6C,0xACFA5656,0xF307F4F4,0xCF25EAEA,0xCAAF6565,0xF48E7A7A,0x47E9AEAE,0x10180808, + 0x6FD5BABA,0xF0887878,0x4A6F2525,0x5C722E2E,0x38241C1C,0x57F1A6A6,0x73C7B4B4,0x9751C6C6, + 0xCB23E8E8,0xA17CDDDD,0xE89C7474,0x3E211F1F,0x96DD4B4B,0x61DCBDBD,0x0D868B8B,0x0F858A8A, + 0xE0907070,0x7C423E3E,0x71C4B5B5,0xCCAA6666,0x90D84848,0x06050303,0xF701F6F6,0x1C120E0E, + 0xC2A36161,0x6A5F3535,0xAEF95757,0x69D0B9B9,0x17918686,0x9958C1C1,0x3A271D1D,0x27B99E9E, + 0xD938E1E1,0xEB13F8F8,0x2BB39898,0x22331111,0xD2BB6969,0xA970D9D9,0x07898E8E,0x33A79494, + 0x2DB69B9B,0x3C221E1E,0x15928787,0xC920E9E9,0x8749CECE,0xAAFF5555,0x50782828,0xA57ADFDF, + 0x038F8C8C,0x59F8A1A1,0x09808989,0x1A170D0D,0x65DABFBF,0xD731E6E6,0x84C64242,0xD0B86868, + 0x82C34141,0x29B09999,0x5A772D2D,0x1E110F0F,0x7BCBB0B0,0xA8FC5454,0x6DD6BBBB,0x2C3A1616 +}; +/* +inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t *product_hi) +{ + // multiplier = ab = a * 2^32 + b + // multiplicand = cd = c * 2^32 + d + // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d + uint64_t a = multiplier >> 32; + uint64_t b = multiplier & 0xFFFFFFFF; + uint64_t c = multiplicand >> 32; + uint64_t d = multiplicand & 0xFFFFFFFF; + + //uint64_t ac = a * c; + uint64_t ad = a * d; + //uint64_t bc = b * c; + uint64_t bd = b * d; + + uint64_t adbc = ad + (b * c); + uint64_t adbc_carry = adbc < ad ? 1 : 0; + + // multiplier * multiplicand = product_hi * 2^64 + product_lo + uint64_t product_lo = bd + (adbc << 32); + uint64_t product_lo_carry = product_lo < bd ? 1 : 0; + *product_hi = (a * c) + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry; + //assert(ac <= *product_hi); + + return product_lo; +}*/ + +// void m64to128(uint64_t *a, uint64_t *b, uint64_t *r) +// { +// uint64_t lo, hi; +// __asm__("mul %0, %1, %2\n\t" : "=r"(lo) : "r"(a[0]), "r"(b[0]) ); +// __asm__("umulh %0, %1, %2\n\t" : "=r"(hi) : "r"(a[0]), "r"(b[0]) ); +// r[0] = hi; +// r[1] = lo; +// } +// + + + +void mult64to128(uint64_t op1, uint64_t op2, uint64_t *hi, uint64_t *lo) +{ + uint64_t u1 = (op1 & 0xffffffff); + uint64_t v1 = (op2 & 0xffffffff); + uint64_t t = (u1 * v1); + uint64_t w3 = (t & 0xffffffff); + uint64_t k = (t >> 32); + + op1 >>= 32; + t = (op1 * v1) + k; + k = (t & 0xffffffff); + v1 = (t >> 32); + + op2 >>= 32; + t = (u1 * op2) + k; + k = (t >> 32); + + *hi = (op1 * op2) + v1 + k; + *lo = (t << 32) + w3; +} + + +void mul_sum_xor_dst(const uint8_t *a, uint8_t *c, uint8_t *dst) +{ + + uint64_t hi = ((uint64_t *)a)[0]; + uint64_t lo = ((uint64_t *)dst)[0]; + + //mult64to128(((uint64_t *)a)[0], ((uint64_t *)dst)[0],&hi,&lo); + + uint64_t u1 = (hi & 0xffffffff); + uint64_t v1 = (lo & 0xffffffff); + uint64_t t = (u1 * v1); + uint64_t w3 = (t & 0xffffffff); + uint64_t k = (t >> 32); + + hi >>= 32; + t = (hi * v1) + k; + k = (t & 0xffffffff); + v1 = (t >> 32); + + lo >>= 32; + t = (u1 * lo) + k; + k = (t >> 32); + + hi = (hi * lo) + v1 + k; + lo = (t << 32) + w3; + + lo += ((uint64_t *)c)[1]; + hi += ((uint64_t *)c)[0]; + + ((uint64_t *)c)[0] = ((uint64_t*) dst)[0] ^ hi; + ((uint64_t *)c)[1] = ((uint64_t*) dst)[1] ^ lo; + ((uint64_t *)dst)[0] = hi; + ((uint64_t *)dst)[1] = lo; +} + +void xor_blocks(uint8_t * a, const uint8_t * b) { + ((uint64_t*) a)[0] ^= ((uint64_t*) b)[0]; + ((uint64_t*) a)[1] ^= ((uint64_t*) b)[1]; +} + + + + +void SubAndShiftAndMixAddRound(uint32_t * out, uint8_t *temp, uint32_t * AesEncKey) +{ + //uint8_t *state = (uint8_t *)&temp[0]; + + out[0] = TestTable1[temp[0]] ^ TestTable2[temp[5]] ^ TestTable3[temp[10]] ^ TestTable4[temp[15]] ^ AesEncKey[0]; + out[1] = TestTable4[temp[3]] ^ TestTable1[temp[4]] ^ TestTable2[temp[9]] ^ TestTable3[temp[14]] ^ AesEncKey[1]; + out[2] = TestTable3[temp[2]] ^ TestTable4[temp[7]] ^ TestTable1[temp[8]] ^ TestTable2[temp[13]] ^ AesEncKey[2]; + out[3] = TestTable2[temp[1]] ^ TestTable3[temp[6]] ^ TestTable4[temp[11]] ^ TestTable1[temp[12]] ^ AesEncKey[3]; + +} + + +void SubAndShiftAndMixAddRoundInPlace(uint32_t * temp, uint32_t * AesEncKey) +{ + uint8_t *state = (uint8_t *)&temp[0]; + + uint8_t saved[6]; + + saved[0] = state[3]; + saved[1] = state[2]; + saved[2] = state[7]; + saved[3] = state[1]; + saved[4] = state[6]; + saved[5] = state[11]; + + + temp[0]= TestTable1[state[0]] ^ TestTable2[state[5]] ^ TestTable3[state[10]] ^ TestTable4[state[15]] ^ AesEncKey[0]; + temp[1]= TestTable4[saved[0]] ^ TestTable1[state[4]] ^ TestTable2[state[9]] ^ TestTable3[state[14]] ^ AesEncKey[1]; + temp[2]= TestTable3[saved[1]] ^ TestTable4[saved[2]] ^ TestTable1[state[8]] ^ TestTable2[state[13]] ^ AesEncKey[2]; + temp[3]= TestTable2[saved[3]] ^ TestTable3[saved[4]] ^ TestTable4[saved[5]] ^ TestTable1[state[12]] ^ AesEncKey[3]; + +} + + +void cryptonight_hash_ctx(void * output, const void * input, struct cryptonight_ctx * ctx) { + ctx->aes_ctx = (oaes_ctx*) oaes_alloc(); + size_t i, j; + //hash_process(&ctx->state.hs, (const uint8_t*) input, 76); + keccak((const uint8_t *)input, 76, ctx->state.hs.b, 200); + memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); + + + int variant = ((const uint8_t*)input)[0] >= 7 ? ((const uint8_t*)input)[0] - 6 : 0; + //int variant = 1; + + VARIANT1_INIT(); + + oaes_key_import_data(ctx->aes_ctx, ctx->state.hs.b, AES_KEY_SIZE); + + for(i = 0; likely(i < MEMORY); i += INIT_SIZE_BYTE) + { + for(j = 0; j < 10; j++) + { + + uint32_t *ptr = (uint32_t *)&ctx->aes_ctx->key->exp_data[j << 4]; + + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x10], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x20], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x30], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x40], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x50], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x60], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x70], ptr); + + } + memcpy(&ctx->long_state[i], ctx->text, INIT_SIZE_BYTE); + } + + for (i = 0; i < 2; i++) + { + ((uint64_t *)(ctx->a))[i] = ((uint64_t *)ctx->state.k)[i] ^ ((uint64_t *)ctx->state.k)[i+4]; + ((uint64_t *)(ctx->b))[i] = ((uint64_t *)ctx->state.k)[i+2] ^ ((uint64_t *)ctx->state.k)[i+6]; + } + + //xor_blocks_dst(&ctx->state.k[0], &ctx->state.k[32], ctx->a); + //xor_blocks_dst(&ctx->state.k[16], &ctx->state.k[48], ctx->b); + + for (i = 0; likely(i < ITER / 4); ++i) { + + + // ueberall, woe uint64 & ... steht, sollte prinzipiell auch uint32 möglich sein. + // auch aeon checken. + + // Dependency chain: address -> read value ------+ + // written value <-+ hard function (AES or MUL) <+ + // next address <-+ + // + // Iteration 1 + j = ((uint32_t *)(ctx->a))[0] & 0x1FFFF0; + + //SubAndShiftAndMixAddRound((uint32_t *)ctx->c, (uint32_t *)&ctx->long_state[j], (uint32_t *)ctx->a); + SubAndShiftAndMixAddRound((uint32_t *)ctx->c, &ctx->long_state[j], (uint32_t *)ctx->a); + xor_blocks_dst(ctx->c, ctx->b, &ctx->long_state[j]); + VARIANT1_1(&ctx->long_state[j]); + + // Iteration 2 + mul_sum_xor_dst(ctx->c, ctx->a, &ctx->long_state[((uint32_t *)(ctx->c))[0] & 0x1FFFF0]); + + VARIANT1_2(&ctx->long_state[(((uint32_t *)(ctx->c))[0] & 0x1FFFF0)]); + + // Iteration 3 + + j = ((uint32_t *)(ctx->a))[0] & 0x1FFFF0; + + SubAndShiftAndMixAddRound((uint32_t *)ctx->b, &ctx->long_state[j], (uint32_t *)ctx->a); + //SubAndShiftAndMixAddRound((uint32_t *)ctx->b, (uint32_t *)&ctx->long_state[j], (uint32_t *)ctx->a); + xor_blocks_dst(ctx->b, ctx->c, &ctx->long_state[j]); + + VARIANT1_1(&ctx->long_state[j]); + + // Iteration 4 + mul_sum_xor_dst(ctx->b, ctx->a, &ctx->long_state[((uint32_t *)(ctx->b))[0] & 0x1FFFF0]); + + VARIANT1_2(&ctx->long_state[(((uint32_t *)(ctx->b))[0] & 0x1FFFF0)]); + } + + memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); + + oaes_free((OAES_CTX **) &ctx->aes_ctx); + ctx->aes_ctx = (oaes_ctx*) oaes_alloc(); + + oaes_key_import_data(ctx->aes_ctx, &ctx->state.hs.b[32], AES_KEY_SIZE); + + for(i = 0; likely(i < MEMORY); i += INIT_SIZE_BYTE) + { + + xor_blocks(&ctx->text[0x00], &ctx->long_state[i + 0x00]); + xor_blocks(&ctx->text[0x10], &ctx->long_state[i + 0x10]); + xor_blocks(&ctx->text[0x20], &ctx->long_state[i + 0x20]); + xor_blocks(&ctx->text[0x30], &ctx->long_state[i + 0x30]); + xor_blocks(&ctx->text[0x40], &ctx->long_state[i + 0x40]); + xor_blocks(&ctx->text[0x50], &ctx->long_state[i + 0x50]); + xor_blocks(&ctx->text[0x60], &ctx->long_state[i + 0x60]); + xor_blocks(&ctx->text[0x70], &ctx->long_state[i + 0x70]); + + + + for(j = 0; j < 10; j++) + { + uint32_t *ptr = (uint32_t *)&ctx->aes_ctx->key->exp_data[j << 4]; + + + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x10], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x20], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x30], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x40], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x50], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x60], ptr); + SubAndShiftAndMixAddRoundInPlace((uint32_t *)&ctx->text[0x70], ptr); + } + } + + + memcpy(ctx->state.init, ctx->text, INIT_SIZE_BYTE); + //hash_permutation(&ctx->state.hs); + keccakf((uint64_t *)ctx->state.hs.b, 24); + /*memcpy(hash, &state, 32);*/ + extra_hashes[ctx->state.hs.b[0] & 3](&ctx->state, 200, output); + oaes_free((OAES_CTX **) &ctx->aes_ctx); +} + +void cryptonight(void* output, const void* input, size_t len) { + struct cryptonight_ctx *ctx = (struct cryptonight_ctx*)malloc(sizeof(struct cryptonight_ctx)); + cryptonight_hash_ctx(output, input, ctx); + + free(ctx); +} diff --git a/webassembly/xmr/cryptonight.h b/webassembly/xmr/cryptonight.h new file mode 100644 index 0000000..bd705fd --- /dev/null +++ b/webassembly/xmr/cryptonight.h @@ -0,0 +1,15 @@ +#ifndef CRYPTONIGHT_H +#define CRYPTONIGHT_H + +#ifdef __cplusplus +extern "C" { +#endif + +void cryptonight(void *output, const void *input, size_t len); +struct cryptonight_ctx; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/webassembly/xmr/groestl.c b/webassembly/xmr/groestl.c new file mode 100644 index 0000000..5277c8b --- /dev/null +++ b/webassembly/xmr/groestl.c @@ -0,0 +1,393 @@ +/* hash.c April 2012 + * Groestl ANSI C code optimised for 32-bit machines + * Author: Thomas Krinninger + * + * This work is based on the implementation of + * Soeren S. Thomsen and Krystian Matusiewicz + * + * + */ + +#include +#include "groestl_tables.h" + +typedef unsigned char BitSequence; +typedef unsigned long long DataLength; +typedef enum {SUCCESS = 0, FAIL = 1, BAD_HASHLEN = 2} HashReturn; + +/* some sizes (number of bytes) */ +#define ROWS 8 +#define LENGTHFIELDLEN ROWS +#define COLS512 8 + +#define SIZE512 (ROWS*COLS512) + +#define ROUNDS512 10 +#define HASH_BIT_LEN 256 + +#define ROTL32(v, n) ((((v)<<(n))|((v)>>(32-(n))))&li_32(ffffffff)) + +#define li_32(h) 0x##h##u +#define EXT_BYTE(var,n) ((uint8_t)((uint32_t)(var) >> (8*n))) +#define u32BIG(a) \ + ((ROTL32(a,8) & li_32(00FF00FF)) | \ + (ROTL32(a,24) & li_32(FF00FF00))) + +/* NIST API begin */ +typedef struct { + uint32_t chaining[SIZE512/sizeof(uint32_t)]; /* actual state */ + uint32_t block_counter1, + block_counter2; /* message block counter(s) */ + BitSequence buffer[SIZE512]; /* data buffer */ + int buf_ptr; /* data buffer pointer */ + int bits_in_last_byte; /* no. of message bits in last byte of + data buffer */ +} groestlHashState; + +#define P_TYPE 0 +#define Q_TYPE 1 + +const uint8_t shift_Values[2][8] = {{0,1,2,3,4,5,6,7},{1,3,5,7,0,2,4,6}}; + +const uint8_t indices_cyclic[15] = {0,1,2,3,4,5,6,7,0,1,2,3,4,5,6}; + + +#define ROTATE_COLUMN_DOWN(v1, v2, amount_bytes, temp_var) {temp_var = (v1<<(8*amount_bytes))|(v2>>(8*(4-amount_bytes))); \ + v2 = (v2<<(8*amount_bytes))|(v1>>(8*(4-amount_bytes))); \ + v1 = temp_var;} + + +#define COLUMN(x,y,i,c0,c1,c2,c3,c4,c5,c6,c7,tv1,tv2,tu,tl,t) \ + tu = T[2*(uint32_t)x[4*c0+0]]; \ + tl = T[2*(uint32_t)x[4*c0+0]+1]; \ + tv1 = T[2*(uint32_t)x[4*c1+1]]; \ + tv2 = T[2*(uint32_t)x[4*c1+1]+1]; \ + ROTATE_COLUMN_DOWN(tv1,tv2,1,t) \ + tu ^= tv1; \ + tl ^= tv2; \ + tv1 = T[2*(uint32_t)x[4*c2+2]]; \ + tv2 = T[2*(uint32_t)x[4*c2+2]+1]; \ + ROTATE_COLUMN_DOWN(tv1,tv2,2,t) \ + tu ^= tv1; \ + tl ^= tv2; \ + tv1 = T[2*(uint32_t)x[4*c3+3]]; \ + tv2 = T[2*(uint32_t)x[4*c3+3]+1]; \ + ROTATE_COLUMN_DOWN(tv1,tv2,3,t) \ + tu ^= tv1; \ + tl ^= tv2; \ + tl ^= T[2*(uint32_t)x[4*c4+0]]; \ + tu ^= T[2*(uint32_t)x[4*c4+0]+1]; \ + tv1 = T[2*(uint32_t)x[4*c5+1]]; \ + tv2 = T[2*(uint32_t)x[4*c5+1]+1]; \ + ROTATE_COLUMN_DOWN(tv1,tv2,1,t) \ + tl ^= tv1; \ + tu ^= tv2; \ + tv1 = T[2*(uint32_t)x[4*c6+2]]; \ + tv2 = T[2*(uint32_t)x[4*c6+2]+1]; \ + ROTATE_COLUMN_DOWN(tv1,tv2,2,t) \ + tl ^= tv1; \ + tu ^= tv2; \ + tv1 = T[2*(uint32_t)x[4*c7+3]]; \ + tv2 = T[2*(uint32_t)x[4*c7+3]+1]; \ + ROTATE_COLUMN_DOWN(tv1,tv2,3,t) \ + tl ^= tv1; \ + tu ^= tv2; \ + y[i] = tu; \ + y[i+1] = tl; + + +/* compute one round of P (short variants) */ +static void RND512P(uint8_t *x, uint32_t *y, uint32_t r) { + uint32_t temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp; + uint32_t* x32 = (uint32_t*)x; + x32[ 0] ^= 0x00000000^r; + x32[ 2] ^= 0x00000010^r; + x32[ 4] ^= 0x00000020^r; + x32[ 6] ^= 0x00000030^r; + x32[ 8] ^= 0x00000040^r; + x32[10] ^= 0x00000050^r; + x32[12] ^= 0x00000060^r; + x32[14] ^= 0x00000070^r; + COLUMN(x,y, 0, 0, 2, 4, 6, 9, 11, 13, 15, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y, 2, 2, 4, 6, 8, 11, 13, 15, 1, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y, 4, 4, 6, 8, 10, 13, 15, 1, 3, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y, 6, 6, 8, 10, 12, 15, 1, 3, 5, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y, 8, 8, 10, 12, 14, 1, 3, 5, 7, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y,10, 10, 12, 14, 0, 3, 5, 7, 9, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y,12, 12, 14, 0, 2, 5, 7, 9, 11, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y,14, 14, 0, 2, 4, 7, 9, 11, 13, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); +} + +/* compute one round of Q (short variants) */ +static void RND512Q(uint8_t *x, uint32_t *y, uint32_t r) { + uint32_t temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp; + uint32_t* x32 = (uint32_t*)x; + x32[ 0] = ~x32[ 0]; + x32[ 1] ^= 0xffffffff^r; + x32[ 2] = ~x32[ 2]; + x32[ 3] ^= 0xefffffff^r; + x32[ 4] = ~x32[ 4]; + x32[ 5] ^= 0xdfffffff^r; + x32[ 6] = ~x32[ 6]; + x32[ 7] ^= 0xcfffffff^r; + x32[ 8] = ~x32[ 8]; + x32[ 9] ^= 0xbfffffff^r; + x32[10] = ~x32[10]; + x32[11] ^= 0xafffffff^r; + x32[12] = ~x32[12]; + x32[13] ^= 0x9fffffff^r; + x32[14] = ~x32[14]; + x32[15] ^= 0x8fffffff^r; + COLUMN(x,y, 0, 2, 6, 10, 14, 1, 5, 9, 13, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y, 2, 4, 8, 12, 0, 3, 7, 11, 15, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y, 4, 6, 10, 14, 2, 5, 9, 13, 1, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y, 6, 8, 12, 0, 4, 7, 11, 15, 3, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y, 8, 10, 14, 2, 6, 9, 13, 1, 5, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y,10, 12, 0, 4, 8, 11, 15, 3, 7, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y,12, 14, 2, 6, 10, 13, 1, 5, 9, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); + COLUMN(x,y,14, 0, 4, 8, 12, 15, 3, 7, 11, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); +} + +/* compute compression function (short variants) */ +static void F512(uint32_t *h, const uint32_t *m) { + int i; + uint32_t Ptmp[2*COLS512]; + uint32_t Qtmp[2*COLS512]; + uint32_t y[2*COLS512]; + uint32_t z[2*COLS512]; + + for (i = 0; i < 2*COLS512; i++) { + z[i] = m[i]; + Ptmp[i] = h[i]^m[i]; + } + + /* compute Q(m) */ + RND512Q((uint8_t*)z, y, 0x00000000); + RND512Q((uint8_t*)y, z, 0x01000000); + RND512Q((uint8_t*)z, y, 0x02000000); + RND512Q((uint8_t*)y, z, 0x03000000); + RND512Q((uint8_t*)z, y, 0x04000000); + RND512Q((uint8_t*)y, z, 0x05000000); + RND512Q((uint8_t*)z, y, 0x06000000); + RND512Q((uint8_t*)y, z, 0x07000000); + RND512Q((uint8_t*)z, y, 0x08000000); + RND512Q((uint8_t*)y, Qtmp, 0x09000000); + + /* compute P(h+m) */ + RND512P((uint8_t*)Ptmp, y, 0x00000000); + RND512P((uint8_t*)y, z, 0x00000001); + RND512P((uint8_t*)z, y, 0x00000002); + RND512P((uint8_t*)y, z, 0x00000003); + RND512P((uint8_t*)z, y, 0x00000004); + RND512P((uint8_t*)y, z, 0x00000005); + RND512P((uint8_t*)z, y, 0x00000006); + RND512P((uint8_t*)y, z, 0x00000007); + RND512P((uint8_t*)z, y, 0x00000008); + RND512P((uint8_t*)y, Ptmp, 0x00000009); + + /* compute P(h+m) + Q(m) + h */ + for (i = 0; i < 2*COLS512; i++) { + h[i] ^= Ptmp[i]^Qtmp[i]; + } +} + + +/* digest up to msglen bytes of input (full blocks only) */ +static void Transform(groestlHashState *ctx, + const uint8_t *input, + int msglen) { + + /* digest message, one block at a time */ + for (; msglen >= SIZE512; + msglen -= SIZE512, input += SIZE512) { + F512(ctx->chaining,(uint32_t*)input); + + /* increment block counter */ + ctx->block_counter1++; + if (ctx->block_counter1 == 0) ctx->block_counter2++; + } +} + +/* given state h, do h <- P(h)+h */ +static void OutputTransformation(groestlHashState *ctx) { + int j; + uint32_t temp[2*COLS512]; + uint32_t y[2*COLS512]; + uint32_t z[2*COLS512]; + + + + for (j = 0; j < 2*COLS512; j++) { + temp[j] = ctx->chaining[j]; + } + RND512P((uint8_t*)temp, y, 0x00000000); + RND512P((uint8_t*)y, z, 0x00000001); + RND512P((uint8_t*)z, y, 0x00000002); + RND512P((uint8_t*)y, z, 0x00000003); + RND512P((uint8_t*)z, y, 0x00000004); + RND512P((uint8_t*)y, z, 0x00000005); + RND512P((uint8_t*)z, y, 0x00000006); + RND512P((uint8_t*)y, z, 0x00000007); + RND512P((uint8_t*)z, y, 0x00000008); + RND512P((uint8_t*)y, temp, 0x00000009); + for (j = 0; j < 2*COLS512; j++) { + ctx->chaining[j] ^= temp[j]; + } +} + +/* initialise context */ +static void Init(groestlHashState* ctx) { + int i = 0; + /* allocate memory for state and data buffer */ + + for(;i<(SIZE512/sizeof(uint32_t));i++) + { + ctx->chaining[i] = 0; + } + + /* set initial value */ + ctx->chaining[2*COLS512-1] = u32BIG((uint32_t)HASH_BIT_LEN); + + /* set other variables */ + ctx->buf_ptr = 0; + ctx->block_counter1 = 0; + ctx->block_counter2 = 0; + ctx->bits_in_last_byte = 0; +} + +/* update state with databitlen bits of input */ +static void Update(groestlHashState* ctx, + const BitSequence* input, + DataLength databitlen) { + int index = 0; + int msglen = (int)(databitlen/8); + int rem = (int)(databitlen%8); + + /* if the buffer contains data that has not yet been digested, first + add data to buffer until full */ + if (ctx->buf_ptr) { + while (ctx->buf_ptr < SIZE512 && index < msglen) { + ctx->buffer[(int)ctx->buf_ptr++] = input[index++]; + } + if (ctx->buf_ptr < SIZE512) { + /* buffer still not full, return */ + if (rem) { + ctx->bits_in_last_byte = rem; + ctx->buffer[(int)ctx->buf_ptr++] = input[index]; + } + return; + } + + /* digest buffer */ + ctx->buf_ptr = 0; + Transform(ctx, ctx->buffer, SIZE512); + } + + /* digest bulk of message */ + Transform(ctx, input+index, msglen-index); + index += ((msglen-index)/SIZE512)*SIZE512; + + /* store remaining data in buffer */ + while (index < msglen) { + ctx->buffer[(int)ctx->buf_ptr++] = input[index++]; + } + + /* if non-integral number of bytes have been supplied, store + remaining bits in last byte, together with information about + number of bits */ + if (rem) { + ctx->bits_in_last_byte = rem; + ctx->buffer[(int)ctx->buf_ptr++] = input[index]; + } +} + +#define BILB ctx->bits_in_last_byte + +/* finalise: process remaining data (including padding), perform + output transformation, and write hash result to 'output' */ +static void Final(groestlHashState* ctx, + BitSequence* output) { + int i, j = 0, hashbytelen = HASH_BIT_LEN/8; + uint8_t *s = (BitSequence*)ctx->chaining; + + /* pad with '1'-bit and first few '0'-bits */ + if (BILB) { + ctx->buffer[(int)ctx->buf_ptr-1] &= ((1<buffer[(int)ctx->buf_ptr-1] ^= 0x1<<(7-BILB); + BILB = 0; + } + else ctx->buffer[(int)ctx->buf_ptr++] = 0x80; + + /* pad with '0'-bits */ + if (ctx->buf_ptr > SIZE512-LENGTHFIELDLEN) { + /* padding requires two blocks */ + while (ctx->buf_ptr < SIZE512) { + ctx->buffer[(int)ctx->buf_ptr++] = 0; + } + /* digest first padding block */ + Transform(ctx, ctx->buffer, SIZE512); + ctx->buf_ptr = 0; + } + while (ctx->buf_ptr < SIZE512-LENGTHFIELDLEN) { + ctx->buffer[(int)ctx->buf_ptr++] = 0; + } + + /* length padding */ + ctx->block_counter1++; + if (ctx->block_counter1 == 0) ctx->block_counter2++; + ctx->buf_ptr = SIZE512; + + while (ctx->buf_ptr > SIZE512-(int)sizeof(uint32_t)) { + ctx->buffer[(int)--ctx->buf_ptr] = (uint8_t)ctx->block_counter1; + ctx->block_counter1 >>= 8; + } + while (ctx->buf_ptr > SIZE512-LENGTHFIELDLEN) { + ctx->buffer[(int)--ctx->buf_ptr] = (uint8_t)ctx->block_counter2; + ctx->block_counter2 >>= 8; + } + /* digest final padding block */ + Transform(ctx, ctx->buffer, SIZE512); + /* perform output transformation */ + OutputTransformation(ctx); + + /* store hash result in output */ + for (i = SIZE512-hashbytelen; i < SIZE512; i++,j++) { + output[j] = s[i]; + } + + /* zeroise relevant variables and deallocate memory */ + for (i = 0; i < COLS512; i++) { + ctx->chaining[i] = 0; + } + for (i = 0; i < SIZE512; i++) { + ctx->buffer[i] = 0; + } +} + +/* hash bit sequence */ +void groestl(const BitSequence* data, + DataLength databitlen, + BitSequence* hashval) { + + groestlHashState context; + + /* initialise */ + Init(&context); + + + /* process message */ + Update(&context, data, databitlen); + + /* finalise */ + Final(&context, hashval); +} +/* +static int crypto_hash(unsigned char *out, + const unsigned char *in, + unsigned long long len) +{ + groestl(in, 8*len, out); + return 0; +} + +*/ diff --git a/webassembly/xmr/groestl.h b/webassembly/xmr/groestl.h new file mode 100644 index 0000000..29287fc --- /dev/null +++ b/webassembly/xmr/groestl.h @@ -0,0 +1,16 @@ +#ifndef GROESTL_H +#define GROESTL_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern void groestl(const unsigned char *input, + unsigned long long len, + unsigned char *output); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/webassembly/xmr/groestl_tables.h b/webassembly/xmr/groestl_tables.h new file mode 100644 index 0000000..a23295c --- /dev/null +++ b/webassembly/xmr/groestl_tables.h @@ -0,0 +1,38 @@ +#ifndef __tables_h +#define __tables_h + + +const uint32_t T[512] = {0xa5f432c6, 0xc6a597f4, 0x84976ff8, 0xf884eb97, 0x99b05eee, 0xee99c7b0, 0x8d8c7af6, 0xf68df78c, 0xd17e8ff, 0xff0de517, 0xbddc0ad6, 0xd6bdb7dc, 0xb1c816de, 0xdeb1a7c8, 0x54fc6d91, 0x915439fc +, 0x50f09060, 0x6050c0f0, 0x3050702, 0x2030405, 0xa9e02ece, 0xcea987e0, 0x7d87d156, 0x567dac87, 0x192bcce7, 0xe719d52b, 0x62a613b5, 0xb56271a6, 0xe6317c4d, 0x4de69a31, 0x9ab559ec, 0xec9ac3b5 +, 0x45cf408f, 0x8f4505cf, 0x9dbca31f, 0x1f9d3ebc, 0x40c04989, 0x894009c0, 0x879268fa, 0xfa87ef92, 0x153fd0ef, 0xef15c53f, 0xeb2694b2, 0xb2eb7f26, 0xc940ce8e, 0x8ec90740, 0xb1de6fb, 0xfb0bed1d +, 0xec2f6e41, 0x41ec822f, 0x67a91ab3, 0xb3677da9, 0xfd1c435f, 0x5ffdbe1c, 0xea256045, 0x45ea8a25, 0xbfdaf923, 0x23bf46da, 0xf7025153, 0x53f7a602, 0x96a145e4, 0xe496d3a1, 0x5bed769b, 0x9b5b2ded +, 0xc25d2875, 0x75c2ea5d, 0x1c24c5e1, 0xe11cd924, 0xaee9d43d, 0x3dae7ae9, 0x6abef24c, 0x4c6a98be, 0x5aee826c, 0x6c5ad8ee, 0x41c3bd7e, 0x7e41fcc3, 0x206f3f5, 0xf502f106, 0x4fd15283, 0x834f1dd1 +, 0x5ce48c68, 0x685cd0e4, 0xf4075651, 0x51f4a207, 0x345c8dd1, 0xd134b95c, 0x818e1f9, 0xf908e918, 0x93ae4ce2, 0xe293dfae, 0x73953eab, 0xab734d95, 0x53f59762, 0x6253c4f5, 0x3f416b2a, 0x2a3f5441 +, 0xc141c08, 0x80c1014, 0x52f66395, 0x955231f6, 0x65afe946, 0x46658caf, 0x5ee27f9d, 0x9d5e21e2, 0x28784830, 0x30286078, 0xa1f8cf37, 0x37a16ef8, 0xf111b0a, 0xa0f1411, 0xb5c4eb2f, 0x2fb55ec4 +, 0x91b150e, 0xe091c1b, 0x365a7e24, 0x2436485a, 0x9bb6ad1b, 0x1b9b36b6, 0x3d4798df, 0xdf3da547, 0x266aa7cd, 0xcd26816a, 0x69bbf54e, 0x4e699cbb, 0xcd4c337f, 0x7fcdfe4c, 0x9fba50ea, 0xea9fcfba +, 0x1b2d3f12, 0x121b242d, 0x9eb9a41d, 0x1d9e3ab9, 0x749cc458, 0x5874b09c, 0x2e724634, 0x342e6872, 0x2d774136, 0x362d6c77, 0xb2cd11dc, 0xdcb2a3cd, 0xee299db4, 0xb4ee7329, 0xfb164d5b, 0x5bfbb616 +, 0xf601a5a4, 0xa4f65301, 0x4dd7a176, 0x764decd7, 0x61a314b7, 0xb76175a3, 0xce49347d, 0x7dcefa49, 0x7b8ddf52, 0x527ba48d, 0x3e429fdd, 0xdd3ea142, 0x7193cd5e, 0x5e71bc93, 0x97a2b113, 0x139726a2 +, 0xf504a2a6, 0xa6f55704, 0x68b801b9, 0xb96869b8, 0x0, 0x0, 0x2c74b5c1, 0xc12c9974, 0x60a0e040, 0x406080a0, 0x1f21c2e3, 0xe31fdd21, 0xc8433a79, 0x79c8f243, 0xed2c9ab6, 0xb6ed772c +, 0xbed90dd4, 0xd4beb3d9, 0x46ca478d, 0x8d4601ca, 0xd9701767, 0x67d9ce70, 0x4bddaf72, 0x724be4dd, 0xde79ed94, 0x94de3379, 0xd467ff98, 0x98d42b67, 0xe82393b0, 0xb0e87b23, 0x4ade5b85, 0x854a11de +, 0x6bbd06bb, 0xbb6b6dbd, 0x2a7ebbc5, 0xc52a917e, 0xe5347b4f, 0x4fe59e34, 0x163ad7ed, 0xed16c13a, 0xc554d286, 0x86c51754, 0xd762f89a, 0x9ad72f62, 0x55ff9966, 0x6655ccff, 0x94a7b611, 0x119422a7 +, 0xcf4ac08a, 0x8acf0f4a, 0x1030d9e9, 0xe910c930, 0x60a0e04, 0x406080a, 0x819866fe, 0xfe81e798, 0xf00baba0, 0xa0f05b0b, 0x44ccb478, 0x7844f0cc, 0xbad5f025, 0x25ba4ad5, 0xe33e754b, 0x4be3963e +, 0xf30eaca2, 0xa2f35f0e, 0xfe19445d, 0x5dfeba19, 0xc05bdb80, 0x80c01b5b, 0x8a858005, 0x58a0a85, 0xadecd33f, 0x3fad7eec, 0xbcdffe21, 0x21bc42df, 0x48d8a870, 0x7048e0d8, 0x40cfdf1, 0xf104f90c +, 0xdf7a1963, 0x63dfc67a, 0xc1582f77, 0x77c1ee58, 0x759f30af, 0xaf75459f, 0x63a5e742, 0x426384a5, 0x30507020, 0x20304050, 0x1a2ecbe5, 0xe51ad12e, 0xe12effd, 0xfd0ee112, 0x6db708bf, 0xbf6d65b7 +, 0x4cd45581, 0x814c19d4, 0x143c2418, 0x1814303c, 0x355f7926, 0x26354c5f, 0x2f71b2c3, 0xc32f9d71, 0xe13886be, 0xbee16738, 0xa2fdc835, 0x35a26afd, 0xcc4fc788, 0x88cc0b4f, 0x394b652e, 0x2e395c4b +, 0x57f96a93, 0x93573df9, 0xf20d5855, 0x55f2aa0d, 0x829d61fc, 0xfc82e39d, 0x47c9b37a, 0x7a47f4c9, 0xacef27c8, 0xc8ac8bef, 0xe73288ba, 0xbae76f32, 0x2b7d4f32, 0x322b647d, 0x95a442e6, 0xe695d7a4 +, 0xa0fb3bc0, 0xc0a09bfb, 0x98b3aa19, 0x199832b3, 0xd168f69e, 0x9ed12768, 0x7f8122a3, 0xa37f5d81, 0x66aaee44, 0x446688aa, 0x7e82d654, 0x547ea882, 0xabe6dd3b, 0x3bab76e6, 0x839e950b, 0xb83169e +, 0xca45c98c, 0x8cca0345, 0x297bbcc7, 0xc729957b, 0xd36e056b, 0x6bd3d66e, 0x3c446c28, 0x283c5044, 0x798b2ca7, 0xa779558b, 0xe23d81bc, 0xbce2633d, 0x1d273116, 0x161d2c27, 0x769a37ad, 0xad76419a +, 0x3b4d96db, 0xdb3bad4d, 0x56fa9e64, 0x6456c8fa, 0x4ed2a674, 0x744ee8d2, 0x1e223614, 0x141e2822, 0xdb76e492, 0x92db3f76, 0xa1e120c, 0xc0a181e, 0x6cb4fc48, 0x486c90b4, 0xe4378fb8, 0xb8e46b37 +, 0x5de7789f, 0x9f5d25e7, 0x6eb20fbd, 0xbd6e61b2, 0xef2a6943, 0x43ef862a, 0xa6f135c4, 0xc4a693f1, 0xa8e3da39, 0x39a872e3, 0xa4f7c631, 0x31a462f7, 0x37598ad3, 0xd337bd59, 0x8b8674f2, 0xf28bff86 +, 0x325683d5, 0xd532b156, 0x43c54e8b, 0x8b430dc5, 0x59eb856e, 0x6e59dceb, 0xb7c218da, 0xdab7afc2, 0x8c8f8e01, 0x18c028f, 0x64ac1db1, 0xb16479ac, 0xd26df19c, 0x9cd2236d, 0xe03b7249, 0x49e0923b +, 0xb4c71fd8, 0xd8b4abc7, 0xfa15b9ac, 0xacfa4315, 0x709faf3, 0xf307fd09, 0x256fa0cf, 0xcf25856f, 0xafea20ca, 0xcaaf8fea, 0x8e897df4, 0xf48ef389, 0xe9206747, 0x47e98e20, 0x18283810, 0x10182028 +, 0xd5640b6f, 0x6fd5de64, 0x888373f0, 0xf088fb83, 0x6fb1fb4a, 0x4a6f94b1, 0x7296ca5c, 0x5c72b896, 0x246c5438, 0x3824706c, 0xf1085f57, 0x57f1ae08, 0xc7522173, 0x73c7e652, 0x51f36497, 0x975135f3 +, 0x2365aecb, 0xcb238d65, 0x7c8425a1, 0xa17c5984, 0x9cbf57e8, 0xe89ccbbf, 0x21635d3e, 0x3e217c63, 0xdd7cea96, 0x96dd377c, 0xdc7f1e61, 0x61dcc27f, 0x86919c0d, 0xd861a91, 0x85949b0f, 0xf851e94 +, 0x90ab4be0, 0xe090dbab, 0x42c6ba7c, 0x7c42f8c6, 0xc4572671, 0x71c4e257, 0xaae529cc, 0xccaa83e5, 0xd873e390, 0x90d83b73, 0x50f0906, 0x6050c0f, 0x103f4f7, 0xf701f503, 0x12362a1c, 0x1c123836 +, 0xa3fe3cc2, 0xc2a39ffe, 0x5fe18b6a, 0x6a5fd4e1, 0xf910beae, 0xaef94710, 0xd06b0269, 0x69d0d26b, 0x91a8bf17, 0x17912ea8, 0x58e87199, 0x995829e8, 0x2769533a, 0x3a277469, 0xb9d0f727, 0x27b94ed0 +, 0x384891d9, 0xd938a948, 0x1335deeb, 0xeb13cd35, 0xb3cee52b, 0x2bb356ce, 0x33557722, 0x22334455, 0xbbd604d2, 0xd2bbbfd6, 0x709039a9, 0xa9704990, 0x89808707, 0x7890e80, 0xa7f2c133, 0x33a766f2 +, 0xb6c1ec2d, 0x2db65ac1, 0x22665a3c, 0x3c227866, 0x92adb815, 0x15922aad, 0x2060a9c9, 0xc9208960, 0x49db5c87, 0x874915db, 0xff1ab0aa, 0xaaff4f1a, 0x7888d850, 0x5078a088, 0x7a8e2ba5, 0xa57a518e +, 0x8f8a8903, 0x38f068a, 0xf8134a59, 0x59f8b213, 0x809b9209, 0x980129b, 0x1739231a, 0x1a173439, 0xda751065, 0x65daca75, 0x315384d7, 0xd731b553, 0xc651d584, 0x84c61351, 0xb8d303d0, 0xd0b8bbd3 +, 0xc35edc82, 0x82c31f5e, 0xb0cbe229, 0x29b052cb, 0x7799c35a, 0x5a77b499, 0x11332d1e, 0x1e113c33, 0xcb463d7b, 0x7bcbf646, 0xfc1fb7a8, 0xa8fc4b1f, 0xd6610c6d, 0x6dd6da61, 0x3a4e622c, 0x2c3a584e}; + +#endif /* __tables_h */ diff --git a/webassembly/xmr/html_template/shell_minimal.html b/webassembly/xmr/html_template/shell_minimal.html new file mode 100644 index 0000000..75f1b81 --- /dev/null +++ b/webassembly/xmr/html_template/shell_minimal.html @@ -0,0 +1,146 @@ + + + + + + Emscripten-Generated Code + + + +
+
emscripten
+
Downloading...
+
+ +
+
+ +
+
+
+ Resize canvas + Lock/hide mouse pointer +     + +
+ +
+ +
+ + {{{ SCRIPT }}} + + \ No newline at end of file diff --git a/webassembly/xmr/int-util.h b/webassembly/xmr/int-util.h new file mode 100644 index 0000000..3428880 --- /dev/null +++ b/webassembly/xmr/int-util.h @@ -0,0 +1,245 @@ +// Copyright (c) 2014-2017, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#pragma once + +#include +#include +#include +#include +#include + +#if defined(__ANDROID__) +#include +#endif + +#if defined(_MSC_VER) +#include + +static inline uint32_t rol32(uint32_t x, int r) { + static_assert(sizeof(uint32_t) == sizeof(unsigned int), "this code assumes 32-bit integers"); + return _rotl(x, r); +} + +static inline uint64_t rol64(uint64_t x, int r) { + return _rotl64(x, r); +} + +#else + +static inline uint32_t rol32(uint32_t x, int r) { + return (x << (r & 31)) | (x >> (-r & 31)); +} + +static inline uint64_t rol64(uint64_t x, int r) { + return (x << (r & 63)) | (x >> (-r & 63)); +} + +#endif + +static inline uint64_t hi_dword(uint64_t val) { + return val >> 32; +} + +static inline uint64_t lo_dword(uint64_t val) { + return val & 0xFFFFFFFF; +} + +static inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) { + // multiplier = ab = a * 2^32 + b + // multiplicand = cd = c * 2^32 + d + // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d + uint64_t a = hi_dword(multiplier); + uint64_t b = lo_dword(multiplier); + uint64_t c = hi_dword(multiplicand); + uint64_t d = lo_dword(multiplicand); + + uint64_t ac = a * c; + uint64_t ad = a * d; + uint64_t bc = b * c; + uint64_t bd = b * d; + + uint64_t adbc = ad + bc; + uint64_t adbc_carry = adbc < ad ? 1 : 0; + + // multiplier * multiplicand = product_hi * 2^64 + product_lo + uint64_t product_lo = bd + (adbc << 32); + uint64_t product_lo_carry = product_lo < bd ? 1 : 0; + *product_hi = ac + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry; + assert(ac <= *product_hi); + + return product_lo; +} + +static inline uint64_t div_with_reminder(uint64_t dividend, uint32_t divisor, uint32_t* remainder) { + dividend |= ((uint64_t)*remainder) << 32; + *remainder = dividend % divisor; + return dividend / divisor; +} + +// Long division with 2^32 base +static inline uint32_t div128_32(uint64_t dividend_hi, uint64_t dividend_lo, uint32_t divisor, uint64_t* quotient_hi, uint64_t* quotient_lo) { + uint64_t dividend_dwords[4]; + uint32_t remainder = 0; + + dividend_dwords[3] = hi_dword(dividend_hi); + dividend_dwords[2] = lo_dword(dividend_hi); + dividend_dwords[1] = hi_dword(dividend_lo); + dividend_dwords[0] = lo_dword(dividend_lo); + + *quotient_hi = div_with_reminder(dividend_dwords[3], divisor, &remainder) << 32; + *quotient_hi |= div_with_reminder(dividend_dwords[2], divisor, &remainder); + *quotient_lo = div_with_reminder(dividend_dwords[1], divisor, &remainder) << 32; + *quotient_lo |= div_with_reminder(dividend_dwords[0], divisor, &remainder); + + return remainder; +} + +#define IDENT32(x) ((uint32_t) (x)) +#define IDENT64(x) ((uint64_t) (x)) + +#define SWAP32(x) ((((uint32_t) (x) & 0x000000ff) << 24) | \ + (((uint32_t) (x) & 0x0000ff00) << 8) | \ + (((uint32_t) (x) & 0x00ff0000) >> 8) | \ + (((uint32_t) (x) & 0xff000000) >> 24)) +#define SWAP64(x) ((((uint64_t) (x) & 0x00000000000000ff) << 56) | \ + (((uint64_t) (x) & 0x000000000000ff00) << 40) | \ + (((uint64_t) (x) & 0x0000000000ff0000) << 24) | \ + (((uint64_t) (x) & 0x00000000ff000000) << 8) | \ + (((uint64_t) (x) & 0x000000ff00000000) >> 8) | \ + (((uint64_t) (x) & 0x0000ff0000000000) >> 24) | \ + (((uint64_t) (x) & 0x00ff000000000000) >> 40) | \ + (((uint64_t) (x) & 0xff00000000000000) >> 56)) + +static inline uint32_t ident32(uint32_t x) { return x; } +static inline uint64_t ident64(uint64_t x) { return x; } + +#ifndef __OpenBSD__ +# if defined(__ANDROID__) && defined(__swap32) && !defined(swap32) +# define swap32 __swap32 +# elif !defined(swap32) +static inline uint32_t swap32(uint32_t x) { + x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >> 8); + return (x << 16) | (x >> 16); +} +# endif +# if defined(__ANDROID__) && defined(__swap64) && !defined(swap64) +# define swap64 __swap64 +# elif !defined(swap64) +static inline uint64_t swap64(uint64_t x) { + x = ((x & 0x00ff00ff00ff00ff) << 8) | ((x & 0xff00ff00ff00ff00) >> 8); + x = ((x & 0x0000ffff0000ffff) << 16) | ((x & 0xffff0000ffff0000) >> 16); + return (x << 32) | (x >> 32); +} +# endif +#endif /* __OpenBSD__ */ + +#if defined(__GNUC__) +#define UNUSED __attribute__((unused)) +#else +#define UNUSED +#endif +static inline void mem_inplace_ident(void *mem UNUSED, size_t n UNUSED) { } +#undef UNUSED + +static inline void mem_inplace_swap32(void *mem, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + ((uint32_t *) mem)[i] = swap32(((const uint32_t *) mem)[i]); + } +} +static inline void mem_inplace_swap64(void *mem, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + ((uint64_t *) mem)[i] = swap64(((const uint64_t *) mem)[i]); + } +} + +static inline void memcpy_ident32(void *dst, const void *src, size_t n) { + memcpy(dst, src, 4 * n); +} +static inline void memcpy_ident64(void *dst, const void *src, size_t n) { + memcpy(dst, src, 8 * n); +} + +static inline void memcpy_swap32(void *dst, const void *src, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + ((uint32_t *) dst)[i] = swap32(((const uint32_t *) src)[i]); + } +} +static inline void memcpy_swap64(void *dst, const void *src, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + ((uint64_t *) dst)[i] = swap64(((const uint64_t *) src)[i]); + } +} + +#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN) +static_assert(false, "BYTE_ORDER is undefined. Perhaps, GNU extensions are not enabled"); +#endif + +#if BYTE_ORDER == LITTLE_ENDIAN +#define SWAP32LE IDENT32 +#define SWAP32BE SWAP32 +#define swap32le ident32 +#define swap32be swap32 +#define mem_inplace_swap32le mem_inplace_ident +#define mem_inplace_swap32be mem_inplace_swap32 +#define memcpy_swap32le memcpy_ident32 +#define memcpy_swap32be memcpy_swap32 +#define SWAP64LE IDENT64 +#define SWAP64BE SWAP64 +#define swap64le ident64 +#define swap64be swap64 +#define mem_inplace_swap64le mem_inplace_ident +#define mem_inplace_swap64be mem_inplace_swap64 +#define memcpy_swap64le memcpy_ident64 +#define memcpy_swap64be memcpy_swap64 +#endif + +#if BYTE_ORDER == BIG_ENDIAN +#define SWAP32BE IDENT32 +#define SWAP32LE SWAP32 +#define swap32be ident32 +#define swap32le swap32 +#define mem_inplace_swap32be mem_inplace_ident +#define mem_inplace_swap32le mem_inplace_swap32 +#define memcpy_swap32be memcpy_ident32 +#define memcpy_swap32le memcpy_swap32 +#define SWAP64BE IDENT64 +#define SWAP64LE SWAP64 +#define swap64be ident64 +#define swap64le swap64 +#define mem_inplace_swap64be mem_inplace_ident +#define mem_inplace_swap64le mem_inplace_swap64 +#define memcpy_swap64be memcpy_ident64 +#define memcpy_swap64le memcpy_swap64 +#endif diff --git a/webassembly/xmr/jh.h b/webassembly/xmr/jh.h new file mode 100644 index 0000000..959ba05 --- /dev/null +++ b/webassembly/xmr/jh.h @@ -0,0 +1,16 @@ +#ifndef JH_H +#define JH_H +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void jh(unsigned bit_len, const uint8_t input[], + size_t input_bit_length, uint8_t output[]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/webassembly/xmr/jh_ansi_opt64.c b/webassembly/xmr/jh_ansi_opt64.c new file mode 100644 index 0000000..7aa0310 --- /dev/null +++ b/webassembly/xmr/jh_ansi_opt64.c @@ -0,0 +1,377 @@ +/*This program gives the 64-bit optimized bitslice implementation of JH using ANSI C + + -------------------------------- + Performance + + Microprocessor: Intel CORE 2 processor (Core 2 Duo Mobile T6600 2.2GHz) + Operating System: 64-bit Ubuntu 10.04 (Linux kernel 2.6.32-22-generic) + Speed for long message: + 1) 45.8 cycles/byte compiler: Intel C++ Compiler 11.1 compilation option: icc -O2 + 2) 56.8 cycles/byte compiler: gcc 4.4.3 compilation option: gcc -O3 + + -------------------------------- + Last Modified: January 16, 2011 +*/ + + + +#include +#include +#include + +typedef unsigned long long uint64; + +typedef unsigned char BitSequence; +typedef unsigned long long DataLength; +typedef enum {SUCCESS = 0, FAIL = 1, BAD_HASHLEN = 2} HashReturn; + +/*define data alignment for different C compilers*/ +#if defined(__GNUC__) + #define DATA_ALIGN16(x) x __attribute__ ((aligned(16))) +#else + #define DATA_ALIGN16(x) __declspec(align(16)) x +#endif + + +typedef struct { + int hashbitlen; /*the message digest size*/ + unsigned long long databitlen; /*the message size in bits*/ + unsigned long long datasize_in_buffer; /*the size of the message remained in buffer; assumed to be multiple of 8bits except for the last partial block at the end of the message*/ + DATA_ALIGN16(uint64 x[8][2]); /*the 1024-bit state, ( x[i][0] || x[i][1] ) is the ith row of the state in the pseudocode*/ + unsigned char buffer[64]; /*the 512-bit message block to be hashed;*/ +} hashState; + + +/*The initial hash value H(0)*/ +static const unsigned char JH224_H0[128]={0x2d,0xfe,0xdd,0x62,0xf9,0x9a,0x98,0xac,0xae,0x7c,0xac,0xd6,0x19,0xd6,0x34,0xe7,0xa4,0x83,0x10,0x5,0xbc,0x30,0x12,0x16,0xb8,0x60,0x38,0xc6,0xc9,0x66,0x14,0x94,0x66,0xd9,0x89,0x9f,0x25,0x80,0x70,0x6f,0xce,0x9e,0xa3,0x1b,0x1d,0x9b,0x1a,0xdc,0x11,0xe8,0x32,0x5f,0x7b,0x36,0x6e,0x10,0xf9,0x94,0x85,0x7f,0x2,0xfa,0x6,0xc1,0x1b,0x4f,0x1b,0x5c,0xd8,0xc8,0x40,0xb3,0x97,0xf6,0xa1,0x7f,0x6e,0x73,0x80,0x99,0xdc,0xdf,0x93,0xa5,0xad,0xea,0xa3,0xd3,0xa4,0x31,0xe8,0xde,0xc9,0x53,0x9a,0x68,0x22,0xb4,0xa9,0x8a,0xec,0x86,0xa1,0xe4,0xd5,0x74,0xac,0x95,0x9c,0xe5,0x6c,0xf0,0x15,0x96,0xd,0xea,0xb5,0xab,0x2b,0xbf,0x96,0x11,0xdc,0xf0,0xdd,0x64,0xea,0x6e}; +static const unsigned char JH256_H0[128]={0xeb,0x98,0xa3,0x41,0x2c,0x20,0xd3,0xeb,0x92,0xcd,0xbe,0x7b,0x9c,0xb2,0x45,0xc1,0x1c,0x93,0x51,0x91,0x60,0xd4,0xc7,0xfa,0x26,0x0,0x82,0xd6,0x7e,0x50,0x8a,0x3,0xa4,0x23,0x9e,0x26,0x77,0x26,0xb9,0x45,0xe0,0xfb,0x1a,0x48,0xd4,0x1a,0x94,0x77,0xcd,0xb5,0xab,0x26,0x2,0x6b,0x17,0x7a,0x56,0xf0,0x24,0x42,0xf,0xff,0x2f,0xa8,0x71,0xa3,0x96,0x89,0x7f,0x2e,0x4d,0x75,0x1d,0x14,0x49,0x8,0xf7,0x7d,0xe2,0x62,0x27,0x76,0x95,0xf7,0x76,0x24,0x8f,0x94,0x87,0xd5,0xb6,0x57,0x47,0x80,0x29,0x6c,0x5c,0x5e,0x27,0x2d,0xac,0x8e,0xd,0x6c,0x51,0x84,0x50,0xc6,0x57,0x5,0x7a,0xf,0x7b,0xe4,0xd3,0x67,0x70,0x24,0x12,0xea,0x89,0xe3,0xab,0x13,0xd3,0x1c,0xd7,0x69}; +static const unsigned char JH384_H0[128]={0x48,0x1e,0x3b,0xc6,0xd8,0x13,0x39,0x8a,0x6d,0x3b,0x5e,0x89,0x4a,0xde,0x87,0x9b,0x63,0xfa,0xea,0x68,0xd4,0x80,0xad,0x2e,0x33,0x2c,0xcb,0x21,0x48,0xf,0x82,0x67,0x98,0xae,0xc8,0x4d,0x90,0x82,0xb9,0x28,0xd4,0x55,0xea,0x30,0x41,0x11,0x42,0x49,0x36,0xf5,0x55,0xb2,0x92,0x48,0x47,0xec,0xc7,0x25,0xa,0x93,0xba,0xf4,0x3c,0xe1,0x56,0x9b,0x7f,0x8a,0x27,0xdb,0x45,0x4c,0x9e,0xfc,0xbd,0x49,0x63,0x97,0xaf,0xe,0x58,0x9f,0xc2,0x7d,0x26,0xaa,0x80,0xcd,0x80,0xc0,0x8b,0x8c,0x9d,0xeb,0x2e,0xda,0x8a,0x79,0x81,0xe8,0xf8,0xd5,0x37,0x3a,0xf4,0x39,0x67,0xad,0xdd,0xd1,0x7a,0x71,0xa9,0xb4,0xd3,0xbd,0xa4,0x75,0xd3,0x94,0x97,0x6c,0x3f,0xba,0x98,0x42,0x73,0x7f}; +static const unsigned char JH512_H0[128]={0x6f,0xd1,0x4b,0x96,0x3e,0x0,0xaa,0x17,0x63,0x6a,0x2e,0x5,0x7a,0x15,0xd5,0x43,0x8a,0x22,0x5e,0x8d,0xc,0x97,0xef,0xb,0xe9,0x34,0x12,0x59,0xf2,0xb3,0xc3,0x61,0x89,0x1d,0xa0,0xc1,0x53,0x6f,0x80,0x1e,0x2a,0xa9,0x5,0x6b,0xea,0x2b,0x6d,0x80,0x58,0x8e,0xcc,0xdb,0x20,0x75,0xba,0xa6,0xa9,0xf,0x3a,0x76,0xba,0xf8,0x3b,0xf7,0x1,0x69,0xe6,0x5,0x41,0xe3,0x4a,0x69,0x46,0xb5,0x8a,0x8e,0x2e,0x6f,0xe6,0x5a,0x10,0x47,0xa7,0xd0,0xc1,0x84,0x3c,0x24,0x3b,0x6e,0x71,0xb1,0x2d,0x5a,0xc1,0x99,0xcf,0x57,0xf6,0xec,0x9d,0xb1,0xf8,0x56,0xa7,0x6,0x88,0x7c,0x57,0x16,0xb1,0x56,0xe3,0xc2,0xfc,0xdf,0xe6,0x85,0x17,0xfb,0x54,0x5a,0x46,0x78,0xcc,0x8c,0xdd,0x4b}; + +/*42 round constants, each round constant is 32-byte (256-bit)*/ +static const unsigned char E8_bitslice_roundconstant[42][32]={ +{0x72,0xd5,0xde,0xa2,0xdf,0x15,0xf8,0x67,0x7b,0x84,0x15,0xa,0xb7,0x23,0x15,0x57,0x81,0xab,0xd6,0x90,0x4d,0x5a,0x87,0xf6,0x4e,0x9f,0x4f,0xc5,0xc3,0xd1,0x2b,0x40}, +{0xea,0x98,0x3a,0xe0,0x5c,0x45,0xfa,0x9c,0x3,0xc5,0xd2,0x99,0x66,0xb2,0x99,0x9a,0x66,0x2,0x96,0xb4,0xf2,0xbb,0x53,0x8a,0xb5,0x56,0x14,0x1a,0x88,0xdb,0xa2,0x31}, +{0x3,0xa3,0x5a,0x5c,0x9a,0x19,0xe,0xdb,0x40,0x3f,0xb2,0xa,0x87,0xc1,0x44,0x10,0x1c,0x5,0x19,0x80,0x84,0x9e,0x95,0x1d,0x6f,0x33,0xeb,0xad,0x5e,0xe7,0xcd,0xdc}, +{0x10,0xba,0x13,0x92,0x2,0xbf,0x6b,0x41,0xdc,0x78,0x65,0x15,0xf7,0xbb,0x27,0xd0,0xa,0x2c,0x81,0x39,0x37,0xaa,0x78,0x50,0x3f,0x1a,0xbf,0xd2,0x41,0x0,0x91,0xd3}, +{0x42,0x2d,0x5a,0xd,0xf6,0xcc,0x7e,0x90,0xdd,0x62,0x9f,0x9c,0x92,0xc0,0x97,0xce,0x18,0x5c,0xa7,0xb,0xc7,0x2b,0x44,0xac,0xd1,0xdf,0x65,0xd6,0x63,0xc6,0xfc,0x23}, +{0x97,0x6e,0x6c,0x3,0x9e,0xe0,0xb8,0x1a,0x21,0x5,0x45,0x7e,0x44,0x6c,0xec,0xa8,0xee,0xf1,0x3,0xbb,0x5d,0x8e,0x61,0xfa,0xfd,0x96,0x97,0xb2,0x94,0x83,0x81,0x97}, +{0x4a,0x8e,0x85,0x37,0xdb,0x3,0x30,0x2f,0x2a,0x67,0x8d,0x2d,0xfb,0x9f,0x6a,0x95,0x8a,0xfe,0x73,0x81,0xf8,0xb8,0x69,0x6c,0x8a,0xc7,0x72,0x46,0xc0,0x7f,0x42,0x14}, +{0xc5,0xf4,0x15,0x8f,0xbd,0xc7,0x5e,0xc4,0x75,0x44,0x6f,0xa7,0x8f,0x11,0xbb,0x80,0x52,0xde,0x75,0xb7,0xae,0xe4,0x88,0xbc,0x82,0xb8,0x0,0x1e,0x98,0xa6,0xa3,0xf4}, +{0x8e,0xf4,0x8f,0x33,0xa9,0xa3,0x63,0x15,0xaa,0x5f,0x56,0x24,0xd5,0xb7,0xf9,0x89,0xb6,0xf1,0xed,0x20,0x7c,0x5a,0xe0,0xfd,0x36,0xca,0xe9,0x5a,0x6,0x42,0x2c,0x36}, +{0xce,0x29,0x35,0x43,0x4e,0xfe,0x98,0x3d,0x53,0x3a,0xf9,0x74,0x73,0x9a,0x4b,0xa7,0xd0,0xf5,0x1f,0x59,0x6f,0x4e,0x81,0x86,0xe,0x9d,0xad,0x81,0xaf,0xd8,0x5a,0x9f}, +{0xa7,0x5,0x6,0x67,0xee,0x34,0x62,0x6a,0x8b,0xb,0x28,0xbe,0x6e,0xb9,0x17,0x27,0x47,0x74,0x7,0x26,0xc6,0x80,0x10,0x3f,0xe0,0xa0,0x7e,0x6f,0xc6,0x7e,0x48,0x7b}, +{0xd,0x55,0xa,0xa5,0x4a,0xf8,0xa4,0xc0,0x91,0xe3,0xe7,0x9f,0x97,0x8e,0xf1,0x9e,0x86,0x76,0x72,0x81,0x50,0x60,0x8d,0xd4,0x7e,0x9e,0x5a,0x41,0xf3,0xe5,0xb0,0x62}, +{0xfc,0x9f,0x1f,0xec,0x40,0x54,0x20,0x7a,0xe3,0xe4,0x1a,0x0,0xce,0xf4,0xc9,0x84,0x4f,0xd7,0x94,0xf5,0x9d,0xfa,0x95,0xd8,0x55,0x2e,0x7e,0x11,0x24,0xc3,0x54,0xa5}, +{0x5b,0xdf,0x72,0x28,0xbd,0xfe,0x6e,0x28,0x78,0xf5,0x7f,0xe2,0xf,0xa5,0xc4,0xb2,0x5,0x89,0x7c,0xef,0xee,0x49,0xd3,0x2e,0x44,0x7e,0x93,0x85,0xeb,0x28,0x59,0x7f}, +{0x70,0x5f,0x69,0x37,0xb3,0x24,0x31,0x4a,0x5e,0x86,0x28,0xf1,0x1d,0xd6,0xe4,0x65,0xc7,0x1b,0x77,0x4,0x51,0xb9,0x20,0xe7,0x74,0xfe,0x43,0xe8,0x23,0xd4,0x87,0x8a}, +{0x7d,0x29,0xe8,0xa3,0x92,0x76,0x94,0xf2,0xdd,0xcb,0x7a,0x9,0x9b,0x30,0xd9,0xc1,0x1d,0x1b,0x30,0xfb,0x5b,0xdc,0x1b,0xe0,0xda,0x24,0x49,0x4f,0xf2,0x9c,0x82,0xbf}, +{0xa4,0xe7,0xba,0x31,0xb4,0x70,0xbf,0xff,0xd,0x32,0x44,0x5,0xde,0xf8,0xbc,0x48,0x3b,0xae,0xfc,0x32,0x53,0xbb,0xd3,0x39,0x45,0x9f,0xc3,0xc1,0xe0,0x29,0x8b,0xa0}, +{0xe5,0xc9,0x5,0xfd,0xf7,0xae,0x9,0xf,0x94,0x70,0x34,0x12,0x42,0x90,0xf1,0x34,0xa2,0x71,0xb7,0x1,0xe3,0x44,0xed,0x95,0xe9,0x3b,0x8e,0x36,0x4f,0x2f,0x98,0x4a}, +{0x88,0x40,0x1d,0x63,0xa0,0x6c,0xf6,0x15,0x47,0xc1,0x44,0x4b,0x87,0x52,0xaf,0xff,0x7e,0xbb,0x4a,0xf1,0xe2,0xa,0xc6,0x30,0x46,0x70,0xb6,0xc5,0xcc,0x6e,0x8c,0xe6}, +{0xa4,0xd5,0xa4,0x56,0xbd,0x4f,0xca,0x0,0xda,0x9d,0x84,0x4b,0xc8,0x3e,0x18,0xae,0x73,0x57,0xce,0x45,0x30,0x64,0xd1,0xad,0xe8,0xa6,0xce,0x68,0x14,0x5c,0x25,0x67}, +{0xa3,0xda,0x8c,0xf2,0xcb,0xe,0xe1,0x16,0x33,0xe9,0x6,0x58,0x9a,0x94,0x99,0x9a,0x1f,0x60,0xb2,0x20,0xc2,0x6f,0x84,0x7b,0xd1,0xce,0xac,0x7f,0xa0,0xd1,0x85,0x18}, +{0x32,0x59,0x5b,0xa1,0x8d,0xdd,0x19,0xd3,0x50,0x9a,0x1c,0xc0,0xaa,0xa5,0xb4,0x46,0x9f,0x3d,0x63,0x67,0xe4,0x4,0x6b,0xba,0xf6,0xca,0x19,0xab,0xb,0x56,0xee,0x7e}, +{0x1f,0xb1,0x79,0xea,0xa9,0x28,0x21,0x74,0xe9,0xbd,0xf7,0x35,0x3b,0x36,0x51,0xee,0x1d,0x57,0xac,0x5a,0x75,0x50,0xd3,0x76,0x3a,0x46,0xc2,0xfe,0xa3,0x7d,0x70,0x1}, +{0xf7,0x35,0xc1,0xaf,0x98,0xa4,0xd8,0x42,0x78,0xed,0xec,0x20,0x9e,0x6b,0x67,0x79,0x41,0x83,0x63,0x15,0xea,0x3a,0xdb,0xa8,0xfa,0xc3,0x3b,0x4d,0x32,0x83,0x2c,0x83}, +{0xa7,0x40,0x3b,0x1f,0x1c,0x27,0x47,0xf3,0x59,0x40,0xf0,0x34,0xb7,0x2d,0x76,0x9a,0xe7,0x3e,0x4e,0x6c,0xd2,0x21,0x4f,0xfd,0xb8,0xfd,0x8d,0x39,0xdc,0x57,0x59,0xef}, +{0x8d,0x9b,0xc,0x49,0x2b,0x49,0xeb,0xda,0x5b,0xa2,0xd7,0x49,0x68,0xf3,0x70,0xd,0x7d,0x3b,0xae,0xd0,0x7a,0x8d,0x55,0x84,0xf5,0xa5,0xe9,0xf0,0xe4,0xf8,0x8e,0x65}, +{0xa0,0xb8,0xa2,0xf4,0x36,0x10,0x3b,0x53,0xc,0xa8,0x7,0x9e,0x75,0x3e,0xec,0x5a,0x91,0x68,0x94,0x92,0x56,0xe8,0x88,0x4f,0x5b,0xb0,0x5c,0x55,0xf8,0xba,0xbc,0x4c}, +{0xe3,0xbb,0x3b,0x99,0xf3,0x87,0x94,0x7b,0x75,0xda,0xf4,0xd6,0x72,0x6b,0x1c,0x5d,0x64,0xae,0xac,0x28,0xdc,0x34,0xb3,0x6d,0x6c,0x34,0xa5,0x50,0xb8,0x28,0xdb,0x71}, +{0xf8,0x61,0xe2,0xf2,0x10,0x8d,0x51,0x2a,0xe3,0xdb,0x64,0x33,0x59,0xdd,0x75,0xfc,0x1c,0xac,0xbc,0xf1,0x43,0xce,0x3f,0xa2,0x67,0xbb,0xd1,0x3c,0x2,0xe8,0x43,0xb0}, +{0x33,0xa,0x5b,0xca,0x88,0x29,0xa1,0x75,0x7f,0x34,0x19,0x4d,0xb4,0x16,0x53,0x5c,0x92,0x3b,0x94,0xc3,0xe,0x79,0x4d,0x1e,0x79,0x74,0x75,0xd7,0xb6,0xee,0xaf,0x3f}, +{0xea,0xa8,0xd4,0xf7,0xbe,0x1a,0x39,0x21,0x5c,0xf4,0x7e,0x9,0x4c,0x23,0x27,0x51,0x26,0xa3,0x24,0x53,0xba,0x32,0x3c,0xd2,0x44,0xa3,0x17,0x4a,0x6d,0xa6,0xd5,0xad}, +{0xb5,0x1d,0x3e,0xa6,0xaf,0xf2,0xc9,0x8,0x83,0x59,0x3d,0x98,0x91,0x6b,0x3c,0x56,0x4c,0xf8,0x7c,0xa1,0x72,0x86,0x60,0x4d,0x46,0xe2,0x3e,0xcc,0x8,0x6e,0xc7,0xf6}, +{0x2f,0x98,0x33,0xb3,0xb1,0xbc,0x76,0x5e,0x2b,0xd6,0x66,0xa5,0xef,0xc4,0xe6,0x2a,0x6,0xf4,0xb6,0xe8,0xbe,0xc1,0xd4,0x36,0x74,0xee,0x82,0x15,0xbc,0xef,0x21,0x63}, +{0xfd,0xc1,0x4e,0xd,0xf4,0x53,0xc9,0x69,0xa7,0x7d,0x5a,0xc4,0x6,0x58,0x58,0x26,0x7e,0xc1,0x14,0x16,0x6,0xe0,0xfa,0x16,0x7e,0x90,0xaf,0x3d,0x28,0x63,0x9d,0x3f}, +{0xd2,0xc9,0xf2,0xe3,0x0,0x9b,0xd2,0xc,0x5f,0xaa,0xce,0x30,0xb7,0xd4,0xc,0x30,0x74,0x2a,0x51,0x16,0xf2,0xe0,0x32,0x98,0xd,0xeb,0x30,0xd8,0xe3,0xce,0xf8,0x9a}, +{0x4b,0xc5,0x9e,0x7b,0xb5,0xf1,0x79,0x92,0xff,0x51,0xe6,0x6e,0x4,0x86,0x68,0xd3,0x9b,0x23,0x4d,0x57,0xe6,0x96,0x67,0x31,0xcc,0xe6,0xa6,0xf3,0x17,0xa,0x75,0x5}, +{0xb1,0x76,0x81,0xd9,0x13,0x32,0x6c,0xce,0x3c,0x17,0x52,0x84,0xf8,0x5,0xa2,0x62,0xf4,0x2b,0xcb,0xb3,0x78,0x47,0x15,0x47,0xff,0x46,0x54,0x82,0x23,0x93,0x6a,0x48}, +{0x38,0xdf,0x58,0x7,0x4e,0x5e,0x65,0x65,0xf2,0xfc,0x7c,0x89,0xfc,0x86,0x50,0x8e,0x31,0x70,0x2e,0x44,0xd0,0xb,0xca,0x86,0xf0,0x40,0x9,0xa2,0x30,0x78,0x47,0x4e}, +{0x65,0xa0,0xee,0x39,0xd1,0xf7,0x38,0x83,0xf7,0x5e,0xe9,0x37,0xe4,0x2c,0x3a,0xbd,0x21,0x97,0xb2,0x26,0x1,0x13,0xf8,0x6f,0xa3,0x44,0xed,0xd1,0xef,0x9f,0xde,0xe7}, +{0x8b,0xa0,0xdf,0x15,0x76,0x25,0x92,0xd9,0x3c,0x85,0xf7,0xf6,0x12,0xdc,0x42,0xbe,0xd8,0xa7,0xec,0x7c,0xab,0x27,0xb0,0x7e,0x53,0x8d,0x7d,0xda,0xaa,0x3e,0xa8,0xde}, +{0xaa,0x25,0xce,0x93,0xbd,0x2,0x69,0xd8,0x5a,0xf6,0x43,0xfd,0x1a,0x73,0x8,0xf9,0xc0,0x5f,0xef,0xda,0x17,0x4a,0x19,0xa5,0x97,0x4d,0x66,0x33,0x4c,0xfd,0x21,0x6a}, +{0x35,0xb4,0x98,0x31,0xdb,0x41,0x15,0x70,0xea,0x1e,0xf,0xbb,0xed,0xcd,0x54,0x9b,0x9a,0xd0,0x63,0xa1,0x51,0x97,0x40,0x72,0xf6,0x75,0x9d,0xbf,0x91,0x47,0x6f,0xe2}}; + + +static void E8(hashState *state); /*The bijective function E8, in bitslice form*/ +static void F8(hashState *state); /*The compression function F8 */ + +/*The API functions*/ +static HashReturn Init(hashState *state, int hashbitlen); +static HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen); +static HashReturn Final(hashState *state, BitSequence *hashval); +static HashReturn Hash(int hashbitlen, const BitSequence *data,DataLength databitlen, BitSequence *hashval); + +/*swapping bit 2i with bit 2i+1 of 64-bit x*/ +#define SWAP1(x) (x) = ((((x) & 0x5555555555555555ULL) << 1) | (((x) & 0xaaaaaaaaaaaaaaaaULL) >> 1)); +/*swapping bits 4i||4i+1 with bits 4i+2||4i+3 of 64-bit x*/ +#define SWAP2(x) (x) = ((((x) & 0x3333333333333333ULL) << 2) | (((x) & 0xccccccccccccccccULL) >> 2)); +/*swapping bits 8i||8i+1||8i+2||8i+3 with bits 8i+4||8i+5||8i+6||8i+7 of 64-bit x*/ +#define SWAP4(x) (x) = ((((x) & 0x0f0f0f0f0f0f0f0fULL) << 4) | (((x) & 0xf0f0f0f0f0f0f0f0ULL) >> 4)); +/*swapping bits 16i||16i+1||......||16i+7 with bits 16i+8||16i+9||......||16i+15 of 64-bit x*/ +#define SWAP8(x) (x) = ((((x) & 0x00ff00ff00ff00ffULL) << 8) | (((x) & 0xff00ff00ff00ff00ULL) >> 8)); +/*swapping bits 32i||32i+1||......||32i+15 with bits 32i+16||32i+17||......||32i+31 of 64-bit x*/ +#define SWAP16(x) (x) = ((((x) & 0x0000ffff0000ffffULL) << 16) | (((x) & 0xffff0000ffff0000ULL) >> 16)); +/*swapping bits 64i||64i+1||......||64i+31 with bits 64i+32||64i+33||......||64i+63 of 64-bit x*/ +#define SWAP32(x) (x) = (((x) << 32) | ((x) >> 32)); + +/*The MDS transform*/ +#define L(m0,m1,m2,m3,m4,m5,m6,m7) \ + (m4) ^= (m1); \ + (m5) ^= (m2); \ + (m6) ^= (m0) ^ (m3); \ + (m7) ^= (m0); \ + (m0) ^= (m5); \ + (m1) ^= (m6); \ + (m2) ^= (m4) ^ (m7); \ + (m3) ^= (m4); + +/*Two Sboxes are computed in parallel, each Sbox implements S0 and S1, selected by a constant bit*/ +/*The reason to compute two Sboxes in parallel is to try to fully utilize the parallel processing power*/ +#define SS(m0,m1,m2,m3,m4,m5,m6,m7,cc0,cc1) \ + m3 = ~(m3); \ + m7 = ~(m7); \ + m0 ^= ((~(m2)) & (cc0)); \ + m4 ^= ((~(m6)) & (cc1)); \ + temp0 = (cc0) ^ ((m0) & (m1));\ + temp1 = (cc1) ^ ((m4) & (m5));\ + m0 ^= ((m2) & (m3)); \ + m4 ^= ((m6) & (m7)); \ + m3 ^= ((~(m1)) & (m2)); \ + m7 ^= ((~(m5)) & (m6)); \ + m1 ^= ((m0) & (m2)); \ + m5 ^= ((m4) & (m6)); \ + m2 ^= ((m0) & (~(m3))); \ + m6 ^= ((m4) & (~(m7))); \ + m0 ^= ((m1) | (m3)); \ + m4 ^= ((m5) | (m7)); \ + m3 ^= ((m1) & (m2)); \ + m7 ^= ((m5) & (m6)); \ + m1 ^= (temp0 & (m0)); \ + m5 ^= (temp1 & (m4)); \ + m2 ^= temp0; \ + m6 ^= temp1; + +/*The bijective function E8, in bitslice form*/ +static void E8(hashState *state) +{ + uint64 i,roundnumber,temp0,temp1; + + for (roundnumber = 0; roundnumber < 42; roundnumber = roundnumber+7) { + /*round 7*roundnumber+0: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+0])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+0])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP1(state->x[1][i]); SWAP1(state->x[3][i]); SWAP1(state->x[5][i]); SWAP1(state->x[7][i]); + } + + /*round 7*roundnumber+1: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+1])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+1])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP2(state->x[1][i]); SWAP2(state->x[3][i]); SWAP2(state->x[5][i]); SWAP2(state->x[7][i]); + } + + /*round 7*roundnumber+2: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+2])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+2])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP4(state->x[1][i]); SWAP4(state->x[3][i]); SWAP4(state->x[5][i]); SWAP4(state->x[7][i]); + } + + /*round 7*roundnumber+3: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+3])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+3])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP8(state->x[1][i]); SWAP8(state->x[3][i]); SWAP8(state->x[5][i]); SWAP8(state->x[7][i]); + } + + /*round 7*roundnumber+4: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+4])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+4])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP16(state->x[1][i]); SWAP16(state->x[3][i]); SWAP16(state->x[5][i]); SWAP16(state->x[7][i]); + } + + /*round 7*roundnumber+5: Sbox, MDS and Swapping layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+5])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+5])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + SWAP32(state->x[1][i]); SWAP32(state->x[3][i]); SWAP32(state->x[5][i]); SWAP32(state->x[7][i]); + } + + /*round 7*roundnumber+6: Sbox and MDS layers*/ + for (i = 0; i < 2; i++) { + SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+6])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+6])[i+2] ); + L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]); + } + /*round 7*roundnumber+6: swapping layer*/ + for (i = 1; i < 8; i = i+2) { + temp0 = state->x[i][0]; state->x[i][0] = state->x[i][1]; state->x[i][1] = temp0; + } + } + +} + +/*The compression function F8 */ +static void F8(hashState *state) +{ + uint64 i; + + /*xor the 512-bit message with the fist half of the 1024-bit hash state*/ + for (i = 0; i < 8; i++) state->x[i >> 1][i & 1] ^= ((uint64*)state->buffer)[i]; + + /*the bijective function E8 */ + E8(state); + + /*xor the 512-bit message with the second half of the 1024-bit hash state*/ + for (i = 0; i < 8; i++) state->x[(8+i) >> 1][(8+i) & 1] ^= ((uint64*)state->buffer)[i]; +} + +/*before hashing a message, initialize the hash state as H0 */ +static HashReturn Init(hashState *state, int hashbitlen) +{ + state->databitlen = 0; + state->datasize_in_buffer = 0; + + /*initialize the initial hash value of JH*/ + state->hashbitlen = hashbitlen; + + /*load the intital hash value into state*/ + switch (hashbitlen) + { + case 224: memcpy(state->x,JH224_H0,128); break; + case 256: memcpy(state->x,JH256_H0,128); break; + case 384: memcpy(state->x,JH384_H0,128); break; + case 512: memcpy(state->x,JH512_H0,128); break; + } + + return(SUCCESS); +} + + +/*hash each 512-bit message block, except the last partial block*/ +static HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen) +{ + DataLength index; /*the starting address of the data to be compressed*/ + + state->databitlen += databitlen; + index = 0; + + /*if there is remaining data in the buffer, fill it to a full message block first*/ + /*we assume that the size of the data in the buffer is the multiple of 8 bits if it is not at the end of a message*/ + + /*There is data in the buffer, but the incoming data is insufficient for a full block*/ + if ( (state->datasize_in_buffer > 0 ) && (( state->datasize_in_buffer + databitlen) < 512) ) { + if ( (databitlen & 7) == 0 ) { + memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3)) ; + } + else memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3)+1) ; + state->datasize_in_buffer += databitlen; + databitlen = 0; + } + + /*There is data in the buffer, and the incoming data is sufficient for a full block*/ + if ( (state->datasize_in_buffer > 0 ) && (( state->datasize_in_buffer + databitlen) >= 512) ) { + memcpy( state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3) ) ; + index = 64-(state->datasize_in_buffer >> 3); + databitlen = databitlen - (512 - state->datasize_in_buffer); + F8(state); + state->datasize_in_buffer = 0; + } + + /*hash the remaining full message blocks*/ + for ( ; databitlen >= 512; index = index+64, databitlen = databitlen - 512) { + memcpy(state->buffer, data+index, 64); + F8(state); + } + + /*store the partial block into buffer, assume that -- if part of the last byte is not part of the message, then that part consists of 0 bits*/ + if ( databitlen > 0) { + if ((databitlen & 7) == 0) + memcpy(state->buffer, data+index, (databitlen & 0x1ff) >> 3); + else + memcpy(state->buffer, data+index, ((databitlen & 0x1ff) >> 3)+1); + state->datasize_in_buffer = databitlen; + } + + return(SUCCESS); +} + +/*pad the message, process the padded block(s), truncate the hash value H to obtain the message digest*/ +static HashReturn Final(hashState *state, BitSequence *hashval) +{ + unsigned int i; + + if ( (state->databitlen & 0x1ff) == 0 ) { + /*pad the message when databitlen is multiple of 512 bits, then process the padded block*/ + memset(state->buffer, 0, 64); + state->buffer[0] = 0x80; + state->buffer[63] = state->databitlen & 0xff; + state->buffer[62] = (state->databitlen >> 8) & 0xff; + state->buffer[61] = (state->databitlen >> 16) & 0xff; + state->buffer[60] = (state->databitlen >> 24) & 0xff; + state->buffer[59] = (state->databitlen >> 32) & 0xff; + state->buffer[58] = (state->databitlen >> 40) & 0xff; + state->buffer[57] = (state->databitlen >> 48) & 0xff; + state->buffer[56] = (state->databitlen >> 56) & 0xff; + F8(state); + } + else { + /*set the rest of the bytes in the buffer to 0*/ + if ( (state->datasize_in_buffer & 7) == 0) + for (i = (state->databitlen & 0x1ff) >> 3; i < 64; i++) state->buffer[i] = 0; + else + for (i = ((state->databitlen & 0x1ff) >> 3)+1; i < 64; i++) state->buffer[i] = 0; + + /*pad and process the partial block when databitlen is not multiple of 512 bits, then hash the padded blocks*/ + state->buffer[((state->databitlen & 0x1ff) >> 3)] |= 1 << (7- (state->databitlen & 7)); + + F8(state); + memset(state->buffer, 0, 64); + state->buffer[63] = state->databitlen & 0xff; + state->buffer[62] = (state->databitlen >> 8) & 0xff; + state->buffer[61] = (state->databitlen >> 16) & 0xff; + state->buffer[60] = (state->databitlen >> 24) & 0xff; + state->buffer[59] = (state->databitlen >> 32) & 0xff; + state->buffer[58] = (state->databitlen >> 40) & 0xff; + state->buffer[57] = (state->databitlen >> 48) & 0xff; + state->buffer[56] = (state->databitlen >> 56) & 0xff; + F8(state); + } + + /*truncating the final hash value to generate the message digest*/ + switch(state->hashbitlen) { + case 224: memcpy(hashval,(unsigned char*)state->x+64+36,28); break; + case 256: memcpy(hashval,(unsigned char*)state->x+64+32,32); break; + case 384: memcpy(hashval,(unsigned char*)state->x+64+16,48); break; + case 512: memcpy(hashval,(unsigned char*)state->x+64,64); break; + } + + return(SUCCESS); +} + +/* hash a message, + three inputs: message digest size in bits (hashbitlen); message (data); message length in bits (databitlen) + one output: message digest (hashval) +*/ +static HashReturn Hash(int hashbitlen, const BitSequence *data,DataLength databitlen, BitSequence *hashval) +{ + hashState state; + + if ( hashbitlen == 224 || hashbitlen == 256 || hashbitlen == 384 || hashbitlen == 512 ) { + Init(&state, hashbitlen); + Update(&state, data, databitlen); + Final(&state, hashval); + return SUCCESS; + } + else + return(BAD_HASHLEN); +} + +void jh(unsigned bit_len, const uint8_t input[], size_t input_bit_length, uint8_t output[]) +{ + HashReturn ret = Hash(bit_len, input, input_bit_length, output); + assert(ret == SUCCESS); +} diff --git a/webassembly/xmr/keccak.c b/webassembly/xmr/keccak.c new file mode 100644 index 0000000..45aa4f9 --- /dev/null +++ b/webassembly/xmr/keccak.c @@ -0,0 +1,129 @@ +// keccak.c +// 19-Nov-11 Markku-Juhani O. Saarinen +// A baseline Keccak (3rd round) implementation. + +#include +#include +#include "keccak.h" + +#define HASH_DATA_AREA 136 +#define KECCAK_ROUNDS 24 + +#ifndef ROTL64 +#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) +#endif + +const uint64_t keccakf_rndc[24] = +{ + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 +}; + +const int keccakf_rotc[24] = +{ + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 +}; + +const int keccakf_piln[24] = +{ + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 +}; + +// update the state with given number of rounds + +void keccakf(uint64_t st[25], int rounds) +{ + int i, j, round; + uint64_t t, bc[5]; + + for (round = 0; round < rounds; ++round) { + + // Theta + bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20]; + bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21]; + bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22]; + bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23]; + bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24]; + + for (i = 0; i < 5; ++i) { + t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); + st[i ] ^= t; + st[i + 5] ^= t; + st[i + 10] ^= t; + st[i + 15] ^= t; + st[i + 20] ^= t; + } + + // Rho Pi + t = st[1]; + for (i = 0; i < 24; ++i) { + bc[0] = st[keccakf_piln[i]]; + st[keccakf_piln[i]] = ROTL64(t, keccakf_rotc[i]); + t = bc[0]; + } + + // Chi + for (j = 0; j < 25; j += 5) { + bc[0] = st[j ]; + bc[1] = st[j + 1]; + bc[2] = st[j + 2]; + bc[3] = st[j + 3]; + bc[4] = st[j + 4]; + st[j ] ^= (~bc[1]) & bc[2]; + st[j + 1] ^= (~bc[2]) & bc[3]; + st[j + 2] ^= (~bc[3]) & bc[4]; + st[j + 3] ^= (~bc[4]) & bc[0]; + st[j + 4] ^= (~bc[0]) & bc[1]; + } + + // Iota + st[0] ^= keccakf_rndc[round]; + } +} + +// compute a keccak hash (md) of given byte length from "in" +typedef uint64_t state_t[25]; + +void keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen) +{ + state_t st; + uint8_t temp[144]; + int i, rsiz, rsizw; + + rsiz = sizeof(state_t) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen; + rsizw = rsiz / 8; + + memset(st, 0, sizeof(st)); + + for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) { + for (i = 0; i < rsizw; i++) + st[i] ^= ((uint64_t *) in)[i]; + keccakf(st, KECCAK_ROUNDS); + } + + // last block and padding + memcpy(temp, in, inlen); + temp[inlen++] = 1; + memset(temp + inlen, 0, rsiz - inlen); + temp[rsiz - 1] |= 0x80; + + for (i = 0; i < rsizw; i++) + st[i] ^= ((uint64_t *) temp)[i]; + + keccakf(st, KECCAK_ROUNDS); + + memcpy(md, st, mdlen); +} + +void keccak1600(const uint8_t *in, int inlen, uint8_t *md) +{ + keccak(in, inlen, md, sizeof(state_t)); +} diff --git a/webassembly/xmr/keccak.h b/webassembly/xmr/keccak.h new file mode 100644 index 0000000..0b22d04 --- /dev/null +++ b/webassembly/xmr/keccak.h @@ -0,0 +1,23 @@ +// keccak.h +// 19-Nov-11 Markku-Juhani O. Saarinen + +#ifndef KECCAK_H +#define KECCAK_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen); + +void keccakf(uint64_t st[25], int norounds); + +void keccak1600(const uint8_t *in, int inlen, uint8_t *md); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/webassembly/xmr/license.txt b/webassembly/xmr/license.txt new file mode 100644 index 0000000..50fac93 --- /dev/null +++ b/webassembly/xmr/license.txt @@ -0,0 +1,39 @@ +code is based on + +https://github.com/noahdesu/xmonarch + +which is based on the monero code. + + + +Copyright (c) 2014-2018, The Monero Project + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Parts of the project are originally copyright (c) 2012-2013 The Cryptonote +developers diff --git a/webassembly/xmr/main.c b/webassembly/xmr/main.c new file mode 100644 index 0000000..e7fb7d5 --- /dev/null +++ b/webassembly/xmr/main.c @@ -0,0 +1,53 @@ +#include +#include +#include "cryptonight.h" + +#include +#include +#include +#include "jh.h" + +#include + +char* tohex(unsigned char * in) +{ + size_t size = 32; + + char output[(size * 2) + 1]; + + char *ptr = &output[0]; + + int i; + + for (i = 0; i < size; i++) + { + ptr += sprintf (ptr, "%02x",in[i]); + } + + return &output[0]; +} + + +char* hash_cn(char* hex, char* nonce) +{ + unsigned char inp[76]; + + char *pos = hex; + for( size_t i = 0; i < 76; i++) { sscanf(pos, "%2hhx", &inp[i]); pos += 2; } + + pos = nonce; + + for(size_t i = 39; i < 43; i++) { sscanf(pos, "%2hhx", &inp[i]); pos += 2; } + + unsigned char hash[76]; + cryptonight(hash, inp, 76); + + + return tohex(hash); +} + + +int main (void) +{ + return 0; +} diff --git a/webassembly/xmr/oaes_config.h b/webassembly/xmr/oaes_config.h new file mode 100644 index 0000000..3fc0e1b --- /dev/null +++ b/webassembly/xmr/oaes_config.h @@ -0,0 +1,50 @@ +/* + * --------------------------------------------------------------------------- + * OpenAES License + * --------------------------------------------------------------------------- + * Copyright (c) 2012, Nabil S. Al Ramli, www.nalramli.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * --------------------------------------------------------------------------- + */ + +#ifndef _OAES_CONFIG_H +#define _OAES_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#ifndef OAES_HAVE_ISAAC +//#define OAES_HAVE_ISAAC 1 +//#endif // OAES_HAVE_ISAAC + +//#ifndef OAES_DEBUG +//#define OAES_DEBUG 0 +//#endif // OAES_DEBUG + +#ifdef __cplusplus +} +#endif + +#endif // _OAES_CONFIG_H diff --git a/webassembly/xmr/oaes_lib.c b/webassembly/xmr/oaes_lib.c new file mode 100644 index 0000000..d213823 --- /dev/null +++ b/webassembly/xmr/oaes_lib.c @@ -0,0 +1,1414 @@ +/* + * --------------------------------------------------------------------------- + * OpenAES License + * --------------------------------------------------------------------------- + * Copyright (c) 2012, Nabil S. Al Ramli, www.nalramli.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * --------------------------------------------------------------------------- + */ +//static const char _NR[] = { +// 0x4e,0x61,0x62,0x69,0x6c,0x20,0x53,0x2e,0x20, +// 0x41,0x6c,0x20,0x52,0x61,0x6d,0x6c,0x69,0x00 }; + +#include +#include +#include +#if !((defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__APPLE__)) +#include +#endif +#include +#include +#include + +#ifdef WIN32 +#include +#else +#include +#include +#endif + +#include "oaes_config.h" +#include "oaes_lib.h" + +#ifdef OAES_HAVE_ISAAC +#include "rand.h" +#endif // OAES_HAVE_ISAAC + +#define OAES_RKEY_LEN 4 +#define OAES_COL_LEN 4 +#define OAES_ROUND_BASE 7 + +// the block is padded +#define OAES_FLAG_PAD 0x01 + +#ifndef min +# define min(a,b) (((a)<(b)) ? (a) : (b)) +#endif /* min */ + +// "OAES<8-bit header version><8-bit type><16-bit options><8-bit flags><56-bit reserved>" +static uint8_t oaes_header[OAES_BLOCK_SIZE] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ 0x4f, 0x41, 0x45, 0x53, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static uint8_t oaes_gf_8[] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; + +static uint8_t oaes_sub_byte_value[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76 }, + /*1*/ { 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0 }, + /*2*/ { 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15 }, + /*3*/ { 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75 }, + /*4*/ { 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84 }, + /*5*/ { 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf }, + /*6*/ { 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8 }, + /*7*/ { 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2 }, + /*8*/ { 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73 }, + /*9*/ { 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb }, + /*a*/ { 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79 }, + /*b*/ { 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08 }, + /*c*/ { 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a }, + /*d*/ { 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e }, + /*e*/ { 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf }, + /*f*/ { 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }, +}; + +static uint8_t oaes_inv_sub_byte_value[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb }, + /*1*/ { 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb }, + /*2*/ { 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e }, + /*3*/ { 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 }, + /*4*/ { 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 }, + /*5*/ { 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 }, + /*6*/ { 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 }, + /*7*/ { 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b }, + /*8*/ { 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 }, + /*9*/ { 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e }, + /*a*/ { 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b }, + /*b*/ { 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 }, + /*c*/ { 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f }, + /*d*/ { 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef }, + /*e*/ { 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 }, + /*f*/ { 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }, +}; + +static uint8_t oaes_gf_mul_2[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e }, + /*1*/ { 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e }, + /*2*/ { 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e }, + /*3*/ { 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e }, + /*4*/ { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e }, + /*5*/ { 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe }, + /*6*/ { 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde }, + /*7*/ { 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe }, + /*8*/ { 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05 }, + /*9*/ { 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25 }, + /*a*/ { 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45 }, + /*b*/ { 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65 }, + /*c*/ { 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85 }, + /*d*/ { 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5 }, + /*e*/ { 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5 }, + /*f*/ { 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5 }, +}; + +static uint8_t oaes_gf_mul_3[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11 }, + /*1*/ { 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21 }, + /*2*/ { 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71 }, + /*3*/ { 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41 }, + /*4*/ { 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1 }, + /*5*/ { 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1 }, + /*6*/ { 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1 }, + /*7*/ { 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81 }, + /*8*/ { 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a }, + /*9*/ { 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba }, + /*a*/ { 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea }, + /*b*/ { 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda }, + /*c*/ { 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a }, + /*d*/ { 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a }, + /*e*/ { 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a }, + /*f*/ { 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a }, +}; + +static uint8_t oaes_gf_mul_9[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77 }, + /*1*/ { 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7 }, + /*2*/ { 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c }, + /*3*/ { 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc }, + /*4*/ { 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01 }, + /*5*/ { 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91 }, + /*6*/ { 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a }, + /*7*/ { 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa }, + /*8*/ { 0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b }, + /*9*/ { 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b }, + /*a*/ { 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0 }, + /*b*/ { 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30 }, + /*c*/ { 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed }, + /*d*/ { 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d }, + /*e*/ { 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6 }, + /*f*/ { 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46 }, +}; + +static uint8_t oaes_gf_mul_b[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69 }, + /*1*/ { 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9 }, + /*2*/ { 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12 }, + /*3*/ { 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2 }, + /*4*/ { 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f }, + /*5*/ { 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f }, + /*6*/ { 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4 }, + /*7*/ { 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54 }, + /*8*/ { 0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e }, + /*9*/ { 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e }, + /*a*/ { 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5 }, + /*b*/ { 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55 }, + /*c*/ { 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68 }, + /*d*/ { 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8 }, + /*e*/ { 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13 }, + /*f*/ { 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3 }, +}; + +static uint8_t oaes_gf_mul_d[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b }, + /*1*/ { 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b }, + /*2*/ { 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0 }, + /*3*/ { 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20 }, + /*4*/ { 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26 }, + /*5*/ { 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6 }, + /*6*/ { 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d }, + /*7*/ { 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d }, + /*8*/ { 0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91 }, + /*9*/ { 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41 }, + /*a*/ { 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a }, + /*b*/ { 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa }, + /*c*/ { 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc }, + /*d*/ { 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c }, + /*e*/ { 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47 }, + /*f*/ { 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97 }, +}; + +static uint8_t oaes_gf_mul_e[16][16] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, + /*0*/ { 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a }, + /*1*/ { 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba }, + /*2*/ { 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81 }, + /*3*/ { 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61 }, + /*4*/ { 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7 }, + /*5*/ { 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17 }, + /*6*/ { 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c }, + /*7*/ { 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc }, + /*8*/ { 0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b }, + /*9*/ { 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb }, + /*a*/ { 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0 }, + /*b*/ { 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20 }, + /*c*/ { 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6 }, + /*d*/ { 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56 }, + /*e*/ { 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d }, + /*f*/ { 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d }, +}; + +static OAES_RET oaes_sub_byte( uint8_t * byte ) +{ + size_t _x, _y; + + if(NULL == byte) + return OAES_RET_ARG1; + + _y = ((_x = *byte) >> 4) & 0x0f; + _x &= 0x0f; + *byte = oaes_sub_byte_value[_y][_x]; + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_inv_sub_byte( uint8_t * byte ) +{ + size_t _x, _y; + + if( NULL == byte ) + return OAES_RET_ARG1; + + _x = _y = *byte; + _x &= 0x0f; + _y &= 0xf0; + _y >>= 4; + *byte = oaes_inv_sub_byte_value[_y][_x]; + + return OAES_RET_SUCCESS; +} +/* +static OAES_RET oaes_word_rot_right( uint8_t word[OAES_COL_LEN] ) +{ + uint8_t _temp[OAES_COL_LEN]; + + if( NULL == word ) + return OAES_RET_ARG1; + + memcpy( _temp + 1, word, OAES_COL_LEN - 1 ); + _temp[0] = word[OAES_COL_LEN - 1]; + memcpy( word, _temp, OAES_COL_LEN ); + + return OAES_RET_SUCCESS; +} +*/ + +static OAES_RET oaes_word_rot_left( uint8_t word[OAES_COL_LEN] ) +{ + uint8_t _temp[OAES_COL_LEN]; + + if( NULL == word ) + return OAES_RET_ARG1; + + memcpy( _temp, word + 1, OAES_COL_LEN - 1 ); + _temp[OAES_COL_LEN - 1] = word[0]; + memcpy( word, _temp, OAES_COL_LEN ); + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_shift_rows( uint8_t block[OAES_BLOCK_SIZE] ) +{ + if(NULL == block) + return OAES_RET_ARG1; + + uint8_t _temp[] = { block[0x03], block[0x02], block[0x01], block[0x06], block[0x0b] }; + + block[0x0b] = block[0x07]; + block[0x01] = block[0x05]; + block[0x02] = block[0x0a]; + block[0x03] = block[0x0f]; + block[0x05] = block[0x09]; + block[0x06] = block[0x0e]; + block[0x07] = _temp[0]; + block[0x09] = block[0x0d]; + block[0x0a] = _temp[1]; + block[0x0d] = _temp[2]; + block[0x0e] = _temp[3]; + block[0x0f] = _temp[4]; + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_inv_shift_rows( uint8_t block[OAES_BLOCK_SIZE] ) +{ + uint8_t _temp[OAES_BLOCK_SIZE]; + + if( NULL == block ) + return OAES_RET_ARG1; + + _temp[0x00] = block[0x00]; + _temp[0x01] = block[0x0d]; + _temp[0x02] = block[0x0a]; + _temp[0x03] = block[0x07]; + _temp[0x04] = block[0x04]; + _temp[0x05] = block[0x01]; + _temp[0x06] = block[0x0e]; + _temp[0x07] = block[0x0b]; + _temp[0x08] = block[0x08]; + _temp[0x09] = block[0x05]; + _temp[0x0a] = block[0x02]; + _temp[0x0b] = block[0x0f]; + _temp[0x0c] = block[0x0c]; + _temp[0x0d] = block[0x09]; + _temp[0x0e] = block[0x06]; + _temp[0x0f] = block[0x03]; + memcpy( block, _temp, OAES_BLOCK_SIZE ); + + return OAES_RET_SUCCESS; +} + +static uint8_t oaes_gf_mul(uint8_t left, uint8_t right) +{ + size_t _x, _y; + + _y = ((_x = left) >> 4) & 0x0f; + _x &= 0x0f; + + switch( right ) + { + case 0x02: + return oaes_gf_mul_2[_y][_x]; + break; + case 0x03: + return oaes_gf_mul_3[_y][_x]; + break; + case 0x09: + return oaes_gf_mul_9[_y][_x]; + break; + case 0x0b: + return oaes_gf_mul_b[_y][_x]; + break; + case 0x0d: + return oaes_gf_mul_d[_y][_x]; + break; + case 0x0e: + return oaes_gf_mul_e[_y][_x]; + break; + default: + return left; + break; + } +} + +static OAES_RET oaes_mix_cols( uint8_t word[OAES_COL_LEN] ) +{ + uint8_t _temp[OAES_COL_LEN]; + + if(NULL == word) + return OAES_RET_ARG1; + + _temp[0] = oaes_gf_mul(word[0], 0x02) ^ oaes_gf_mul( word[1], 0x03 ) ^ + word[2] ^ word[3]; + _temp[1] = word[0] ^ oaes_gf_mul( word[1], 0x02 ) ^ + oaes_gf_mul( word[2], 0x03 ) ^ word[3]; + _temp[2] = word[0] ^ word[1] ^ + oaes_gf_mul( word[2], 0x02 ) ^ oaes_gf_mul( word[3], 0x03 ); + _temp[3] = oaes_gf_mul( word[0], 0x03 ) ^ word[1] ^ + word[2] ^ oaes_gf_mul( word[3], 0x02 ); + memcpy( word, _temp, OAES_COL_LEN ); + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_inv_mix_cols( uint8_t word[OAES_COL_LEN] ) +{ + uint8_t _temp[OAES_COL_LEN]; + + if( NULL == word ) + return OAES_RET_ARG1; + + _temp[0] = oaes_gf_mul( word[0], 0x0e ) ^ oaes_gf_mul( word[1], 0x0b ) ^ + oaes_gf_mul( word[2], 0x0d ) ^ oaes_gf_mul( word[3], 0x09 ); + _temp[1] = oaes_gf_mul( word[0], 0x09 ) ^ oaes_gf_mul( word[1], 0x0e ) ^ + oaes_gf_mul( word[2], 0x0b ) ^ oaes_gf_mul( word[3], 0x0d ); + _temp[2] = oaes_gf_mul( word[0], 0x0d ) ^ oaes_gf_mul( word[1], 0x09 ) ^ + oaes_gf_mul( word[2], 0x0e ) ^ oaes_gf_mul( word[3], 0x0b ); + _temp[3] = oaes_gf_mul( word[0], 0x0b ) ^ oaes_gf_mul( word[1], 0x0d ) ^ + oaes_gf_mul( word[2], 0x09 ) ^ oaes_gf_mul( word[3], 0x0e ); + memcpy( word, _temp, OAES_COL_LEN ); + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_sprintf( + char * buf, size_t * buf_len, const uint8_t * data, size_t data_len ) +{ + size_t _i, _buf_len_in; + char _temp[4]; + + if( NULL == buf_len ) + return OAES_RET_ARG2; + + _buf_len_in = *buf_len; + *buf_len = data_len * 3 + data_len / OAES_BLOCK_SIZE + 1; + + if( NULL == buf ) + return OAES_RET_SUCCESS; + + if( *buf_len > _buf_len_in ) + return OAES_RET_BUF; + + if( NULL == data ) + return OAES_RET_ARG3; + + strcpy( buf, "" ); + + for( _i = 0; _i < data_len; _i++ ) + { + sprintf( _temp, "%02x ", data[_i] ); + strcat( buf, _temp ); + if( _i && 0 == ( _i + 1 ) % OAES_BLOCK_SIZE ) + strcat( buf, "\n" ); + } + + return OAES_RET_SUCCESS; +} + +#ifdef OAES_HAVE_ISAAC +static void oaes_get_seed( char buf[RANDSIZ + 1] ) +{ + struct timeb timer; + struct tm *gmTimer; + char * _test = NULL; + + ftime (&timer); + gmTimer = gmtime( &timer.time ); + _test = (char *) calloc( sizeof( char ), timer.millitm ); + sprintf( buf, "%04d%02d%02d%02d%02d%02d%03d%p%d", + gmTimer->tm_year + 1900, gmTimer->tm_mon + 1, gmTimer->tm_mday, + gmTimer->tm_hour, gmTimer->tm_min, gmTimer->tm_sec, timer.millitm, + _test + timer.millitm, getpid() ); + + if( _test ) + free( _test ); +} +#else +static uint32_t oaes_get_seed(void) +{ + struct timeb timer; + struct tm *gmTimer; + char * _test = NULL; + uint32_t _ret = 0; + + ftime (&timer); + gmTimer = gmtime( &timer.time ); + _test = (char *) calloc( sizeof( char ), timer.millitm ); + _ret = gmTimer->tm_year + 1900 + gmTimer->tm_mon + 1 + gmTimer->tm_mday + + gmTimer->tm_hour + gmTimer->tm_min + gmTimer->tm_sec + timer.millitm + + (uintptr_t) ( _test + timer.millitm ) + getpid(); + + if( _test ) + free( _test ); + + return _ret; +} +#endif // OAES_HAVE_ISAAC + +static OAES_RET oaes_key_destroy( oaes_key ** key ) +{ + if( NULL == *key ) + return OAES_RET_SUCCESS; + + if( (*key)->data ) + { + free( (*key)->data ); + (*key)->data = NULL; + } + + if( (*key)->exp_data ) + { + free( (*key)->exp_data ); + (*key)->exp_data = NULL; + } + + (*key)->data_len = 0; + (*key)->exp_data_len = 0; + (*key)->num_keys = 0; + (*key)->key_base = 0; + free( *key ); + *key = NULL; + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_key_expand( OAES_CTX * ctx ) +{ + size_t _i, _j; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + // First, all these macros confuse me - so I'll make them simpler + //_ctx->key->key_base = _ctx->key->data_len / OAES_RKEY_LEN; 32 / 4 + _ctx->key->key_base = 8; + //_ctx->key->num_keys = _ctx->key->key_base + OAES_ROUND_BASE; 8 + 7 + _ctx->key->num_keys = 15; + + //_ctx->key->exp_data_len = _ctx->key->num_keys * OAES_RKEY_LEN * OAES_COL_LEN; 15 * 4 * 4 + _ctx->key->exp_data_len = 240; + + _ctx->key->exp_data = (uint8_t *)calloc( _ctx->key->exp_data_len, sizeof( uint8_t )); + + // the first _ctx->key->data_len are a direct copy + memcpy( _ctx->key->exp_data, _ctx->key->data, _ctx->key->data_len ); + + // apply ExpandKey algorithm for remainder + //for( _i = _ctx->key->key_base; _i < _ctx->key->num_keys * OAES_RKEY_LEN; _i++ ) + for(_i = 8; _i < 60; _i++) + { + uint8_t _temp[OAES_COL_LEN]; + + memcpy( _temp, _ctx->key->exp_data + ( _i - 1 ) * OAES_RKEY_LEN, OAES_COL_LEN ); + + // transform key column + if( 0 == _i % 8 ) + { + oaes_word_rot_left( _temp ); + + for( _j = 0; _j < OAES_COL_LEN; _j++ ) + oaes_sub_byte( _temp + _j ); + + _temp[0] = _temp[0] ^ oaes_gf_8[ _i / _ctx->key->key_base - 1 ]; + } + else if( 4 == _i % _ctx->key->key_base ) + { + for( _j = 0; _j < OAES_COL_LEN; _j++ ) + oaes_sub_byte( _temp + _j ); + } + + for( _j = 0; _j < OAES_COL_LEN; _j++ ) + { + _ctx->key->exp_data[ _i * OAES_RKEY_LEN + _j ] = + _ctx->key->exp_data[ ( _i - _ctx->key->key_base ) * + OAES_RKEY_LEN + _j ] ^ _temp[_j]; + } + } + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_key_gen( OAES_CTX * ctx, size_t key_size ) +{ + size_t _i; + oaes_key * _key = NULL; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + OAES_RET _rc = OAES_RET_SUCCESS; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + _key = (oaes_key *) calloc( sizeof( oaes_key ), 1 ); + + if( NULL == _key ) + return OAES_RET_MEM; + + if( _ctx->key ) + oaes_key_destroy( &(_ctx->key) ); + + _key->data_len = key_size; + _key->data = (uint8_t *) calloc( key_size, sizeof( uint8_t )); + + if( NULL == _key->data ) + return OAES_RET_MEM; + + for( _i = 0; _i < key_size; _i++ ) +#ifdef OAES_HAVE_ISAAC + _key->data[_i] = (uint8_t) rand( _ctx->rctx ); +#else + _key->data[_i] = (uint8_t) rand(); +#endif // OAES_HAVE_ISAAC + + _ctx->key = _key; + _rc = _rc || oaes_key_expand( ctx ); + + if( _rc != OAES_RET_SUCCESS ) + { + oaes_key_destroy( &(_ctx->key) ); + return _rc; + } + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_key_gen_128( OAES_CTX * ctx ) +{ + return oaes_key_gen( ctx, 16 ); +} + +OAES_RET oaes_key_gen_192( OAES_CTX * ctx ) +{ + return oaes_key_gen( ctx, 24 ); +} + +OAES_RET oaes_key_gen_256( OAES_CTX * ctx ) +{ + return oaes_key_gen( ctx, 32 ); +} + +OAES_RET oaes_key_export( OAES_CTX * ctx, + uint8_t * data, size_t * data_len ) +{ + size_t _data_len_in; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + + if( NULL == data_len ) + return OAES_RET_ARG3; + + _data_len_in = *data_len; + // data + header + *data_len = _ctx->key->data_len + OAES_BLOCK_SIZE; + + if( NULL == data ) + return OAES_RET_SUCCESS; + + if( _data_len_in < *data_len ) + return OAES_RET_BUF; + + // header + memcpy( data, oaes_header, OAES_BLOCK_SIZE ); + data[5] = 0x01; + data[7] = _ctx->key->data_len; + memcpy( data + OAES_BLOCK_SIZE, _ctx->key->data, _ctx->key->data_len ); + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_key_export_data( OAES_CTX * ctx, + uint8_t * data, size_t * data_len ) +{ + size_t _data_len_in; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + + if( NULL == data_len ) + return OAES_RET_ARG3; + + _data_len_in = *data_len; + *data_len = _ctx->key->data_len; + + if( NULL == data ) + return OAES_RET_SUCCESS; + + if( _data_len_in < *data_len ) + return OAES_RET_BUF; + + memcpy( data, _ctx->key->data, *data_len ); + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_key_import( OAES_CTX * ctx, + const uint8_t * data, size_t data_len ) +{ + oaes_ctx * _ctx = (oaes_ctx *) ctx; + OAES_RET _rc = OAES_RET_SUCCESS; + int _key_length; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == data ) + return OAES_RET_ARG2; + + switch( data_len ) + { + case 16 + OAES_BLOCK_SIZE: + case 24 + OAES_BLOCK_SIZE: + case 32 + OAES_BLOCK_SIZE: + break; + default: + return OAES_RET_ARG3; + } + + // header + if( 0 != memcmp( data, oaes_header, 4 ) ) + return OAES_RET_HEADER; + + // header version + switch( data[4] ) + { + case 0x01: + break; + default: + return OAES_RET_HEADER; + } + + // header type + switch( data[5] ) + { + case 0x01: + break; + default: + return OAES_RET_HEADER; + } + + // options + _key_length = data[7]; + switch( _key_length ) + { + case 16: + case 24: + case 32: + break; + default: + return OAES_RET_HEADER; + } + + if( (int)data_len != _key_length + OAES_BLOCK_SIZE ) + return OAES_RET_ARG3; + + if( _ctx->key ) + oaes_key_destroy( &(_ctx->key) ); + + _ctx->key = (oaes_key *) calloc( sizeof( oaes_key ), 1 ); + + if( NULL == _ctx->key ) + return OAES_RET_MEM; + + _ctx->key->data_len = _key_length; + _ctx->key->data = (uint8_t *) + calloc( _key_length, sizeof( uint8_t )); + + if( NULL == _ctx->key->data ) + { + oaes_key_destroy( &(_ctx->key) ); + return OAES_RET_MEM; + } + + memcpy( _ctx->key->data, data + OAES_BLOCK_SIZE, _key_length ); + _rc = _rc || oaes_key_expand( ctx ); + + if( _rc != OAES_RET_SUCCESS ) + { + oaes_key_destroy( &(_ctx->key) ); + return _rc; + } + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_key_import_data( OAES_CTX * ctx, + const uint8_t * data, size_t data_len ) +{ + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + _ctx->key = (oaes_key *) calloc( sizeof( oaes_key ), 1 ); + + _ctx->key->data_len = data_len; + _ctx->key->data = (uint8_t *)calloc( data_len, sizeof( uint8_t )); + + memcpy( _ctx->key->data, data, data_len ); + oaes_key_expand( ctx ); + + return OAES_RET_SUCCESS; +} + +OAES_CTX * oaes_alloc(void) +{ + oaes_ctx * _ctx = (oaes_ctx *) calloc( sizeof( oaes_ctx ), 1 ); + + if( NULL == _ctx ) + return NULL; + +#ifdef OAES_HAVE_ISAAC + { + ub4 _i = 0; + char _seed[RANDSIZ + 1]; + + _ctx->rctx = (randctx *) calloc( sizeof( randctx ), 1 ); + + if( NULL == _ctx->rctx ) + { + free( _ctx ); + return NULL; + } + + oaes_get_seed( _seed ); + memset( _ctx->rctx->randrsl, 0, RANDSIZ ); + memcpy( _ctx->rctx->randrsl, _seed, RANDSIZ ); + randinit( _ctx->rctx, TRUE); + } +#else + srand( oaes_get_seed() ); +#endif // OAES_HAVE_ISAAC + + _ctx->key = NULL; + oaes_set_option( _ctx, OAES_OPTION_CBC, NULL ); + +#ifdef OAES_DEBUG + _ctx->step_cb = NULL; + oaes_set_option( _ctx, OAES_OPTION_STEP_OFF, NULL ); +#endif // OAES_DEBUG + + return (OAES_CTX *) _ctx; +} + +OAES_RET oaes_free( OAES_CTX ** ctx ) +{ + oaes_ctx ** _ctx = (oaes_ctx **) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == *_ctx ) + return OAES_RET_SUCCESS; + + if( (*_ctx)->key ) + oaes_key_destroy( &((*_ctx)->key) ); + +#ifdef OAES_HAVE_ISAAC + if( (*_ctx)->rctx ) + { + free( (*_ctx)->rctx ); + (*_ctx)->rctx = NULL; + } +#endif // OAES_HAVE_ISAAC + + free( *_ctx ); + *_ctx = NULL; + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_set_option( OAES_CTX * ctx, + OAES_OPTION option, const void * value ) +{ + size_t _i; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + switch( option ) + { + case OAES_OPTION_ECB: + _ctx->options &= ~OAES_OPTION_CBC; + memset( _ctx->iv, 0, OAES_BLOCK_SIZE ); + break; + + case OAES_OPTION_CBC: + _ctx->options &= ~OAES_OPTION_ECB; + if( value ) + memcpy( _ctx->iv, value, OAES_BLOCK_SIZE ); + else + { + for( _i = 0; _i < OAES_BLOCK_SIZE; _i++ ) +#ifdef OAES_HAVE_ISAAC + _ctx->iv[_i] = (uint8_t) rand( _ctx->rctx ); +#else + _ctx->iv[_i] = (uint8_t) rand(); +#endif // OAES_HAVE_ISAAC + } + break; + +#ifdef OAES_DEBUG + + case OAES_OPTION_STEP_ON: + if( value ) + { + _ctx->options &= ~OAES_OPTION_STEP_OFF; + _ctx->step_cb = value; + } + else + { + _ctx->options &= ~OAES_OPTION_STEP_ON; + _ctx->options |= OAES_OPTION_STEP_OFF; + _ctx->step_cb = NULL; + return OAES_RET_ARG3; + } + break; + + case OAES_OPTION_STEP_OFF: + _ctx->options &= ~OAES_OPTION_STEP_ON; + _ctx->step_cb = NULL; + break; + +#endif // OAES_DEBUG + + default: + return OAES_RET_ARG2; + } + + _ctx->options |= option; + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_encrypt_block( + OAES_CTX * ctx, uint8_t * c, size_t c_len ) +{ + size_t _i, _j; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == c ) + return OAES_RET_ARG2; + + if( c_len != OAES_BLOCK_SIZE ) + return OAES_RET_ARG3; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "input", 1, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(State, K0) + for( _i = 0; _i < c_len; _i++ ) + c[_i] = c[_i] ^ _ctx->key->exp_data[_i]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data, "k_sch", 1, NULL ); + _ctx->step_cb( c, "k_add", 1, NULL ); + } +#endif // OAES_DEBUG + + // for round = 1 step 1 to Nr–1 + for( _i = 1; _i < _ctx->key->num_keys - 1; _i++ ) + { + // SubBytes(state) + for( _j = 0; _j < c_len; _j++ ) + oaes_sub_byte( c + _j ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "s_box", _i, NULL ); +#endif // OAES_DEBUG + + // ShiftRows(state) + oaes_shift_rows( c ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "s_row", _i, NULL ); +#endif // OAES_DEBUG + + // MixColumns(state) + oaes_mix_cols( c ); + oaes_mix_cols( c + 4 ); + oaes_mix_cols( c + 8 ); + oaes_mix_cols( c + 12 ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "m_col", _i, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(state, w[round*Nb, (round+1)*Nb-1]) + for( _j = 0; _j < c_len; _j++ ) + c[_j] = c[_j] ^ + _ctx->key->exp_data[_i * OAES_RKEY_LEN * OAES_COL_LEN + _j]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data + _i * OAES_RKEY_LEN * OAES_COL_LEN, + "k_sch", _i, NULL ); + _ctx->step_cb( c, "k_add", _i, NULL ); + } +#endif // OAES_DEBUG + + } + + // SubBytes(state) + for( _i = 0; _i < c_len; _i++ ) + oaes_sub_byte( c + _i ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "s_box", _ctx->key->num_keys - 1, NULL ); +#endif // OAES_DEBUG + + // ShiftRows(state) + oaes_shift_rows( c ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "s_row", _ctx->key->num_keys - 1, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) + for( _i = 0; _i < c_len; _i++ ) + c[_i] = c[_i] ^ _ctx->key->exp_data[ + ( _ctx->key->num_keys - 1 ) * OAES_RKEY_LEN * OAES_COL_LEN + _i ]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data + + ( _ctx->key->num_keys - 1 ) * OAES_RKEY_LEN * OAES_COL_LEN, + "k_sch", _ctx->key->num_keys - 1, NULL ); + _ctx->step_cb( c, "output", _ctx->key->num_keys - 1, NULL ); + } +#endif // OAES_DEBUG + + return OAES_RET_SUCCESS; +} + +static OAES_RET oaes_decrypt_block( + OAES_CTX * ctx, uint8_t * c, size_t c_len ) +{ + size_t _i, _j; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == c ) + return OAES_RET_ARG2; + + if( c_len != OAES_BLOCK_SIZE ) + return OAES_RET_ARG3; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "iinput", _ctx->key->num_keys - 1, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) + for( _i = 0; _i < c_len; _i++ ) + c[_i] = c[_i] ^ _ctx->key->exp_data[ + ( _ctx->key->num_keys - 1 ) * OAES_RKEY_LEN * OAES_COL_LEN + _i ]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data + + ( _ctx->key->num_keys - 1 ) * OAES_RKEY_LEN * OAES_COL_LEN, + "ik_sch", _ctx->key->num_keys - 1, NULL ); + _ctx->step_cb( c, "ik_add", _ctx->key->num_keys - 1, NULL ); + } +#endif // OAES_DEBUG + + for( _i = _ctx->key->num_keys - 2; _i > 0; _i-- ) + { + // InvShiftRows(state) + oaes_inv_shift_rows( c ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "is_row", _i, NULL ); +#endif // OAES_DEBUG + + // InvSubBytes(state) + for( _j = 0; _j < c_len; _j++ ) + oaes_inv_sub_byte( c + _j ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "is_box", _i, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(state, w[round*Nb, (round+1)*Nb-1]) + for( _j = 0; _j < c_len; _j++ ) + c[_j] = c[_j] ^ + _ctx->key->exp_data[_i * OAES_RKEY_LEN * OAES_COL_LEN + _j]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data + _i * OAES_RKEY_LEN * OAES_COL_LEN, + "ik_sch", _i, NULL ); + _ctx->step_cb( c, "ik_add", _i, NULL ); + } +#endif // OAES_DEBUG + + // InvMixColums(state) + oaes_inv_mix_cols( c ); + oaes_inv_mix_cols( c + 4 ); + oaes_inv_mix_cols( c + 8 ); + oaes_inv_mix_cols( c + 12 ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "im_col", _i, NULL ); +#endif // OAES_DEBUG + + } + + // InvShiftRows(state) + oaes_inv_shift_rows( c ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "is_row", 1, NULL ); +#endif // OAES_DEBUG + + // InvSubBytes(state) + for( _i = 0; _i < c_len; _i++ ) + oaes_inv_sub_byte( c + _i ); + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + _ctx->step_cb( c, "is_box", 1, NULL ); +#endif // OAES_DEBUG + + // AddRoundKey(state, w[0, Nb-1]) + for( _i = 0; _i < c_len; _i++ ) + c[_i] = c[_i] ^ _ctx->key->exp_data[_i]; + +#ifdef OAES_DEBUG + if( _ctx->step_cb ) + { + _ctx->step_cb( _ctx->key->exp_data, "ik_sch", 1, NULL ); + _ctx->step_cb( c, "ioutput", 1, NULL ); + } +#endif // OAES_DEBUG + + return OAES_RET_SUCCESS; +} + +OAES_RET oaes_encrypt( OAES_CTX * ctx, + const uint8_t * m, size_t m_len, uint8_t * c, size_t * c_len ) +{ + size_t _i, _j, _c_len_in, _c_data_len; + size_t _pad_len = m_len % OAES_BLOCK_SIZE == 0 ? + 0 : OAES_BLOCK_SIZE - m_len % OAES_BLOCK_SIZE; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + OAES_RET _rc = OAES_RET_SUCCESS; + uint8_t _flags = _pad_len ? OAES_FLAG_PAD : 0; + + if( NULL == _ctx ) + return OAES_RET_ARG1; + + if( NULL == m ) + return OAES_RET_ARG2; + + if( NULL == c_len ) + return OAES_RET_ARG5; + + _c_len_in = *c_len; + // data + pad + _c_data_len = m_len + _pad_len; + // header + iv + data + pad + *c_len = 2 * OAES_BLOCK_SIZE + m_len + _pad_len; + + if( NULL == c ) + return OAES_RET_SUCCESS; + + if( _c_len_in < *c_len ) + return OAES_RET_BUF; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + + // header + memcpy(c, oaes_header, OAES_BLOCK_SIZE ); + memcpy(c + 6, &_ctx->options, sizeof(_ctx->options)); + memcpy(c + 8, &_flags, sizeof(_flags)); + // iv + memcpy(c + OAES_BLOCK_SIZE, _ctx->iv, OAES_BLOCK_SIZE ); + // data + memcpy(c + 2 * OAES_BLOCK_SIZE, m, m_len ); + + for( _i = 0; _i < _c_data_len; _i += OAES_BLOCK_SIZE ) + { + uint8_t _block[OAES_BLOCK_SIZE]; + size_t _block_size = min( m_len - _i, OAES_BLOCK_SIZE ); + + memcpy( _block, c + 2 * OAES_BLOCK_SIZE + _i, _block_size ); + + // insert pad + for( _j = 0; _j < OAES_BLOCK_SIZE - _block_size; _j++ ) + _block[ _block_size + _j ] = _j + 1; + + // CBC + if( _ctx->options & OAES_OPTION_CBC ) + { + for( _j = 0; _j < OAES_BLOCK_SIZE; _j++ ) + _block[_j] = _block[_j] ^ _ctx->iv[_j]; + } + + _rc = _rc || + oaes_encrypt_block( ctx, _block, OAES_BLOCK_SIZE ); + memcpy( c + 2 * OAES_BLOCK_SIZE + _i, _block, OAES_BLOCK_SIZE ); + + if( _ctx->options & OAES_OPTION_CBC ) + memcpy( _ctx->iv, _block, OAES_BLOCK_SIZE ); + } + + return _rc; +} + +OAES_RET oaes_decrypt( OAES_CTX * ctx, + const uint8_t * c, size_t c_len, uint8_t * m, size_t * m_len ) +{ + size_t _i, _j, _m_len_in; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + OAES_RET _rc = OAES_RET_SUCCESS; + uint8_t _iv[OAES_BLOCK_SIZE]; + uint8_t _flags; + OAES_OPTION _options; + + if( NULL == ctx ) + return OAES_RET_ARG1; + + if( NULL == c ) + return OAES_RET_ARG2; + + if( c_len % OAES_BLOCK_SIZE ) + return OAES_RET_ARG3; + + if( NULL == m_len ) + return OAES_RET_ARG5; + + _m_len_in = *m_len; + *m_len = c_len - 2 * OAES_BLOCK_SIZE; + + if( NULL == m ) + return OAES_RET_SUCCESS; + + if( _m_len_in < *m_len ) + return OAES_RET_BUF; + + if( NULL == _ctx->key ) + return OAES_RET_NOKEY; + + // header + if( 0 != memcmp( c, oaes_header, 4 ) ) + return OAES_RET_HEADER; + + // header version + switch( c[4] ) + { + case 0x01: + break; + default: + return OAES_RET_HEADER; + } + + // header type + switch( c[5] ) + { + case 0x02: + break; + default: + return OAES_RET_HEADER; + } + + // options + memcpy(&_options, c + 6, sizeof(_options)); + // validate that all options are valid + if( _options & ~( + OAES_OPTION_ECB + | OAES_OPTION_CBC +#ifdef OAES_DEBUG + | OAES_OPTION_STEP_ON + | OAES_OPTION_STEP_OFF +#endif // OAES_DEBUG + ) ) + return OAES_RET_HEADER; + if( ( _options & OAES_OPTION_ECB ) && + ( _options & OAES_OPTION_CBC ) ) + return OAES_RET_HEADER; + if( _options == OAES_OPTION_NONE ) + return OAES_RET_HEADER; + + // flags + memcpy(&_flags, c + 8, sizeof(_flags)); + // validate that all flags are valid + if( _flags & ~( + OAES_FLAG_PAD + ) ) + return OAES_RET_HEADER; + + // iv + memcpy( _iv, c + OAES_BLOCK_SIZE, OAES_BLOCK_SIZE); + // data + pad + memcpy( m, c + 2 * OAES_BLOCK_SIZE, *m_len ); + + for( _i = 0; _i < *m_len; _i += OAES_BLOCK_SIZE ) + { + if( ( _options & OAES_OPTION_CBC ) && _i > 0 ) + memcpy( _iv, c + OAES_BLOCK_SIZE + _i, OAES_BLOCK_SIZE ); + + _rc = _rc || + oaes_decrypt_block( ctx, m + _i, min( *m_len - _i, OAES_BLOCK_SIZE ) ); + + // CBC + if( _options & OAES_OPTION_CBC ) + { + for( _j = 0; _j < OAES_BLOCK_SIZE; _j++ ) + m[ _i + _j ] = m[ _i + _j ] ^ _iv[_j]; + } + } + + // remove pad + if( _flags & OAES_FLAG_PAD ) + { + int _is_pad = 1; + size_t _temp = (size_t) m[*m_len - 1]; + + if( _temp <= 0x00 || _temp > 0x0f ) + return OAES_RET_HEADER; + for( _i = 0; _i < _temp; _i++ ) + if( m[*m_len - 1 - _i] != _temp - _i ) + _is_pad = 0; + if( _is_pad ) + { + memset( m + *m_len - _temp, 0, _temp ); + *m_len -= _temp; + } + else + return OAES_RET_HEADER; + } + + return OAES_RET_SUCCESS; +} + + +OAES_API OAES_RET oaes_encryption_round( const uint8_t * key, uint8_t * c ) +{ + size_t _i; + + if(NULL == key) + return OAES_RET_ARG1; + + if(NULL == c) + return OAES_RET_ARG2; + + // SubBytes(state) + for( _i = 0; _i < OAES_BLOCK_SIZE; _i++ ) + oaes_sub_byte( c + _i ); + + // ShiftRows(state) + oaes_shift_rows( c ); + + // MixColumns(state) + oaes_mix_cols( c ); + oaes_mix_cols( c + 4 ); + oaes_mix_cols( c + 8 ); + oaes_mix_cols( c + 12 ); + + // AddRoundKey(State, key) + for( _i = 0; _i < OAES_BLOCK_SIZE; _i++ ) + c[_i] ^= key[_i]; + + return OAES_RET_SUCCESS; +} + +OAES_API OAES_RET oaes_pseudo_encrypt_ecb( OAES_CTX * ctx, uint8_t * c ) +{ + size_t _i; + oaes_ctx * _ctx = (oaes_ctx *) ctx; + + if(NULL == _ctx) + return OAES_RET_ARG1; + + if(NULL == c) + return OAES_RET_ARG2; + + if(NULL == _ctx->key) + return OAES_RET_NOKEY; + + for ( _i = 0; _i < 10; ++_i ) + { + oaes_encryption_round( &_ctx->key->exp_data[_i * OAES_RKEY_LEN * OAES_COL_LEN], c ); + } + + return OAES_RET_SUCCESS; +} diff --git a/webassembly/xmr/oaes_lib.h b/webassembly/xmr/oaes_lib.h new file mode 100644 index 0000000..a22bbf4 --- /dev/null +++ b/webassembly/xmr/oaes_lib.h @@ -0,0 +1,214 @@ +/* + * --------------------------------------------------------------------------- + * OpenAES License + * --------------------------------------------------------------------------- + * Copyright (c) 2012, Nabil S. Al Ramli, www.nalramli.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * --------------------------------------------------------------------------- + */ + +#ifndef _OAES_LIB_H +#define _OAES_LIB_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +# ifdef OAES_SHARED +# ifdef oaes_lib_EXPORTS +# define OAES_API __declspec(dllexport) +# else +# define OAES_API __declspec(dllimport) +# endif +# else +# define OAES_API +# endif +#else +# define OAES_API +#endif // WIN32 + +#define OAES_VERSION "0.8.1" +#define OAES_BLOCK_SIZE 16 + +typedef void OAES_CTX; + +typedef enum +{ + OAES_RET_FIRST = 0, + OAES_RET_SUCCESS = 0, + OAES_RET_UNKNOWN, + OAES_RET_ARG1, + OAES_RET_ARG2, + OAES_RET_ARG3, + OAES_RET_ARG4, + OAES_RET_ARG5, + OAES_RET_NOKEY, + OAES_RET_MEM, + OAES_RET_BUF, + OAES_RET_HEADER, + OAES_RET_COUNT +} OAES_RET; + +/* + * oaes_set_option() takes one of these values for its [option] parameter + * some options accept either an optional or a required [value] parameter + */ +// no option +#define OAES_OPTION_NONE 0 +// enable ECB mode, disable CBC mode +#define OAES_OPTION_ECB 1 +// enable CBC mode, disable ECB mode +// value is optional, may pass uint8_t iv[OAES_BLOCK_SIZE] to specify +// the value of the initialization vector, iv +#define OAES_OPTION_CBC 2 + +#ifdef OAES_DEBUG +typedef int ( * oaes_step_cb ) ( + const uint8_t state[OAES_BLOCK_SIZE], + const char * step_name, + int step_count, + void * user_data ); +// enable state stepping mode +// value is required, must pass oaes_step_cb to receive the state at each step +#define OAES_OPTION_STEP_ON 4 +// disable state stepping mode +#define OAES_OPTION_STEP_OFF 8 +#endif // OAES_DEBUG + +typedef uint16_t OAES_OPTION; + +typedef struct _oaes_key +{ + size_t data_len; + uint8_t *data; + size_t exp_data_len; + uint8_t *exp_data; + size_t num_keys; + size_t key_base; +} oaes_key; + +typedef struct _oaes_ctx +{ +#ifdef OAES_HAVE_ISAAC + randctx * rctx; +#endif // OAES_HAVE_ISAAC + +#ifdef OAES_DEBUG + oaes_step_cb step_cb; +#endif // OAES_DEBUG + + oaes_key * key; + OAES_OPTION options; + uint8_t iv[OAES_BLOCK_SIZE]; +} oaes_ctx; +/* + * // usage: + * + * OAES_CTX * ctx = oaes_alloc(); + * . + * . + * . + * { + * oaes_gen_key_xxx( ctx ); + * { + * oaes_key_export( ctx, _buf, &_buf_len ); + * // or + * oaes_key_export_data( ctx, _buf, &_buf_len );\ + * } + * } + * // or + * { + * oaes_key_import( ctx, _buf, _buf_len ); + * // or + * oaes_key_import_data( ctx, _buf, _buf_len ); + * } + * . + * . + * . + * oaes_encrypt( ctx, m, m_len, c, &c_len ); + * . + * . + * . + * oaes_decrypt( ctx, c, c_len, m, &m_len ); + * . + * . + * . + * oaes_free( &ctx ); + */ + +OAES_API OAES_CTX * oaes_alloc(void); + +OAES_API OAES_RET oaes_free( OAES_CTX ** ctx ); + +OAES_API OAES_RET oaes_set_option( OAES_CTX * ctx, + OAES_OPTION option, const void * value ); + +OAES_API OAES_RET oaes_key_gen_128( OAES_CTX * ctx ); + +OAES_API OAES_RET oaes_key_gen_192( OAES_CTX * ctx ); + +OAES_API OAES_RET oaes_key_gen_256( OAES_CTX * ctx ); + +// export key with header information +// set data == NULL to get the required data_len +OAES_API OAES_RET oaes_key_export( OAES_CTX * ctx, + uint8_t * data, size_t * data_len ); + +// directly export the data from key +// set data == NULL to get the required data_len +OAES_API OAES_RET oaes_key_export_data( OAES_CTX * ctx, + uint8_t * data, size_t * data_len ); + +// import key with header information +OAES_API OAES_RET oaes_key_import( OAES_CTX * ctx, + const uint8_t * data, size_t data_len ); + +// directly import data into key +OAES_API OAES_RET oaes_key_import_data( OAES_CTX * ctx, + const uint8_t * data, size_t data_len ); + +// set c == NULL to get the required c_len +OAES_API OAES_RET oaes_encrypt( OAES_CTX * ctx, + const uint8_t * m, size_t m_len, uint8_t * c, size_t * c_len ); + +// set m == NULL to get the required m_len +OAES_API OAES_RET oaes_decrypt( OAES_CTX * ctx, + const uint8_t * c, size_t c_len, uint8_t * m, size_t * m_len ); + +// set buf == NULL to get the required buf_len +OAES_API OAES_RET oaes_sprintf( + char * buf, size_t * buf_len, const uint8_t * data, size_t data_len ); + +OAES_API OAES_RET oaes_encryption_round( const uint8_t * key, uint8_t * c ); + +OAES_API OAES_RET oaes_pseudo_encrypt_ecb( OAES_CTX * ctx, uint8_t * c ); + +#ifdef __cplusplus +} +#endif + +#endif // _OAES_LIB_H diff --git a/webassembly/xmr/skein.c b/webassembly/xmr/skein.c new file mode 100644 index 0000000..4368d15 --- /dev/null +++ b/webassembly/xmr/skein.c @@ -0,0 +1,2047 @@ +/*********************************************************************** +** +** Implementation of the Skein hash function. +** +** Source code author: Doug Whiting, 2008. +** +** This algorithm and source code is released to the public domain. +** +************************************************************************/ + +#define SKEIN_PORT_CODE /* instantiate any code in skein_port.h */ + +#include /* get size_t definition */ +#include /* get the memcpy/memset functions */ +#include "skein_port.h" + +typedef enum +{ + SKEIN_SUCCESS = 0, /* return codes from Skein calls */ + SKEIN_FAIL = 1, + SKEIN_BAD_HASHLEN = 2 +} +SkeinHashReturn; + +typedef size_t SkeinDataLength; /* bit count type */ +typedef u08b_t SkeinBitSequence; /* bit stream type */ + +#define DISABLE_UNUSED 0 + +#ifndef SKEIN_256_NIST_MAX_HASHBITS +#define SKEIN_256_NIST_MAX_HASHBITS (0) +#endif + +#ifndef SKEIN_512_NIST_MAX_HASHBITS +#define SKEIN_512_NIST_MAX_HASHBITS (512) +#endif + +#define SKEIN_MODIFIER_WORDS ( 2) /* number of modifier (tweak) words */ + +#define SKEIN_256_STATE_WORDS ( 4) +#define SKEIN_512_STATE_WORDS ( 8) +#define SKEIN1024_STATE_WORDS (16) +#define SKEIN_MAX_STATE_WORDS (16) + +#define SKEIN_256_STATE_BYTES ( 8*SKEIN_256_STATE_WORDS) +#define SKEIN_512_STATE_BYTES ( 8*SKEIN_512_STATE_WORDS) +#define SKEIN1024_STATE_BYTES ( 8*SKEIN1024_STATE_WORDS) + +#define SKEIN_256_STATE_BITS (64*SKEIN_256_STATE_WORDS) +#define SKEIN_512_STATE_BITS (64*SKEIN_512_STATE_WORDS) +#define SKEIN1024_STATE_BITS (64*SKEIN1024_STATE_WORDS) + +#define SKEIN_256_BLOCK_BYTES ( 8*SKEIN_256_STATE_WORDS) +#define SKEIN_512_BLOCK_BYTES ( 8*SKEIN_512_STATE_WORDS) +#define SKEIN1024_BLOCK_BYTES ( 8*SKEIN1024_STATE_WORDS) + +#define SKEIN_RND_SPECIAL (1000u) +#define SKEIN_RND_KEY_INITIAL (SKEIN_RND_SPECIAL+0u) +#define SKEIN_RND_KEY_INJECT (SKEIN_RND_SPECIAL+1u) +#define SKEIN_RND_FEED_FWD (SKEIN_RND_SPECIAL+2u) + +typedef struct +{ + size_t hashBitLen; /* size of hash result, in bits */ + size_t bCnt; /* current byte count in buffer b[] */ + u64b_t T[SKEIN_MODIFIER_WORDS]; /* tweak words: T[0]=byte cnt, T[1]=flags */ +} Skein_Ctxt_Hdr_t; + +typedef struct /* 256-bit Skein hash context structure */ +{ + Skein_Ctxt_Hdr_t h; /* common header context variables */ + u64b_t X[SKEIN_256_STATE_WORDS]; /* chaining variables */ + u08b_t b[SKEIN_256_BLOCK_BYTES]; /* partial block buffer (8-byte aligned) */ +} Skein_256_Ctxt_t; + +typedef struct /* 512-bit Skein hash context structure */ +{ + Skein_Ctxt_Hdr_t h; /* common header context variables */ + u64b_t X[SKEIN_512_STATE_WORDS]; /* chaining variables */ + u08b_t b[SKEIN_512_BLOCK_BYTES]; /* partial block buffer (8-byte aligned) */ +} Skein_512_Ctxt_t; + +typedef struct /* 1024-bit Skein hash context structure */ +{ + Skein_Ctxt_Hdr_t h; /* common header context variables */ + u64b_t X[SKEIN1024_STATE_WORDS]; /* chaining variables */ + u08b_t b[SKEIN1024_BLOCK_BYTES]; /* partial block buffer (8-byte aligned) */ +} Skein1024_Ctxt_t; + +/* Skein APIs for (incremental) "straight hashing" */ +#if SKEIN_256_NIST_MAX_HASH_BITS +static int Skein_256_Init (Skein_256_Ctxt_t *ctx, size_t hashBitLen); +#endif +static int Skein_512_Init (Skein_512_Ctxt_t *ctx, size_t hashBitLen); +static int Skein1024_Init (Skein1024_Ctxt_t *ctx, size_t hashBitLen); + +static int Skein_256_Update(Skein_256_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt); +static int Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt); +static int Skein1024_Update(Skein1024_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt); + +static int Skein_256_Final (Skein_256_Ctxt_t *ctx, u08b_t * hashVal); +static int Skein_512_Final (Skein_512_Ctxt_t *ctx, u08b_t * hashVal); +static int Skein1024_Final (Skein1024_Ctxt_t *ctx, u08b_t * hashVal); + +/* +** Skein APIs for "extended" initialization: MAC keys, tree hashing. +** After an InitExt() call, just use Update/Final calls as with Init(). +** +** Notes: Same parameters as _Init() calls, plus treeInfo/key/keyBytes. +** When keyBytes == 0 and treeInfo == SKEIN_SEQUENTIAL, +** the results of InitExt() are identical to calling Init(). +** The function Init() may be called once to "precompute" the IV for +** a given hashBitLen value, then by saving a copy of the context +** the IV computation may be avoided in later calls. +** Similarly, the function InitExt() may be called once per MAC key +** to precompute the MAC IV, then a copy of the context saved and +** reused for each new MAC computation. +**/ +#if 0 +static int Skein_256_InitExt(Skein_256_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes); +static int Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes); +static int Skein1024_InitExt(Skein1024_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes); +#endif + +/* +** Skein APIs for MAC and tree hash: +** Final_Pad: pad, do final block, but no OUTPUT type +** Output: do just the output stage +*/ +#if 0 +static int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, u08b_t * hashVal); +static int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t * hashVal); +static int Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, u08b_t * hashVal); +#endif + +#ifndef SKEIN_TREE_HASH +#define SKEIN_TREE_HASH (1) +#endif +#if 0 +#if SKEIN_TREE_HASH +static int Skein_256_Output (Skein_256_Ctxt_t *ctx, u08b_t * hashVal); +static int Skein_512_Output (Skein_512_Ctxt_t *ctx, u08b_t * hashVal); +static int Skein1024_Output (Skein1024_Ctxt_t *ctx, u08b_t * hashVal); +#endif +#endif + +/***************************************************************** +** "Internal" Skein definitions +** -- not needed for sequential hashing API, but will be +** helpful for other uses of Skein (e.g., tree hash mode). +** -- included here so that they can be shared between +** reference and optimized code. +******************************************************************/ + +/* tweak word T[1]: bit field starting positions */ +#define SKEIN_T1_BIT(BIT) ((BIT) - 64) /* offset 64 because it's the second word */ + +#define SKEIN_T1_POS_TREE_LVL SKEIN_T1_BIT(112) /* bits 112..118: level in hash tree */ +#define SKEIN_T1_POS_BIT_PAD SKEIN_T1_BIT(119) /* bit 119 : partial final input byte */ +#define SKEIN_T1_POS_BLK_TYPE SKEIN_T1_BIT(120) /* bits 120..125: type field */ +#define SKEIN_T1_POS_FIRST SKEIN_T1_BIT(126) /* bits 126 : first block flag */ +#define SKEIN_T1_POS_FINAL SKEIN_T1_BIT(127) /* bit 127 : final block flag */ + +/* tweak word T[1]: flag bit definition(s) */ +#define SKEIN_T1_FLAG_FIRST (((u64b_t) 1 ) << SKEIN_T1_POS_FIRST) +#define SKEIN_T1_FLAG_FINAL (((u64b_t) 1 ) << SKEIN_T1_POS_FINAL) +#define SKEIN_T1_FLAG_BIT_PAD (((u64b_t) 1 ) << SKEIN_T1_POS_BIT_PAD) + +/* tweak word T[1]: tree level bit field mask */ +#define SKEIN_T1_TREE_LVL_MASK (((u64b_t)0x7F) << SKEIN_T1_POS_TREE_LVL) +#define SKEIN_T1_TREE_LEVEL(n) (((u64b_t) (n)) << SKEIN_T1_POS_TREE_LVL) + +/* tweak word T[1]: block type field */ +#define SKEIN_BLK_TYPE_KEY ( 0) /* key, for MAC and KDF */ +#define SKEIN_BLK_TYPE_CFG ( 4) /* configuration block */ +#define SKEIN_BLK_TYPE_PERS ( 8) /* personalization string */ +#define SKEIN_BLK_TYPE_PK (12) /* public key (for digital signature hashing) */ +#define SKEIN_BLK_TYPE_KDF (16) /* key identifier for KDF */ +#define SKEIN_BLK_TYPE_NONCE (20) /* nonce for PRNG */ +#define SKEIN_BLK_TYPE_MSG (48) /* message processing */ +#define SKEIN_BLK_TYPE_OUT (63) /* output stage */ +#define SKEIN_BLK_TYPE_MASK (63) /* bit field mask */ + +#define SKEIN_T1_BLK_TYPE(T) (((u64b_t) (SKEIN_BLK_TYPE_##T)) << SKEIN_T1_POS_BLK_TYPE) +#define SKEIN_T1_BLK_TYPE_KEY SKEIN_T1_BLK_TYPE(KEY) /* key, for MAC and KDF */ +#define SKEIN_T1_BLK_TYPE_CFG SKEIN_T1_BLK_TYPE(CFG) /* configuration block */ +#define SKEIN_T1_BLK_TYPE_PERS SKEIN_T1_BLK_TYPE(PERS) /* personalization string */ +#define SKEIN_T1_BLK_TYPE_PK SKEIN_T1_BLK_TYPE(PK) /* public key (for digital signature hashing) */ +#define SKEIN_T1_BLK_TYPE_KDF SKEIN_T1_BLK_TYPE(KDF) /* key identifier for KDF */ +#define SKEIN_T1_BLK_TYPE_NONCE SKEIN_T1_BLK_TYPE(NONCE)/* nonce for PRNG */ +#define SKEIN_T1_BLK_TYPE_MSG SKEIN_T1_BLK_TYPE(MSG) /* message processing */ +#define SKEIN_T1_BLK_TYPE_OUT SKEIN_T1_BLK_TYPE(OUT) /* output stage */ +#define SKEIN_T1_BLK_TYPE_MASK SKEIN_T1_BLK_TYPE(MASK) /* field bit mask */ + +#define SKEIN_T1_BLK_TYPE_CFG_FINAL (SKEIN_T1_BLK_TYPE_CFG | SKEIN_T1_FLAG_FINAL) +#define SKEIN_T1_BLK_TYPE_OUT_FINAL (SKEIN_T1_BLK_TYPE_OUT | SKEIN_T1_FLAG_FINAL) + +#define SKEIN_VERSION (1) + +#ifndef SKEIN_ID_STRING_LE /* allow compile-time personalization */ +#define SKEIN_ID_STRING_LE (0x33414853) /* "SHA3" (little-endian)*/ +#endif + +#define SKEIN_MK_64(hi32,lo32) ((lo32) + (((u64b_t) (hi32)) << 32)) +#define SKEIN_SCHEMA_VER SKEIN_MK_64(SKEIN_VERSION,SKEIN_ID_STRING_LE) +#define SKEIN_KS_PARITY SKEIN_MK_64(0x1BD11BDA,0xA9FC1A22) + +#define SKEIN_CFG_STR_LEN (4*8) + +/* bit field definitions in config block treeInfo word */ +#define SKEIN_CFG_TREE_LEAF_SIZE_POS ( 0) +#define SKEIN_CFG_TREE_NODE_SIZE_POS ( 8) +#define SKEIN_CFG_TREE_MAX_LEVEL_POS (16) + +#define SKEIN_CFG_TREE_LEAF_SIZE_MSK (((u64b_t) 0xFF) << SKEIN_CFG_TREE_LEAF_SIZE_POS) +#define SKEIN_CFG_TREE_NODE_SIZE_MSK (((u64b_t) 0xFF) << SKEIN_CFG_TREE_NODE_SIZE_POS) +#define SKEIN_CFG_TREE_MAX_LEVEL_MSK (((u64b_t) 0xFF) << SKEIN_CFG_TREE_MAX_LEVEL_POS) + +#define SKEIN_CFG_TREE_INFO(leaf,node,maxLvl) \ + ( (((u64b_t)(leaf )) << SKEIN_CFG_TREE_LEAF_SIZE_POS) | \ + (((u64b_t)(node )) << SKEIN_CFG_TREE_NODE_SIZE_POS) | \ + (((u64b_t)(maxLvl)) << SKEIN_CFG_TREE_MAX_LEVEL_POS) ) + +#define SKEIN_CFG_TREE_INFO_SEQUENTIAL SKEIN_CFG_TREE_INFO(0,0,0) /* use as treeInfo in InitExt() call for sequential processing */ + +/* +** Skein macros for getting/setting tweak words, etc. +** These are useful for partial input bytes, hash tree init/update, etc. +**/ +#define Skein_Get_Tweak(ctxPtr,TWK_NUM) ((ctxPtr)->h.T[TWK_NUM]) +#define Skein_Set_Tweak(ctxPtr,TWK_NUM,tVal) {(ctxPtr)->h.T[TWK_NUM] = (tVal);} + +#define Skein_Get_T0(ctxPtr) Skein_Get_Tweak(ctxPtr,0) +#define Skein_Get_T1(ctxPtr) Skein_Get_Tweak(ctxPtr,1) +#define Skein_Set_T0(ctxPtr,T0) Skein_Set_Tweak(ctxPtr,0,T0) +#define Skein_Set_T1(ctxPtr,T1) Skein_Set_Tweak(ctxPtr,1,T1) + +/* set both tweak words at once */ +#define Skein_Set_T0_T1(ctxPtr,T0,T1) \ +{ \ + Skein_Set_T0(ctxPtr,(T0)); \ + Skein_Set_T1(ctxPtr,(T1)); \ +} + +#define Skein_Set_Type(ctxPtr,BLK_TYPE) \ + Skein_Set_T1(ctxPtr,SKEIN_T1_BLK_TYPE_##BLK_TYPE) + +/* set up for starting with a new type: h.T[0]=0; h.T[1] = NEW_TYPE; h.bCnt=0; */ +#define Skein_Start_New_Type(ctxPtr,BLK_TYPE) \ +{ Skein_Set_T0_T1(ctxPtr,0,SKEIN_T1_FLAG_FIRST | SKEIN_T1_BLK_TYPE_##BLK_TYPE); (ctxPtr)->h.bCnt=0; } + +#define Skein_Clear_First_Flag(hdr) { (hdr).T[1] &= ~SKEIN_T1_FLAG_FIRST; } +#define Skein_Set_Bit_Pad_Flag(hdr) { (hdr).T[1] |= SKEIN_T1_FLAG_BIT_PAD; } + +#define Skein_Set_Tree_Level(hdr,height) { (hdr).T[1] |= SKEIN_T1_TREE_LEVEL(height);} + +/***************************************************************** +** "Internal" Skein definitions for debugging and error checking +******************************************************************/ +#define Skein_Show_Block(bits,ctx,X,blkPtr,wPtr,ksEvenPtr,ksOddPtr) +#define Skein_Show_Round(bits,ctx,r,X) +#define Skein_Show_R_Ptr(bits,ctx,r,X_ptr) +#define Skein_Show_Final(bits,ctx,cnt,outPtr) +#define Skein_Show_Key(bits,ctx,key,keyBytes) + + +#ifndef SKEIN_ERR_CHECK /* run-time checks (e.g., bad params, uninitialized context)? */ +#define Skein_Assert(x,retCode)/* default: ignore all Asserts, for performance */ +#define Skein_assert(x) +#elif defined(SKEIN_ASSERT) +#include +#define Skein_Assert(x,retCode) assert(x) +#define Skein_assert(x) assert(x) +#else +#include +#define Skein_Assert(x,retCode) { if (!(x)) return retCode; } /* caller error */ +#define Skein_assert(x) assert(x) /* internal error */ +#endif + +/***************************************************************** +** Skein block function constants (shared across Ref and Opt code) +******************************************************************/ +enum +{ + /* Skein_256 round rotation constants */ + R_256_0_0=14, R_256_0_1=16, + R_256_1_0=52, R_256_1_1=57, + R_256_2_0=23, R_256_2_1=40, + R_256_3_0= 5, R_256_3_1=37, + R_256_4_0=25, R_256_4_1=33, + R_256_5_0=46, R_256_5_1=12, + R_256_6_0=58, R_256_6_1=22, + R_256_7_0=32, R_256_7_1=32, + + /* Skein_512 round rotation constants */ + R_512_0_0=46, R_512_0_1=36, R_512_0_2=19, R_512_0_3=37, + R_512_1_0=33, R_512_1_1=27, R_512_1_2=14, R_512_1_3=42, + R_512_2_0=17, R_512_2_1=49, R_512_2_2=36, R_512_2_3=39, + R_512_3_0=44, R_512_3_1= 9, R_512_3_2=54, R_512_3_3=56, + R_512_4_0=39, R_512_4_1=30, R_512_4_2=34, R_512_4_3=24, + R_512_5_0=13, R_512_5_1=50, R_512_5_2=10, R_512_5_3=17, + R_512_6_0=25, R_512_6_1=29, R_512_6_2=39, R_512_6_3=43, + R_512_7_0= 8, R_512_7_1=35, R_512_7_2=56, R_512_7_3=22, + + /* Skein1024 round rotation constants */ + R1024_0_0=24, R1024_0_1=13, R1024_0_2= 8, R1024_0_3=47, R1024_0_4= 8, R1024_0_5=17, R1024_0_6=22, R1024_0_7=37, + R1024_1_0=38, R1024_1_1=19, R1024_1_2=10, R1024_1_3=55, R1024_1_4=49, R1024_1_5=18, R1024_1_6=23, R1024_1_7=52, + R1024_2_0=33, R1024_2_1= 4, R1024_2_2=51, R1024_2_3=13, R1024_2_4=34, R1024_2_5=41, R1024_2_6=59, R1024_2_7=17, + R1024_3_0= 5, R1024_3_1=20, R1024_3_2=48, R1024_3_3=41, R1024_3_4=47, R1024_3_5=28, R1024_3_6=16, R1024_3_7=25, + R1024_4_0=41, R1024_4_1= 9, R1024_4_2=37, R1024_4_3=31, R1024_4_4=12, R1024_4_5=47, R1024_4_6=44, R1024_4_7=30, + R1024_5_0=16, R1024_5_1=34, R1024_5_2=56, R1024_5_3=51, R1024_5_4= 4, R1024_5_5=53, R1024_5_6=42, R1024_5_7=41, + R1024_6_0=31, R1024_6_1=44, R1024_6_2=47, R1024_6_3=46, R1024_6_4=19, R1024_6_5=42, R1024_6_6=44, R1024_6_7=25, + R1024_7_0= 9, R1024_7_1=48, R1024_7_2=35, R1024_7_3=52, R1024_7_4=23, R1024_7_5=31, R1024_7_6=37, R1024_7_7=20 +}; + +#ifndef SKEIN_ROUNDS +#define SKEIN_256_ROUNDS_TOTAL (72) /* number of rounds for the different block sizes */ +#define SKEIN_512_ROUNDS_TOTAL (72) +#define SKEIN1024_ROUNDS_TOTAL (80) +#else /* allow command-line define in range 8*(5..14) */ +#define SKEIN_256_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS/100) + 5) % 10) + 5)) +#define SKEIN_512_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS/ 10) + 5) % 10) + 5)) +#define SKEIN1024_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS ) + 5) % 10) + 5)) +#endif + + +/* +***************** Pre-computed Skein IVs ******************* +** +** NOTE: these values are not "magic" constants, but +** are generated using the Threefish block function. +** They are pre-computed here only for speed; i.e., to +** avoid the need for a Threefish call during Init(). +** +** The IV for any fixed hash length may be pre-computed. +** Only the most common values are included here. +** +************************************************************ +**/ + +#define MK_64 SKEIN_MK_64 + +/* blkSize = 256 bits. hashSize = 128 bits */ +const u64b_t SKEIN_256_IV_128[] = + { + MK_64(0xE1111906,0x964D7260), + MK_64(0x883DAAA7,0x7C8D811C), + MK_64(0x10080DF4,0x91960F7A), + MK_64(0xCCF7DDE5,0xB45BC1C2) + }; + +/* blkSize = 256 bits. hashSize = 160 bits */ +const u64b_t SKEIN_256_IV_160[] = + { + MK_64(0x14202314,0x72825E98), + MK_64(0x2AC4E9A2,0x5A77E590), + MK_64(0xD47A5856,0x8838D63E), + MK_64(0x2DD2E496,0x8586AB7D) + }; + +/* blkSize = 256 bits. hashSize = 224 bits */ +const u64b_t SKEIN_256_IV_224[] = + { + MK_64(0xC6098A8C,0x9AE5EA0B), + MK_64(0x876D5686,0x08C5191C), + MK_64(0x99CB88D7,0xD7F53884), + MK_64(0x384BDDB1,0xAEDDB5DE) + }; + +/* blkSize = 256 bits. hashSize = 256 bits */ +const u64b_t SKEIN_256_IV_256[] = + { + MK_64(0xFC9DA860,0xD048B449), + MK_64(0x2FCA6647,0x9FA7D833), + MK_64(0xB33BC389,0x6656840F), + MK_64(0x6A54E920,0xFDE8DA69) + }; + +/* blkSize = 512 bits. hashSize = 128 bits */ +const u64b_t SKEIN_512_IV_128[] = + { + MK_64(0xA8BC7BF3,0x6FBF9F52), + MK_64(0x1E9872CE,0xBD1AF0AA), + MK_64(0x309B1790,0xB32190D3), + MK_64(0xBCFBB854,0x3F94805C), + MK_64(0x0DA61BCD,0x6E31B11B), + MK_64(0x1A18EBEA,0xD46A32E3), + MK_64(0xA2CC5B18,0xCE84AA82), + MK_64(0x6982AB28,0x9D46982D) + }; + +/* blkSize = 512 bits. hashSize = 160 bits */ +const u64b_t SKEIN_512_IV_160[] = + { + MK_64(0x28B81A2A,0xE013BD91), + MK_64(0xC2F11668,0xB5BDF78F), + MK_64(0x1760D8F3,0xF6A56F12), + MK_64(0x4FB74758,0x8239904F), + MK_64(0x21EDE07F,0x7EAF5056), + MK_64(0xD908922E,0x63ED70B8), + MK_64(0xB8EC76FF,0xECCB52FA), + MK_64(0x01A47BB8,0xA3F27A6E) + }; + +/* blkSize = 512 bits. hashSize = 224 bits */ +const u64b_t SKEIN_512_IV_224[] = + { + MK_64(0xCCD06162,0x48677224), + MK_64(0xCBA65CF3,0xA92339EF), + MK_64(0x8CCD69D6,0x52FF4B64), + MK_64(0x398AED7B,0x3AB890B4), + MK_64(0x0F59D1B1,0x457D2BD0), + MK_64(0x6776FE65,0x75D4EB3D), + MK_64(0x99FBC70E,0x997413E9), + MK_64(0x9E2CFCCF,0xE1C41EF7) + }; + +/* blkSize = 512 bits. hashSize = 256 bits */ +const u64b_t SKEIN_512_IV_256[] = + { + MK_64(0xCCD044A1,0x2FDB3E13), + MK_64(0xE8359030,0x1A79A9EB), + MK_64(0x55AEA061,0x4F816E6F), + MK_64(0x2A2767A4,0xAE9B94DB), + MK_64(0xEC06025E,0x74DD7683), + MK_64(0xE7A436CD,0xC4746251), + MK_64(0xC36FBAF9,0x393AD185), + MK_64(0x3EEDBA18,0x33EDFC13) + }; + +/* blkSize = 512 bits. hashSize = 384 bits */ +const u64b_t SKEIN_512_IV_384[] = + { + MK_64(0xA3F6C6BF,0x3A75EF5F), + MK_64(0xB0FEF9CC,0xFD84FAA4), + MK_64(0x9D77DD66,0x3D770CFE), + MK_64(0xD798CBF3,0xB468FDDA), + MK_64(0x1BC4A666,0x8A0E4465), + MK_64(0x7ED7D434,0xE5807407), + MK_64(0x548FC1AC,0xD4EC44D6), + MK_64(0x266E1754,0x6AA18FF8) + }; + +/* blkSize = 512 bits. hashSize = 512 bits */ +const u64b_t SKEIN_512_IV_512[] = + { + MK_64(0x4903ADFF,0x749C51CE), + MK_64(0x0D95DE39,0x9746DF03), + MK_64(0x8FD19341,0x27C79BCE), + MK_64(0x9A255629,0xFF352CB1), + MK_64(0x5DB62599,0xDF6CA7B0), + MK_64(0xEABE394C,0xA9D5C3F4), + MK_64(0x991112C7,0x1A75B523), + MK_64(0xAE18A40B,0x660FCC33) + }; + +/* blkSize = 1024 bits. hashSize = 384 bits */ +const u64b_t SKEIN1024_IV_384[] = + { + MK_64(0x5102B6B8,0xC1894A35), + MK_64(0xFEEBC9E3,0xFE8AF11A), + MK_64(0x0C807F06,0xE32BED71), + MK_64(0x60C13A52,0xB41A91F6), + MK_64(0x9716D35D,0xD4917C38), + MK_64(0xE780DF12,0x6FD31D3A), + MK_64(0x797846B6,0xC898303A), + MK_64(0xB172C2A8,0xB3572A3B), + MK_64(0xC9BC8203,0xA6104A6C), + MK_64(0x65909338,0xD75624F4), + MK_64(0x94BCC568,0x4B3F81A0), + MK_64(0x3EBBF51E,0x10ECFD46), + MK_64(0x2DF50F0B,0xEEB08542), + MK_64(0x3B5A6530,0x0DBC6516), + MK_64(0x484B9CD2,0x167BBCE1), + MK_64(0x2D136947,0xD4CBAFEA) + }; + +/* blkSize = 1024 bits. hashSize = 512 bits */ +const u64b_t SKEIN1024_IV_512[] = + { + MK_64(0xCAEC0E5D,0x7C1B1B18), + MK_64(0xA01B0E04,0x5F03E802), + MK_64(0x33840451,0xED912885), + MK_64(0x374AFB04,0xEAEC2E1C), + MK_64(0xDF25A0E2,0x813581F7), + MK_64(0xE4004093,0x8B12F9D2), + MK_64(0xA662D539,0xC2ED39B6), + MK_64(0xFA8B85CF,0x45D8C75A), + MK_64(0x8316ED8E,0x29EDE796), + MK_64(0x053289C0,0x2E9F91B8), + MK_64(0xC3F8EF1D,0x6D518B73), + MK_64(0xBDCEC3C4,0xD5EF332E), + MK_64(0x549A7E52,0x22974487), + MK_64(0x67070872,0x5B749816), + MK_64(0xB9CD28FB,0xF0581BD1), + MK_64(0x0E2940B8,0x15804974) + }; + +/* blkSize = 1024 bits. hashSize = 1024 bits */ +const u64b_t SKEIN1024_IV_1024[] = + { + MK_64(0xD593DA07,0x41E72355), + MK_64(0x15B5E511,0xAC73E00C), + MK_64(0x5180E5AE,0xBAF2C4F0), + MK_64(0x03BD41D3,0xFCBCAFAF), + MK_64(0x1CAEC6FD,0x1983A898), + MK_64(0x6E510B8B,0xCDD0589F), + MK_64(0x77E2BDFD,0xC6394ADA), + MK_64(0xC11E1DB5,0x24DCB0A3), + MK_64(0xD6D14AF9,0xC6329AB5), + MK_64(0x6A9B0BFC,0x6EB67E0D), + MK_64(0x9243C60D,0xCCFF1332), + MK_64(0x1A1F1DDE,0x743F02D4), + MK_64(0x0996753C,0x10ED0BB8), + MK_64(0x6572DD22,0xF2B4969A), + MK_64(0x61FD3062,0xD00A579A), + MK_64(0x1DE0536E,0x8682E539) + }; + + +#ifndef SKEIN_USE_ASM +#define SKEIN_USE_ASM (0) /* default is all C code (no ASM) */ +#endif + +#ifndef SKEIN_LOOP +#define SKEIN_LOOP 001 /* default: unroll 256 and 512, but not 1024 */ +#endif + +#define BLK_BITS (WCNT*64) /* some useful definitions for code here */ +#define KW_TWK_BASE (0) +#define KW_KEY_BASE (3) +#define ks (kw + KW_KEY_BASE) +#define ts (kw + KW_TWK_BASE) + +#ifdef SKEIN_DEBUG +#define DebugSaveTweak(ctx) { ctx->h.T[0] = ts[0]; ctx->h.T[1] = ts[1]; } +#else +#define DebugSaveTweak(ctx) +#endif + +/***************************** Skein_256 ******************************/ +#if !(SKEIN_USE_ASM & 256) +static void Skein_256_Process_Block(Skein_256_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd) + { /* do it in C */ + enum + { + WCNT = SKEIN_256_STATE_WORDS + }; +#undef RCNT +#define RCNT (SKEIN_256_ROUNDS_TOTAL/8) + +#ifdef SKEIN_LOOP /* configure how much to unroll the loop */ +#define SKEIN_UNROLL_256 (((SKEIN_LOOP)/100)%10) +#else +#define SKEIN_UNROLL_256 (0) +#endif + +#if SKEIN_UNROLL_256 +#if (RCNT % SKEIN_UNROLL_256) +#error "Invalid SKEIN_UNROLL_256" /* sanity check on unroll count */ +#endif + size_t r; + u64b_t kw[WCNT+4+RCNT*2]; /* key schedule words : chaining vars + tweak + "rotation"*/ +#else + u64b_t kw[WCNT+4]; /* key schedule words : chaining vars + tweak */ +#endif + u64b_t X0,X1,X2,X3; /* local copy of context vars, for speed */ + u64b_t w [WCNT]; /* local copy of input block */ +#ifdef SKEIN_DEBUG + const u64b_t *Xptr[4]; /* use for debugging (help compiler put Xn in registers) */ + Xptr[0] = &X0; Xptr[1] = &X1; Xptr[2] = &X2; Xptr[3] = &X3; +#endif + Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ + ts[0] = ctx->h.T[0]; + ts[1] = ctx->h.T[1]; + do { + /* this implementation only supports 2**64 input bytes (no carry out here) */ + ts[0] += byteCntAdd; /* update processed length */ + + /* precompute the key schedule for this block */ + ks[0] = ctx->X[0]; + ks[1] = ctx->X[1]; + ks[2] = ctx->X[2]; + ks[3] = ctx->X[3]; + ks[4] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ SKEIN_KS_PARITY; + + ts[2] = ts[0] ^ ts[1]; + + Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */ + DebugSaveTweak(ctx); + Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts); + + X0 = w[0] + ks[0]; /* do the first full key injection */ + X1 = w[1] + ks[1] + ts[0]; + X2 = w[2] + ks[2] + ts[1]; + X3 = w[3] + ks[3]; + + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr); /* show starting state values */ + + blkPtr += SKEIN_256_BLOCK_BYTES; + + /* run the rounds */ + +#define Round256(p0,p1,p2,p3,ROT,rNum) \ + X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \ + X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \ + +#if SKEIN_UNROLL_256 == 0 +#define R256(p0,p1,p2,p3,ROT,rNum) /* fully unrolled */ \ + Round256(p0,p1,p2,p3,ROT,rNum) \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rNum,Xptr); + +#define I256(R) \ + X0 += ks[((R)+1) % 5]; /* inject the key schedule value */ \ + X1 += ks[((R)+2) % 5] + ts[((R)+1) % 3]; \ + X2 += ks[((R)+3) % 5] + ts[((R)+2) % 3]; \ + X3 += ks[((R)+4) % 5] + (R)+1; \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); +#else /* looping version */ +#define R256(p0,p1,p2,p3,ROT,rNum) \ + Round256(p0,p1,p2,p3,ROT,rNum) \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rNum,Xptr); + +#define I256(R) \ + X0 += ks[r+(R)+0]; /* inject the key schedule value */ \ + X1 += ks[r+(R)+1] + ts[r+(R)+0]; \ + X2 += ks[r+(R)+2] + ts[r+(R)+1]; \ + X3 += ks[r+(R)+3] + r+(R) ; \ + ks[r + (R)+4 ] = ks[r+(R)-1]; /* rotate key schedule */\ + ts[r + (R)+2 ] = ts[r+(R)-1]; \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); + + for (r=1;r < 2*RCNT;r+=2*SKEIN_UNROLL_256) /* loop thru it */ +#endif + { +#define R256_8_rounds(R) \ + R256(0,1,2,3,R_256_0,8*(R) + 1); \ + R256(0,3,2,1,R_256_1,8*(R) + 2); \ + R256(0,1,2,3,R_256_2,8*(R) + 3); \ + R256(0,3,2,1,R_256_3,8*(R) + 4); \ + I256(2*(R)); \ + R256(0,1,2,3,R_256_4,8*(R) + 5); \ + R256(0,3,2,1,R_256_5,8*(R) + 6); \ + R256(0,1,2,3,R_256_6,8*(R) + 7); \ + R256(0,3,2,1,R_256_7,8*(R) + 8); \ + I256(2*(R)+1); + + R256_8_rounds( 0); + +#define R256_Unroll_R(NN) ((SKEIN_UNROLL_256 == 0 && SKEIN_256_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_256 > (NN))) + + #if R256_Unroll_R( 1) + R256_8_rounds( 1); + #endif + #if R256_Unroll_R( 2) + R256_8_rounds( 2); + #endif + #if R256_Unroll_R( 3) + R256_8_rounds( 3); + #endif + #if R256_Unroll_R( 4) + R256_8_rounds( 4); + #endif + #if R256_Unroll_R( 5) + R256_8_rounds( 5); + #endif + #if R256_Unroll_R( 6) + R256_8_rounds( 6); + #endif + #if R256_Unroll_R( 7) + R256_8_rounds( 7); + #endif + #if R256_Unroll_R( 8) + R256_8_rounds( 8); + #endif + #if R256_Unroll_R( 9) + R256_8_rounds( 9); + #endif + #if R256_Unroll_R(10) + R256_8_rounds(10); + #endif + #if R256_Unroll_R(11) + R256_8_rounds(11); + #endif + #if R256_Unroll_R(12) + R256_8_rounds(12); + #endif + #if R256_Unroll_R(13) + R256_8_rounds(13); + #endif + #if R256_Unroll_R(14) + R256_8_rounds(14); + #endif + #if (SKEIN_UNROLL_256 > 14) +#error "need more unrolling in Skein_256_Process_Block" + #endif + } + /* do the final "feedforward" xor, update context chaining vars */ + ctx->X[0] = X0 ^ w[0]; + ctx->X[1] = X1 ^ w[1]; + ctx->X[2] = X2 ^ w[2]; + ctx->X[3] = X3 ^ w[3]; + + Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X); + + ts[1] &= ~SKEIN_T1_FLAG_FIRST; + } + while (--blkCnt); + ctx->h.T[0] = ts[0]; + ctx->h.T[1] = ts[1]; + } + +#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) +static size_t Skein_256_Process_Block_CodeSize(void) + { + return ((u08b_t *) Skein_256_Process_Block_CodeSize) - + ((u08b_t *) Skein_256_Process_Block); + } +static uint_t Skein_256_Unroll_Cnt(void) + { + return SKEIN_UNROLL_256; + } +#endif +#endif + +/***************************** Skein_512 ******************************/ +#if !(SKEIN_USE_ASM & 512) +static void Skein_512_Process_Block(Skein_512_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd) + { /* do it in C */ + enum + { + WCNT = SKEIN_512_STATE_WORDS + }; +#undef RCNT +#define RCNT (SKEIN_512_ROUNDS_TOTAL/8) + +#ifdef SKEIN_LOOP /* configure how much to unroll the loop */ +#define SKEIN_UNROLL_512 (((SKEIN_LOOP)/10)%10) +#else +#define SKEIN_UNROLL_512 (0) +#endif + +#if SKEIN_UNROLL_512 +#if (RCNT % SKEIN_UNROLL_512) +#error "Invalid SKEIN_UNROLL_512" /* sanity check on unroll count */ +#endif + size_t r; + u64b_t kw[WCNT+4+RCNT*2]; /* key schedule words : chaining vars + tweak + "rotation"*/ +#else + u64b_t kw[WCNT+4]; /* key schedule words : chaining vars + tweak */ +#endif + u64b_t X0,X1,X2,X3,X4,X5,X6,X7; /* local copy of vars, for speed */ + u64b_t w [WCNT]; /* local copy of input block */ +#ifdef SKEIN_DEBUG + const u64b_t *Xptr[8]; /* use for debugging (help compiler put Xn in registers) */ + Xptr[0] = &X0; Xptr[1] = &X1; Xptr[2] = &X2; Xptr[3] = &X3; + Xptr[4] = &X4; Xptr[5] = &X5; Xptr[6] = &X6; Xptr[7] = &X7; +#endif + + Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ + ts[0] = ctx->h.T[0]; + ts[1] = ctx->h.T[1]; + do { + /* this implementation only supports 2**64 input bytes (no carry out here) */ + ts[0] += byteCntAdd; /* update processed length */ + + /* precompute the key schedule for this block */ + ks[0] = ctx->X[0]; + ks[1] = ctx->X[1]; + ks[2] = ctx->X[2]; + ks[3] = ctx->X[3]; + ks[4] = ctx->X[4]; + ks[5] = ctx->X[5]; + ks[6] = ctx->X[6]; + ks[7] = ctx->X[7]; + ks[8] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ + ks[4] ^ ks[5] ^ ks[6] ^ ks[7] ^ SKEIN_KS_PARITY; + + ts[2] = ts[0] ^ ts[1]; + + Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */ + DebugSaveTweak(ctx); + Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts); + + X0 = w[0] + ks[0]; /* do the first full key injection */ + X1 = w[1] + ks[1]; + X2 = w[2] + ks[2]; + X3 = w[3] + ks[3]; + X4 = w[4] + ks[4]; + X5 = w[5] + ks[5] + ts[0]; + X6 = w[6] + ks[6] + ts[1]; + X7 = w[7] + ks[7]; + + blkPtr += SKEIN_512_BLOCK_BYTES; + + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr); + /* run the rounds */ +#define Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ + X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \ + X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \ + X##p4 += X##p5; X##p5 = RotL_64(X##p5,ROT##_2); X##p5 ^= X##p4; \ + X##p6 += X##p7; X##p7 = RotL_64(X##p7,ROT##_3); X##p7 ^= X##p6; \ + +#if SKEIN_UNROLL_512 == 0 +#define R512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) /* unrolled */ \ + Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rNum,Xptr); + +#define I512(R) \ + X0 += ks[((R)+1) % 9]; /* inject the key schedule value */ \ + X1 += ks[((R)+2) % 9]; \ + X2 += ks[((R)+3) % 9]; \ + X3 += ks[((R)+4) % 9]; \ + X4 += ks[((R)+5) % 9]; \ + X5 += ks[((R)+6) % 9] + ts[((R)+1) % 3]; \ + X6 += ks[((R)+7) % 9] + ts[((R)+2) % 3]; \ + X7 += ks[((R)+8) % 9] + (R)+1; \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); +#else /* looping version */ +#define R512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ + Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rNum,Xptr); + +#define I512(R) \ + X0 += ks[r+(R)+0]; /* inject the key schedule value */ \ + X1 += ks[r+(R)+1]; \ + X2 += ks[r+(R)+2]; \ + X3 += ks[r+(R)+3]; \ + X4 += ks[r+(R)+4]; \ + X5 += ks[r+(R)+5] + ts[r+(R)+0]; \ + X6 += ks[r+(R)+6] + ts[r+(R)+1]; \ + X7 += ks[r+(R)+7] + r+(R) ; \ + ks[r + (R)+8] = ks[r+(R)-1]; /* rotate key schedule */ \ + ts[r + (R)+2] = ts[r+(R)-1]; \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); + + for (r=1;r < 2*RCNT;r+=2*SKEIN_UNROLL_512) /* loop thru it */ +#endif /* end of looped code definitions */ + { +#define R512_8_rounds(R) /* do 8 full rounds */ \ + R512(0,1,2,3,4,5,6,7,R_512_0,8*(R)+ 1); \ + R512(2,1,4,7,6,5,0,3,R_512_1,8*(R)+ 2); \ + R512(4,1,6,3,0,5,2,7,R_512_2,8*(R)+ 3); \ + R512(6,1,0,7,2,5,4,3,R_512_3,8*(R)+ 4); \ + I512(2*(R)); \ + R512(0,1,2,3,4,5,6,7,R_512_4,8*(R)+ 5); \ + R512(2,1,4,7,6,5,0,3,R_512_5,8*(R)+ 6); \ + R512(4,1,6,3,0,5,2,7,R_512_6,8*(R)+ 7); \ + R512(6,1,0,7,2,5,4,3,R_512_7,8*(R)+ 8); \ + I512(2*(R)+1); /* and key injection */ + + R512_8_rounds( 0); + +#define R512_Unroll_R(NN) ((SKEIN_UNROLL_512 == 0 && SKEIN_512_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_512 > (NN))) + + #if R512_Unroll_R( 1) + R512_8_rounds( 1); + #endif + #if R512_Unroll_R( 2) + R512_8_rounds( 2); + #endif + #if R512_Unroll_R( 3) + R512_8_rounds( 3); + #endif + #if R512_Unroll_R( 4) + R512_8_rounds( 4); + #endif + #if R512_Unroll_R( 5) + R512_8_rounds( 5); + #endif + #if R512_Unroll_R( 6) + R512_8_rounds( 6); + #endif + #if R512_Unroll_R( 7) + R512_8_rounds( 7); + #endif + #if R512_Unroll_R( 8) + R512_8_rounds( 8); + #endif + #if R512_Unroll_R( 9) + R512_8_rounds( 9); + #endif + #if R512_Unroll_R(10) + R512_8_rounds(10); + #endif + #if R512_Unroll_R(11) + R512_8_rounds(11); + #endif + #if R512_Unroll_R(12) + R512_8_rounds(12); + #endif + #if R512_Unroll_R(13) + R512_8_rounds(13); + #endif + #if R512_Unroll_R(14) + R512_8_rounds(14); + #endif + #if (SKEIN_UNROLL_512 > 14) +#error "need more unrolling in Skein_512_Process_Block" + #endif + } + + /* do the final "feedforward" xor, update context chaining vars */ + ctx->X[0] = X0 ^ w[0]; + ctx->X[1] = X1 ^ w[1]; + ctx->X[2] = X2 ^ w[2]; + ctx->X[3] = X3 ^ w[3]; + ctx->X[4] = X4 ^ w[4]; + ctx->X[5] = X5 ^ w[5]; + ctx->X[6] = X6 ^ w[6]; + ctx->X[7] = X7 ^ w[7]; + Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X); + + ts[1] &= ~SKEIN_T1_FLAG_FIRST; + } + while (--blkCnt); + ctx->h.T[0] = ts[0]; + ctx->h.T[1] = ts[1]; + } + +#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) +static size_t Skein_512_Process_Block_CodeSize(void) + { + return ((u08b_t *) Skein_512_Process_Block_CodeSize) - + ((u08b_t *) Skein_512_Process_Block); + } +static uint_t Skein_512_Unroll_Cnt(void) + { + return SKEIN_UNROLL_512; + } +#endif +#endif + +/***************************** Skein1024 ******************************/ +#if !(SKEIN_USE_ASM & 1024) +static void Skein1024_Process_Block(Skein1024_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd) + { /* do it in C, always looping (unrolled is bigger AND slower!) */ + enum + { + WCNT = SKEIN1024_STATE_WORDS + }; +#undef RCNT +#define RCNT (SKEIN1024_ROUNDS_TOTAL/8) + +#ifdef SKEIN_LOOP /* configure how much to unroll the loop */ +#define SKEIN_UNROLL_1024 ((SKEIN_LOOP)%10) +#else +#define SKEIN_UNROLL_1024 (0) +#endif + +#if (SKEIN_UNROLL_1024 != 0) +#if (RCNT % SKEIN_UNROLL_1024) +#error "Invalid SKEIN_UNROLL_1024" /* sanity check on unroll count */ +#endif + size_t r; + u64b_t kw[WCNT+4+RCNT*2]; /* key schedule words : chaining vars + tweak + "rotation"*/ +#else + u64b_t kw[WCNT+4]; /* key schedule words : chaining vars + tweak */ +#endif + + u64b_t X00,X01,X02,X03,X04,X05,X06,X07, /* local copy of vars, for speed */ + X08,X09,X10,X11,X12,X13,X14,X15; + u64b_t w [WCNT]; /* local copy of input block */ +#ifdef SKEIN_DEBUG + const u64b_t *Xptr[16]; /* use for debugging (help compiler put Xn in registers) */ + Xptr[ 0] = &X00; Xptr[ 1] = &X01; Xptr[ 2] = &X02; Xptr[ 3] = &X03; + Xptr[ 4] = &X04; Xptr[ 5] = &X05; Xptr[ 6] = &X06; Xptr[ 7] = &X07; + Xptr[ 8] = &X08; Xptr[ 9] = &X09; Xptr[10] = &X10; Xptr[11] = &X11; + Xptr[12] = &X12; Xptr[13] = &X13; Xptr[14] = &X14; Xptr[15] = &X15; +#endif + + Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ + ts[0] = ctx->h.T[0]; + ts[1] = ctx->h.T[1]; + do { + /* this implementation only supports 2**64 input bytes (no carry out here) */ + ts[0] += byteCntAdd; /* update processed length */ + + /* precompute the key schedule for this block */ + ks[ 0] = ctx->X[ 0]; + ks[ 1] = ctx->X[ 1]; + ks[ 2] = ctx->X[ 2]; + ks[ 3] = ctx->X[ 3]; + ks[ 4] = ctx->X[ 4]; + ks[ 5] = ctx->X[ 5]; + ks[ 6] = ctx->X[ 6]; + ks[ 7] = ctx->X[ 7]; + ks[ 8] = ctx->X[ 8]; + ks[ 9] = ctx->X[ 9]; + ks[10] = ctx->X[10]; + ks[11] = ctx->X[11]; + ks[12] = ctx->X[12]; + ks[13] = ctx->X[13]; + ks[14] = ctx->X[14]; + ks[15] = ctx->X[15]; + ks[16] = ks[ 0] ^ ks[ 1] ^ ks[ 2] ^ ks[ 3] ^ + ks[ 4] ^ ks[ 5] ^ ks[ 6] ^ ks[ 7] ^ + ks[ 8] ^ ks[ 9] ^ ks[10] ^ ks[11] ^ + ks[12] ^ ks[13] ^ ks[14] ^ ks[15] ^ SKEIN_KS_PARITY; + + ts[2] = ts[0] ^ ts[1]; + + Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */ + DebugSaveTweak(ctx); + Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts); + + X00 = w[ 0] + ks[ 0]; /* do the first full key injection */ + X01 = w[ 1] + ks[ 1]; + X02 = w[ 2] + ks[ 2]; + X03 = w[ 3] + ks[ 3]; + X04 = w[ 4] + ks[ 4]; + X05 = w[ 5] + ks[ 5]; + X06 = w[ 6] + ks[ 6]; + X07 = w[ 7] + ks[ 7]; + X08 = w[ 8] + ks[ 8]; + X09 = w[ 9] + ks[ 9]; + X10 = w[10] + ks[10]; + X11 = w[11] + ks[11]; + X12 = w[12] + ks[12]; + X13 = w[13] + ks[13] + ts[0]; + X14 = w[14] + ks[14] + ts[1]; + X15 = w[15] + ks[15]; + + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr); + +#define Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rNum) \ + X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \ + X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \ + X##p4 += X##p5; X##p5 = RotL_64(X##p5,ROT##_2); X##p5 ^= X##p4; \ + X##p6 += X##p7; X##p7 = RotL_64(X##p7,ROT##_3); X##p7 ^= X##p6; \ + X##p8 += X##p9; X##p9 = RotL_64(X##p9,ROT##_4); X##p9 ^= X##p8; \ + X##pA += X##pB; X##pB = RotL_64(X##pB,ROT##_5); X##pB ^= X##pA; \ + X##pC += X##pD; X##pD = RotL_64(X##pD,ROT##_6); X##pD ^= X##pC; \ + X##pE += X##pF; X##pF = RotL_64(X##pF,ROT##_7); X##pF ^= X##pE; \ + +#if SKEIN_UNROLL_1024 == 0 +#define R1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \ + Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rn,Xptr); + +#define I1024(R) \ + X00 += ks[((R)+ 1) % 17]; /* inject the key schedule value */ \ + X01 += ks[((R)+ 2) % 17]; \ + X02 += ks[((R)+ 3) % 17]; \ + X03 += ks[((R)+ 4) % 17]; \ + X04 += ks[((R)+ 5) % 17]; \ + X05 += ks[((R)+ 6) % 17]; \ + X06 += ks[((R)+ 7) % 17]; \ + X07 += ks[((R)+ 8) % 17]; \ + X08 += ks[((R)+ 9) % 17]; \ + X09 += ks[((R)+10) % 17]; \ + X10 += ks[((R)+11) % 17]; \ + X11 += ks[((R)+12) % 17]; \ + X12 += ks[((R)+13) % 17]; \ + X13 += ks[((R)+14) % 17] + ts[((R)+1) % 3]; \ + X14 += ks[((R)+15) % 17] + ts[((R)+2) % 3]; \ + X15 += ks[((R)+16) % 17] + (R)+1; \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); +#else /* looping version */ +#define R1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \ + Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rn,Xptr); + +#define I1024(R) \ + X00 += ks[r+(R)+ 0]; /* inject the key schedule value */ \ + X01 += ks[r+(R)+ 1]; \ + X02 += ks[r+(R)+ 2]; \ + X03 += ks[r+(R)+ 3]; \ + X04 += ks[r+(R)+ 4]; \ + X05 += ks[r+(R)+ 5]; \ + X06 += ks[r+(R)+ 6]; \ + X07 += ks[r+(R)+ 7]; \ + X08 += ks[r+(R)+ 8]; \ + X09 += ks[r+(R)+ 9]; \ + X10 += ks[r+(R)+10]; \ + X11 += ks[r+(R)+11]; \ + X12 += ks[r+(R)+12]; \ + X13 += ks[r+(R)+13] + ts[r+(R)+0]; \ + X14 += ks[r+(R)+14] + ts[r+(R)+1]; \ + X15 += ks[r+(R)+15] + r+(R) ; \ + ks[r + (R)+16] = ks[r+(R)-1]; /* rotate key schedule */ \ + ts[r + (R)+ 2] = ts[r+(R)-1]; \ + Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); + + for (r=1;r <= 2*RCNT;r+=2*SKEIN_UNROLL_1024) /* loop thru it */ +#endif + { +#define R1024_8_rounds(R) /* do 8 full rounds */ \ + R1024(00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,R1024_0,8*(R) + 1); \ + R1024(00,09,02,13,06,11,04,15,10,07,12,03,14,05,08,01,R1024_1,8*(R) + 2); \ + R1024(00,07,02,05,04,03,06,01,12,15,14,13,08,11,10,09,R1024_2,8*(R) + 3); \ + R1024(00,15,02,11,06,13,04,09,14,01,08,05,10,03,12,07,R1024_3,8*(R) + 4); \ + I1024(2*(R)); \ + R1024(00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,R1024_4,8*(R) + 5); \ + R1024(00,09,02,13,06,11,04,15,10,07,12,03,14,05,08,01,R1024_5,8*(R) + 6); \ + R1024(00,07,02,05,04,03,06,01,12,15,14,13,08,11,10,09,R1024_6,8*(R) + 7); \ + R1024(00,15,02,11,06,13,04,09,14,01,08,05,10,03,12,07,R1024_7,8*(R) + 8); \ + I1024(2*(R)+1); + + R1024_8_rounds( 0); + +#define R1024_Unroll_R(NN) ((SKEIN_UNROLL_1024 == 0 && SKEIN1024_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_1024 > (NN))) + + #if R1024_Unroll_R( 1) + R1024_8_rounds( 1); + #endif + #if R1024_Unroll_R( 2) + R1024_8_rounds( 2); + #endif + #if R1024_Unroll_R( 3) + R1024_8_rounds( 3); + #endif + #if R1024_Unroll_R( 4) + R1024_8_rounds( 4); + #endif + #if R1024_Unroll_R( 5) + R1024_8_rounds( 5); + #endif + #if R1024_Unroll_R( 6) + R1024_8_rounds( 6); + #endif + #if R1024_Unroll_R( 7) + R1024_8_rounds( 7); + #endif + #if R1024_Unroll_R( 8) + R1024_8_rounds( 8); + #endif + #if R1024_Unroll_R( 9) + R1024_8_rounds( 9); + #endif + #if R1024_Unroll_R(10) + R1024_8_rounds(10); + #endif + #if R1024_Unroll_R(11) + R1024_8_rounds(11); + #endif + #if R1024_Unroll_R(12) + R1024_8_rounds(12); + #endif + #if R1024_Unroll_R(13) + R1024_8_rounds(13); + #endif + #if R1024_Unroll_R(14) + R1024_8_rounds(14); + #endif + #if (SKEIN_UNROLL_1024 > 14) +#error "need more unrolling in Skein_1024_Process_Block" + #endif + } + /* do the final "feedforward" xor, update context chaining vars */ + + ctx->X[ 0] = X00 ^ w[ 0]; + ctx->X[ 1] = X01 ^ w[ 1]; + ctx->X[ 2] = X02 ^ w[ 2]; + ctx->X[ 3] = X03 ^ w[ 3]; + ctx->X[ 4] = X04 ^ w[ 4]; + ctx->X[ 5] = X05 ^ w[ 5]; + ctx->X[ 6] = X06 ^ w[ 6]; + ctx->X[ 7] = X07 ^ w[ 7]; + ctx->X[ 8] = X08 ^ w[ 8]; + ctx->X[ 9] = X09 ^ w[ 9]; + ctx->X[10] = X10 ^ w[10]; + ctx->X[11] = X11 ^ w[11]; + ctx->X[12] = X12 ^ w[12]; + ctx->X[13] = X13 ^ w[13]; + ctx->X[14] = X14 ^ w[14]; + ctx->X[15] = X15 ^ w[15]; + + Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X); + + ts[1] &= ~SKEIN_T1_FLAG_FIRST; + blkPtr += SKEIN1024_BLOCK_BYTES; + } + while (--blkCnt); + ctx->h.T[0] = ts[0]; + ctx->h.T[1] = ts[1]; + } + +#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) +static size_t Skein1024_Process_Block_CodeSize(void) + { + return ((u08b_t *) Skein1024_Process_Block_CodeSize) - + ((u08b_t *) Skein1024_Process_Block); + } +static uint_t Skein1024_Unroll_Cnt(void) + { + return SKEIN_UNROLL_1024; + } +#endif +#endif + + +#if 0 +/*****************************************************************/ +/* 256-bit Skein */ +/*****************************************************************/ + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a straight hashing operation */ +static int Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen) + { + union + { + u08b_t b[SKEIN_256_STATE_BYTES]; + u64b_t w[SKEIN_256_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); + ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ + + switch (hashBitLen) + { /* use pre-computed values, where available */ +#ifndef SKEIN_NO_PRECOMP + case 256: memcpy(ctx->X,SKEIN_256_IV_256,sizeof(ctx->X)); break; + case 224: memcpy(ctx->X,SKEIN_256_IV_224,sizeof(ctx->X)); break; + case 160: memcpy(ctx->X,SKEIN_256_IV_160,sizeof(ctx->X)); break; + case 128: memcpy(ctx->X,SKEIN_256_IV_128,sizeof(ctx->X)); break; +#endif + default: + /* here if there is no precomputed IV value available */ + /* build/process the config block, type == CONFIG (could be precomputed) */ + Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */ + + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */ + cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ + cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); + memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */ + + /* compute the initial chaining values from config block */ + memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */ + Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); + break; + } + /* The chaining vars ctx->X are now initialized for the given hashBitLen. */ + /* Set up to process the data message portion of the hash (default) */ + Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type */ + + return SKEIN_SUCCESS; + } + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a MAC and/or tree hash operation */ +/* [identical to Skein_256_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */ +static int Skein_256_InitExt(Skein_256_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes) + { + union + { + u08b_t b[SKEIN_256_STATE_BYTES]; + u64b_t w[SKEIN_256_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); + Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL); + + /* compute the initial chaining values ctx->X[], based on key */ + if (keyBytes == 0) /* is there a key? */ + { + memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */ + } + else /* here to pre-process a key */ + { + Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X)); + /* do a mini-Init right here */ + ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */ + Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */ + memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */ + Skein_256_Update(ctx,key,keyBytes); /* hash the key */ + Skein_256_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */ + memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */ +#if SKEIN_NEED_SWAP + { + uint_t i; + for (i=0;iX[i] = Skein_Swap64(ctx->X[i]); + } +#endif + } + /* build/process the config block, type == CONFIG (could be precomputed for each key) */ + ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ + Skein_Start_New_Type(ctx,CFG_FINAL); + + memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */ + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); + cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ + cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ + + Skein_Show_Key(256,&ctx->h,key,keyBytes); + + /* compute the initial chaining values from config block */ + Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); + + /* The chaining vars ctx->X are now initialized */ + /* Set up to process the data message portion of the hash (default) */ + ctx->h.bCnt = 0; /* buffer b[] starts out empty */ + Skein_Start_New_Type(ctx,MSG); + + return SKEIN_SUCCESS; + } +#endif + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* process the input bytes */ +static int Skein_256_Update(Skein_256_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt) + { + size_t n; + + Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + /* process full blocks, if any */ + if (msgByteCnt + ctx->h.bCnt > SKEIN_256_BLOCK_BYTES) + { + if (ctx->h.bCnt) /* finish up any buffered message data */ + { + n = SKEIN_256_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */ + if (n) + { + Skein_assert(n < msgByteCnt); /* check on our logic here */ + memcpy(&ctx->b[ctx->h.bCnt],msg,n); + msgByteCnt -= n; + msg += n; + ctx->h.bCnt += n; + } + Skein_assert(ctx->h.bCnt == SKEIN_256_BLOCK_BYTES); + Skein_256_Process_Block(ctx,ctx->b,1,SKEIN_256_BLOCK_BYTES); + ctx->h.bCnt = 0; + } + /* now process any remaining full blocks, directly from input message data */ + if (msgByteCnt > SKEIN_256_BLOCK_BYTES) + { + n = (msgByteCnt-1) / SKEIN_256_BLOCK_BYTES; /* number of full blocks to process */ + Skein_256_Process_Block(ctx,msg,n,SKEIN_256_BLOCK_BYTES); + msgByteCnt -= n * SKEIN_256_BLOCK_BYTES; + msg += n * SKEIN_256_BLOCK_BYTES; + } + Skein_assert(ctx->h.bCnt == 0); + } + + /* copy any remaining source message data bytes into b[] */ + if (msgByteCnt) + { + Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES); + memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt); + ctx->h.bCnt += msgByteCnt; + } + + return SKEIN_SUCCESS; + } + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the result */ +static int Skein_256_Final(Skein_256_Ctxt_t *ctx, u08b_t *hashVal) + { + size_t i,n,byteCnt; + u64b_t X[SKEIN_256_STATE_WORDS]; + Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ + if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES) /* zero pad b[] if necessary */ + memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt); + + Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ + + /* now output the result */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ + + /* run Threefish in "counter mode" to generate output */ + memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ + memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ + for (i=0;i < byteCnt;i += SKEIN_256_BLOCK_BYTES) + { + ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ + Skein_Start_New_Type(ctx,OUT_FINAL); + Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ + n = byteCnt - i; /* number of output bytes left to go */ + if (n >= SKEIN_256_BLOCK_BYTES) + n = SKEIN_256_BLOCK_BYTES; + Skein_Put64_LSB_First(hashVal+i,ctx->X,n); /* "output" the ctr mode bytes */ + Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES); + memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ + } + return SKEIN_SUCCESS; + } + +#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) +static size_t Skein_256_API_CodeSize(void) + { + return ((u08b_t *) Skein_256_API_CodeSize) - + ((u08b_t *) Skein_256_Init); + } +#endif + +/*****************************************************************/ +/* 512-bit Skein */ +/*****************************************************************/ + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a straight hashing operation */ +static int Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen) + { + union + { + u08b_t b[SKEIN_512_STATE_BYTES]; + u64b_t w[SKEIN_512_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); + ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ + + switch (hashBitLen) + { /* use pre-computed values, where available */ +#ifndef SKEIN_NO_PRECOMP + case 512: memcpy(ctx->X,SKEIN_512_IV_512,sizeof(ctx->X)); break; + case 384: memcpy(ctx->X,SKEIN_512_IV_384,sizeof(ctx->X)); break; + case 256: memcpy(ctx->X,SKEIN_512_IV_256,sizeof(ctx->X)); break; + case 224: memcpy(ctx->X,SKEIN_512_IV_224,sizeof(ctx->X)); break; +#endif + default: + /* here if there is no precomputed IV value available */ + /* build/process the config block, type == CONFIG (could be precomputed) */ + Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */ + + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */ + cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ + cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); + memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */ + + /* compute the initial chaining values from config block */ + memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */ + Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); + break; + } + + /* The chaining vars ctx->X are now initialized for the given hashBitLen. */ + /* Set up to process the data message portion of the hash (default) */ + Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type */ + + return SKEIN_SUCCESS; + } + +#if 0 +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a MAC and/or tree hash operation */ +/* [identical to Skein_512_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */ +static int Skein_512_InitExt(Skein_512_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes) + { + union + { + u08b_t b[SKEIN_512_STATE_BYTES]; + u64b_t w[SKEIN_512_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); + Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL); + + /* compute the initial chaining values ctx->X[], based on key */ + if (keyBytes == 0) /* is there a key? */ + { + memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */ + } + else /* here to pre-process a key */ + { + Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X)); + /* do a mini-Init right here */ + ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */ + Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */ + memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */ + Skein_512_Update(ctx,key,keyBytes); /* hash the key */ + Skein_512_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */ + memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */ +#if SKEIN_NEED_SWAP + { + uint_t i; + for (i=0;iX[i] = Skein_Swap64(ctx->X[i]); + } +#endif + } + /* build/process the config block, type == CONFIG (could be precomputed for each key) */ + ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ + Skein_Start_New_Type(ctx,CFG_FINAL); + + memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */ + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); + cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ + cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ + + Skein_Show_Key(512,&ctx->h,key,keyBytes); + + /* compute the initial chaining values from config block */ + Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); + + /* The chaining vars ctx->X are now initialized */ + /* Set up to process the data message portion of the hash (default) */ + ctx->h.bCnt = 0; /* buffer b[] starts out empty */ + Skein_Start_New_Type(ctx,MSG); + + return SKEIN_SUCCESS; + } +#endif + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* process the input bytes */ +static int Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt) + { + size_t n; + + Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + /* process full blocks, if any */ + if (msgByteCnt + ctx->h.bCnt > SKEIN_512_BLOCK_BYTES) + { + if (ctx->h.bCnt) /* finish up any buffered message data */ + { + n = SKEIN_512_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */ + if (n) + { + Skein_assert(n < msgByteCnt); /* check on our logic here */ + memcpy(&ctx->b[ctx->h.bCnt],msg,n); + msgByteCnt -= n; + msg += n; + ctx->h.bCnt += n; + } + Skein_assert(ctx->h.bCnt == SKEIN_512_BLOCK_BYTES); + Skein_512_Process_Block(ctx,ctx->b,1,SKEIN_512_BLOCK_BYTES); + ctx->h.bCnt = 0; + } + /* now process any remaining full blocks, directly from input message data */ + if (msgByteCnt > SKEIN_512_BLOCK_BYTES) + { + n = (msgByteCnt-1) / SKEIN_512_BLOCK_BYTES; /* number of full blocks to process */ + Skein_512_Process_Block(ctx,msg,n,SKEIN_512_BLOCK_BYTES); + msgByteCnt -= n * SKEIN_512_BLOCK_BYTES; + msg += n * SKEIN_512_BLOCK_BYTES; + } + Skein_assert(ctx->h.bCnt == 0); + } + + /* copy any remaining source message data bytes into b[] */ + if (msgByteCnt) + { + Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES); + memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt); + ctx->h.bCnt += msgByteCnt; + } + + return SKEIN_SUCCESS; + } + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the result */ +static int Skein_512_Final(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) + { + size_t i,n,byteCnt; + u64b_t X[SKEIN_512_STATE_WORDS]; + Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ + if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) /* zero pad b[] if necessary */ + memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt); + + Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ + + /* now output the result */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ + + /* run Threefish in "counter mode" to generate output */ + memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ + memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ + for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++) + { + ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ + Skein_Start_New_Type(ctx,OUT_FINAL); + Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ + n = byteCnt - i*SKEIN_512_BLOCK_BYTES; /* number of output bytes left to go */ + if (n >= SKEIN_512_BLOCK_BYTES) + n = SKEIN_512_BLOCK_BYTES; + Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ + Skein_Show_Final(512,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES); + memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ + } + return SKEIN_SUCCESS; + } + +#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) +static size_t Skein_512_API_CodeSize(void) + { + return ((u08b_t *) Skein_512_API_CodeSize) - + ((u08b_t *) Skein_512_Init); + } +#endif + +/*****************************************************************/ +/* 1024-bit Skein */ +/*****************************************************************/ +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a straight hashing operation */ +static int Skein1024_Init(Skein1024_Ctxt_t *ctx, size_t hashBitLen) + { + union + { + u08b_t b[SKEIN1024_STATE_BYTES]; + u64b_t w[SKEIN1024_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); + ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ + + switch (hashBitLen) + { /* use pre-computed values, where available */ +#ifndef SKEIN_NO_PRECOMP + case 512: memcpy(ctx->X,SKEIN1024_IV_512 ,sizeof(ctx->X)); break; + case 384: memcpy(ctx->X,SKEIN1024_IV_384 ,sizeof(ctx->X)); break; + case 1024: memcpy(ctx->X,SKEIN1024_IV_1024,sizeof(ctx->X)); break; +#endif + default: + /* here if there is no precomputed IV value available */ + /* build/process the config block, type == CONFIG (could be precomputed) */ + Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */ + + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */ + cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ + cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); + memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */ + + /* compute the initial chaining values from config block */ + memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */ + Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); + break; + } + + /* The chaining vars ctx->X are now initialized for the given hashBitLen. */ + /* Set up to process the data message portion of the hash (default) */ + Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type */ + + return SKEIN_SUCCESS; + } + +#if 0 +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* init the context for a MAC and/or tree hash operation */ +/* [identical to Skein1024_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */ +static int Skein1024_InitExt(Skein1024_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes) + { + union + { + u08b_t b[SKEIN1024_STATE_BYTES]; + u64b_t w[SKEIN1024_STATE_WORDS]; + } cfg; /* config block */ + + Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); + Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL); + + /* compute the initial chaining values ctx->X[], based on key */ + if (keyBytes == 0) /* is there a key? */ + { + memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */ + } + else /* here to pre-process a key */ + { + Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X)); + /* do a mini-Init right here */ + ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */ + Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */ + memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */ + Skein1024_Update(ctx,key,keyBytes); /* hash the key */ + Skein1024_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */ + memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */ +#if SKEIN_NEED_SWAP + { + uint_t i; + for (i=0;iX[i] = Skein_Swap64(ctx->X[i]); + } +#endif + } + /* build/process the config block, type == CONFIG (could be precomputed for each key) */ + ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ + Skein_Start_New_Type(ctx,CFG_FINAL); + + memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */ + cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); + cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ + cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ + + Skein_Show_Key(1024,&ctx->h,key,keyBytes); + + /* compute the initial chaining values from config block */ + Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); + + /* The chaining vars ctx->X are now initialized */ + /* Set up to process the data message portion of the hash (default) */ + ctx->h.bCnt = 0; /* buffer b[] starts out empty */ + Skein_Start_New_Type(ctx,MSG); + + return SKEIN_SUCCESS; + } +#endif + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* process the input bytes */ +static int Skein1024_Update(Skein1024_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt) + { + size_t n; + + Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + /* process full blocks, if any */ + if (msgByteCnt + ctx->h.bCnt > SKEIN1024_BLOCK_BYTES) + { + if (ctx->h.bCnt) /* finish up any buffered message data */ + { + n = SKEIN1024_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */ + if (n) + { + Skein_assert(n < msgByteCnt); /* check on our logic here */ + memcpy(&ctx->b[ctx->h.bCnt],msg,n); + msgByteCnt -= n; + msg += n; + ctx->h.bCnt += n; + } + Skein_assert(ctx->h.bCnt == SKEIN1024_BLOCK_BYTES); + Skein1024_Process_Block(ctx,ctx->b,1,SKEIN1024_BLOCK_BYTES); + ctx->h.bCnt = 0; + } + /* now process any remaining full blocks, directly from input message data */ + if (msgByteCnt > SKEIN1024_BLOCK_BYTES) + { + n = (msgByteCnt-1) / SKEIN1024_BLOCK_BYTES; /* number of full blocks to process */ + Skein1024_Process_Block(ctx,msg,n,SKEIN1024_BLOCK_BYTES); + msgByteCnt -= n * SKEIN1024_BLOCK_BYTES; + msg += n * SKEIN1024_BLOCK_BYTES; + } + Skein_assert(ctx->h.bCnt == 0); + } + + /* copy any remaining source message data bytes into b[] */ + if (msgByteCnt) + { + Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES); + memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt); + ctx->h.bCnt += msgByteCnt; + } + + return SKEIN_SUCCESS; + } + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the result */ +static int Skein1024_Final(Skein1024_Ctxt_t *ctx, u08b_t *hashVal) + { + size_t i,n,byteCnt; + u64b_t X[SKEIN1024_STATE_WORDS]; + Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ + if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES) /* zero pad b[] if necessary */ + memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt); + + Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ + + /* now output the result */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ + + /* run Threefish in "counter mode" to generate output */ + memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ + memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ + for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++) + { + ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ + Skein_Start_New_Type(ctx,OUT_FINAL); + Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ + n = byteCnt - i*SKEIN1024_BLOCK_BYTES; /* number of output bytes left to go */ + if (n >= SKEIN1024_BLOCK_BYTES) + n = SKEIN1024_BLOCK_BYTES; + Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ + Skein_Show_Final(1024,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES); + memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ + } + return SKEIN_SUCCESS; + } + +#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) +static size_t Skein1024_API_CodeSize(void) + { + return ((u08b_t *) Skein1024_API_CodeSize) - + ((u08b_t *) Skein1024_Init); + } +#endif + +/**************** Functions to support MAC/tree hashing ***************/ +/* (this code is identical for Optimized and Reference versions) */ + +#if 0 +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the block, no OUTPUT stage */ +static int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, u08b_t *hashVal) + { + Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ + if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES) /* zero pad b[] if necessary */ + memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt); + Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ + + Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_256_BLOCK_BYTES); /* "output" the state bytes */ + + return SKEIN_SUCCESS; + } + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the block, no OUTPUT stage */ +static int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) + { + Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ + if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) /* zero pad b[] if necessary */ + memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt); + Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ + + Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_512_BLOCK_BYTES); /* "output" the state bytes */ + + return SKEIN_SUCCESS; + } + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize the hash computation and output the block, no OUTPUT stage */ +static int Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, u08b_t *hashVal) + { + Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ + if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES) /* zero pad b[] if necessary */ + memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt); + Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ + + Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN1024_BLOCK_BYTES); /* "output" the state bytes */ + + return SKEIN_SUCCESS; + } + + +#if SKEIN_TREE_HASH +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* just do the OUTPUT stage */ +static int Skein_256_Output(Skein_256_Ctxt_t *ctx, u08b_t *hashVal) + { + size_t i,n,byteCnt; + u64b_t X[SKEIN_256_STATE_WORDS]; + Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + /* now output the result */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ + + /* run Threefish in "counter mode" to generate output */ + memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ + memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ + for (i=0;i*SKEIN_256_BLOCK_BYTES < byteCnt;i++) + { + ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ + Skein_Start_New_Type(ctx,OUT_FINAL); + Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ + n = byteCnt - i*SKEIN_256_BLOCK_BYTES; /* number of output bytes left to go */ + if (n >= SKEIN_256_BLOCK_BYTES) + n = SKEIN_256_BLOCK_BYTES; + Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ + Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES); + memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ + } + return SKEIN_SUCCESS; + } + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* just do the OUTPUT stage */ +static int Skein_512_Output(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) + { + size_t i,n,byteCnt; + u64b_t X[SKEIN_512_STATE_WORDS]; + Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + /* now output the result */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ + + /* run Threefish in "counter mode" to generate output */ + memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ + memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ + for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++) + { + ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ + Skein_Start_New_Type(ctx,OUT_FINAL); + Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ + n = byteCnt - i*SKEIN_512_BLOCK_BYTES; /* number of output bytes left to go */ + if (n >= SKEIN_512_BLOCK_BYTES) + n = SKEIN_512_BLOCK_BYTES; + Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ + Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES); + memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ + } + return SKEIN_SUCCESS; + } + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* just do the OUTPUT stage */ +static int Skein1024_Output(Skein1024_Ctxt_t *ctx, u08b_t *hashVal) + { + size_t i,n,byteCnt; + u64b_t X[SKEIN1024_STATE_WORDS]; + Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ + + /* now output the result */ + byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ + + /* run Threefish in "counter mode" to generate output */ + memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ + memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ + for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++) + { + ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ + Skein_Start_New_Type(ctx,OUT_FINAL); + Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ + n = byteCnt - i*SKEIN1024_BLOCK_BYTES; /* number of output bytes left to go */ + if (n >= SKEIN1024_BLOCK_BYTES) + n = SKEIN1024_BLOCK_BYTES; + Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ + Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES); + memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ + } + return SKEIN_SUCCESS; + } +#endif +#endif + +typedef struct +{ + uint_t statebits; /* 256, 512, or 1024 */ + union + { + Skein_Ctxt_Hdr_t h; /* common header "overlay" */ + Skein_256_Ctxt_t ctx_256; + Skein_512_Ctxt_t ctx_512; + Skein1024_Ctxt_t ctx1024; + } u; +} +hashState; + +/* "incremental" hashing API */ +static SkeinHashReturn Init (hashState *state, int hashbitlen); +static SkeinHashReturn Update(hashState *state, const SkeinBitSequence *data, SkeinDataLength databitlen); +static SkeinHashReturn Final (hashState *state, SkeinBitSequence *hashval); + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* select the context size and init the context */ +static SkeinHashReturn Init(hashState *state, int hashbitlen) +{ +#if SKEIN_256_NIST_MAX_HASH_BITS + if (hashbitlen <= SKEIN_256_NIST_MAX_HASHBITS) + { + Skein_Assert(hashbitlen > 0,BAD_HASHLEN); + state->statebits = 64*SKEIN_256_STATE_WORDS; + return Skein_256_Init(&state->u.ctx_256,(size_t) hashbitlen); + } +#endif + if (hashbitlen <= SKEIN_512_NIST_MAX_HASHBITS) + { + state->statebits = 64*SKEIN_512_STATE_WORDS; + return Skein_512_Init(&state->u.ctx_512,(size_t) hashbitlen); + } + else + { + state->statebits = 64*SKEIN1024_STATE_WORDS; + return Skein1024_Init(&state->u.ctx1024,(size_t) hashbitlen); + } +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* process data to be hashed */ +static SkeinHashReturn Update(hashState *state, const SkeinBitSequence *data, SkeinDataLength databitlen) +{ + /* only the final Update() call is allowed do partial bytes, else assert an error */ + Skein_Assert((state->u.h.T[1] & SKEIN_T1_FLAG_BIT_PAD) == 0 || databitlen == 0, SKEIN_FAIL); + + Skein_Assert(state->statebits % 256 == 0 && (state->statebits-256) < 1024,SKEIN_FAIL); + if ((databitlen & 7) == 0) /* partial bytes? */ + { + switch ((state->statebits >> 8) & 3) + { + case 2: return Skein_512_Update(&state->u.ctx_512,data,databitlen >> 3); + case 1: return Skein_256_Update(&state->u.ctx_256,data,databitlen >> 3); + case 0: return Skein1024_Update(&state->u.ctx1024,data,databitlen >> 3); + default: return SKEIN_FAIL; + } + } + else + { /* handle partial final byte */ + size_t bCnt = (databitlen >> 3) + 1; /* number of bytes to handle (nonzero here!) */ + u08b_t b,mask; + + mask = (u08b_t) (1u << (7 - (databitlen & 7))); /* partial byte bit mask */ + b = (u08b_t) ((data[bCnt-1] & (0-mask)) | mask); /* apply bit padding on final byte */ + + switch ((state->statebits >> 8) & 3) + { + case 2: Skein_512_Update(&state->u.ctx_512,data,bCnt-1); /* process all but the final byte */ + Skein_512_Update(&state->u.ctx_512,&b , 1 ); /* process the (masked) partial byte */ + break; + case 1: Skein_256_Update(&state->u.ctx_256,data,bCnt-1); /* process all but the final byte */ + Skein_256_Update(&state->u.ctx_256,&b , 1 ); /* process the (masked) partial byte */ + break; + case 0: Skein1024_Update(&state->u.ctx1024,data,bCnt-1); /* process all but the final byte */ + Skein1024_Update(&state->u.ctx1024,&b , 1 ); /* process the (masked) partial byte */ + break; + default: return SKEIN_FAIL; + } + Skein_Set_Bit_Pad_Flag(state->u.h); /* set tweak flag for the final call */ + + return SKEIN_SUCCESS; + } +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* finalize hash computation and output the result (hashbitlen bits) */ +static SkeinHashReturn Final(hashState *state, SkeinBitSequence *hashval) +{ + Skein_Assert(state->statebits % 256 == 0 && (state->statebits-256) < 1024,FAIL); + switch ((state->statebits >> 8) & 3) + { + case 2: return Skein_512_Final(&state->u.ctx_512,hashval); + case 1: return Skein_256_Final(&state->u.ctx_256,hashval); + case 0: return Skein1024_Final(&state->u.ctx1024,hashval); + default: return SKEIN_FAIL; + } +} + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +/* all-in-one hash function */ +SkeinHashReturn skein(int hashbitlen, const SkeinBitSequence *data, /* all-in-one call */ + SkeinDataLength databitlen,SkeinBitSequence *hashval) +{ + hashState state; + SkeinHashReturn r = Init(&state,hashbitlen); + if (r == SKEIN_SUCCESS) + { /* these calls do not fail when called properly */ + r = Update(&state,data,databitlen); + Final(&state,hashval); + } + return r; +} diff --git a/webassembly/xmr/skein.h b/webassembly/xmr/skein.h new file mode 100644 index 0000000..e672479 --- /dev/null +++ b/webassembly/xmr/skein.h @@ -0,0 +1,15 @@ +#ifndef SKEIN_H +#define SKEIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern int skein(int hashbitlen, const unsigned char *input, + size_t input_len, unsigned char *output); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/webassembly/xmr/skein_port.h b/webassembly/xmr/skein_port.h new file mode 100644 index 0000000..9cbefcb --- /dev/null +++ b/webassembly/xmr/skein_port.h @@ -0,0 +1,179 @@ +#ifndef _SKEIN_PORT_H_ +#define _SKEIN_PORT_H_ + +#include +#include +#include + +#ifndef RETURN_VALUES +# define RETURN_VALUES +# if defined( DLL_EXPORT ) +# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) +# define VOID_RETURN __declspec( dllexport ) void __stdcall +# define INT_RETURN __declspec( dllexport ) int __stdcall +# elif defined( __GNUC__ ) +# define VOID_RETURN __declspec( __dllexport__ ) void +# define INT_RETURN __declspec( __dllexport__ ) int +# else +# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers +# endif +# elif defined( DLL_IMPORT ) +# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) +# define VOID_RETURN __declspec( dllimport ) void __stdcall +# define INT_RETURN __declspec( dllimport ) int __stdcall +# elif defined( __GNUC__ ) +# define VOID_RETURN __declspec( __dllimport__ ) void +# define INT_RETURN __declspec( __dllimport__ ) int +# else +# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers +# endif +# elif defined( __WATCOMC__ ) +# define VOID_RETURN void __cdecl +# define INT_RETURN int __cdecl +# else +# define VOID_RETURN void +# define INT_RETURN int +# endif +#endif + +/* These defines are used to declare buffers in a way that allows + faster operations on longer variables to be used. In all these + defines 'size' must be a power of 2 and >= 8 + + dec_unit_type(size,x) declares a variable 'x' of length + 'size' bits + + dec_bufr_type(size,bsize,x) declares a buffer 'x' of length 'bsize' + bytes defined as an array of variables + each of 'size' bits (bsize must be a + multiple of size / 8) + + ptr_cast(x,size) casts a pointer to a pointer to a + varaiable of length 'size' bits +*/ + +#define ui_type(size) uint##size##_t +#define dec_unit_type(size,x) typedef ui_type(size) x +#define dec_bufr_type(size,bsize,x) typedef ui_type(size) x[bsize / (size >> 3)] +#define ptr_cast(x,size) ((ui_type(size)*)(x)) + +typedef unsigned int uint_t; /* native unsigned integer */ +typedef uint8_t u08b_t; /* 8-bit unsigned integer */ +typedef uint64_t u64b_t; /* 64-bit unsigned integer */ + +#ifndef RotL_64 +#define RotL_64(x,N) (((x) << (N)) | ((x) >> (64-(N)))) +#endif + +/* + * Skein is "natively" little-endian (unlike SHA-xxx), for optimal + * performance on x86 CPUs. The Skein code requires the following + * definitions for dealing with endianness: + * + * SKEIN_NEED_SWAP: 0 for little-endian, 1 for big-endian + * Skein_Put64_LSB_First + * Skein_Get64_LSB_First + * Skein_Swap64 + * + * If SKEIN_NEED_SWAP is defined at compile time, it is used here + * along with the portable versions of Put64/Get64/Swap64, which + * are slow in general. + * + * Otherwise, an "auto-detect" of endianness is attempted below. + * If the default handling doesn't work well, the user may insert + * platform-specific code instead (e.g., for big-endian CPUs). + * + */ +#ifndef SKEIN_NEED_SWAP /* compile-time "override" for endianness? */ + +#define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN + +/* special handler for IA64, which may be either endianness (?) */ +/* here we assume little-endian, but this may need to be changed */ +#if defined(__ia64) || defined(__ia64__) || defined(_M_IA64) +# define PLATFORM_MUST_ALIGN (1) +#ifndef PLATFORM_BYTE_ORDER +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif +#endif + +#ifndef PLATFORM_MUST_ALIGN +# define PLATFORM_MUST_ALIGN (0) +#endif + + +#if PLATFORM_BYTE_ORDER == IS_BIG_ENDIAN + /* here for big-endian CPUs */ +#define SKEIN_NEED_SWAP (1) +#elif PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN + /* here for x86 and x86-64 CPUs (and other detected little-endian CPUs) */ +#define SKEIN_NEED_SWAP (0) +#if PLATFORM_MUST_ALIGN == 0 /* ok to use "fast" versions? */ +#define Skein_Put64_LSB_First(dst08,src64,bCnt) memcpy(dst08,src64,bCnt) +#define Skein_Get64_LSB_First(dst64,src08,wCnt) memcpy(dst64,src08,8*(wCnt)) +#endif +#else +#error "Skein needs endianness setting!" +#endif + +#endif /* ifndef SKEIN_NEED_SWAP */ + +/* + ****************************************************************** + * Provide any definitions still needed. + ****************************************************************** + */ +#ifndef Skein_Swap64 /* swap for big-endian, nop for little-endian */ +#if SKEIN_NEED_SWAP +#define Skein_Swap64(w64) \ + ( (( ((u64b_t)(w64)) & 0xFF) << 56) | \ + (((((u64b_t)(w64)) >> 8) & 0xFF) << 48) | \ + (((((u64b_t)(w64)) >>16) & 0xFF) << 40) | \ + (((((u64b_t)(w64)) >>24) & 0xFF) << 32) | \ + (((((u64b_t)(w64)) >>32) & 0xFF) << 24) | \ + (((((u64b_t)(w64)) >>40) & 0xFF) << 16) | \ + (((((u64b_t)(w64)) >>48) & 0xFF) << 8) | \ + (((((u64b_t)(w64)) >>56) & 0xFF) ) ) +#else +#define Skein_Swap64(w64) (w64) +#endif +#endif /* ifndef Skein_Swap64 */ + + +#ifndef Skein_Put64_LSB_First +void Skein_Put64_LSB_First(u08b_t *dst,const u64b_t *src,size_t bCnt) +#ifdef SKEIN_PORT_CODE /* instantiate the function code here? */ + { /* this version is fully portable (big-endian or little-endian), but slow */ + size_t n; + + for (n=0;n>3] >> (8*(n&7))); + } +#else + ; /* output only the function prototype */ +#endif +#endif /* ifndef Skein_Put64_LSB_First */ + + +#ifndef Skein_Get64_LSB_First +void Skein_Get64_LSB_First(u64b_t *dst,const u08b_t *src,size_t wCnt) +#ifdef SKEIN_PORT_CODE /* instantiate the function code here? */ + { /* this version is fully portable (big-endian or little-endian), but slow */ + size_t n; + + for (n=0;n<8*wCnt;n+=8) + dst[n/8] = (((u64b_t) src[n ]) ) + + (((u64b_t) src[n+1]) << 8) + + (((u64b_t) src[n+2]) << 16) + + (((u64b_t) src[n+3]) << 24) + + (((u64b_t) src[n+4]) << 32) + + (((u64b_t) src[n+5]) << 40) + + (((u64b_t) src[n+6]) << 48) + + (((u64b_t) src[n+7]) << 56) ; + } +#else + ; /* output only the function prototype */ +#endif +#endif /* ifndef Skein_Get64_LSB_First */ + +#endif /* ifndef _SKEIN_PORT_H_ */