http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/js/RSA.js
----------------------------------------------------------------------
diff --git a/version22/js/RSA.js b/version22/js/RSA.js
new file mode 100644
index 0000000..ff27ac6
--- /dev/null
+++ b/version22/js/RSA.js
@@ -0,0 +1,392 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+       
+       http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+/* RSA API Functions */
+
+var rsa_private_key=function(n)
+{
+       this.p=new FF(n);
+       this.q=new FF(n);
+       this.dp=new FF(n);
+       this.dq=new FF(n);
+       this.c=new FF(n);
+};
+
+var rsa_public_key=function(m)
+{
+       this.e=0;
+       this.n=new FF(m);
+};
+
+RSA= {
+       RFS: ROM.MODBYTES*ROM.FFLEN,
+       SHA256 : 32,
+       SHA384 : 48,
+       SHA512 : 64,
+
+       HASH_TYPE:32,
+
+/* SHAXXX identifier strings */
+       SHA256ID : 
[0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20],
+       SHA384ID : 
[0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30],
+       SHA512ID : 
[0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40],
+
+       bytestohex: function(b)
+       {
+               var s="";
+               var len=b.length;
+               var ch;
+
+               for (var i=0;i<len;i++)
+               {
+                       ch=b[i];
+                       s+=((ch>>>4)&15).toString(16);
+                       s+=(ch&15).toString(16);
+
+               }
+               return s;
+       },
+
+       bytestostring: function(b)
+       {
+               var s="";
+               for (var i=0;i<b.length;i++)
+               {
+                       s+=String.fromCharCode(b[i]);
+               }
+               return s;
+       },
+
+       stringtobytes: function(s)
+       {
+               var b=[];
+               for (var i=0;i<s.length;i++)
+                       b.push(s.charCodeAt(i));
+               return b;
+       },
+
+       hashit: function(sha,A,n)
+       {
+               var R=[];
+               if (sha==this.SHA256)
+               {
+                       var H=new HASH256();
+                       if (A!=null) H.process_array(A); 
+                       if (n>=0) H.process_num(n);
+                       R=H.hash();
+               }
+               if (sha==this.SHA384)
+               {
+                       H=new HASH384();
+                       if (A!=null) H.process_array(A); 
+                       if (n>=0) H.process_num(n);
+                       R=H.hash();
+               }
+               if (sha==this.SHA512)
+               {
+                       H=new HASH512();
+                       if (A!=null) H.process_array(A); 
+                       if (n>=0) H.process_num(n);
+                       R=H.hash();
+               }
+               return R;
+       },
+
+       KEY_PAIR: function(rng,e,PRIV,PUB)
+       { /* IEEE1363 A16.11/A16.12 more or less */
+
+       //      var m,r,bytes,hbytes,words,err,res=0;
+               var n=PUB.n.length>>1;
+               var t = new FF(n);
+               var p1=new FF(n);
+               var q1=new FF(n);
+
+               for (;;)
+               {
+
+                       PRIV.p.random(rng);
+                       while (PRIV.p.lastbits(2)!=3) PRIV.p.inc(1);
+                       while (!FF.prime(PRIV.p,rng)) PRIV.p.inc(4);
+
+                       p1.copy(PRIV.p);
+                       p1.dec(1);
+
+                       if (p1.cfactor(e)) continue;
+                       break;
+               }
+
+               for (;;)
+               {
+                       PRIV.q.random(rng);
+                       while (PRIV.q.lastbits(2)!=3) PRIV.q.inc(1);
+                       while (!FF.prime(PRIV.q,rng)) PRIV.q.inc(4);
+                       
+                       q1.copy(PRIV.q);
+                       q1.dec(1);
+
+                       if (q1.cfactor(e)) continue;
+                       break;
+               }
+
+               PUB.n=FF.mul(PRIV.p,PRIV.q);
+               PUB.e=e;
+
+               t.copy(p1);
+               t.shr();
+               PRIV.dp.set(e);
+               PRIV.dp.invmodp(t);
+               if (PRIV.dp.parity()===0) PRIV.dp.add(t);
+               PRIV.dp.norm();
+
+               t.copy(q1);
+               t.shr();
+               PRIV.dq.set(e);
+               PRIV.dq.invmodp(t);
+               if (PRIV.dq.parity()===0) PRIV.dq.add(t);
+               PRIV.dq.norm();
+
+               PRIV.c.copy(PRIV.p);
+               PRIV.c.invmodp(PRIV.q);
+
+               return;
+       },
+
+/* Mask Generation Function */
+       MGF1: function(sha,Z,olen,K)
+       {
+               var i,hlen=sha;
+               var B=[];
+
+               var counter,cthreshold,k=0;
+               for (i=0;i<K.length;i++) K[i]=0;
+
+               cthreshold=Math.floor(olen/hlen); if (olen%hlen!==0) 
cthreshold++;
+               for (counter=0;counter<cthreshold;counter++)
+               {
+                       B=this.hashit(sha,Z,counter);
+                       if (k+hlen>olen) for (i=0;i<olen%hlen;i++) K[k++]=B[i];
+                       else for (i=0;i<hlen;i++) K[k++]=B[i];
+               }       
+       },
+
+       PKCS15: function(sha,m,w)
+       {
+               var olen=ROM.FF_BITS/8;
+               var i,hlen=sha;
+               var idlen=19; 
+
+               if (olen<idlen+hlen+10) return false;
+               var H=this.hashit(sha,m,-1);
+
+               for (i=0;i<w.length;i++) w[i]=0;
+               i=0;
+               w[i++]=0;
+               w[i++]=1;
+               for (var j=0;j<olen-idlen-hlen-3;j++)
+                       w[i++]=0xff;
+               w[i++]=0;
+
+
+               if (hlen==this.SHA256) for (var j=0;j<idlen;j++) 
w[i++]=this.SHA256ID[j];
+               if (hlen==this.SHA384) for (var j=0;j<idlen;j++) 
w[i++]=this.SHA384ID[j];
+               if (hlen==this.SHA512) for (var j=0;j<idlen;j++) 
w[i++]=this.SHA512ID[j];
+
+               for (var j=0;j<hlen;j++)
+                       w[i++]=H[j];
+
+               return true;
+       },
+
+       /* OAEP Message Encoding for Encryption */
+       OAEP_ENCODE: function(sha,m,rng,p)
+       { 
+               var i,slen,olen=RSA.RFS-1;
+               var mlen=m.length;
+               var hlen,seedlen;
+               var f=[];
+
+               hlen=sha;
+               var SEED=[];
+               seedlen=hlen;
+
+               if (mlen>olen-hlen-seedlen-1) return null; 
+
+               var DBMASK=[];
+
+               var h=this.hashit(sha,p,-1);
+               for (i=0;i<hlen;i++) f[i]=h[i];
+
+               slen=olen-mlen-hlen-seedlen-1;      
+
+               for (i=0;i<slen;i++) f[hlen+i]=0;
+               f[hlen+slen]=1;
+               for (i=0;i<mlen;i++) f[hlen+slen+1+i]=m[i];
+
+               for (i=0;i<seedlen;i++) SEED[i]=rng.getByte();
+               this.MGF1(sha,SEED,olen-seedlen,DBMASK);
+
+               for (i=0;i<olen-seedlen;i++) DBMASK[i]^=f[i];
+               this.MGF1(sha,DBMASK,seedlen,f);
+
+               for (i=0;i<seedlen;i++) f[i]^=SEED[i];
+
+               for (i=0;i<olen-seedlen;i++) f[i+seedlen]=DBMASK[i];
+
+               /* pad to length RFS */
+               var d=1;
+               for (i=RSA.RFS-1;i>=d;i--)
+                       f[i]=f[i-d];
+               for (i=d-1;i>=0;i--)
+                       f[i]=0;
+
+               return f;
+       },
+
+       /* OAEP Message Decoding for Decryption */
+       OAEP_DECODE: function(sha,p,f)
+       {
+               var x,t;
+               var comp;
+               var i,k,olen=RSA.RFS-1;
+               var hlen,seedlen;
+
+               hlen=sha;
+               var SEED=[];
+               seedlen=hlen;
+               var CHASH=[];
+               seedlen=hlen=sha;
+
+               if (olen<seedlen+hlen+1) return null;
+
+               var DBMASK=[];
+               for (i=0;i<olen-seedlen;i++) DBMASK[i]=0;
+
+               if (f.length<RSA.RFS)
+               {
+                       var d=RSA.RFS-f.length;
+                       for (i=RFS-1;i>=d;i--)
+                               f[i]=f[i-d];
+                       for (i=d-1;i>=0;i--)
+                               f[i]=0;
+
+               }
+
+               var h=this.hashit(sha,p,-1);
+               for (i=0;i<hlen;i++) CHASH[i]=h[i];
+
+               x=f[0];
+
+               for (i=seedlen;i<olen;i++)
+                       DBMASK[i-seedlen]=f[i+1]; 
+
+               this.MGF1(sha,DBMASK,seedlen,SEED);
+               for (i=0;i<seedlen;i++) SEED[i]^=f[i+1];
+               this.MGF1(sha,SEED,olen-seedlen,f);
+               for (i=0;i<olen-seedlen;i++) DBMASK[i]^=f[i];
+
+               comp=true;
+               for (i=0;i<hlen;i++)
+               {
+                       if (CHASH[i]!=DBMASK[i]) comp=false;
+               }
+
+               for (i=0;i<olen-seedlen-hlen;i++)
+                       DBMASK[i]=DBMASK[i+hlen];
+
+               for (i=0;i<hlen;i++)
+                       SEED[i]=CHASH[i]=0;
+               
+               for (k=0;;k++)
+               {
+                       if (k>=olen-seedlen-hlen) return null;
+                       if (DBMASK[k]!==0) break;
+               }
+
+               t=DBMASK[k];
+
+               if (!comp || x!==0 || t!=0x01) 
+               {
+                       for (i=0;i<olen-seedlen;i++) DBMASK[i]=0;
+                       return null;
+               }
+
+               var r=[];
+
+               for (i=0;i<olen-seedlen-hlen-k-1;i++)
+                       r[i]=DBMASK[i+k+1];
+       
+               for (i=0;i<olen-seedlen;i++) DBMASK[i]=0;
+
+               return r;
+       },
+
+       /* destroy the Private Key structure */
+       PRIVATE_KEY_KILL: function(PRIV)
+       {
+               PRIV.p.zero();
+               PRIV.q.zero();
+               PRIV.dp.zero();
+               PRIV.dq.zero();
+               PRIV.c.zero();
+       },
+
+       /* RSA encryption with the public key */
+       ENCRYPT: function(PUB,F,G)
+       {
+               var n=PUB.n.getlen();
+               var f=new FF(n);
+
+               FF.fromBytes(f,F);
+
+               f.power(PUB.e,PUB.n);   
+               
+               f.toBytes(G);
+       },
+
+       /* RSA decryption with the private key */
+       DECRYPT: function(PRIV,G,F)
+       {
+               var n=PRIV.p.getlen();
+               var g=new FF(2*n);
+
+               FF.fromBytes(g,G);
+               var jp=g.dmod(PRIV.p);
+               var jq=g.dmod(PRIV.q);
+
+               jp.skpow(PRIV.dp,PRIV.p);
+               jq.skpow(PRIV.dq,PRIV.q);
+
+               g.zero();
+               g.dscopy(jp);
+               jp.mod(PRIV.q);
+               if (FF.comp(jp,jq)>0) jq.add(PRIV.q);
+               jq.sub(jp);
+               jq.norm();
+
+               var t=FF.mul(PRIV.c,jq);
+               jq=t.dmod(PRIV.q);
+
+               t=FF.mul(jq,PRIV.p);
+               g.add(t);
+               g.norm();
+
+               g.toBytes(F);
+       }
+
+};
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/js/TestECDH.html
----------------------------------------------------------------------
diff --git a/version22/js/TestECDH.html b/version22/js/TestECDH.html
new file mode 100644
index 0000000..1ddf0c2
--- /dev/null
+++ b/version22/js/TestECDH.html
@@ -0,0 +1,143 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>JavaScript Test ECC</title>
+</head>
+<body>
+<h1>JavaScript Test ECC Example</h1>
+<script type="text/javascript" src="DBIG.js"></script>
+<script type="text/javascript" src="BIG.js"></script>
+<script type="text/javascript" src="FP.js"></script>
+<script type="text/javascript" src="ROM.js"></script>
+<script type="text/javascript" src="UInt64.js"></script>
+<script type="text/javascript" src="HASH256.js"></script>
+<script type="text/javascript" src="HASH384.js"></script>
+<script type="text/javascript" src="HASH512.js"></script>
+<script type="text/javascript" src="RAND.js"></script>
+<script type="text/javascript" src="AES.js"></script>
+<script type="text/javascript" src="GCM.js"></script>
+<script type="text/javascript" src="ECP.js"></script>
+<script type="text/javascript" src="ECDH.js"></script>
+
+<script>
+/* test driver and function exerciser for ECDH/ECIES/ECDSA API Functions */
+               var i,j=0,res;
+               var result;
+               var pp="M0ng00se";
+
+               var EGS=ECDH.EGS;
+               var EFS=ECDH.EFS;
+               var EAS=16;
+               var sha=ECDH.HASH_TYPE;
+
+               var S1=[];
+               var W0=[];
+               var W1=[];
+               var Z0=[];
+               var Z1=[];
+               var RAW=[];
+               var SALT=[];
+               var P1=[];
+               var P2=[];
+               var V=[];
+               var M=[];
+               var T=new Array(12);  // must specify required length
+               var CS=[];
+               var DS=[];
+
+               var rng=new RAND();
+
+               rng.clean();
+               for (i=0;i<100;i++) RAW[i]=i;
+
+               rng.seed(100,RAW);
+//for (j=0;j<100;j++)
+//{
+
+               for (i=0;i<8;i++) SALT[i]=(i+1);  // set Salt
+
+               window.document.write("Alice's Passphrase= " + pp + "<br>");
+
+               var PW=ECDH.stringtobytes(pp);
+/* private key S0 of size EGS bytes derived from Password and Salt */
+               var S0=ECDH.PBKDF2(sha,PW,SALT,1000,EGS);
+
+               window.document.write("Alice's private key= 
0x"+ECDH.bytestostring(S0)+ "<br>");
+/* Generate Key pair S/W */
+               ECDH.KEY_PAIR_GENERATE(null,S0,W0); 
+
+               window.document.write("Alice's public key= 
0x"+ECDH.bytestostring(W0)+ "<br>");
+
+               res=ECDH.PUBLIC_KEY_VALIDATE(true,W0);
+               if (res!=0)
+                       alert("ECP Public Key is invalid!");
+/* Random private key for other party */
+               ECDH.KEY_PAIR_GENERATE(rng,S1,W1);
+
+               window.document.write("Servers private key= 
0x"+ECDH.bytestostring(S1)+ "<br>");
+               window.document.write("Servers public key= 
0x"+ECDH.bytestostring(W1)+ "<br>");
+
+               res=ECDH.PUBLIC_KEY_VALIDATE(true,W1);
+               if (res!=0)
+                       alert("ECP Public Key is invalid!");
+                       
+
+/* Calculate common key using DH - IEEE 1363 method */
+
+               ECDH.ECPSVDP_DH(S0,W1,Z0);
+               ECDH.ECPSVDP_DH(S1,W0,Z1);
+
+               var same=true;
+               for (i=0;i<ECDH.EFS;i++)
+                       if (Z0[i]!=Z1[i]) same=false;
+
+               if (!same)
+                       alert("*** ECPSVDP-DH Failed");
+
+               var KEY=ECDH.KDF2(sha,Z0,null,ECDH.EAS);
+
+               window.document.write("Alice's DH Key=  
0x"+ECDH.bytestostring(KEY)+ "<br>");
+               window.document.write("Servers DH Key=  
0x"+ECDH.bytestostring(KEY)+ "<br>");
+
+               if (ROM.CURVETYPE!=ROM.MONTGOMERY)
+               {
+                       window.document.write("Testing ECIES"+ "<br>");
+
+                       P1[0]=0x0; P1[1]=0x1; P1[2]=0x2; 
+                       P2[0]=0x0; P2[1]=0x1; P2[2]=0x2; P2[3]=0x3; 
+
+                       for (i=0;i<=16;i++) M[i]=i; 
+
+                       var C=ECDH.ECIES_ENCRYPT(sha,P1,P2,rng,W1,M,V,T);
+
+                       window.document.write("Ciphertext= "+ "<br>");
+                       window.document.write("V= 0x"+ECDH.bytestostring(V)+ 
"<br>");
+                       window.document.write("C= 0x"+ECDH.bytestostring(C)+ 
"<br>");
+                       window.document.write("T= 0x"+ECDH.bytestostring(T)+ 
"<br>");
+
+
+                       M=ECDH.ECIES_DECRYPT(sha,P1,P2,V,C,T,S1);
+                       if (M.length==0)
+                               alert("*** ECIES Decryption Failed ");
+                       else window.document.write("Decryption succeeded"+ 
"<br>");
+
+                       window.document.write("Message is 
0x"+ECDH.bytestostring(M)+ "<br>");
+
+                       window.document.write("Testing ECDSA"+ "<br>");
+
+                       if (ECDH.ECPSP_DSA(sha,rng,S0,M,CS,DS)!=0)
+                               alert("***ECDSA Signature Failed");
+               
+                       window.document.write("Signature= "+ "<br>");
+                       window.document.write("C= 0x"+ECDH.bytestostring(CS)+ 
"<br>");
+                       window.document.write("D= 0x"+ECDH.bytestostring(DS)+ 
"<br>");
+
+                       if (ECDH.ECPVP_DSA(sha,W0,M,CS,DS)!=0)
+                               alert("***ECDSA Verification Failed");
+                       else window.document.write("ECDSA 
Signature/Verification succeeded "+  "<br>");
+               }
+//}
+//window.document.write("Test Completed Successfully"+ "<br>");
+</script>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/js/TestMPIN.html
----------------------------------------------------------------------
diff --git a/version22/js/TestMPIN.html b/version22/js/TestMPIN.html
new file mode 100644
index 0000000..0cb6f67
--- /dev/null
+++ b/version22/js/TestMPIN.html
@@ -0,0 +1,330 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>JavaScript Test MPIN</title>
+</head>
+<body>
+<h1>JavaScript Test MPIN Example</h1>
+<script type="text/javascript" src="DBIG.js"></script>
+<script type="text/javascript" src="BIG.js"></script>
+<script type="text/javascript" src="FP.js"></script>
+<script type="text/javascript" src="ROM.js"></script>
+<script type="text/javascript" src="UInt64.js"></script>
+<script type="text/javascript" src="HASH256.js"></script>
+<script type="text/javascript" src="HASH384.js"></script>
+<script type="text/javascript" src="HASH512.js"></script>
+<script type="text/javascript" src="RAND.js"></script>
+<script type="text/javascript" src="AES.js"></script>
+<script type="text/javascript" src="GCM.js"></script>
+<script type="text/javascript" src="ECP.js"></script>
+<script type="text/javascript" src="FP2.js"></script>
+<script type="text/javascript" src="ECP2.js"></script>
+<script type="text/javascript" src="FP4.js"></script>
+<script type="text/javascript" src="FP12.js"></script>
+<script type="text/javascript" src="PAIR.js"></script>
+<script type="text/javascript" src="MPIN.js"></script>
+
+<script>
+/* test driver and function exerciser for MPIN API Functions */
+
+               var i,res;
+               var result;
+
+               var EGS=MPIN.EGS;
+               var EFS=MPIN.EFS;
+               var EAS=16;
+
+               var sha=MPIN.HASH_TYPE;
+
+               var rng=new RAND();
+               rng.clean();
+
+               var RAW=[];
+               for (i=0;i<100;i++) RAW[i]=i+1;
+               rng.seed(100,RAW);
+
+               var G1S=2*EFS+1; /* Group 1 Size */
+               var G2S=4*EFS; /* Group 2 Size */
+
+               var S=[];
+               var SST=[];
+               var TOKEN = [];
+               var PERMIT = [];
+               var SEC = [];
+               var xID = [];
+               var xCID = [];
+               var X= [];
+               var Y= [];
+               var E=[];
+               var F=[];
+               var HCID=[];
+               var HID=[];
+               var HTID=[];
+
+               var G1=[];
+               var G2=[];
+               var R=[];
+               var Z=[];
+               var W=[];
+               var T=[];
+               var CK=[];
+               var SK=[];
+
+               var HSID=[];
+
+/* Set configuration */
+               var PERMITS=true;
+               var PINERROR=true;
+               var FULL=true;
+    var ONE_PASS=false;
+    var TIME_FUNCTIONS=false;
+    var total_time=0;
+    var nIter=100
+/*
+    var PR=[];
+ pin=parseInt(prompt("Enter PIN= "));
+    window.document.write("Test Pairing" + "<br>");
+    for (i=0;i<100;i++)
+      MPIN.TEST_PAIR(PR);
+    window.document.write("Pairing= "+MPIN.bytestostring(PR) + "<br>");
+
+  pin=parseInt(prompt("Enter PIN= "));
+*/
+
+/* Trusted Authority set-up */
+               MPIN.RANDOM_GENERATE(rng,S);
+               window.document.write("Master Secret s: 
0x"+MPIN.bytestostring(S) + "<br>");
+ 
+ /* Create Client Identity */
+               var IDstr = "[email protected]";
+               var CLIENT_ID = MPIN.stringtobytes(IDstr);  
+               HCID=MPIN.HASH_ID(sha,CLIENT_ID);  /* Either Client or TA 
calculates Hash(ID) - you decide! */
+               
+               window.document.write("Client ID= 
"+MPIN.bytestostring(CLIENT_ID) + "<br>");
+
+/* Client and Server are issued secrets by DTA */
+               MPIN.GET_SERVER_SECRET(S,SST);
+               window.document.write("Server Secret SS: 
0x"+MPIN.bytestostring(SST) + "<br>");
+
+               MPIN.GET_CLIENT_SECRET(S,HCID,TOKEN);
+               window.document.write("Client Secret CS: 
0x"+MPIN.bytestostring(TOKEN) + "<br>");     
+       
+/* Client extracts PIN from secret to create Token */
+               var pin=1234;
+       window.document.write("Client extracts PIN= "+pin + "<br>"); 
+               var rtn=MPIN.EXTRACT_PIN(sha,CLIENT_ID,pin,TOKEN);
+               if (rtn != 0)
+                       window.document.write("Failed to extract PIN " + 
"<br>");  
+
+               window.document.write("Client Token TK: 
0x"+MPIN.bytestostring(TOKEN) + "<br>");        
+
+               if (FULL)
+               {
+                       MPIN.PRECOMPUTE(TOKEN,HCID,G1,G2);
+               }
+
+               var date;
+               if (PERMITS)
+               {
+                       date=MPIN.today();
+/* Client gets "Time Token" permit from DTA */         
+                       MPIN.GET_CLIENT_PERMIT(sha,date,S,HCID,PERMIT);
+                       window.document.write("Time Permit TP: 
0x"+MPIN.bytestostring(PERMIT) + "<br>");   
+
+/* This encoding makes Time permit look random - Elligator squared */
+                       MPIN.ENCODING(rng,PERMIT);
+                       window.document.write("Encoded Time Permit TP: 
0x"+MPIN.bytestostring(PERMIT) + "<br>");   
+                       MPIN.DECODING(PERMIT);
+                       window.document.write("Decoded Time Permit TP: 
0x"+MPIN.bytestostring(PERMIT) + "<br>");   
+               }
+               else date=0;
+
+
+               pin=parseInt(prompt("Enter PIN= "));
+
+/* Set date=0 and PERMIT=null if time permits not in use
+
+Client First pass: Inputs CLIENT_ID, optional RNG, pin, TOKEN and PERMIT. 
Output xID = x.H(CLIENT_ID) and re-combined secret SEC
+If PERMITS are is use, then date!=0 and PERMIT is added to secret and xCID = 
x.(H(CLIENT_ID)+H_T(date|H(CLIENT_ID)))
+Random value x is supplied externally if RNG=null, otherwise generated and 
passed out by RNG
+
+If Time Permits OFF set xCID = null, HTID=null and use xID and HID only
+If Time permits are ON, AND pin error detection is required then all of xID, 
xCID, HID and HTID are required
+If Time permits are ON, AND pin error detection is NOT required, set xID=null, 
HID=null and use xCID and HTID only.
+
+
+*/
+               var pxID=xID;
+               var pxCID=xCID;
+               var pHID=HID;
+               var pHTID=HTID;
+               var pE=E;
+               var pF=F;
+               var pPERMIT=PERMIT;
+               var prHID;
+
+               if (date!=0)
+               {
+                       prHID=pHTID;
+                       if (!PINERROR)
+                       {
+                               pxID=null;
+                       //      pHID=null;
+                       }
+               }
+               else
+               {
+                       prHID=pHID;
+                       pPERMIT=null;
+                       pxCID=null;
+                       pHTID=null;
+               }
+               if (!PINERROR)
+               {
+                       pE=null;
+                       pF=null;
+               }
+
+                if (ONE_PASS)
+                {
+                  window.document.write("MPIN Single Pass " + "<br>");   
+                  timeValue = MPIN.GET_TIME();
+                  window.document.write("Epoch " + timeValue + "<br>");   
+                  if (TIME_FUNCTIONS)
+                  {
+                   var start = new Date().getTime();
+                   for (i = 0; i < nIter; ++i) {
+                     
rtn=MPIN.CLIENT(sha,date,CLIENT_ID,rng,X,pin,TOKEN,SEC,pxID,pxCID,pPERMIT,timeValue,Y);
+                   }
+                   var end = new Date().getTime();
+                   var t1 = end - start;
+                   total_time = total_time + t1;
+                   var iter_time = t1 / nIter;
+                   var iter_per_sec = nIter / (t1 / 1000);
+                   window.document.write("MPIN.CLIENT: time " + t1 + "ms 
iteration time " + iter_time + "ms iterations per second " + iter_per_sec + 
"<br>");   
+                  }
+                  else
+                  {
+                    
rtn=MPIN.CLIENT(sha,date,CLIENT_ID,rng,X,pin,TOKEN,SEC,pxID,pxCID,pPERMIT,timeValue,Y);
+                  }
+                 if (rtn != 0)
+                    window.document.write("FAILURE: CLIENT rtn: " + rtn + 
"<br>");   
+
+                  if (FULL)
+                 {
+                    if (TIME_FUNCTIONS)
+                    {
+                     var start = new Date().getTime();
+                     for (i = 0; i < nIter; ++i) {
+                        HCID=MPIN.HASH_ID(sha,CLIENT_ID);
+                        MPIN.GET_G1_MULTIPLE(rng,1,R,HCID,Z); 
+                     }
+                     var end = new Date().getTime();
+                     var t2 = end - start;
+                     total_time = total_time + t2;
+                     var iter_time = t2 / nIter;
+                     var iter_per_sec = nIter / (t2 / 1000);
+                     window.document.write("MPIN.GET_G1_MULTIPLE: time " + t2 
+ "ms iteration time " + iter_time + "ms iterations per second " + iter_per_sec 
+ "<br>");   
+                    }
+                    else
+                    {
+                      HCID=MPIN.HASH_ID(sha,CLIENT_ID);
+                      MPIN.GET_G1_MULTIPLE(rng,1,R,HCID,Z);  /* Also Send 
Z=r.ID to Server, remember random r */
+                    }
+                  }
+
+                  
rtn=MPIN.SERVER(sha,date,pHID,pHTID,Y,SST,pxID,pxCID,SEC,pE,pF,CLIENT_ID,timeValue);
+                  if (rtn != 0)
+                    window.document.write("FAILURE: SERVER rtn: " + rtn+ 
"<br>");  
+
+                  if (FULL)
+                  {
+                                       HSID=MPIN.HASH_ID(sha,CLIENT_ID);
+                    MPIN.GET_G1_MULTIPLE(rng,0,W,prHID,T);  /* Also send 
T=w.ID to client, remember random w  */
+                  }
+                }
+                else 
+                {
+                  window.document.write("MPIN Multi Pass " + "<br>");   
+                  
rtn=MPIN.CLIENT_1(sha,date,CLIENT_ID,rng,X,pin,TOKEN,SEC,pxID,pxCID,pPERMIT);
+                 if (rtn != 0)
+                       window.document.write("FAILURE: CLIENT_1 rtn: " + rtn + 
"<br>");   
+  
+                 if (FULL)
+                 {
+                       HCID=MPIN.HASH_ID(sha,CLIENT_ID);
+                       MPIN.GET_G1_MULTIPLE(rng,1,R,HCID,Z);  /* Also Send 
Z=r.ID to Server, remember random r */
+                 }
+    
+                  /* Server calculates H(ID) and H(T|H(ID)) (if time permits 
enabled), and maps them to points on the curve HID and HTID resp. */
+                 MPIN.SERVER_1(sha,date,CLIENT_ID,pHID,pHTID);
+    
+                  /* Server generates Random number Y and sends it to Client */
+                 MPIN.RANDOM_GENERATE(rng,Y);
+    
+                 if (FULL)
+                 {
+                                       HSID=MPIN.HASH_ID(sha,CLIENT_ID);
+                               MPIN.GET_G1_MULTIPLE(rng,0,W,prHID,T);  /* Also 
send T=w.ID to client, remember random w  */
+                 }
+    
+                  /* Client Second Pass: Inputs Client secret SEC, x and y. 
Outputs -(x+y)*SEC */
+                 rtn=MPIN.CLIENT_2(X,Y,SEC);
+                 if (rtn != 0)
+                   window.document.write("FAILURE: CLIENT_2 rtn: " + rtn + 
"<br>");  
+                    /* Server Second pass. Inputs hashed client id, random Y, 
-(x+y)*SEC, xID and xCID and Server secret SST. E and F help kangaroos to find 
error. */
+                    /* If PIN error not required, set E and F = NULL */
+                 rtn=MPIN.SERVER_2(date,pHID,pHTID,Y,SST,pxID,pxCID,SEC,pE,pF);
+    
+                 if (rtn != 0)
+                       window.document.write("FAILURE: SERVER_1 rtn: " + rtn+ 
"<br>");  
+    
+                }
+                 
+
+                if (rtn == this.MPIN.BAD_PIN)
+               {
+                 window.document.write("Server says - Bad Pin. I don't know 
you. Feck off." + "<br>"); 
+                 if (PINERROR)
+                 {
+                   var err=MPIN.KANGAROO(E,F);
+                   if (err!=0) window.document.write("(Client PIN is out by 
"+err + ")<br>");
+                 }
+                }
+               else 
+               {
+                 window.document.write("Server says - PIN is good! You really 
are "+IDstr + "<br>"); 
+                 if (FULL)
+                 {
+                    if (TIME_FUNCTIONS)
+                    {
+                     var start = new Date().getTime();
+                     for (i = 0; i < nIter; ++i) {
+                       MPIN.CLIENT_KEY(sha,G1,G2,pin,R,X,T,CK);
+                     }
+                     var end = new Date().getTime();
+                     var t3 = end - start;
+                     total_time = total_time + t3;
+                     var iter_time = t3 / nIter;
+                     var iter_per_sec = nIter / (t3 / 1000);
+                     window.document.write("MPIN.CLIENT_KEY: time " + t1 + "ms 
iteration time " + iter_time + "ms iterations per second " + iter_per_sec + 
"<br>");   
+                    }
+                    else
+                    {
+                                               
H=MPIN.HASH_ALL(sha,HCID,pxID,pxCID,SEC,Y,Z,T);
+                                               
MPIN.CLIENT_KEY(sha,G1,G2,pin,R,X,H,T,CK);
+                    }
+                   window.document.write("Client Key =  
0x"+MPIN.bytestostring(CK) + "<br>");    
+                                       
H=MPIN.HASH_ALL(sha,HSID,pxID,pxCID,SEC,Y,Z,T);
+                    MPIN.SERVER_KEY(sha,Z,SST,W,H,pHID,pxID,pxCID,SK);
+                    window.document.write("Server Key =  
0x"+MPIN.bytestostring(SK) + "<br>");    
+                 }
+                }
+         //       var iter_time = total_time / nIter;
+         //       var iter_per_sec = nIter / (total_time / 1000);
+         //       window.document.write("CLIENT: total time " + total_time + 
"ms iteration time " + iter_time + "ms iterations per second " + iter_per_sec + 
"<br>");   
+
+    
+</script>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/js/TestRSA.html
----------------------------------------------------------------------
diff --git a/version22/js/TestRSA.html b/version22/js/TestRSA.html
new file mode 100644
index 0000000..ba650ca
--- /dev/null
+++ b/version22/js/TestRSA.html
@@ -0,0 +1,115 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>JavaScript Test RSA</title>
+</head>
+<body>
+<h1>JavaScript Test RSA Example</h1>
+<script type="text/javascript" src="ROM.js"></script>
+<script type="text/javascript" src="DBIG.js"></script>
+<script type="text/javascript" src="BIG.js"></script>
+<script type="text/javascript" src="UInt64.js"></script>
+<script type="text/javascript" src="HASH256.js"></script>
+<script type="text/javascript" src="HASH384.js"></script>
+<script type="text/javascript" src="HASH512.js"></script>
+<script type="text/javascript" src="RAND.js"></script>
+<script type="text/javascript" src="FF.js"></script>
+<script type="text/javascript" src="RSA.js"></script>
+
+
+<script>
+/* test driver and function exerciser for RSA API Functions */
+
+       var i,j=0,res;
+       var result;
+
+       var RFS=RSA.RFS;
+       var sha=RSA.HASH_TYPE;
+
+       var message="Hello World\n";
+
+       var pub=new rsa_public_key(ROM.FFLEN);
+       var priv=new rsa_private_key(ROM.HFLEN);
+
+       var ML=[];
+       var C=[];
+       var S=[];
+       var RAW=[];
+       
+       var rng=new RAND();
+       rng.clean();
+
+       for (i=0;i<100;i++) RAW[i]=i;
+       rng.seed(100,RAW);
+
+       var start,end,time;
+       start=new Date().getTime();
+       window.document.write("Generating public/private key pair (slow!)  
<br>");
+       RSA.KEY_PAIR(rng,65537,priv,pub);
+       end=new Date().getTime();
+       time=end-start;
+       window.document.write("Time in ms= "+time+"<br>");
+
+       var M=RSA.stringtobytes(message);  
+       window.document.write("Encrypting test string <br>");
+
+       var E=RSA.OAEP_ENCODE(sha,M,rng,null); /* OAEP encode message m to e  */
+       window.document.write("Encoding= 0x" + RSA.bytestohex(E) + "<br>");  
+
+       window.document.write("Public key= 0x"+pub.n.toString() + "<br>"); 
+
+       start=new Date().getTime();     
+       RSA.ENCRYPT(pub,E,C);     /* encrypt encoded message */
+       end=new Date().getTime();       
+       time=end-start;
+       window.document.write("Time in ms= "+time+"<br>");
+
+       window.document.write("Ciphertext= 0x" + RSA.bytestohex(C) + "<br>");  
+
+       window.document.write("Decrypting test string <br>");
+       start=new Date().getTime();     
+       RSA.DECRYPT(priv,C,ML); 
+       end=new Date().getTime();
+       time=end-start;
+       window.document.write("Time in ms= "+time+"<br>");
+
+       var cmp=true;
+       if (E.length!=ML.length) cmp=false;
+       else
+       {
+               for (var j=0;j<E.length;j++)
+                       if (E[j]!=ML[j]) cmp=false;
+       }
+       if (cmp) window.document.write("Decryption is OK <br>");
+       else window.document.write("Decryption Failed <br>");
+
+       var MS=RSA.OAEP_DECODE(sha,null,ML); /* OAEP decode message  */
+       window.document.write("Decoding= 0x" + RSA.bytestohex(MS) + "<br>");  
+
+       window.document.write("message= "+RSA.bytestostring(MS) + "<br>");  
+
+
+       window.document.write("Signing message <br>");
+       RSA.PKCS15(sha,M,C);
+
+       RSA.DECRYPT(priv,C,S); /* create signature in S */ 
+
+       window.document.write("Signature= 0x" + RSA.bytestohex(S) + "<br>");  
+
+       RSA.ENCRYPT(pub,S,ML); 
+
+       cmp=true;
+       if (C.length!=ML.length) cmp=false;
+       else
+       {
+               for (var j=0;j<C.length;j++)
+                       if (C[j]!=ML[j]) cmp=false;
+       }
+       if (cmp) window.document.write("Signature is valid <br>");
+       else window.document.write("Signature is INVALID <br>");
+
+       RSA.PRIVATE_KEY_KILL(priv);
+
+</script>
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/js/UInt64.js
----------------------------------------------------------------------
diff --git a/version22/js/UInt64.js b/version22/js/UInt64.js
new file mode 100644
index 0000000..2d93b9c
--- /dev/null
+++ b/version22/js/UInt64.js
@@ -0,0 +1,54 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+       
+       http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+/* rudimentary unsigned 64-bit type for SHA384 and SHA512 */
+
+var UInt64 = function(top,bot) {
+       this.top=top;
+       this.bot=bot;
+};
+
+UInt64.prototype={
+       add: function(y)
+       {
+               var t=(this.bot>>>0)+(y.bot>>>0);
+               var low=t >>> 0;
+               var high=(this.top>>>0)+(y.top>>>0);
+
+               this.bot=low;
+               if (low!=t)
+                       this.top=(high+1)>>>0;
+               else
+                       this.top=high;
+
+               return this;
+       },
+       copy: function()
+       {
+               var r=new UInt64(this.top,this.bot);
+               return r;
+       },
+       shlb: function()
+       {
+               var t=this.bot>>>24;
+               this.top=t+(this.top<<8);
+               this.bot<<=8;
+               return this;
+       }
+};

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/js/readme.txt
----------------------------------------------------------------------
diff --git a/version22/js/readme.txt b/version22/js/readme.txt
new file mode 100644
index 0000000..e040021
--- /dev/null
+++ b/version22/js/readme.txt
@@ -0,0 +1,41 @@
+AMCL is very simple to build for JavaScript.
+
+First - decide the modulus type and curve type you want to use. Edit ROM.js 
+where indicated. You might want to use one of the curves whose details are
+already in there.
+
+Three example API files are provided, MPIN.js which 
+supports our M-Pin (tm) protocol, ECDH.js which supports elliptic 
+curve key exchange, digital signature and public key crypto, and RSA.js
+which supports RSA encryption. The first  can be tested using the 
+TestMPIN.html driver programs, the second can be tested using TestECDH.html, 
+and the third using TestRSA.html
+
+In the ROM.js file you must provide the curve constants. Several examples
+are provided there, if you are willing to use one of these.
+
+To help generate the ROM constants for your own curve some MIRACL helper 
+programs are included. The programs bngen.cpp and blsgen.cpp generate ROM 
+data for a BN and BLS pairing friendly curves, and the program ecgen.cpp 
+generates ROM data for regular EC curves.
+
+The MIRACL based program check.cpp helps choose the best number base for
+big number representation, given the word-length and the size of the modulus.
+
+The program bigtobig.cpp converts a big number to the AMCL 
+BIG format.
+
+
+For quick jumpstart:-
+
+Run Chrome browser and navigate to TestECDH.html
+
+or TestMPIN.html
+
+or BenchtestEC.html
+
+or BenchtestPAIR.html
+
+You might need to wait a couple of minutes for the output to appear.
+
+

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/rust/.gitignore
----------------------------------------------------------------------
diff --git a/version22/rust/.gitignore b/version22/rust/.gitignore
new file mode 100644
index 0000000..fc8bcce
--- /dev/null
+++ b/version22/rust/.gitignore
@@ -0,0 +1,5 @@
+cargo-registry
+target
+Cargo.lock
+.idea
+

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/rust/Cargo.toml
----------------------------------------------------------------------
diff --git a/version22/rust/Cargo.toml b/version22/rust/Cargo.toml
new file mode 100644
index 0000000..5d07d78
--- /dev/null
+++ b/version22/rust/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "amcl"
+version = "0.1.3"
+authors = [
+  "Vyacheslav Gudkov <[email protected]>",
+  "Evgeniy Razinkov <[email protected]>"
+  ]
+
+description = "The Apache Milagro Cryptographic Library(version 2.2)"
+license = "Apache-2.0"
+repository = "https://github.com/MRJCrunch/amcl";
+[lib]
+name = "amcl"
+path = "src/lib.rs"
+
+[features]
+default = ["BLS383"]
+Ed25519 = []
+GOLDILOCKS = []
+BN254 = []
+BLS383 = []
+BLS455 = []
+
+[dependencies]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/rust/readme.txt
----------------------------------------------------------------------
diff --git a/version22/rust/readme.txt b/version22/rust/readme.txt
new file mode 100644
index 0000000..128f665
--- /dev/null
+++ b/version22/rust/readme.txt
@@ -0,0 +1,56 @@
+AMCL is very simple to build for Rust.
+
+This version supports both 32-bit and 64-bit builds.
+If your processor and operating system are both 64-bit, a 64-bit build 
+will probably be best. Otherwise use a 32-bit build.
+
+First - decide the modulus and curve type you want to use. Edit rom32.rs 
+or rom64.rs where indicated. You will probably want to use one of the curves 
+whose details are already in there. You might want to "raid" the rom 
+file from the C version of the library for more curves.
+
+Three example API files are provided, mpin.rs which 
+supports our M-Pin (tm) protocol, ecdh.rs which supports elliptic 
+curve key exchange, digital signature and public key crypto, and rsa.rs
+which supports the RSA method. The first can be tested using the 
+TestMPIN.rs driver program, the second can be tested using TestECDH.rs,
+and the third with TestRSA.rs
+
+
+In the rom32.rs/rom64.rs file you must provide the curve constants. Several 
+examples are provided there, if you are willing to use one of these.
+
+To help generate the ROM constants for your own curve some MIRACL helper 
+programs are included. The programs bngen.cpp and blsgen.cpp generate ROM 
+data for a BN and BLS pairing friendly curves, and the program ecgen.cpp 
+generates ROM data for regular EC curves.
+
+The MIRACL based program check.cpp helps choose the best number base for
+big number representation, given the word-length and the size of the modulus.
+
+The program bigtobig.cpp converts a big number to the AMCL 
+BIG format.
+
+For a quick jumpstart:-
+
+Copy rom32.rs to rom.rs for a 32-bit build
+
+rustc --cfg D32 -O -A dead_code TestMPIN.rs
+
+or 
+
+rustc --cfg D32 -O -A dead_code TestECDH.rs
+
+or
+
+rustc --cfg D32 -O -A dead_code TestRSA.rs
+
+also
+
+rustc --cfg D32 -O -A dead_code BenchtestEC.rs
+
+rustc --cfg D32 -O -A dead_code BenchtestPAIR.rs
+
+
+For a 64-bit build copy rom64.rs to rom.rs, and use instead the 
+flag --cfg D64

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/rust/src/aes.rs
----------------------------------------------------------------------
diff --git a/version22/rust/src/aes.rs b/version22/rust/src/aes.rs
new file mode 100644
index 0000000..5298837
--- /dev/null
+++ b/version22/rust/src/aes.rs
@@ -0,0 +1,628 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+pub const ECB: usize=0;
+pub const CBC: usize=1;
+pub const CFB1: usize=2;
+pub const CFB2: usize=3;
+pub const CFB4: usize=5;
+pub const OFB1: usize=14;
+pub const OFB2: usize=15;
+pub const OFB4: usize=17;
+pub const OFB8:usize=21;
+pub const OFB16: usize=29;
+pub const CTR1: usize=30;
+pub const CTR2: usize=31;
+pub const CTR4: usize=33;
+pub const CTR8: usize=37;
+pub const CTR16: usize=45;
+
+const INCO : [u8;4] = [0xB,0xD,0x9,0xE];  /* Inverse Coefficients */
+
+const PTAB : [u8;256] = [
+     1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53,
+     95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170,
+     229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49,
+     83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205,
+     76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136,
+     131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 
154,
+     181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163,
+     254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160,
+     251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65,
+     195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117,
+     159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 
128,
+     155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84,
+     252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202,
+     69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14,
+     18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23,
+     57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1];
+
+const LTAB : [u8;256] = [
+      0, 255, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238, 223, 3,
+     100, 4, 224, 14, 52, 141, 129, 239, 76, 113, 8, 200, 248, 105, 28, 193,
+     125, 194, 29, 181, 249, 185, 39, 106, 77, 228, 166, 114, 154, 201, 9, 120,
+     101, 47, 138, 5, 33, 15, 225, 36, 18, 240, 130, 69, 53, 147, 218, 142,
+     150, 143, 219, 189, 54, 208, 206, 148, 19, 92, 210, 241, 64, 70, 131, 56,
+     102, 221, 253, 48, 191, 6, 139, 98, 179, 37, 226, 152, 34, 136, 145, 16,
+     126, 110, 72, 195, 163, 182, 30, 66, 58, 107, 40, 84, 250, 133, 61, 186,
+     43, 121, 10, 21, 155, 159, 94, 202, 78, 212, 172, 229, 243, 115, 167, 87,
+     175, 88, 168, 80, 244, 234, 214, 116, 79, 174, 233, 213, 231, 230, 173, 
232,
+     44, 215, 117, 122, 235, 22, 11, 245, 89, 203, 95, 176, 156, 169, 81, 160,
+     127, 12, 246, 111, 23, 196, 73, 236, 216, 67, 31, 45, 164, 118, 123, 183,
+     204, 187, 62, 90, 251, 96, 177, 134, 59, 82, 161, 108, 170, 85, 41, 157,
+     151, 178, 135, 144, 97, 190, 220, 252, 188, 149, 207, 205, 55, 63, 91, 
209,
+     83, 57, 132, 60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242, 211, 171,
+     68, 17, 146, 217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153, 227, 165,
+     103, 74, 237, 222, 197, 49, 254, 24, 13, 99, 140, 128, 192, 247, 112, 7];
+
+
+const FBSUB : [u8;256] = [
+     99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
+     202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 
192,
+     183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21,
+     4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117,
+     9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132,
+     83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207,
+     208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168,
+     81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210,
+     205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115,
+     96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219,
+     224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121,
+     231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8,
+     186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138,
+     112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158,
+     225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 
223,
+     140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22];
+
+const RBSUB : [u8;256] = [
+     82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251,
+     124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203,
+     84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78,
+     8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37,
+     114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 
146,
+     108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132,
+     144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6,
+     208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107,
+     58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 
115,
+     150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 
110,
+     71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27,
+     252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244,
+     31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95,
+     96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239,
+     160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97,
+     23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125];
+
+const RCO : [u8;16] = [1,2,4,8,16,32,64,128,27,54,108,216,171,77,154,47];
+
+const FTABLE : [u32;256] = [
+    0xa56363c6,0x847c7cf8,0x997777ee,0x8d7b7bf6,0xdf2f2ff,0xbd6b6bd6,
+    0xb16f6fde,0x54c5c591,0x50303060,0x3010102,0xa96767ce,0x7d2b2b56,
+    0x19fefee7,0x62d7d7b5,0xe6abab4d,0x9a7676ec,0x45caca8f,0x9d82821f,
+    0x40c9c989,0x877d7dfa,0x15fafaef,0xeb5959b2,0xc947478e,0xbf0f0fb,
+    0xecadad41,0x67d4d4b3,0xfda2a25f,0xeaafaf45,0xbf9c9c23,0xf7a4a453,
+    0x967272e4,0x5bc0c09b,0xc2b7b775,0x1cfdfde1,0xae93933d,0x6a26264c,
+    0x5a36366c,0x413f3f7e,0x2f7f7f5,0x4fcccc83,0x5c343468,0xf4a5a551,
+    0x34e5e5d1,0x8f1f1f9,0x937171e2,0x73d8d8ab,0x53313162,0x3f15152a,
+    0xc040408,0x52c7c795,0x65232346,0x5ec3c39d,0x28181830,0xa1969637,
+    0xf05050a,0xb59a9a2f,0x907070e,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,0x0,0x2cededc1,
+    0x60202040,0x1ffcfce3,0xc8b1b179,0xed5b5bb6,0xbe6a6ad4,0x46cbcb8d,
+    0xd9bebe67,0x4b393972,0xde4a4a94,0xd44c4c98,0xe85858b0,0x4acfcf85,
+    0x6bd0d0bb,0x2aefefc5,0xe5aaaa4f,0x16fbfbed,0xc5434386,0xd74d4d9a,
+    0x55333366,0x94858511,0xcf45458a,0x10f9f9e9,0x6020204,0x817f7ffe,
+    0xf05050a0,0x443c3c78,0xba9f9f25,0xe3a8a84b,0xf35151a2,0xfea3a35d,
+    0xc0404080,0x8a8f8f05,0xad92923f,0xbc9d9d21,0x48383870,0x4f5f5f1,
+    0xdfbcbc63,0xc1b6b677,0x75dadaaf,0x63212142,0x30101020,0x1affffe5,
+    0xef3f3fd,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,0xa06060c,0x6c242448,0xe45c5cb8,
+    0x5dc2c29f,0x6ed3d3bd,0xefacac43,0xa66262c4,0xa8919139,0xa4959531,
+    0x37e4e4d3,0x8b7979f2,0x32e7e7d5,0x43c8c88b,0x5937376e,0xb76d6dda,
+    0x8c8d8d01,0x64d5d5b1,0xd24e4e9c,0xe0a9a949,0xb46c6cd8,0xfa5656ac,
+    0x7f4f4f3,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,0x5030306,0x1f6f6f7,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 RTABLE : [u32;256] = [
+    0x50a7f451,0x5365417e,0xc3a4171a,0x965e273a,0xcb6bab3b,0xf1459d1f,
+    0xab58faac,0x9303e34b,0x55fa3020,0xf66d76ad,0x9176cc88,0x254c02f5,
+    0xfcd7e54f,0xd7cb2ac5,0x80443526,0x8fa362b5,0x495ab1de,0x671bba25,
+    0x980eea45,0xe1c0fe5d,0x2752fc3,0x12f04c81,0xa397468d,0xc6f9d36b,
+    0xe75f8f03,0x959c9215,0xeb7a6dbf,0xda595295,0x2d83bed4,0xd3217458,
+    0x2969e049,0x44c8c98e,0x6a89c275,0x78798ef4,0x6b3e5899,0xdd71b927,
+    0xb64fe1be,0x17ad88f0,0x66ac20c9,0xb43ace7d,0x184adf63,0x82311ae5,
+    0x60335197,0x457f5362,0xe07764b1,0x84ae6bbb,0x1ca081fe,0x942b08f9,
+    0x58684870,0x19fd458f,0x876cde94,0xb7f87b52,0x23d373ab,0xe2024b72,
+    0x578f1fe3,0x2aab5566,0x728ebb2,0x3c2b52f,0x9a7bc586,0xa50837d3,
+    0xf2872830,0xb2a5bf23,0xba6a0302,0x5c8216ed,0x2b1ccf8a,0x92b479a7,
+    0xf0f207f3,0xa1e2694e,0xcdf4da65,0xd5be0506,0x1f6234d1,0x8afea6c4,
+    0x9d532e34,0xa055f3a2,0x32e18a05,0x75ebf6a4,0x39ec830b,0xaaef6040,
+    0x69f715e,0x51106ebd,0xf98a213e,0x3d06dd96,0xae053edd,0x46bde64d,
+    0xb58d5491,0x55dc471,0x6fd40604,0xff155060,0x24fb9819,0x97e9bdd6,
+    0xcc434089,0x779ed967,0xbd42e8b0,0x888b8907,0x385b19e7,0xdbeec879,
+    0x470a7ca1,0xe90f427c,0xc91e84f8,0x0,0x83868009,0x48ed2b32,
+    0xac70111e,0x4e725a6c,0xfbff0efd,0x5638850f,0x1ed5ae3d,0x27392d36,
+    0x64d90f0a,0x21a65c68,0xd1545b9b,0x3a2e3624,0xb1670a0c,0xfe75793,
+    0xd296eeb4,0x9e919b1b,0x4fc5c080,0xa220dc61,0x694b775a,0x161a121c,
+    0xaba93e2,0xe52aa0c0,0x43e0223c,0x1d171b12,0xb0d090e,0xadc78bf2,
+    0xb9a8b62d,0xc8a91e14,0x8519f157,0x4c0775af,0xbbdd99ee,0xfd607fa3,
+    0x9f2601f7,0xbcf5725c,0xc53b6644,0x347efb5b,0x7629438b,0xdcc623cb,
+    0x68fcedb6,0x63f1e4b8,0xcadc31d7,0x10856342,0x40229713,0x2011c684,
+    0x7d244a85,0xf83dbbd2,0x1132f9ae,0x6da129c7,0x4b2f9e1d,0xf330b2dc,
+    0xec52860d,0xd0e3c177,0x6c16b32b,0x99b970a9,0xfa489411,0x2264e947,
+    0xc48cfca8,0x1a3ff0a0,0xd82c7d56,0xef903322,0xc74e4987,0xc1d138d9,
+    0xfea2ca8c,0x360bd498,0xcf81f5a6,0x28de7aa5,0x268eb7da,0xa4bfad3f,
+    0xe49d3a2c,0xd927850,0x9bcc5f6a,0x62467e54,0xc2138df6,0xe8b8d890,
+    0x5ef7392e,0xf5afc382,0xbe805d9f,0x7c93d069,0xa92dd56f,0xb31225cf,
+    0x3b99acc8,0xa77d1810,0x6e639ce8,0x7bbb3bdb,0x97826cd,0xf418596e,
+    0x1b79aec,0xa89a4f83,0x656e95e6,0x7ee6ffaa,0x8cfbc21,0xe6e815ef,
+    0xd99be7ba,0xce366f4a,0xd4099fea,0xd67cb029,0xafb2a431,0x31233f2a,
+    0x3094a5c6,0xc066a235,0x37bc4e74,0xa6ca82fc,0xb0d090e0,0x15d8a733,
+    0x4a9804f1,0xf7daec41,0xe50cd7f,0x2ff69117,0x8dd64d76,0x4db0ef43,
+    0x544daacc,0xdf0496e4,0xe3b5d19e,0x1b886a4c,0xb81f2cc1,0x7f516546,
+    0x4ea5e9d,0x5d358c01,0x737487fa,0x2e410bfb,0x5a1d67b3,0x52d2db92,
+    0x335610e9,0x1347d66d,0x8c61d79a,0x7a0ca137,0x8e14f859,0x893c13eb,
+    0xee27a9ce,0x35c961b7,0xede51ce1,0x3cb1477a,0x59dfd29c,0x3f73f255,
+    0x79ce1418,0xbf37c773,0xeacdf753,0x5baafd5f,0x146f3ddf,0x86db4478,
+    0x81f3afca,0x3ec468b9,0x2c342438,0x5f40a3c2,0x72c31d16,0xc25e2bc,
+    0x8b493c28,0x41950dff,0x7101a839,0xdeb30c08,0x9ce4b4d8,0x90c15664,
+    0x6184cb7b,0x70b632d5,0x745c6c48,0x4257b8d0];
+
+
+pub struct AES {
+       nk: usize,
+       nr: usize,
+       mode: usize,
+       fkey: [u32;60],
+       rkey: [u32;60],
+       pub f: [u8;16]
+}
+
+impl AES {
+
+       fn rotl8(x: u32) -> u32 {
+               return ((x)<<8)|((x)>>24);
+       }
+
+       fn rotl16(x: u32) -> u32 {
+               return ((x)<<16)|((x)>>16);
+       }
+
+       fn rotl24(x: u32) -> u32 {
+               return ((x)<<24)|((x)>>8);
+       }
+
+       fn pack(b: [u8;4]) -> u32 { /* pack bytes into a 32-bit Word */
+        return ((((b[3])&0xff) as u32)<<24)|((((b[2])&0xff) as 
u32)<<16)|((((b[1])&0xff) as u32)<<8)|(((b[0])&0xff) as u32);
+       }
+  
+       fn unpack(a: u32) -> [u8;4] { /* unpack bytes from a word */
+        let b:[u8;4]=[(a&0xff) as u8,((a>>8)&0xff) as u8,((a>>16)&0xff) as 
u8,((a>>24)&0xff) as u8];
+               return b;
+       }
+
+       fn bmul(x: u8,y: u8) -> u8 { /* x.y= AntiLog(Log(x) + Log(y)) */
+        let ix=(x as usize)&0xff;
+        let iy=(y as usize)&0xff;
+        let lx=(LTAB[ix] as usize)&0xff;
+        let ly=(LTAB[iy] as usize)&0xff;
+    
+        if x != 0 && y != 0 {
+                       return PTAB[(lx+ly)%255];
+               } else {return 0}
+       }       
+
+       fn subbyte(a: u32) -> u32 {
+        let mut b=AES::unpack(a);
+        b[0]=FBSUB[b[0] as usize];
+        b[1]=FBSUB[b[1] as usize];
+        b[2]=FBSUB[b[2] as usize];
+        b[3]=FBSUB[b[3] as usize];
+        return AES::pack(b);
+       }   
+
+       fn product(x: u32,y: u32) -> u8 { /* dot product of two 4-byte arrays */
+        let xb=AES::unpack(x);
+        let yb=AES::unpack(y);
+    
+        return 
AES::bmul(xb[0],yb[0])^AES::bmul(xb[1],yb[1])^AES::bmul(xb[2],yb[2])^AES::bmul(xb[3],yb[3]);
+       }
+
+       fn invmixcol(x: u32) -> u32 { /* matrix Multiplication */
+        let mut b:[u8;4]=[0;4];
+        let mut m=AES::pack(INCO);
+        b[3]=AES::product(m,x);
+        m=AES::rotl24(m);
+        b[2]=AES::product(m,x);
+        m=AES::rotl24(m);
+        b[1]=AES::product(m,x);
+        m=AES::rotl24(m);
+        b[0]=AES::product(m,x);
+        let y=AES::pack(b);
+        return y;
+       }
+
+       fn increment(f: &mut [u8;16]) {
+               for i in 0..16 {
+                       f[i]+=1;
+                       if f[i]!=0 {break}
+               }
+       }
+
+       pub fn new() -> AES {
+               AES {
+                       nk:0,
+                       nr:0,
+                       mode:0,
+                       fkey:[0;60],
+                       rkey:[0;60],
+                       f:[0;16]
+
+               }
+       }
+
+/* reset cipher */
+       pub fn reset(&mut self,m: usize,iv: Option<[u8;16]>) { /* reset mode, 
or reset iv */
+               self.mode=m;
+        for i in 0..16 {self.f[i]=0}
+        if self.mode != ECB
+        {
+               if let Some(x) = iv {
+                       for i in 0..16 {self.f[i]=x[i]}
+               }
+               }
+       }       
+
+       pub fn init(&mut self,m: usize,nkey: usize,key: &[u8],iv: 
Option<[u8;16]>) -> bool {   
+/* Key Scheduler. Create expanded encryption key */
+               let mut cipherkey:[u32;8]=[0;8];
+        let mut b:[u8;4]=[0;4];
+        let nk=nkey/4;
+               if nk!=4 && nk!=6 && nk!=8 {return false}
+               let nr=6+nk;
+               self.nk=nk;
+               self.nr=nr;
+        self.reset(m,iv);
+        let n=4*(nr+1);
+        
+        let mut j=0;
+        for  i in 0..nk {
+            for k in 0..4 {b[k]=key[j+k]}
+            cipherkey[i]=AES::pack(b);
+            j+=4;
+        }
+
+        for i in 0..nk {self.fkey[i]=cipherkey[i]}
+        j=nk;
+               let mut k=0;    
+        while j<n  {           
+            
self.fkey[j]=self.fkey[j-nk]^AES::subbyte(AES::rotl24(self.fkey[j-1]))^(RCO[k] 
as u32);
+            for i in 1..nk {
+               if (i+j) >= n {break}           
+                self.fkey[i+j]=self.fkey[i+j-nk]^self.fkey[i+j-1];             
+            }
+            j+=nk;
+            k+=1;
+        }
+     
+        /* now for the expanded decrypt key in reverse order */
+        
+        for j in 0..4 {self.rkey[j+n-4]=self.fkey[j]}
+        let mut i=4;
+        while i<n-4 {
+            let k=n-4-i;
+            for j in 0..4 {self.rkey[k+j]=AES::invmixcol(self.fkey[i+j])}
+            i+=4;
+        }
+        for j in n-4..n {self.rkey[j-n+4]=self.fkey[j]}
+               return true;
+       }
+
+       pub fn getreg(&mut self) -> [u8;16] {
+        let mut ir:[u8;16]=[0;16];
+        for i in 0..16 {ir[i]=self.f[i]}
+        return ir;
+       }
+
+    /* Encrypt a single block */
+       pub fn ecb_encrypt(&mut self,buff: &mut [u8;16]) {
+        let mut b:[u8;4]=[0;4]; 
+        let mut p:[u32;4]=[0;4]; 
+        let mut q:[u32;4]=[0;4]; 
+    
+        let mut j=0;
+        for i in 0..4 {
+            for k in 0..4 {b[k]=buff[j+k]}
+            p[i]=AES::pack(b);
+            p[i]^=self.fkey[i];
+            j+=4;
+        }
+    
+        let mut k=4;
+    
+    /* State alternates between p and q */
+        for _ in 1..self.nr {
+            q[0]=self.fkey[k]^FTABLE[(p[0]&0xff) as 
usize]^AES::rotl8(FTABLE[((p[1]>>8)&0xff) as 
usize])^AES::rotl16(FTABLE[((p[2]>>16)&0xff) as 
usize])^AES::rotl24(FTABLE[((p[3]>>24)&0xff) as usize]);
+            
+            q[1]=self.fkey[k+1]^FTABLE[(p[1]&0xff) as 
usize]^AES::rotl8(FTABLE[((p[2]>>8)&0xff) as 
usize])^AES::rotl16(FTABLE[((p[3]>>16)&0xff) as 
usize])^AES::rotl24(FTABLE[((p[0]>>24)&0xff) as usize]);
+            
+            q[2]=self.fkey[k+2]^FTABLE[(p[2]&0xff) as 
usize]^AES::rotl8(FTABLE[((p[3]>>8)&0xff) as 
usize])^AES::rotl16(FTABLE[((p[0]>>16)&0xff) as 
usize])^AES::rotl24(FTABLE[((p[1]>>24)&0xff) as usize]);
+            
+            q[3]=self.fkey[k+3]^FTABLE[(p[3]&0xff) as 
usize]^AES::rotl8(FTABLE[((p[0]>>8)&0xff) as 
usize])^AES::rotl16(FTABLE[((p[1]>>16)&0xff) as 
usize])^AES::rotl24(FTABLE[((p[2]>>24)&0xff) as usize]);
+            
+            k+=4;
+            for j in 0..4 {
+                               let t=p[j]; p[j]=q[j]; q[j]=t;
+            }
+        }
+    
+    /* Last Round */
+    
+        q[0]=self.fkey[k]^(FBSUB[(p[0]&0xff) as usize] as 
u32)^AES::rotl8((FBSUB[((p[1]>>8)&0xff) as usize]) as 
u32)^AES::rotl16((FBSUB[((p[2]>>16)&0xff) as usize]) as 
u32)^AES::rotl24((FBSUB[((p[3]>>24)&0xff) as usize]) as u32);
+    
+        q[1]=self.fkey[k+1]^(FBSUB[(p[1]&0xff) as usize] as 
u32)^AES::rotl8((FBSUB[((p[2]>>8)&0xff) as usize]) as 
u32)^AES::rotl16((FBSUB[((p[3]>>16)&0xff) as usize]) as 
u32)^AES::rotl24((FBSUB[((p[0]>>24)&0xff) as usize]) as u32);
+    
+        q[2]=self.fkey[k+2]^(FBSUB[(p[2]&0xff) as usize] as 
u32)^AES::rotl8((FBSUB[((p[3]>>8)&0xff) as usize]) as 
u32)^AES::rotl16((FBSUB[((p[0]>>16)&0xff) as usize]) as 
u32)^AES::rotl24((FBSUB[((p[1]>>24)&0xff) as usize]) as u32);
+    
+        q[3]=self.fkey[k+3]^(FBSUB[(p[3]&0xff) as usize] as 
u32)^AES::rotl8((FBSUB[((p[0]>>8)&0xff) as usize]) as 
u32)^AES::rotl16((FBSUB[((p[1]>>16)&0xff) as usize]) as 
u32)^AES::rotl24((FBSUB[((p[2]>>24)&0xff) as usize]) as u32);
+    
+        j=0;
+        for i in 0..4 {
+            b=AES::unpack(q[i]);
+            for k in 0..4 {buff[j+k]=b[k]}
+            j+=4;
+        }
+       }
+
+    /* Decrypt a single block */
+       pub fn ecb_decrypt(&mut self,buff: &mut [u8;16]) {
+        let mut b:[u8;4]=[0;4]; 
+        let mut p:[u32;4]=[0;4]; 
+        let mut q:[u32;4]=[0;4]; 
+    
+        let mut j=0;
+        for i in 0..4 {
+            for k in 0..4 {b[k]=buff[j+k]}
+            p[i]=AES::pack(b);
+            p[i]^=self.rkey[i];
+            j+=4;
+        }
+    
+         let mut k=4;
+    
+    /* State alternates between p and q */
+        for _ in 1..self.nr {
+            
+            q[0]=self.rkey[k]^RTABLE[(p[0]&0xff) as 
usize]^AES::rotl8(RTABLE[((p[3]>>8)&0xff) as 
usize])^AES::rotl16(RTABLE[((p[2]>>16)&0xff) as 
usize])^AES::rotl24(RTABLE[((p[1]>>24)&0xff) as usize]);
+            
+            q[1]=self.rkey[k+1]^RTABLE[(p[1]&0xff) as 
usize]^AES::rotl8(RTABLE[((p[0]>>8)&0xff) as 
usize])^AES::rotl16(RTABLE[((p[3]>>16)&0xff) as 
usize])^AES::rotl24(RTABLE[((p[2]>>24)&0xff) as usize]);
+            
+        
+            q[2]=self.rkey[k+2]^RTABLE[(p[2]&0xff) as 
usize]^AES::rotl8(RTABLE[((p[1]>>8)&0xff) as 
usize])^AES::rotl16(RTABLE[((p[0]>>16)&0xff) as 
usize])^AES::rotl24(RTABLE[((p[3]>>24)&0xff) as usize]);
+       
+            q[3]=self.rkey[k+3]^RTABLE[(p[3]&0xff) as 
usize]^AES::rotl8(RTABLE[((p[2]>>8)&0xff) as 
usize])^AES::rotl16(RTABLE[((p[1]>>16)&0xff) as 
usize])^AES::rotl24(RTABLE[((p[0]>>24)&0xff) as usize]);
+            
+    
+            k+=4;
+            for j in 0..4 {
+                               let t=p[j]; p[j]=q[j]; q[j]=t;
+            }
+        }
+    
+    /* Last Round */
+        
+        q[0]=self.rkey[k]^(RBSUB[(p[0]&0xff) as usize] as 
u32)^AES::rotl8((RBSUB[((p[3]>>8)&0xff) as usize]) as 
u32)^AES::rotl16((RBSUB[((p[2]>>16)&0xff) as usize]) as 
u32)^AES::rotl24((RBSUB[((p[1]>>24)&0xff) as usize]) as u32);
+        
+        q[1]=self.rkey[k+1]^(RBSUB[(p[1]&0xff) as usize] as 
u32)^AES::rotl8((RBSUB[((p[0]>>8)&0xff) as usize]) as 
u32)^AES::rotl16((RBSUB[((p[3]>>16)&0xff) as usize]) as 
u32)^AES::rotl24((RBSUB[((p[2]>>24)&0xff) as usize]) as u32);
+        
+        
+        q[2]=self.rkey[k+2]^(RBSUB[(p[2]&0xff) as usize] as 
u32)^AES::rotl8((RBSUB[((p[1]>>8)&0xff) as usize]) as 
u32)^AES::rotl16((RBSUB[((p[0]>>16)&0xff) as usize]) as 
u32)^AES::rotl24((RBSUB[((p[3]>>24)&0xff) as usize]) as u32);
+
+        q[3]=self.rkey[k+3]^(RBSUB[((p[3])&0xff) as usize] as 
u32)^AES::rotl8((RBSUB[((p[2]>>8)&0xff) as usize]) as 
u32)^AES::rotl16((RBSUB[((p[1]>>16)&0xff) as usize]) as 
u32)^AES::rotl24((RBSUB[((p[0]>>24)&0xff) as usize]) as u32);
+    
+        j=0;
+        for i in 0..4 {
+            b=AES::unpack(q[i]);
+            for k in 0..4 {buff[j+k]=b[k]}
+            j+=4;
+        }
+       }
+
+/* Encrypt using selected mode of operation */
+       pub fn encrypt(&mut self,buff: &mut [u8;16]) -> u32 {
+               let mut st:[u8;16]=[0;16]; 
+    
+    // Supported Modes of Operation
+    
+        let mut fell_off: u32=0;
+
+        match self.mode {
+               ECB => {
+               self.ecb_encrypt(buff);
+               return 0;
+               },
+               CBC => {
+               for j in 0..16 {buff[j]^=self.f[j]}
+               self.ecb_encrypt(buff);
+               for j in 0..16 {self.f[j]=buff[j]}
+               return 0;
+               },
+    
+               CFB1 | CFB2 | CFB4 => {
+               let bytes=self.mode-CFB1+1;
+               for j in 0..bytes {fell_off=(fell_off<<8)|(self.f[j] as u32)}
+               for j in 0..16 {st[j]=self.f[j]}
+               for j in bytes..16 {self.f[j-bytes]=self.f[j]}
+               self.ecb_encrypt(&mut st);
+               for j in 0..bytes {
+                                       buff[j]^=st[j];
+                               self.f[16-bytes+j]=buff[j];
+               }
+               return fell_off;
+               },
+    
+               OFB1 | OFB2 | OFB4 | OFB8 | OFB16 => {
+                       let bytes=self.mode-OFB1+1;
+               for j in 0..16 {st[j]=self.f[j]}
+               self.ecb_encrypt(&mut st);
+                       for j in 0..bytes {buff[j]^=st[j]}       
+               for j in 0..16 {self.f[j]=st[j]}                                
                
+
+               //self.ecb_encrypt(&mut (self.f));
+               //for j in 0..bytes {buff[j]^=self.f[j]}
+               return 0;
+               },
+    
+                       CTR1 | CTR2 | CTR4 | CTR8 | CTR16 => {
+                       let bytes=self.mode-CTR1+1;
+                       for j in 0..16 {st[j]=self.f[j]}
+                       self.ecb_encrypt(&mut st);
+                       for j in 0..bytes {buff[j]^=st[j]}
+                       AES::increment(&mut (self.f));
+                       return 0;
+               },
+
+               _ => {
+               return 0;
+               }
+        }
+    }
+
+    /* Decrypt using selected mode of operation */
+       pub fn decrypt(&mut self,buff: &mut [u8;16]) -> u32 {
+
+               let mut st:[u8;16]=[0;16]; 
+        
+        // Supported Modes of Operation
+        
+               let mut fell_off: u32=0;
+
+        match self.mode {
+               ECB => {
+               self.ecb_decrypt(buff);
+               return 0;
+            },
+               CBC => {
+               for j in 0..16 {
+                                       st[j]=self.f[j];
+                                       self.f[j]=buff[j];
+               }
+               self.ecb_decrypt(buff);
+               for j in 0..16 {
+                                       buff[j]^=st[j];
+                                       st[j]=0;
+               }
+               return 0;
+               },
+               CFB1 | CFB2 | CFB4 => {
+               let bytes=self.mode-CFB1+1;
+               for j in 0..bytes {fell_off=(fell_off<<8)|(self.f[j] as u32)}
+               for j in 0..16 {st[j]=self.f[j]}
+               for j in bytes..16 {self.f[j-bytes]=self.f[j]}
+               self.ecb_encrypt(&mut st);
+               for j in 0..bytes {
+                                       self.f[16-bytes+j]=buff[j];
+                                       buff[j]^=st[j];
+               }
+               return fell_off;
+            },
+               OFB1 | OFB2 | OFB4 | OFB8 | OFB16 => {
+                       let bytes=self.mode-OFB1+1;
+               for j in 0..16 {st[j]=self.f[j]}
+               self.ecb_encrypt(&mut st);
+                       for j in 0..bytes {buff[j]^=st[j]}       
+               for j in 0..16 {self.f[j]=st[j]}                        
+            // self.ecb_encrypt(A.f[:]);
+            // for j in 0..bytes {buff[j]^=self.f[j]}
+               return 0;
+            },
+
+                       CTR1 | CTR2 | CTR4 | CTR8 | CTR16 => {
+                       let bytes=self.mode-CTR1+1;
+                       for j in 0..16 {st[j]=self.f[j]}
+                       self.ecb_encrypt(&mut st);
+                       for j in 0..bytes {buff[j]^=st[j]}
+                       AES::increment(&mut (self.f));
+                       return 0;
+               },
+
+               _ => {
+               return 0;
+               }
+        }
+    } 
+
+/* Clean up and delete left-overs */
+       pub fn end(&mut self) { // clean up
+       for i in 0..4*(self.nr+1) {self.fkey[i]=0; self.rkey[i]=0}
+       for i in 0..16 {self.f[i]=0}
+       }
+}
+
+/*
+fn main()
+{
+       let mut key:[u8;32]=[0;32];
+       let mut block:[u8;16]=[0;16];
+       let mut iv: [u8;16] = [0;16];
+
+       for i in 0..32 {key[i]=0}
+       key[0]=1;
+       for i in 0..16 {iv[i]=i as u8}
+       for i in 0..16 {block[i]=i as u8}
+
+       let mut aes=AES::new();
+       aes.init(CTR16,32,&key,Some(iv));
+
+       println!("Plain= ");
+       for i in 0..16 {print!("{:02x} ",block[i])}
+       println!("");   
+
+       aes.encrypt(&mut block);
+
+       println!("Encrypt= ");
+       for i in 0..16 {print!("{:02x} ",block[i])}
+       println!("");   
+
+       aes.reset(CTR16,Some(iv));
+       aes.decrypt(&mut block);
+
+       println!("Decrypt= ");
+       for i in 0..16 {print!("{:02x} ",block[i])}
+       println!("");   
+
+       aes.end();
+}
+*/

Reply via email to