http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/rust/src/gcm.rs
----------------------------------------------------------------------
diff --git a/version22/rust/src/gcm.rs b/version22/rust/src/gcm.rs
new file mode 100644
index 0000000..32e2749
--- /dev/null
+++ b/version22/rust/src/gcm.rs
@@ -0,0 +1,356 @@
+/*
+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.
+*/
+
+const GCM_NB:usize=4;
+const GCM_ACCEPTING_HEADER:usize=0;
+const GCM_ACCEPTING_CIPHER:usize=1;
+const GCM_NOT_ACCEPTING_MORE:usize=2;
+const GCM_FINISHED:usize=3;
+const GCM_ENCRYPTING:usize=0;
+const GCM_DECRYPTING:usize=1;
+
+use aes;
+use aes::AES;
+
+pub struct GCM {
+       table: [[u32;4];128],
+       statex: [u8;16],
+       y_0: [u8;16],
+//     counter: usize,
+       lena:[u32;2],
+       lenc:[u32;2],
+       status:usize,
+       a:AES
+}
+
+impl GCM {
+
+       fn pack(b: [u8;4]) -> u32 { /* pack bytes into a 32-bit Word */
+        return ((((b[0])&0xff) as u32)<<24)|((((b[1])&0xff) as 
u32)<<16)|((((b[2])&0xff) as u32)<<8)|(((b[3])&0xff) as u32);
+       }
+  
+       fn unpack(a: u32) -> [u8;4] { /* unpack bytes from a word */
+        let b:[u8;4]=[((a>>24)&0xff) as u8,((a>>16)&0xff) as u8,((a>>8)&0xff) 
as u8,(a&0xff) as u8];
+               return b;
+       }
+
+       fn precompute(&mut self,h: &[u8]) {
+               let mut b:[u8;4]=[0;4];
+        let mut j=0;
+        for i in 0..GCM_NB {
+            b[0]=h[j]; b[1]=h[j+1]; b[2]=h[j+2]; b[3]=h[j+3];
+            self.table[0][i]=GCM::pack(b);
+            j+=4;
+        }
+        for i in 1..128 {
+               let mut c:u32=0;
+            for j in 0..GCM_NB {self.table[i][j]=c|(self.table[i-1][j])>>1; 
c=self.table[i-1][j]<<31;}
+            if c != 0  {self.table[i][0]^=0xE1000000} /* irreducible 
polynomial */
+        }          
+       }
+
+       fn gf2mul(&mut self) { /* gf2m mul - Z=H*X mod 2^128 */
+        let mut p:[u32;4]=[0;4]; 
+    
+        for i in 0..4 {p[i]=0}
+        let mut j:usize=8; 
+        let mut m=0;
+        for i in 0..128 {
+               j-=1;
+            let mut c=((self.statex[m]>>j)&1) as u32; c= (!c) +1;
+               for k in 0..GCM_NB {p[k]^=self.table[i][k]&c}
+            if j==0 {
+                               j=8; m+=1;
+                if m==16 {break}
+            }
+        }
+        j=0;
+        for i in 0..GCM_NB {
+            let b=GCM::unpack(p[i]);
+            self.statex[j]=b[0]; self.statex[j+1]=b[1]; self.statex[j+2]=b[2]; 
self.statex[j+3]=b[3];
+            j+=4;
+        }
+       }
+
+       fn wrap(&mut self) { /* Finish off GHASH */
+        let mut f:[u32;4]=[0;4]; 
+        let mut el:[u8;16]=[0;16];  
+   
+    /* convert lengths from bytes to bits */
+        f[0]=(self.lena[0]<<3)|(self.lena[1]&0xE0000000)>>29;
+        f[1]=self.lena[1]<<3;
+        f[2]=(self.lenc[0]<<3)|(self.lenc[1]&0xE0000000)>>29;
+        f[3]=self.lenc[1]<<3;
+        let mut j=0;
+        for i in 0..GCM_NB {
+            let b=GCM::unpack(f[i]);
+            el[j]=b[0]; el[j+1]=b[1]; el[j+2]=b[2]; el[j+3]=b[3];
+            j+=4;
+        }
+        for i in 0..16 {self.statex[i]^=el[i]}
+        self.gf2mul();
+       }
+
+       fn ghash(&mut self,plain: &[u8],len: usize) -> bool {
+        if self.status==GCM_ACCEPTING_HEADER {self.status=GCM_ACCEPTING_CIPHER}
+        if self.status != GCM_ACCEPTING_CIPHER {return false}
+        
+        let mut j=0;
+        while j<len {
+            for i in 0..16 {
+               if j>=len {break}
+                               self.statex[i]^=plain[j]; j+=1;
+                self.lenc[1]+=1; if self.lenc[1]==0 {self.lenc[0]+=1}
+            }
+            self.gf2mul();
+        }
+        if len%16 != 0 {self.status=GCM_NOT_ACCEPTING_MORE}
+        return true;
+    }
+
+    /* Initialize GCM mode */
+       pub fn init(&mut self,nk: usize,key: &[u8],niv: usize,iv: &[u8]) { /* 
iv size niv is usually 12 bytes (96 bits). AES key size nk can be 16,24 or 32 
bytes */
+               let mut h:[u8;16]=[0;16];
+    
+        for i in 0..16 {h[i]=0; self.statex[i]=0}
+        
+               self.a=AES::new();
+
+        self.a.init(aes::ECB,nk,key,None);
+        self.a.ecb_encrypt(&mut h);    /* E(K,0) */
+        self.precompute(&h);
+        
+        self.lena[0]=0;self.lenc[0]=0;self.lena[1]=0;self.lenc[1]=0;
+        if niv==12 {
+            for i in 0..12 {self.a.f[i]=iv[i]}
+            let b=GCM::unpack(1);
+            self.a.f[12]=b[0]; self.a.f[13]=b[1]; self.a.f[14]=b[2]; 
self.a.f[15]=b[3];  /* initialise IV */
+            for i in 0..16 {self.y_0[i]=self.a.f[i]}
+        } else {
+            self.status=GCM_ACCEPTING_CIPHER;
+            self.ghash(iv,niv); /* GHASH(H,0,IV) */
+            self.wrap();
+            for i in 0..16 
{self.a.f[i]=self.statex[i];self.y_0[i]=self.a.f[i];self.statex[i]=0}
+            self.lena[0]=0;self.lenc[0]=0;self.lena[1]=0;self.lenc[1]=0;
+        }
+        self.status=GCM_ACCEPTING_HEADER;
+       }
+
+       pub fn new() -> GCM {
+               GCM {
+                       table:[[0;4];128],
+                       statex:[0;16],
+                       y_0:[0;16],
+                       //counter:0,
+                       lena:[0;2],
+                       lenc:[0;2],
+                       status:0,
+                       a:AES::new()
+               }
+       }
+
+/* Add Header data - included but not encrypted */
+       pub fn add_header(&mut self,header: &[u8],len: usize) -> bool { /* Add 
some header. Won't be encrypted, but will be authenticated. len is length of 
header */
+        if self.status != GCM_ACCEPTING_HEADER {return false}
+        let mut j=0;
+        while j<len {
+            for i in 0..16 {
+               if j>=len {break}
+                               self.statex[i]^=header[j]; j+=1;
+                self.lena[1]+=1; if self.lena[1]==0 {self.lena[0]+=1}
+            }
+            self.gf2mul();
+        }
+        if len%16 != 0 {self.status=GCM_ACCEPTING_CIPHER}
+        return true;
+    }
+
+/* Add Plaintext - included and encrypted */
+       pub fn add_plain(&mut self,cipher: &mut [u8],plain: &[u8],len: usize) 
-> bool {
+               let mut cb:[u8;16]=[0;16]; 
+               let mut b:[u8;4]=[0;4];
+       
+        let mut counter: u32;
+        if self.status == GCM_ACCEPTING_HEADER 
{self.status=GCM_ACCEPTING_CIPHER}
+        if self.status != GCM_ACCEPTING_CIPHER {return false}
+        
+        let mut j=0;
+        while j<len {
+            b[0]=self.a.f[12]; b[1]=self.a.f[13]; b[2]=self.a.f[14]; 
b[3]=self.a.f[15];
+            counter=GCM::pack(b);
+            counter+=1;
+            b=GCM::unpack(counter);
+            self.a.f[12]=b[0]; self.a.f[13]=b[1]; self.a.f[14]=b[2]; 
self.a.f[15]=b[3]; /* increment counter */
+            for i in 0..16 {cb[i]=self.a.f[i]}
+            self.a.ecb_encrypt(&mut cb);        /* encrypt it  */
+    
+            for i in 0..16 {
+               if j>=len {break}
+                               cipher[j]=plain[j]^cb[i];
+                               self.statex[i]^=cipher[j]; j+=1;
+                self.lenc[1]+=1; if self.lenc[1]==0 {self.lenc[0]+=1}
+            }
+            self.gf2mul()
+        }
+        if len%16 != 0 {self.status=GCM_NOT_ACCEPTING_MORE}
+        return true;
+       }
+
+/* Add Ciphertext - decrypts to plaintext */
+       pub fn add_cipher(&mut self,plain: &mut [u8],cipher: &[u8],len: usize) 
-> bool {
+               let mut cb:[u8;16]=[0;16]; 
+               let mut b:[u8;4]=[0;4];
+        
+       let mut counter: u32;
+        
+        if self.status==GCM_ACCEPTING_HEADER {self.status=GCM_ACCEPTING_CIPHER}
+        if self.status != GCM_ACCEPTING_CIPHER {return false}
+    
+        let mut j=0;
+        while j<len {
+            b[0]=self.a.f[12]; b[1]=self.a.f[13]; b[2]=self.a.f[14]; 
b[3]=self.a.f[15];
+            counter=GCM::pack(b);
+            counter+=1;
+            b=GCM::unpack(counter);
+            self.a.f[12]=b[0]; self.a.f[13]=b[1]; self.a.f[14]=b[2]; 
self.a.f[15]=b[3]; /* increment counter */
+            for i in 0..16 {cb[i]=self.a.f[i]}
+            self.a.ecb_encrypt(&mut cb);        /* encrypt it  */
+            for i in 0..16 {
+               if j>=len {break}
+                               let oc=cipher[j];
+                               plain[j]=cipher[j]^cb[i];
+                               self.statex[i]^=oc; j+=1;
+                self.lenc[1]+=1; if self.lenc[1]==0 {self.lenc[0]+=1}
+            }
+            self.gf2mul()
+        }
+        if len%16 != 0 {self.status=GCM_NOT_ACCEPTING_MORE}
+        return true;
+       }
+
+/* Finish and extract Tag */
+       pub fn finish(&mut self,extract: bool) -> [u8;16]  { /* Finish off 
GHASH and extract tag (MAC) */
+               let mut tag:[u8;16]=[0;16]; 
+    
+        self.wrap();
+        /* extract tag */
+        if extract {
+            self.a.ecb_encrypt(&mut (self.y_0));        /* E(K,Y0) */
+            for i in 0..16 {self.y_0[i]^=self.statex[i]}
+            for i in 0..16 {tag[i]=self.y_0[i];self.y_0[i]=0;self.statex[i]=0}
+        }
+        self.status=GCM_FINISHED;
+        self.a.end();
+        return tag;
+       }
+
+       pub fn hex2bytes(hex: &[u8],bin: &mut [u8]) {
+               let len=hex.len();
+
+               for i in 0..len/2 {
+                       let mut v:u8;
+               let mut c = hex[2*i];
+               if c >= b'0' && c <= b'9' {
+               v = c - b'0';
+               } else if c >= b'A' && c <= b'F' {
+               v = c - b'A' + 10;
+               } else if c >= b'a' && c <= b'f' {
+               v = c - b'a' + 10;
+               } else {
+               v = 0;
+               }
+               v <<= 4;
+               c = hex[2*i + 1];
+               if c >= b'0' && c <= b'9' {
+               v += c - b'0';
+               } else if c >= b'A' && c <= b'F' {
+               v += c - b'A' + 10;
+               } else if c >= b'a' && c <= b'f' {
+               v += c - b'a' + 10;
+               } else {
+               v = 0;
+               }
+               bin[i] = v;
+       }
+       }
+
+}
+/*
+fn main()
+{
+       let kt=b"feffe9928665731c6d6a8f9467308308";
+       let 
mt=b"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39";
+       let ht=b"feedfacedeadbeeffeedfacedeadbeefabaddad2";
+       let 
nt=b"9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b";
+// Tag should be 619cc5aefffe0bfa462af43c1699d050
+
+       let mut gcm=GCM::new();
+
+       let len=mt.len()/2;
+       let lenh=ht.len()/2;
+       let lenk=kt.len()/2;
+       let leniv=nt.len()/2;
+
+       //let mut t:[u8;16]=[0;16];     // Tag
+       let mut k:[u8;16]=[0;16];   // AES Key
+       let mut h:[u8;64]=[0;64];       // Header - to be included in 
Authentication, but not encrypted
+       let mut n:[u8;100]=[0;100];     // IV - Initialisation vector
+       let mut m:[u8;100]=[0;100];     // Plaintext to be 
encrypted/authenticated
+       let mut c:[u8;100]=[0;100];     // Ciphertext
+       let mut p:[u8;100]=[0;100];     // Recovered Plaintext 
+
+       GCM::hex2bytes(mt,&mut m);
+       GCM::hex2bytes(ht,&mut h);
+       GCM::hex2bytes(kt,&mut k);
+       GCM::hex2bytes(nt,&mut n);
+
+       println!("Plaintext=");
+       for i in 0..len {print!("{:02x}",m[i])}
+       println!("");
+
+       gcm.init(lenk,&k,leniv,&n);
+       
+       gcm.add_header(&h,lenh);
+       gcm.add_plain(&mut c,&m,len);
+       let mut t=gcm.finish(true);
+
+       println!("Ciphertext=");
+       for i in 0..len {print!("{:02x}",c[i])}
+       println!("");
+  
+       println!("Tag=");
+       for i in 0..16 {print!("{:02x}",t[i])}
+       println!("");
+
+       gcm.init(lenk,&k,leniv,&n);
+       
+       gcm.add_header(&h,lenh);
+       gcm.add_cipher(&mut p,&c,len);
+       t=gcm.finish(true);
+
+       println!("Plaintext=");
+       for i in 0..len {print!("{:02x}",p[i])}
+       println!("");
+
+       println!("Tag=");
+       for i in 0..16 {print!("{:02x}",t[i])}
+       println!("");
+
+}
+*/

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/rust/src/hash256.rs
----------------------------------------------------------------------
diff --git a/version22/rust/src/hash256.rs b/version22/rust/src/hash256.rs
new file mode 100644
index 0000000..e2aca06
--- /dev/null
+++ b/version22/rust/src/hash256.rs
@@ -0,0 +1,182 @@
+/*
+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.
+*/
+
+const HASH256_H0: u32=0x6A09E667;
+const HASH256_H1: u32=0xBB67AE85;
+const HASH256_H2: u32=0x3C6EF372;
+const HASH256_H3: u32=0xA54FF53A;
+const HASH256_H4: u32=0x510E527F;
+const HASH256_H5: u32=0x9B05688C;
+const HASH256_H6: u32=0x1F83D9AB;
+const HASH256_H7: u32=0x5BE0CD19;
+
+const HASH256_K : [u32;64]=[
+       
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
+       
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
+       
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
+       
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
+       
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
+       
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
+       
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
+       
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2];
+
+
+pub struct HASH256 {
+       length: [u32;2],
+       h: [u32;8],
+       w: [u32;64]
+}
+
+impl HASH256 {
+       fn s(n: u32,x: u32) -> u32 {
+               return ((x)>>n) | ((x)<<(32-n));
+       }
+       fn r(n: u32,x: u32) -> u32 {
+               return (x)>>n;
+       }
+
+       fn ch(x: u32,y: u32,z: u32) -> u32 {
+               return (x&y)^(!(x)&z);
+       }
+
+       fn maj(x: u32,y: u32,z: u32) -> u32 {
+               return (x&y)^(x&z)^(y&z);
+       }
+       fn sig0(x: u32) -> u32 {
+               return HASH256::s(2,x)^HASH256::s(13,x)^HASH256::s(22,x);
+       }
+
+       fn sig1(x: u32) -> u32 {
+               return HASH256::s(6,x)^HASH256::s(11,x)^HASH256::s(25,x);
+       }
+
+       fn theta0(x: u32) -> u32 {
+               return HASH256::s(7,x)^HASH256::s(18,x)^HASH256::r(3,x);
+       }
+
+       fn theta1(x: u32) -> u32 {
+               return HASH256::s(17,x)^HASH256::s(19,x)^HASH256::r(10,x);
+       }
+
+       fn transform(&mut self) { /* basic transformation step */
+               for j in 16..64 {
+                       
self.w[j]=HASH256::theta1(self.w[j-2]).wrapping_add(self.w[j-7]).wrapping_add(HASH256::theta0(self.w[j-15])).wrapping_add(self.w[j-16]);
+               }
+               let mut a=self.h[0]; let mut b=self.h[1]; let mut c=self.h[2]; 
let mut d=self.h[3];
+               let mut e=self.h[4]; let mut f=self.h[5]; let mut g=self.h[6]; 
let mut hh=self.h[7];
+               for j in 0..64 { /* 64 times - mush it up */
+                       let 
t1=hh.wrapping_add(HASH256::sig1(e)).wrapping_add(HASH256::ch(e,f,g)).wrapping_add(HASH256_K[j]).wrapping_add(self.w[j]);
+                       let 
t2=HASH256::sig0(a).wrapping_add(HASH256::maj(a,b,c));
+                       hh=g; g=f; f=e;
+                       e=d.wrapping_add(t1);
+                       d=c;
+                       c=b;
+                       b=a;
+                       a=t1.wrapping_add(t2);
+               }
+               self.h[0] = self.h[0].wrapping_add(a);
+               self.h[1] = self.h[1].wrapping_add(b);
+               self.h[2] = self.h[2].wrapping_add(c);
+               self.h[3] = self.h[3].wrapping_add(d);
+               self.h[4] = self.h[4].wrapping_add(e);
+               self.h[5] = self.h[5].wrapping_add(f);
+               self.h[6] = self.h[6].wrapping_add(g);
+               self.h[7] = self.h[7].wrapping_add(hh);
+       }
+
+/* Initialise Hash function */
+       pub fn init(&mut self) { /* initialise */
+               for i in 0..64 {self.w[i]=0}
+               self.length[0]=0; self.length[1]=0;
+               self.h[0]=HASH256_H0;
+               self.h[1]=HASH256_H1;
+               self.h[2]=HASH256_H2;
+               self.h[3]=HASH256_H3;
+               self.h[4]=HASH256_H4;
+               self.h[5]=HASH256_H5;
+               self.h[6]=HASH256_H6;
+               self.h[7]=HASH256_H7;
+       }       
+
+       pub fn new() -> HASH256 {
+               let mut nh=HASH256 {
+                       length: [0;2],
+                       h: [0;8],
+                       w: [0;64]
+               };
+               nh.init();
+               return nh;
+       }
+
+/* process a single byte */
+       pub fn process(&mut self,byt: u8) { /* process the next message byte */
+               let cnt=((self.length[0]/32)%16) as usize;
+               self.w[cnt]<<=8;
+               self.w[cnt]|=(byt&0xFF) as u32;
+               self.length[0]+=8;
+               if self.length[0]==0 {self.length[1]+=1; self.length[0]=0}
+               if (self.length[0]%512)==0 {self.transform()}
+       }
+
+/* process an array of bytes */        
+       pub fn process_array(&mut self,b: &[u8]) {
+               for i in 0..b.len() {self.process((b[i]))}
+       }
+
+/* process a 32-bit integer */
+       pub fn process_num(&mut self,n: i32) {
+               self.process(((n>>24)&0xff) as u8);
+               self.process(((n>>16)&0xff) as u8);
+               self.process(((n>>8)&0xff) as u8);
+               self.process((n&0xff) as u8);
+       }
+
+/* Generate 32-byte Hash */
+       pub fn hash(&mut self) -> [u8;32] { /* pad message and finish - supply 
digest */
+               let mut digest:[u8;32]=[0;32];
+               let len0=self.length[0];
+               let len1=self.length[1];
+               self.process(0x80);
+               while (self.length[0]%512)!=448 {self.process(0)}
+               self.w[14]=len1;
+               self.w[15]=len0;    
+               self.transform();
+               for i in 0..32 { /* convert to bytes */
+                       digest[i]=((self.h[i/4]>>(8*(3-i%4))) & 0xff) as u8;
+               }
+               self.init();
+               return digest;
+       }
+}
+
+//248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1
+/*
+fn main() {
+       let s = 
String::from("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");       
+       let test = s.into_bytes();
+       let mut sh=HASH256::new();
+
+       for i in 0..test.len(){
+               sh.process(test[i]);
+       }
+               
+       let digest=sh.hash();    
+       for i in 0..32 {print!("{:02x}",digest[i])}
+}
+*/

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/rust/src/hash384.rs
----------------------------------------------------------------------
diff --git a/version22/rust/src/hash384.rs b/version22/rust/src/hash384.rs
new file mode 100644
index 0000000..0bb8546
--- /dev/null
+++ b/version22/rust/src/hash384.rs
@@ -0,0 +1,188 @@
+/*
+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.
+*/
+
+const HASH384_H0: u64=0xcbbb9d5dc1059ed8;
+const HASH384_H1: u64=0x629a292a367cd507;
+const HASH384_H2: u64=0x9159015a3070dd17;
+const HASH384_H3: u64=0x152fecd8f70e5939;
+const HASH384_H4: u64=0x67332667ffc00b31;
+const HASH384_H5: u64=0x8eb44a8768581511;
+const HASH384_H6: u64=0xdb0c2e0d64f98fa7;
+const HASH384_H7: u64=0x47b5481dbefa4fa4;
+
+const HASH384_K : [u64;80]=[
+       
0x428a2f98d728ae22,0x7137449123ef65cd,0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc,
+       
0x3956c25bf348b538,0x59f111f1b605d019,0x923f82a4af194f9b,0xab1c5ed5da6d8118,
+       
0xd807aa98a3030242,0x12835b0145706fbe,0x243185be4ee4b28c,0x550c7dc3d5ffb4e2,
+       
0x72be5d74f27b896f,0x80deb1fe3b1696b1,0x9bdc06a725c71235,0xc19bf174cf692694,
+       
0xe49b69c19ef14ad2,0xefbe4786384f25e3,0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65,
+       
0x2de92c6f592b0275,0x4a7484aa6ea6e483,0x5cb0a9dcbd41fbd4,0x76f988da831153b5,
+       
0x983e5152ee66dfab,0xa831c66d2db43210,0xb00327c898fb213f,0xbf597fc7beef0ee4,
+       
0xc6e00bf33da88fc2,0xd5a79147930aa725,0x06ca6351e003826f,0x142929670a0e6e70,
+       
0x27b70a8546d22ffc,0x2e1b21385c26c926,0x4d2c6dfc5ac42aed,0x53380d139d95b3df,
+       
0x650a73548baf63de,0x766a0abb3c77b2a8,0x81c2c92e47edaee6,0x92722c851482353b,
+       
0xa2bfe8a14cf10364,0xa81a664bbc423001,0xc24b8b70d0f89791,0xc76c51a30654be30,
+       
0xd192e819d6ef5218,0xd69906245565a910,0xf40e35855771202a,0x106aa07032bbd1b8,
+       
0x19a4c116b8d2d0c8,0x1e376c085141ab53,0x2748774cdf8eeb99,0x34b0bcb5e19b48a8,
+       
0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb,0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3,
+       
0x748f82ee5defb2fc,0x78a5636f43172f60,0x84c87814a1f0ab72,0x8cc702081a6439ec,
+       
0x90befffa23631e28,0xa4506cebde82bde9,0xbef9a3f7b2c67915,0xc67178f2e372532b,
+       
0xca273eceea26619c,0xd186b8c721c0c207,0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178,
+       
0x06f067aa72176fba,0x0a637dc5a2c898a6,0x113f9804bef90dae,0x1b710b35131c471b,
+       
0x28db77f523047d84,0x32caab7b40c72493,0x3c9ebe0a15c9bebc,0x431d67c49c100d4c,
+       
0x4cc5d4becb3e42b6,0x597f299cfc657e2a,0x5fcb6fab3ad6faec,0x6c44198c4a475817];
+
+
+pub struct HASH384 {
+       length: [u64;2],
+       h: [u64;8],
+       w: [u64;80]
+}
+
+impl HASH384 {
+       fn s(n: u64,x: u64) -> u64 {
+               return ((x)>>n) | ((x)<<(64-n));
+       }
+       fn r(n: u64,x: u64) -> u64 {
+               return (x)>>n;
+       }
+
+       fn ch(x: u64,y: u64,z: u64) -> u64 {
+               return (x&y)^(!(x)&z);
+       }
+
+       fn maj(x: u64,y: u64,z: u64) -> u64 {
+               return (x&y)^(x&z)^(y&z);
+       }
+
+       fn sig0(x: u64) -> u64 {
+               return HASH384::s(28,x)^HASH384::s(34,x)^HASH384::s(39,x);
+       }
+
+       fn sig1(x: u64) -> u64 {
+               return HASH384::s(14,x)^HASH384::s(18,x)^HASH384::s(41,x);
+       }
+
+       fn theta0(x: u64) -> u64 {
+               return HASH384::s(1,x)^HASH384::s(8,x)^HASH384::r(7,x);
+       }
+
+       fn theta1(x: u64) -> u64 {
+               return HASH384::s(19,x)^HASH384::s(61,x)^HASH384::r(6,x);
+       }
+
+       fn transform(&mut self) { /* basic transformation step */
+               for j in 16..80 {
+                       
self.w[j]=HASH384::theta1(self.w[j-2])+self.w[j-7]+HASH384::theta0(self.w[j-15])+self.w[j-16];
+               }
+               let mut a=self.h[0]; let mut b=self.h[1]; let mut c=self.h[2]; 
let mut d=self.h[3]; 
+               let mut e=self.h[4]; let mut f=self.h[5]; let mut g=self.h[6]; 
let mut hh=self.h[7];
+               for j in 0..80 { /* 64 times - mush it up */
+                       let 
t1=hh+HASH384::sig1(e)+HASH384::ch(e,f,g)+HASH384_K[j]+self.w[j];
+                       let t2=HASH384::sig0(a)+HASH384::maj(a,b,c);
+                       hh=g; g=f; f=e;
+                       e=d+t1;
+                       d=c;
+                       c=b;
+                       b=a;
+                       a=t1+t2 ; 
+               }
+               self.h[0]+=a; self.h[1]+=b; self.h[2]+=c; self.h[3]+=d;
+               self.h[4]+=e; self.h[5]+=f; self.h[6]+=g; self.h[7]+=hh; 
+       }       
+
+/* Initialise Hash function */
+       pub fn init(&mut self) { /* initialise */
+               for i in 0..64 {self.w[i]=0}
+               self.length[0]=0; self.length[1]=0;
+               self.h[0]=HASH384_H0;
+               self.h[1]=HASH384_H1;
+               self.h[2]=HASH384_H2;
+               self.h[3]=HASH384_H3;
+               self.h[4]=HASH384_H4;
+               self.h[5]=HASH384_H5;
+               self.h[6]=HASH384_H6;
+               self.h[7]=HASH384_H7;
+       }       
+
+       pub fn new() -> HASH384 {
+               let mut nh=HASH384 {
+                       length: [0;2],
+                       h: [0;8],
+                       w: [0;80]
+               };
+               nh.init();
+               return nh;
+       }
+
+/* process a single byte */
+       pub fn process(&mut self,byt: u8) { /* process the next message byte */
+               let cnt=((self.length[0]/64)%16) as usize;
+               self.w[cnt]<<=8;
+               self.w[cnt]|=(byt&0xFF) as u64;
+               self.length[0]+=8;
+               if self.length[0]==0 {self.length[1]+=1; self.length[0]=0}
+               if (self.length[0]%1024)==0 {self.transform()}
+       }
+
+/* process an array of bytes */        
+       pub fn process_array(&mut self,b: &[u8]) {
+               for i in 0..b.len() {self.process((b[i]))}
+       }
+
+/* process a 32-bit integer */
+       pub fn process_num(&mut self,n: i32) {
+               self.process(((n>>24)&0xff) as u8);
+               self.process(((n>>16)&0xff) as u8);
+               self.process(((n>>8)&0xff) as u8);
+               self.process((n&0xff) as u8);
+       }
+
+/* Generate 48-byte Hash */
+       pub fn hash(&mut self) -> [u8;48] { /* pad message and finish - supply 
digest */
+               let mut digest:[u8;48]=[0;48];
+               let len0=self.length[0];
+               let len1=self.length[1];
+               self.process(0x80);
+               while (self.length[0]%1024)!=896 {self.process(0)}
+               self.w[14]=len1;
+               self.w[15]=len0;    
+               self.transform();
+               for i in 0..48 { /* convert to bytes */
+                       digest[i]=((self.h[i/8]>>(8*(7-i%8))) & 0xff) as u8;
+               }
+               self.init();
+               return digest;
+       }
+}
+
+//09330c33f71147e8 3d192fc782cd1b47 53111b173b3b05d2 2fa08086e3b0f712 
fcc7c71a557e2db9 66c3e9fa91746039
+/*
+fn main() {
+       let s = 
String::from("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
       
+       let test = s.into_bytes();
+       let mut sh=HASH384::new();
+
+       for i in 0..test.len(){
+               sh.process(test[i]);
+       }
+               
+       let digest=sh.hash();    
+       for i in 0..48 {print!("{:02x}",digest[i])}
+} */

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/rust/src/hash512.rs
----------------------------------------------------------------------
diff --git a/version22/rust/src/hash512.rs b/version22/rust/src/hash512.rs
new file mode 100644
index 0000000..a345781
--- /dev/null
+++ b/version22/rust/src/hash512.rs
@@ -0,0 +1,189 @@
+/*
+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.
+*/
+
+
+const HASH512_H0: u64=0x6a09e667f3bcc908;
+const HASH512_H1: u64=0xbb67ae8584caa73b;
+const HASH512_H2: u64=0x3c6ef372fe94f82b;
+const HASH512_H3: u64=0xa54ff53a5f1d36f1;
+const HASH512_H4: u64=0x510e527fade682d1;
+const HASH512_H5: u64=0x9b05688c2b3e6c1f;
+const HASH512_H6: u64=0x1f83d9abfb41bd6b;
+const HASH512_H7: u64=0x5be0cd19137e2179;
+
+const HASH512_K : [u64;80]=[
+       
0x428a2f98d728ae22,0x7137449123ef65cd,0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc,
+       
0x3956c25bf348b538,0x59f111f1b605d019,0x923f82a4af194f9b,0xab1c5ed5da6d8118,
+       
0xd807aa98a3030242,0x12835b0145706fbe,0x243185be4ee4b28c,0x550c7dc3d5ffb4e2,
+       
0x72be5d74f27b896f,0x80deb1fe3b1696b1,0x9bdc06a725c71235,0xc19bf174cf692694,
+       
0xe49b69c19ef14ad2,0xefbe4786384f25e3,0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65,
+       
0x2de92c6f592b0275,0x4a7484aa6ea6e483,0x5cb0a9dcbd41fbd4,0x76f988da831153b5,
+       
0x983e5152ee66dfab,0xa831c66d2db43210,0xb00327c898fb213f,0xbf597fc7beef0ee4,
+       
0xc6e00bf33da88fc2,0xd5a79147930aa725,0x06ca6351e003826f,0x142929670a0e6e70,
+       
0x27b70a8546d22ffc,0x2e1b21385c26c926,0x4d2c6dfc5ac42aed,0x53380d139d95b3df,
+       
0x650a73548baf63de,0x766a0abb3c77b2a8,0x81c2c92e47edaee6,0x92722c851482353b,
+       
0xa2bfe8a14cf10364,0xa81a664bbc423001,0xc24b8b70d0f89791,0xc76c51a30654be30,
+       
0xd192e819d6ef5218,0xd69906245565a910,0xf40e35855771202a,0x106aa07032bbd1b8,
+       
0x19a4c116b8d2d0c8,0x1e376c085141ab53,0x2748774cdf8eeb99,0x34b0bcb5e19b48a8,
+       
0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb,0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3,
+       
0x748f82ee5defb2fc,0x78a5636f43172f60,0x84c87814a1f0ab72,0x8cc702081a6439ec,
+       
0x90befffa23631e28,0xa4506cebde82bde9,0xbef9a3f7b2c67915,0xc67178f2e372532b,
+       
0xca273eceea26619c,0xd186b8c721c0c207,0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178,
+       
0x06f067aa72176fba,0x0a637dc5a2c898a6,0x113f9804bef90dae,0x1b710b35131c471b,
+       
0x28db77f523047d84,0x32caab7b40c72493,0x3c9ebe0a15c9bebc,0x431d67c49c100d4c,
+       
0x4cc5d4becb3e42b6,0x597f299cfc657e2a,0x5fcb6fab3ad6faec,0x6c44198c4a475817];
+
+
+pub struct HASH512 {
+       length: [u64;2],
+       h: [u64;8],
+       w: [u64;80]
+}
+
+impl HASH512 {
+       fn s(n: u64,x: u64) -> u64 {
+               return ((x)>>n) | ((x)<<(64-n));
+       }
+       fn r(n: u64,x: u64) -> u64 {
+               return (x)>>n;
+       }
+
+       fn ch(x: u64,y: u64,z: u64) -> u64 {
+               return (x&y)^(!(x)&z);
+       }
+
+       fn maj(x: u64,y: u64,z: u64) -> u64 {
+               return (x&y)^(x&z)^(y&z);
+       }
+
+       fn sig0(x: u64) -> u64 {
+               return HASH512::s(28,x)^HASH512::s(34,x)^HASH512::s(39,x);
+       }
+
+       fn sig1(x: u64) -> u64 {
+               return HASH512::s(14,x)^HASH512::s(18,x)^HASH512::s(41,x);
+       }
+
+       fn theta0(x: u64) -> u64 {
+               return HASH512::s(1,x)^HASH512::s(8,x)^HASH512::r(7,x);
+       }
+
+       fn theta1(x: u64) -> u64 {
+               return HASH512::s(19,x)^HASH512::s(61,x)^HASH512::r(6,x);
+       }
+
+       fn transform(&mut self) { /* basic transformation step */
+               for j in 16..80 {
+                       
self.w[j]=HASH512::theta1(self.w[j-2])+self.w[j-7]+HASH512::theta0(self.w[j-15])+self.w[j-16];
+               }
+               let mut a=self.h[0]; let mut b=self.h[1]; let mut c=self.h[2]; 
let mut d=self.h[3]; 
+               let mut e=self.h[4]; let mut f=self.h[5]; let mut g=self.h[6]; 
let mut hh=self.h[7];
+               for j in 0..80 { /* 64 times - mush it up */
+                       let 
t1=hh+HASH512::sig1(e)+HASH512::ch(e,f,g)+HASH512_K[j]+self.w[j];
+                       let t2=HASH512::sig0(a)+HASH512::maj(a,b,c);
+                       hh=g; g=f; f=e;
+                       e=d+t1;
+                       d=c;
+                       c=b;
+                       b=a;
+                       a=t1+t2 ; 
+               }
+               self.h[0]+=a; self.h[1]+=b; self.h[2]+=c; self.h[3]+=d;
+               self.h[4]+=e; self.h[5]+=f; self.h[6]+=g; self.h[7]+=hh; 
+       }       
+
+/* Initialise Hash function */
+       pub fn init(&mut self) { /* initialise */
+               for i in 0..64 {self.w[i]=0}
+               self.length[0]=0; self.length[1]=0;
+               self.h[0]=HASH512_H0;
+               self.h[1]=HASH512_H1;
+               self.h[2]=HASH512_H2;
+               self.h[3]=HASH512_H3;
+               self.h[4]=HASH512_H4;
+               self.h[5]=HASH512_H5;
+               self.h[6]=HASH512_H6;
+               self.h[7]=HASH512_H7;
+       }       
+
+       pub fn new() -> HASH512 {
+               let mut nh=HASH512 {
+                       length: [0;2],
+                       h: [0;8],
+                       w: [0;80]
+               };
+               nh.init();
+               return nh;
+       }
+
+/* process a single byte */
+       pub fn process(&mut self,byt: u8) { /* process the next message byte */
+               let cnt=((self.length[0]/64)%16) as usize;
+               self.w[cnt]<<=8;
+               self.w[cnt]|=(byt&0xFF) as u64;
+               self.length[0]+=8;
+               if self.length[0]==0 {self.length[1]+=1; self.length[0]=0}
+               if (self.length[0]%1024)==0 {self.transform()}
+       }
+
+/* process an array of bytes */        
+       pub fn process_array(&mut self,b: &[u8]) {
+               for i in 0..b.len() {self.process((b[i]))}
+       }
+
+/* process a 32-bit integer */
+       pub fn process_num(&mut self,n: i32) {
+               self.process(((n>>24)&0xff) as u8);
+               self.process(((n>>16)&0xff) as u8);
+               self.process(((n>>8)&0xff) as u8);
+               self.process((n&0xff) as u8);
+       }
+
+/* Generate 32-byte Hash */
+       pub fn hash(&mut self) -> [u8;64] { /* pad message and finish - supply 
digest */
+               let mut digest:[u8;64]=[0;64];
+               let len0=self.length[0];
+               let len1=self.length[1];
+               self.process(0x80);
+               while (self.length[0]%1024)!=896 {self.process(0)}
+               self.w[14]=len1;
+               self.w[15]=len0;    
+               self.transform();
+               for i in 0..64 { /* convert to bytes */
+                       digest[i]=((self.h[i/8]>>(8*(7-i%8))) & 0xff) as u8;
+               }
+               self.init();
+               return digest;
+       }
+}
+
+//8e959b75dae313da 8cf4f72814fc143f 8f7779c6eb9f7fa1 7299aeadb6889018 
501d289e4900f7e4 331b99dec4b5433a c7d329eeb6dd2654 5e96e55b874be909
+/*
+fn main() {
+       let s = 
String::from("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
       
+       let test = s.into_bytes();
+       let mut sh=HASH512::new();
+
+       for i in 0..test.len(){
+               sh.process(test[i]);
+       }
+               
+       let digest=sh.hash();    
+       for i in 0..64 {print!("{:02x}",digest[i])}
+} */

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/rust/src/lib.rs
----------------------------------------------------------------------
diff --git a/version22/rust/src/lib.rs b/version22/rust/src/lib.rs
new file mode 100644
index 0000000..db9c412
--- /dev/null
+++ b/version22/rust/src/lib.rs
@@ -0,0 +1,36 @@
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+pub mod aes;
+pub mod big;
+pub mod dbig;
+pub mod ecdh;
+pub mod ecp;
+pub mod ecp2;
+pub mod ff;
+pub mod fp;
+pub mod fp2;
+pub mod fp4;
+pub mod fp12;
+pub mod pair;
+pub mod mpin;
+pub mod rand;
+pub mod hash256;
+pub mod hash384;
+pub mod hash512;
+pub mod rsa;
+
+#[cfg(target_pointer_width = "32")]
+#[path = "rom32.rs"]
+pub mod rom;
+
+#[cfg(target_pointer_width = "64")]
+#[path = "rom64.rs"]
+pub mod rom;
+
+#[cfg(test)]
+mod tests {
+    #[test]
+    fn it_works() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/rust/src/mpin.rs
----------------------------------------------------------------------
diff --git a/version22/rust/src/mpin.rs b/version22/rust/src/mpin.rs
new file mode 100644
index 0000000..8644d1a
--- /dev/null
+++ b/version22/rust/src/mpin.rs
@@ -0,0 +1,768 @@
+/*
+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.
+*/
+
+use std::time::{SystemTime};
+use std::time::UNIX_EPOCH;
+
+use ecp::ECP;
+use fp2::FP2;
+use ecp2::ECP2;
+use fp4::FP4;
+use fp12::FP12;
+use big::BIG;
+use rand::RAND;
+use hash256::HASH256;
+use hash384::HASH384;
+use hash512::HASH512;
+use pair;
+use rom;
+
+/* MPIN API Functions */
+
+/* Configure mode of operation */
+
+pub const PERMITS:bool=true;
+pub const PINERROR:bool=true;
+pub const FULL: bool=true;
+pub const SINGLE_PASS:bool=false;
+
+pub const EFS: usize=rom::MODBYTES as usize;
+pub const EGS: usize=rom::MODBYTES as usize;
+pub const PAS: usize=16;
+pub const BAD_PARAMS: isize=-11;
+pub const INVALID_POINT: isize=-14;
+pub const WRONG_ORDER: isize=-18;
+pub const BAD_PIN: isize=-19;
+pub const SHA256: usize=32;
+pub const SHA384: usize=48;
+pub const SHA512: usize=64;
+
+/* Configure your PIN here */
+
+pub const MAXPIN: i32=10000;  /* PIN less than this */
+pub const PBLEN: i32=14;      /* Number of bits in PIN */
+pub const TS: usize=10;         /* 10 for 4 digit PIN, 14 for 6-digit PIN - 
2^TS/TS approx = sqrt(MAXPIN) */
+pub const TRAP:usize=200;      /* 200 for 4 digit PIN, 2000 for 6-digit PIN  - 
approx 2*sqrt(MAXPIN) */
+
+pub const HASH_TYPE: usize=SHA256;
+
+#[allow(non_snake_case)]
+fn hash(sha: usize,c: &mut FP4,U: &mut ECP,r: &mut [u8]) -> bool {
+       let mut w:[u8;EFS]=[0;EFS];
+       let mut t:[u8;6*EFS]=[0;6*EFS];
+
+       c.geta().geta().tobytes(&mut w); for i in 0..EFS {t[i]=w[i]}
+       c.geta().getb().tobytes(&mut w); for i in EFS..2*EFS {t[i]=w[i-EFS]}
+       c.getb().geta().tobytes(&mut w); for i in 2*EFS..3*EFS {t[i]=w[i-2*EFS]}
+       c.getb().getb().tobytes(&mut w); for i in 3*EFS..4*EFS {t[i]=w[i-3*EFS]}
+
+       U.getx().tobytes(&mut w); for i in 4*EFS..5*EFS {t[i]=w[i-4*EFS]}
+       U.gety().tobytes(&mut w); for i in 5*EFS..6*EFS {t[i]=w[i-5*EFS]}
+
+       if sha==SHA256 {
+               let mut h=HASH256::new();
+               h.process_array(&t);
+               let sh=h.hash();
+               for i in 0..PAS {r[i]=sh[i]}    
+               return true;    
+       }
+       if sha==SHA384 {
+               let mut h=HASH384::new();
+               h.process_array(&t);
+               let sh=h.hash();
+               for i in 0..PAS {r[i]=sh[i]}            
+               return true;
+       }
+       if sha==SHA512 {
+               let mut h=HASH512::new();
+               h.process_array(&t);
+               let sh=h.hash();
+               for i in 0..PAS {r[i]=sh[i]}
+               return true;            
+       }
+       return false;
+
+}
+
+/* Hash number (optional) and string to point on curve */
+
+fn hashit(sha: usize,n: usize,id: &[u8],w: &mut [u8]) -> bool {
+       let mut r:[u8;64]=[0;64];
+       let mut didit=false;
+       if sha==SHA256 {
+               let mut h=HASH256::new();
+               if n>0 {h.process_num(n as i32)}
+               h.process_array(id);
+        let hs=h.hash();       
+        for i in 0..sha {r[i]=hs[i];}  
+        didit=true;
+       }
+       if sha==SHA384 {
+               let mut h=HASH384::new();
+               if n>0 {h.process_num(n as i32)}
+               h.process_array(id);
+               let hs=h.hash();
+        for i in 0..sha {r[i]=hs[i];}                  
+               didit=true;
+       }
+       if sha==SHA512 {
+               let mut h=HASH512::new();
+               if n>0 {h.process_num(n as i32)}
+               h.process_array(id);
+               let hs=h.hash();
+        for i in 0..sha {r[i]=hs[i];}  
+        didit=true;            
+       }
+       if !didit {return false}
+
+       let rm=rom::MODBYTES as usize;
+
+       if sha>rm {
+               for i in 0..rm {w[i]=r[i]}
+       } else {
+               for i in 0..sha {w[i]=r[i]}     
+               for i in sha..rm {w[i]=0}
+       }
+
+       return true;
+}
+
+#[allow(non_snake_case)]
+fn mapit(h: &[u8]) -> ECP {
+       let mut q=BIG::new_ints(&rom::MODULUS);
+       let mut x=BIG::frombytes(h);
+       x.rmod(&mut q);
+       let mut P:ECP;
+
+       loop {
+               P=ECP::new_bigint(&x,0);
+               if !P.is_infinity() {break}
+               x.inc(1); x.norm();
+       }
+       if rom::CURVE_PAIRING_TYPE!=rom::BN_CURVE {
+               let mut c=BIG::new_ints(&rom::CURVE_COF);
+               P=P.mul(&mut c);
+       }       
+       return P;
+}
+
+/* return time in slots since epoch */
+pub fn today() -> usize {
+       return 
(SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs()/(60*1440)) as 
usize;
+}
+
+/* these next two functions help to implement elligator squared - 
http://eprint.iacr.org/2014/043 */
+/* maps a random u to a point on the curve */
+#[allow(non_snake_case)]
+fn emap(u: &BIG,cb: isize) -> ECP {
+       let mut P:ECP;
+       let mut x=BIG::new_copy(u);
+       let mut p=BIG::new_ints(&rom::MODULUS);
+       x.rmod(&mut p);
+       loop {
+               P=ECP::new_bigint(&x,cb);
+               if !P.is_infinity() {break}
+               x.inc(1);  x.norm();
+       }
+       return P;
+}
+
+/* returns u derived from P. Random value in range 1 to return value should 
then be added to u */
+#[allow(non_snake_case)]
+fn unmap(u: &mut BIG,P: &mut ECP) -> isize {
+       let s=P.gets();
+       let mut R:ECP;
+       let mut r=0;
+       let x=P.getx();
+       u.copy(&x);
+       loop {
+               u.dec(1); u.norm();
+               r+=1;
+               R=ECP::new_bigint(u,s);
+               if !R.is_infinity() {break}
+       }
+       return r as isize;
+}
+
+pub fn hash_id(sha: usize,id: &[u8],w: &mut [u8]) -> bool {
+       return hashit(sha,0,id,w);
+}
+
+/* these next two functions implement elligator squared - 
http://eprint.iacr.org/2014/043 */
+/* Elliptic curve point E in format (0x04,x,y} is converted to form {0x0-,u,v} 
*/
+/* Note that u and v are indistinguisible from random strings */
+#[allow(non_snake_case)]
+pub fn encoding(rng: &mut RAND,e: &mut [u8]) ->isize {
+       let mut t:[u8;EFS]=[0;EFS];
+
+       for i in 0..EFS {t[i]=e[i+1]}
+       let mut u=BIG::frombytes(&t);
+       for i in 0..EFS {t[i]=e[i+EFS+1]}
+       let mut v=BIG::frombytes(&t);
+               
+       let mut P=ECP::new_bigs(&u,&v);
+       if P.is_infinity() {return INVALID_POINT}
+
+       let p=BIG::new_ints(&rom::MODULUS);
+       u=BIG::randomnum(&p,rng);
+
+       let mut su=rng.getbyte() as isize; /*if (su<0) su=-su;*/ su%=2;
+               
+       let mut W=emap(&mut u,su);
+       P.sub(&mut W);
+       let sv=P.gets();
+       let rn=unmap(&mut v,&mut P);
+       let mut m=rng.getbyte() as isize; /*if (m<0) m=-m;*/ m%=rn;
+       v.inc(m+1);
+       e[0]=(su+2*sv) as u8;
+       u.tobytes(&mut t);
+       for i in 0..EFS {e[i+1]=t[i]}
+       v.tobytes(&mut t);
+       for i in 0..EFS {e[i+EFS+1]=t[i]}               
+               
+       return 0;
+}
+
+#[allow(non_snake_case)]
+pub fn decoding(d: &mut [u8]) -> isize {
+       let mut t:[u8;EFS]=[0;EFS];
+
+       if (d[0]&0x04)!=0 {return INVALID_POINT}
+
+       for i in 0..EFS {t[i]=d[i+1]}
+       let mut u=BIG::frombytes(&t);
+       for i in 0..EFS {t[i]=d[i+EFS+1]}
+       let mut v=BIG::frombytes(&t);
+
+       let su=(d[0]&1) as isize;
+       let sv=((d[0]>>1)&1) as isize;
+       let mut W=emap(&mut u,su);
+       let mut P=emap(&mut v,sv);
+       P.add(&mut W);
+       u=P.getx();
+       v=P.gety();
+       d[0]=0x04;
+       u.tobytes(&mut t);
+       for i in 0..EFS {d[i+1]=t[i]}
+       v.tobytes(&mut t);
+       for i in 0..EFS {d[i+EFS+1]=t[i]}               
+               
+       return 0;
+}
+
+/* R=R1+R2 in group G1 */
+#[allow(non_snake_case)]
+pub fn recombine_g1(r1: &[u8],r2: &[u8],r: &mut [u8]) -> isize {
+       let mut P=ECP::frombytes(&r1);
+       let mut Q=ECP::frombytes(&r2);
+
+       if P.is_infinity() || Q.is_infinity() {return INVALID_POINT}
+
+       P.add(&mut Q);
+
+       P.tobytes(r);
+       return 0;
+}
+
+/* W=W1+W2 in group G2 */
+#[allow(non_snake_case)]
+pub fn recombine_g2(w1: &[u8],w2: &[u8],w: &mut [u8]) -> isize {
+       let mut P=ECP2::frombytes(&w1);
+       let mut Q=ECP2::frombytes(&w2);
+
+       if P.is_infinity() || Q.is_infinity() {return INVALID_POINT}
+
+       P.add(&mut Q);
+       
+       P.tobytes(w);
+       return 0;
+}
+       
+/* create random secret S */
+pub fn random_generate(rng: &mut RAND,s: &mut [u8]) -> isize {
+       let r=BIG::new_ints(&rom::CURVE_ORDER);
+       let mut sc=BIG::randomnum(&r,rng);
+       if rom::AES_S>0 {
+               sc.mod2m(2*rom::AES_S);
+       }               
+       sc.tobytes(s);
+       return 0;
+}
+
+/* Extract Server Secret SST=S*Q where Q is fixed generator in G2 and S is 
master secret */
+#[allow(non_snake_case)]
+pub fn get_server_secret(s: &[u8],sst: &mut [u8]) -> isize {
+
+       let mut 
Q=ECP2::new_fp2s(&FP2::new_bigs(&BIG::new_ints(&rom::CURVE_PXA),&BIG::new_ints(&rom::CURVE_PXB)),&FP2::new_bigs(&BIG::new_ints(&rom::CURVE_PYA),&BIG::new_ints(&rom::CURVE_PYB)));
+
+       let mut sc=BIG::frombytes(s);
+       Q=pair::g2mul(&mut Q,&mut sc);
+       Q.tobytes(sst);
+       return 0;
+}
+
+/*
+ W=x*H(G);
+ if RNG == NULL then X is passed in 
+ if RNG != NULL the X is passed out 
+ if type=0 W=x*G where G is point on the curve, else W=x*M(G), where M(G) is 
mapping of octet G to point on the curve
+*/
+#[allow(non_snake_case)]
+pub fn get_g1_multiple(rng: Option<&mut RAND>,typ: usize,x: &mut [u8],g: 
&[u8],w: &mut [u8]) -> isize {
+       let mut sx:BIG;
+       let r=BIG::new_ints(&rom::CURVE_ORDER);
+
+       if let Some(mut rd)=rng
+       {
+               sx=BIG::randomnum(&r,rd);
+               if rom::AES_S>0 {
+                       sx.mod2m(2*rom::AES_S);
+               }
+               sx.tobytes(x);
+       } else {
+               sx=BIG::frombytes(x);
+       }
+       let mut P:ECP;
+
+       if typ==0 {
+               P=ECP::frombytes(g);
+               if P.is_infinity() {return INVALID_POINT}
+       } else {
+               P=mapit(g)
+       }
+
+
+
+       pair::g1mul(&mut P,&mut sx).tobytes(w);
+       return 0;
+}
+
+
+/* Client secret CST=S*H(CID) where CID is client ID and S is master secret */
+/* CID is hashed externally */
+pub fn get_client_secret(s: &mut [u8],cid: &[u8],cst: &mut [u8]) -> isize {
+       return get_g1_multiple(None,1,s,cid,cst);
+}
+
+/* Extract PIN from TOKEN for identity CID */
+#[allow(non_snake_case)]
+pub fn extract_pin(sha: usize,cid: &[u8],pin: i32,token: &mut [u8]) -> isize {
+       let mut P=ECP::frombytes(&token);
+       const RM:usize=rom::MODBYTES as usize;
+       let mut h:[u8;RM]=[0;RM];
+       if P.is_infinity() {return INVALID_POINT}
+       hashit(sha,0,cid,&mut h);
+       let mut R=mapit(&h);
+
+       R=R.pinmul(pin%MAXPIN,PBLEN);
+       P.sub(&mut R);
+
+       P.tobytes(token);
+
+       return 0;
+}
+
+/* Functions to support M-Pin Full */
+#[allow(non_snake_case)]
+pub fn precompute(token: &[u8],cid: &[u8],g1: &mut [u8],g2: &mut [u8]) -> 
isize {
+       let mut T=ECP::frombytes(&token);
+       if T.is_infinity() {return INVALID_POINT} 
+
+       let mut P=mapit(&cid);
+
+       let mut 
Q=ECP2::new_fp2s(&FP2::new_bigs(&BIG::new_ints(&rom::CURVE_PXA),&BIG::new_ints(&rom::CURVE_PXB)),&FP2::new_bigs(&BIG::new_ints(&rom::CURVE_PYA),&BIG::new_ints(&rom::CURVE_PYB)));
+
+       let mut g=pair::ate(&mut Q,&mut T);
+       g=pair::fexp(&g);
+       g.tobytes(g1);
+
+       g=pair::ate(&mut Q,&mut P);
+       g=pair::fexp(&g);
+       g.tobytes(g2);
+
+       return 0;
+}
+
+/* Time Permit CTT=S*(date|H(CID)) where S is master secret */
+#[allow(non_snake_case)]
+pub fn get_client_permit(sha: usize,date: usize,s: &[u8],cid: &[u8],ctt: &mut 
[u8]) ->isize {
+       const RM:usize=rom::MODBYTES as usize;
+       let mut h:[u8;RM]=[0;RM];       
+       hashit(sha,date,cid,&mut h);
+       let mut P=mapit(&h);
+
+       let mut sc=BIG::frombytes(s);
+       pair::g1mul(&mut P,&mut sc).tobytes(ctt);
+       return 0;
+}
+
+/* Implement step 1 on client side of MPin protocol */
+#[allow(non_snake_case)]
+pub fn client_1(sha: usize,date: usize,client_id: &[u8],rng: Option<&mut 
RAND>,x: &mut [u8],pin: usize,token: &[u8],sec: &mut [u8],xid: Option<&mut 
[u8]>,xcid: Option<&mut [u8]>,permit: Option<&[u8]>) ->isize {
+       let r=BIG::new_ints(&rom::CURVE_ORDER);
+               
+       let mut sx:BIG;
+
+       if let Some(mut rd)=rng
+       {
+               sx=BIG::randomnum(&r,rd);
+               if rom::AES_S>0 {
+                       sx.mod2m(2*rom::AES_S);
+               }
+               sx.tobytes(x);
+       } else {
+               sx=BIG::frombytes(x);
+       }
+
+       const RM:usize=rom::MODBYTES as usize;
+       let mut h:[u8;RM]=[0;RM];
+
+       hashit(sha,0,&client_id,&mut h);
+       let mut P=mapit(&h);
+       
+       let mut T=ECP::frombytes(&token);
+       if T.is_infinity() {return INVALID_POINT}
+
+       let mut W=P.pinmul((pin as i32)%MAXPIN,PBLEN);
+       T.add(&mut W);
+       if date!=0 {
+               if let Some(rpermit)=permit {W=ECP::frombytes(&rpermit);}
+               if W.is_infinity() {return INVALID_POINT}
+               T.add(&mut W);
+               let mut h2:[u8;RM]=[0;RM];              
+               hashit(sha,date,&h,&mut h2);
+               W=mapit(&h2);
+               if let Some(mut rxid)=xid {
+                       P=pair::g1mul(&mut P,&mut sx);
+                       P.tobytes(&mut rxid);
+                       W=pair::g1mul(&mut W,&mut sx);
+                       P.add(&mut W);
+               } else {
+                       P.add(&mut W);
+                       P=pair::g1mul(&mut P,&mut sx);
+               }
+               if let Some(mut rxcid)=xcid {P.tobytes(&mut rxcid)}
+       } else {
+               if let Some(mut rxid)=xid {
+                       P=pair::g1mul(&mut P,&mut sx);
+                       P.tobytes(&mut rxid);
+               }
+       }
+
+       T.tobytes(sec);
+       return 0;
+}
+
+/* Outputs H(CID) and H(T|H(CID)) for time permits. If no time permits set 
HID=HTID */
+#[allow(non_snake_case)]
+pub fn server_1(sha: usize,date: usize,cid: &[u8],hid: &mut [u8],htid: 
Option<&mut [u8]>) {
+       const RM:usize=rom::MODBYTES as usize;
+       let mut h:[u8;RM]=[0;RM];
+
+       hashit(sha,0,cid,&mut h);       
+
+       let mut P=mapit(&h);
+       
+       P.tobytes(hid);
+       if date!=0 {
+               let mut h2:[u8;RM]=[0;RM];              
+               hashit(sha,date,&h,&mut h2);
+               let mut R=mapit(&h2);
+               P.add(&mut R);
+               if let Some(rhtid)=htid {P.tobytes(rhtid);}
+       } 
+}
+
+/* Implement step 2 on client side of MPin protocol */
+#[allow(non_snake_case)]
+pub fn client_2(x: &[u8],y: &[u8],sec: &mut [u8]) -> isize {
+       let mut r=BIG::new_ints(&rom::CURVE_ORDER);
+       let mut P=ECP::frombytes(sec);
+       if P.is_infinity() {return INVALID_POINT}
+
+       let mut px=BIG::frombytes(x);
+       let py=BIG::frombytes(y);
+       px.add(&py);
+       px.rmod(&mut r);
+       //px.rsub(r)
+
+       P=pair::g1mul(&mut P,&mut px);
+       P.neg();
+       P.tobytes(sec);
+       
+       return 0;
+}
+
+/* return time since epoch */
+pub fn get_time() -> usize {
+       return 
(SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs()) as usize;     
 
+}
+
+/* Generate Y = H(epoch, xCID/xID) */
+pub fn get_y(sha: usize,timevalue: usize,xcid: &[u8],y: &mut [u8]) {
+       const RM:usize=rom::MODBYTES as usize;
+       let mut h:[u8;RM]=[0;RM];
+
+       hashit(sha,timevalue,xcid,&mut h);      
+
+       let mut sy= BIG::frombytes(&h);
+       let mut q=BIG::new_ints(&rom::CURVE_ORDER);
+       sy.rmod(&mut q);
+       if rom::AES_S>0 {
+               sy.mod2m(2*rom::AES_S);
+       }
+       sy.tobytes(y);
+}
+
+/* Implement step 2 of MPin protocol on server side */
+#[allow(non_snake_case)]
+pub fn server_2(date: usize,hid: &[u8],htid: Option<&[u8]>,y: &[u8],sst: 
&[u8],xid: Option<&[u8]>,xcid: Option<&[u8]>,msec: &[u8],e: Option<&mut 
[u8]>,f: Option<&mut [u8]>) -> isize {
+//     q:=NewBIGints(Modulus)
+       let mut 
Q=ECP2::new_fp2s(&FP2::new_bigs(&BIG::new_ints(&rom::CURVE_PXA),&BIG::new_ints(&rom::CURVE_PXB)),&FP2::new_bigs(&BIG::new_ints(&rom::CURVE_PYA),&BIG::new_ints(&rom::CURVE_PYB)));
+
+       let mut sQ=ECP2::frombytes(&sst);
+       if sQ.is_infinity() {return INVALID_POINT}      
+
+       let mut R:ECP;
+       if date!=0 {
+               if let Some(rxcid)=xcid {R=ECP::frombytes(&rxcid);}
+               else {return BAD_PARAMS}
+       } else {
+               if let Some(rxid)=xid {R=ECP::frombytes(&rxid)}
+               else {return BAD_PARAMS}
+       }
+       if R.is_infinity() {return INVALID_POINT}
+
+       let mut sy=BIG::frombytes(&y);
+       let mut P:ECP;
+       if date!=0 {
+               if let Some(rhtid)=htid {P=ECP::frombytes(&rhtid)}
+               else {return BAD_PARAMS}
+       } else {
+               P=ECP::frombytes(&hid);
+       }
+       
+       if P.is_infinity() {return INVALID_POINT}
+
+       P=pair::g1mul(&mut P,&mut sy);
+       P.add(&mut R);
+       R=ECP::frombytes(&msec);
+       if R.is_infinity() {return INVALID_POINT}
+
+       let mut g:FP12;
+//             FP12 g1=new FP12(0);
+
+       g=pair::ate2(&mut Q,&mut R,&mut sQ,&mut P);
+       g=pair::fexp(&g);
+
+       if !g.isunity() {
+               
+               if let Some(rxid)=xid {
+                       if let Some(re)=e {
+                               if let Some(rf)=f {
+
+                                       g.tobytes(re);
+                                       if date!=0 {
+                                               P=ECP::frombytes(&hid);
+                                               if P.is_infinity() {return 
INVALID_POINT}               
+                                               R=ECP::frombytes(&rxid);
+                                               if R.is_infinity() {return 
INVALID_POINT}                       
+                                               P=pair::g1mul(&mut P,&mut sy);
+                                               P.add(&mut R);                  
                                                
+                                       }
+                                       g=pair::ate(&mut Q,&mut P);
+                                       g=pair::fexp(&g);
+                                       g.tobytes(rf);
+
+                               }
+                       }
+               }
+       
+               return BAD_PIN;
+       }
+
+       return 0;
+}
+
+/* Pollards kangaroos used to return PIN error */
+pub fn kangaroo(e: &[u8],f: &[u8]) -> isize {
+       let mut ge=FP12::frombytes(e);
+       let mut gf=FP12::frombytes(f);
+       let mut distance: [isize;TS]=[0;TS];
+       let mut t=FP12::new_copy(&gf);
+
+       let mut table: [FP12;TS]=[FP12::new();TS];
+       let mut s:isize=1;
+       for m in 0..TS {
+               distance[m]=s;
+               table[m]=FP12::new_copy(&t);
+               s*=2;
+               t.usqr();
+       }
+       t.one();
+       let mut dn:isize=0;
+       let mut i:usize;
+       for _ in 0..TRAP {
+               i=(t.geta().geta().geta().lastbits(20)%(TS as isize)) as usize;
+               t.mul(&mut table[i]);
+               dn+=distance[i];
+       }
+       gf.copy(&t); gf.conj();
+       let mut steps:usize=0; let mut dm:isize=0;
+       let mut res:isize=0;
+       while dm-dn<MAXPIN as isize {
+               steps+=1;
+               if steps>4*TRAP {break}
+               i=(ge.geta().geta().geta().lastbits(20)%(TS as isize)) as usize;
+               ge.mul(&mut table[i]);
+               dm+=distance[i];
+               if ge.equals(&mut t) {
+                       res=dm-dn;
+                       break;
+               }
+               if ge.equals(&mut gf) {
+                       res=dn-dm;
+                       break;
+               }
+
+       }
+       if steps>4*TRAP || dm-dn>=MAXPIN as isize {res=0 }    // Trap Failed  - 
probable invalid token
+       return res;
+}
+
+/* Hash the M-Pin transcript - new */
+
+pub fn hash_all(sha: usize,hid: &[u8],xid: &[u8],xcid: Option<&[u8]>,sec: 
&[u8],y: &[u8],r: &[u8],w: &[u8],h: &mut[u8]) -> bool {
+       let mut tlen:usize=0;
+       const RM:usize=rom::MODBYTES as usize;  
+       let mut t: [u8;10*RM+4]=[0;10*RM+4];
+
+       for i in 0 .. hid.len() {t[i]=hid[i]}
+       tlen+=hid.len();
+
+       if let Some(rxcid)=xcid {
+               for i in 0..rxcid.len() {t[i+tlen]=rxcid[i]}
+               tlen+=rxcid.len();
+       } else {
+               for i in 0..xid.len() {t[i+tlen]=xid[i]}
+               tlen+=xid.len();
+       }       
+
+       for i in 0..sec.len() {t[i+tlen]=sec[i]}
+       tlen+=sec.len();                
+       for i in 0..y.len() {t[i+tlen]=y[i]}
+       tlen+=y.len();
+       for i in 0..r.len() {t[i+tlen]=r[i]}
+       tlen+=r.len();          
+       for i in 0..w.len() {t[i+tlen]=w[i]}
+       tlen+=w.len();  
+       if tlen!=10*RM+4 {return false}
+
+       return hashit(sha,0,&t,h);
+}
+
+/* calculate common key on client side */
+/* wCID = w.(A+AT) */
+#[allow(non_snake_case)]
+pub fn client_key(sha: usize,g1: &[u8],g2: &[u8],pin: usize,r: &[u8],x: 
&[u8],h: &[u8],wcid: &[u8],ck: &mut [u8]) -> isize {
+
+       let mut g1=FP12::frombytes(&g1);
+       let mut g2=FP12::frombytes(&g2);
+       let mut z=BIG::frombytes(&r);
+       let mut x=BIG::frombytes(&x);
+       let h=BIG::frombytes(&h);
+
+       let mut W=ECP::frombytes(&wcid);
+       if W.is_infinity() {return INVALID_POINT} 
+
+       W=pair::g1mul(&mut W,&mut x);
+
+       let mut 
f=FP2::new_bigs(&BIG::new_ints(&rom::CURVE_FRA),&BIG::new_ints(&rom::CURVE_FRB));
+       let mut r=BIG::new_ints(&rom::CURVE_ORDER);
+       let q=BIG::new_ints(&rom::MODULUS);
+
+       z.add(&h);      //new
+       z.rmod(&mut r);
+
+       let mut m=BIG::new_copy(&q);
+       m.rmod(&mut r);
+
+       let mut a=BIG::new_copy(&z);
+       a.rmod(&mut m);
+
+       let mut b=BIG::new_copy(&z);
+       b.div(&mut m);
+
+       g2.pinpow(pin as i32,PBLEN);
+       g1.mul(&mut g2);
+
+       let mut c=g1.trace();
+       g2.copy(&g1);
+       g2.frob(&mut f);
+       let cp=g2.trace();
+       g1.conj();
+       g2.mul(&mut g1);
+       let cpm1=g2.trace();
+       g2.mul(&mut g1);
+       let cpm2=g2.trace();
+
+       c=c.xtr_pow2(&cp,&cpm1,&cpm2,&mut a,&mut b);
+
+       hash(sha,&mut c,&mut W,ck);
+
+       return 0
+}
+
+/* calculate common key on server side */
+/* Z=r.A - no time permits involved */
+#[allow(non_snake_case)]
+pub fn server_key(sha: usize,z: &[u8],sst: &[u8],w: &[u8],h: &[u8],hid: 
&[u8],xid: &[u8],xcid: Option<&[u8]>,sk: &mut [u8]) -> isize {
+       let mut sQ=ECP2::frombytes(&sst);
+       if sQ.is_infinity() {return INVALID_POINT} 
+       let mut R=ECP::frombytes(&z);
+       if R.is_infinity() {return INVALID_POINT} 
+       let mut A=ECP::frombytes(&hid);
+       if A.is_infinity() {return INVALID_POINT} 
+
+       let mut U=ECP::new();
+       if let Some(rxcid)=xcid {
+               U.copy(&ECP::frombytes(&rxcid));
+       } else {
+               U.copy(&ECP::frombytes(&xid));
+       }
+       
+       if U.is_infinity() {return INVALID_POINT} 
+
+       let mut w=BIG::frombytes(&w);
+       let mut h=BIG::frombytes(&h);
+       A=pair::g1mul(&mut A,&mut h);   // new
+       R.add(&mut A);
+
+       U=pair::g1mul(&mut U,&mut w);
+       let mut g=pair::ate(&mut sQ,&mut R);
+       g=pair::fexp(&g);
+
+       let mut c=g.trace();
+
+       hash(sha,&mut c,&mut U,sk);
+
+       return 0
+}
+
+

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/rust/src/pair.rs
----------------------------------------------------------------------
diff --git a/version22/rust/src/pair.rs b/version22/rust/src/pair.rs
new file mode 100644
index 0000000..9e162db
--- /dev/null
+++ b/version22/rust/src/pair.rs
@@ -0,0 +1,674 @@
+/*
+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.
+*/
+
+//mod fp;
+use fp::FP;
+//mod ecp;
+use ecp::ECP;
+//mod fp2;
+use fp2::FP2;
+//mod ecp2;
+use ecp2::ECP2;
+//mod fp4;
+use fp4::FP4;
+//mod fp12;
+use fp12::FP12;
+//mod big;
+use big::BIG;
+//mod dbig;
+use dbig::DBIG;
+//mod rand;
+//mod hash256;
+//mod rom;
+use rom;
+
+#[allow(non_snake_case)]
+
+fn linedbl(A: &mut ECP2,qx: &mut FP,qy: &mut  FP) -> FP12 {
+       let mut P=ECP2::new();
+
+       P.copy(A);
+       let mut zz=FP2::new_copy(&P.getpz());
+       zz.sqr();
+       let d=A.dbl();  
+
+       if d<0 {return FP12::new_int(1)}
+
+       let mut z3=FP2::new_copy(&A.getpz());
+       let mut a=FP4::new();
+       let mut b=FP4::new();
+       let c=FP4::new();       
+
+       let mut x=FP2::new_copy(&P.getpx());
+       let mut y=FP2::new_copy(&P.getpy());
+       let mut t=FP2::new_copy(&P.getpx());
+       t.sqr();
+       t.imul(3);
+
+       y.sqr();
+       y.dbl();
+       z3.mul(&mut zz);
+       z3.pmul(qy);
+
+       x.mul(&mut t);
+       x.sub(&y);
+       a.copy(&FP4::new_fp2s(&z3,&x));
+       t.neg();
+       zz.mul(&mut t);
+       zz.pmul(qx);
+       b.copy(&FP4::new_fp2(&zz));
+
+       return FP12::new_fp4s(&a,&b,&c);
+}
+
+#[allow(non_snake_case)]
+fn lineadd(A: &mut ECP2,B: &mut ECP2,qx: &mut FP,qy: &mut  FP) -> FP12 {
+
+       let mut P=ECP2::new();
+
+       P.copy(A);
+       let mut zz=FP2::new_copy(&P.getpz());
+       zz.sqr();
+
+       let d=A.add(B);
+       if d<0 {return FP12::new_int(1)}        
+
+       let mut z3=FP2::new_copy(&A.getpz());
+       let mut a=FP4::new();
+       let mut b=FP4::new();
+       let c=FP4::new();       
+
+       if d==0 { /* Addition */
+               let mut x=FP2::new_copy(&B.getpx());
+               let mut y=FP2::new_copy(&B.getpy());
+               let mut t=FP2::new_copy(&P.getpz()); 
+               t.mul(&mut y);
+               zz.mul(&mut t);
+
+               let mut ny=FP2::new_copy(&P.getpy()); ny.neg();
+               zz.add(&ny); 
+               z3.pmul(qy);
+               t.mul(&mut P.getpx());
+               x.mul(&mut ny);
+               t.add(&x);
+               a.copy(&FP4::new_fp2s(&z3,&t));
+               zz.neg();
+               zz.pmul(qx);
+               b.copy(&FP4::new_fp2(&zz));
+       } else { /* Doubling */
+               let mut x=FP2::new_copy(&P.getpx());
+               let mut y=FP2::new_copy(&P.getpy());
+               let mut t=FP2::new_copy(&P.getpx());
+               t.sqr();
+               t.imul(3);
+
+               y.sqr();
+               y.dbl();
+               z3.mul(&mut zz);
+               z3.pmul(qy);
+
+               x.mul(&mut t);
+               x.sub(&y);
+               a.copy(&FP4::new_fp2s(&z3,&x));
+               t.neg();
+               zz.mul(&mut t);
+               zz.pmul(qx);
+               b.copy(&FP4::new_fp2(&zz));
+       }
+       return FP12::new_fp4s(&a,&b,&c);
+}
+
+#[allow(non_snake_case)]
+/* Optimal R-ate pairing */
+pub fn ate(P: & mut ECP2,Q: &mut ECP) -> FP12 {
+       let mut f = 
FP2::new_bigs(&BIG::new_ints(&rom::CURVE_FRA),&BIG::new_ints(&rom::CURVE_FRB));
+       let x = BIG::new_ints(&rom::CURVE_BNX);
+       let mut n = BIG::new_copy(&x);
+       let mut K = ECP2::new();
+
+       
+       if rom::CURVE_PAIRING_TYPE == rom::BN_CURVE {
+               n.pmul(6); n.dec(2);
+       } else {n.copy(&x)}
+       
+       n.norm();
+       P.affine();
+       Q.affine();
+       let mut qx=FP::new_copy(&Q.getpx());
+       let mut qy=FP::new_copy(&Q.getpy());
+
+       let mut A=ECP2::new();
+       let mut r=FP12::new_int(1);
+
+       A.copy(&P);
+       let nb=n.nbits();
+
+       for i in (1..nb-1).rev() {
+               let mut lv=linedbl(&mut A,&mut qx,&mut qy);
+               r.smul(&mut lv);
+               if n.bit(i)==1 {
+               
+                       lv=lineadd(&mut A,P,&mut qx,&mut qy);
+               
+                       r.smul(&mut lv);
+               }               
+               r.sqr();        
+       }
+
+       let mut lv=linedbl(&mut A,&mut qx,&mut qy);
+       r.smul(&mut lv);
+
+       if n.parity()==1 {
+               lv=lineadd(&mut A,P,&mut qx,&mut qy);
+               r.smul(&mut lv);
+       }
+
+/* R-ate fixup required for BN curves */
+
+       if rom::CURVE_PAIRING_TYPE == rom::BN_CURVE {
+               r.conj();
+               K.copy(&P);
+               K.frob(&mut f);
+               A.neg();
+               lv=lineadd(&mut A,&mut K,&mut qx,&mut qy);
+               r.smul(&mut lv);
+               K.frob(&mut f);
+               K.neg();
+               lv=lineadd(&mut A,&mut K,&mut qx,&mut qy);
+               r.smul(&mut lv);
+       }
+
+       return r;
+}
+
+#[allow(non_snake_case)]
+/* Optimal R-ate double pairing e(P,Q).e(R,S) */
+pub fn ate2(P: &mut ECP2,Q: &mut ECP,R: &mut ECP2,S: &mut ECP) -> FP12 {
+       let mut f = 
FP2::new_bigs(&BIG::new_ints(&rom::CURVE_FRA),&BIG::new_ints(&rom::CURVE_FRB));
+       let x = BIG::new_ints(&rom::CURVE_BNX);
+       let mut n = BIG::new_copy(&x);
+       let mut K = ECP2::new();
+
+
+       if rom::CURVE_PAIRING_TYPE == rom::BN_CURVE {
+               n.pmul(6); n.dec(2);
+       } else {n.copy(&x)}
+       
+       n.norm();
+       P.affine();
+       Q.affine();
+       R.affine();
+       S.affine();
+
+       let mut qx=FP::new_copy(&Q.getpx());
+       let mut qy=FP::new_copy(&Q.getpy());
+
+       let mut sx=FP::new_copy(&S.getpx());
+       let mut sy=FP::new_copy(&S.getpy());
+
+       let mut A=ECP2::new();
+       let mut B=ECP2::new();
+       let mut r=FP12::new_int(1);
+
+       A.copy(&P);
+       B.copy(&R);
+       let nb=n.nbits();
+
+       for i in (1..nb-1).rev() {
+               let mut lv=linedbl(&mut A,&mut qx,&mut qy);
+               r.smul(&mut lv);
+               lv=linedbl(&mut B,&mut sx,&mut sy);
+               r.smul(&mut lv);
+
+               if n.bit(i)==1 {
+                       lv=lineadd(&mut A,P,&mut qx,&mut qy);
+                       r.smul(&mut lv);
+                       lv=lineadd(&mut B,R,&mut sx,&mut sy);
+                       r.smul(&mut lv);
+               }
+               r.sqr();
+       }
+
+       let mut lv=linedbl(&mut A,&mut qx,&mut qy);
+       r.smul(&mut lv);
+       lv=linedbl(&mut B,&mut sx,&mut sy);
+       r.smul(&mut lv);
+       if n.parity()==1 {
+               lv=lineadd(&mut A,P,&mut qx,&mut qy);
+               r.smul(&mut lv);
+               lv=lineadd(&mut B,R,&mut sx,&mut sy);
+               r.smul(&mut lv);
+       }
+
+/* R-ate fixup */
+       if rom::CURVE_PAIRING_TYPE == rom::BN_CURVE {
+               r.conj();
+               K.copy(&P);
+               K.frob(&mut f);
+               A.neg();
+               lv=lineadd(&mut A,&mut K,&mut qx,&mut qy);
+               r.smul(&mut lv);
+               K.frob(&mut f);
+               K.neg();
+               lv=lineadd(&mut A,&mut K,&mut qx,&mut qy);
+               r.smul(&mut lv);
+
+               K.copy(&R);
+               K.frob(&mut f);
+               B.neg();
+               lv=lineadd(&mut B,&mut K,&mut sx,&mut sy);
+               r.smul(&mut lv);
+               K.frob(&mut f);
+               K.neg();
+               lv=lineadd(&mut B,&mut K,&mut sx,&mut sy);
+               r.smul(&mut lv);
+       }
+
+       return r;
+}
+
+/* final exponentiation - keep separate for multi-pairings and to avoid 
thrashing stack */
+pub fn fexp(m: &FP12) -> FP12 {
+       let mut f = 
FP2::new_bigs(&BIG::new_ints(&rom::CURVE_FRA),&BIG::new_ints(&rom::CURVE_FRB));
+       let mut x = BIG::new_ints(&rom::CURVE_BNX);
+       let mut r=FP12::new_copy(m);
+               
+/* Easy part of final exp */
+       let mut lv=FP12::new_copy(&r);
+       lv.inverse();
+       r.conj();
+
+       r.mul(&mut lv);
+       lv.copy(&r);
+       r.frob(&mut f);
+       r.frob(&mut f);
+       r.mul(&mut lv);
+/* Hard part of final exp */
+       if rom::CURVE_PAIRING_TYPE == rom::BN_CURVE {
+               lv.copy(&r);
+               lv.frob(&mut f);
+               let mut x0=FP12::new_copy(&lv);
+               x0.frob(&mut f);
+               lv.mul(&mut r);
+               x0.mul(&mut lv);
+               x0.frob(&mut f);
+               let mut x1=FP12::new_copy(&r);
+               x1.conj();
+               let mut x4=r.pow(&mut x);
+
+               let mut x3=FP12::new_copy(&x4);
+               x3.frob(&mut f);
+
+               let mut x2=x4.pow(&mut x);
+
+               let mut x5=FP12::new_copy(&x2); x5.conj();
+               lv=x2.pow(&mut x);
+
+               x2.frob(&mut f);
+               r.copy(&x2); r.conj();
+
+               x4.mul(&mut r);
+               x2.frob(&mut f);
+
+               r.copy(&lv);
+               r.frob(&mut f);
+               lv.mul(&mut r);
+
+               lv.usqr();
+               lv.mul(&mut x4);
+               lv.mul(&mut x5);
+               r.copy(&x3);
+               r.mul(&mut x5);
+               r.mul(&mut lv);
+               lv.mul(&mut x2);
+               r.usqr();
+               r.mul(&mut lv);
+               r.usqr();
+               lv.copy(&r);
+               lv.mul(&mut x1);
+               r.mul(&mut x0);
+               lv.usqr();
+               r.mul(&mut lv);
+               r.reduce();
+       } else {
+
+// Ghamman & Fouotsa Method
+
+               let mut y0=FP12::new_copy(&r); y0.usqr();
+               let mut y1=y0.pow(&mut x);
+               x.fshr(1); let mut y2=y1.pow(&mut x); x.fshl(1);
+               let mut y3=FP12::new_copy(&r); y3.conj();
+               y1.mul(&mut y3);
+
+               y1.conj();
+               y1.mul(&mut y2);
+
+               y2=y1.pow(&mut x);
+
+               y3=y2.pow(&mut x);
+               y1.conj();
+               y3.mul(&mut y1);
+
+               y1.conj();
+               y1.frob(&mut f); y1.frob(&mut f); y1.frob(&mut f);
+               y2.frob(&mut f); y2.frob(&mut f);
+               y1.mul(&mut y2);
+
+               y2=y3.pow(&mut x);
+               y2.mul(&mut y0);
+               y2.mul(&mut r);
+
+               y1.mul(&mut y2);
+               y2.copy(&y3); y2.frob(&mut f);
+               y1.mul(&mut y2);
+               r.copy(&y1);
+               r.reduce();
+
+
+/*
+               let mut x0=FP12::new_copy(&r);
+               let mut x1=FP12::new_copy(&r);
+               lv.copy(&r); lv.frob(&mut f);
+               let mut x3=FP12::new_copy(&lv); x3.conj(); x1.mul(&mut x3);
+               lv.frob(&mut f); lv.frob(&mut f);
+               x1.mul(&mut lv);
+
+               r=r.pow(&mut x);  //r=r.pow(x);
+               x3.copy(&r); x3.conj(); x1.mul(&mut x3);
+               lv.copy(&r); lv.frob(&mut f);
+               x0.mul(&mut lv);
+               lv.frob(&mut f);
+               x1.mul(&mut lv);
+               lv.frob(&mut f);
+               x3.copy(&lv); x3.conj(); x0.mul(&mut x3);
+
+               r=r.pow(&mut x);
+               x0.mul(&mut r);
+               lv.copy(&r); lv.frob(&mut f); lv.frob(&mut f);
+               x3.copy(&lv); x3.conj(); x0.mul(&mut x3);
+               lv.frob(&mut f);
+               x1.mul(&mut lv);
+
+               r=r.pow(&mut x);
+               lv.copy(&r); lv.frob(&mut f);
+               x3.copy(&lv); x3.conj(); x0.mul(&mut x3);
+               lv.frob(&mut f);
+               x1.mul(&mut lv);
+
+               r=r.pow(&mut x);
+               x3.copy(&r); x3.conj(); x0.mul(&mut x3);
+               lv.copy(&r); lv.frob(&mut f);
+               x1.mul(&mut lv);
+
+               r=r.pow(&mut x);
+               x1.mul(&mut r);
+
+               x0.usqr();
+               x0.mul(&mut x1);
+               r.copy(&x0);
+               r.reduce();  */
+       }
+       return r;
+}
+
+#[allow(non_snake_case)]
+/* GLV method */
+fn glv(e: &mut BIG) -> [BIG;2] {
+       let mut u:[BIG;2]=[BIG::new(),BIG::new()];
+       if rom::CURVE_PAIRING_TYPE == rom::BN_CURVE {
+               let mut t=BIG::new();
+               let q=BIG::new_ints(&rom::CURVE_ORDER);
+               let mut v:[BIG;2]=[BIG::new(),BIG::new()];
+
+               for i in 0..2 {
+                       t.copy(&BIG::new_ints(&rom::CURVE_W[i]));  // why not 
just t=new BIG(ROM.CURVE_W[i]); 
+                       let mut d:DBIG = BIG::mul(&mut t,e);
+                       v[i].copy(&d.div(&q));
+               }
+               u[0].copy(&e);
+               for i in 0..2 {
+                       for j in 0..2 {
+                               t=BIG::new_ints(&rom::CURVE_SB[j][i]);
+                               t=BIG::modmul(&mut v[j],&mut t,&q);
+                               u[i].add(&q);
+                               u[i].sub(&t);
+                               u[i].rmod(&q);
+                       }
+               }
+       } else {
+               let q=BIG::new_ints(&rom::CURVE_ORDER);
+               let x=BIG::new_ints(&rom::CURVE_BNX);
+               let x2=BIG::smul(&x,&x);
+               u[0].copy(&e);  
+               u[0].rmod(&x2);
+               u[1].copy(&e); 
+               u[1].div(&x2);
+               u[1].rsub(&q);
+       }
+       return u;
+}
+
+#[allow(non_snake_case)]
+/* Galbraith & Scott Method */
+pub fn gs(e: &mut BIG) -> [BIG;4] {
+       let mut u:[BIG;4]=[BIG::new(),BIG::new(),BIG::new(),BIG::new()];
+       if rom::CURVE_PAIRING_TYPE == rom::BN_CURVE {
+               let mut t=BIG::new();
+               let q=BIG::new_ints(&rom::CURVE_ORDER);
+
+               let mut v:[BIG;4]=[BIG::new(),BIG::new(),BIG::new(),BIG::new()];
+               for i in 0..4 {
+                       t.copy(&BIG::new_ints(&rom::CURVE_WB[i]));
+                       let mut d:DBIG=BIG::mul(&mut t,e);
+                       v[i].copy(&d.div(&q));
+               }
+               u[0].copy(&e);
+               for i in 0..4 {
+                       for j in 0..4 {
+                               t=BIG::new_ints(&rom::CURVE_BB[j][i]);
+                               t=BIG::modmul(&mut v[j],&mut t,&q);
+                               u[i].add(&q);
+                               u[i].sub(&t);
+                               u[i].rmod(&q);
+                       }
+               }
+       } else {
+               let x=BIG::new_ints(&rom::CURVE_BNX);
+               let mut w=BIG::new_copy(&e);
+               for i in 0..4 {
+                       u[i].copy(&w);
+                       u[i].rmod(&x);
+                       w.div(&x);
+               }
+       }
+       return u;
+}      
+
+#[allow(non_snake_case)]
+/* Multiply P by e in group G1 */
+pub fn g1mul(P: &mut ECP,e: &mut BIG) -> ECP {
+       let mut R=ECP::new();
+       if rom::USE_GLV {
+               P.affine();
+               R.copy(P);
+               let mut Q=ECP::new();
+               Q.copy(P);
+               let q=BIG::new_ints(&rom::CURVE_ORDER);
+               let mut cru=FP::new_big(&BIG::new_ints(&rom::CURVE_CRU));
+               let mut u=glv(e);
+               Q.mulx(&mut cru);
+
+               let mut np=u[0].nbits();
+               let mut t:BIG=BIG::modneg(&mut u[0],&q);
+               let mut nn=t.nbits();
+               if nn<np {
+                       u[0].copy(&t);
+                       R.neg();
+               }
+
+               np=u[1].nbits();
+               t=BIG::modneg(&mut u[1],&q);
+               nn=t.nbits();
+               if nn<np {
+                       u[1].copy(&t);
+                       Q.neg();
+               }
+
+               R=R.mul2(&u[0],&mut Q,&u[1]);
+                       
+       } else {
+               R=P.mul(e);
+       }
+       return R;
+}
+
+#[allow(non_snake_case)]
+/* Multiply P by e in group G2 */
+pub fn g2mul(P: &mut ECP2,e: &mut BIG) -> ECP2 {
+       let mut R=ECP2::new();
+       if rom::USE_GS_G2 {
+               let mut 
Q:[ECP2;4]=[ECP2::new(),ECP2::new(),ECP2::new(),ECP2::new()];
+               let mut f = 
FP2::new_bigs(&BIG::new_ints(&rom::CURVE_FRA),&BIG::new_ints(&rom::CURVE_FRB));
+               let q=BIG::new_ints(&rom::CURVE_ORDER);
+               let mut u=gs(e);
+               let mut T=ECP2::new();
+
+               let mut t=BIG::new();
+               P.affine();
+               Q[0].copy(&P);
+               for i in 1..4 {
+                       T.copy(&Q[i-1]);
+                       Q[i].copy(&T);
+                       Q[i].frob(&mut f);
+               }
+               for i in 0..4 {
+                       let np=u[i].nbits();
+                       t.copy(&BIG::modneg(&mut u[i],&q));
+                       let nn=t.nbits();
+                       if nn<np {
+                               u[i].copy(&t);
+                               Q[i].neg();
+                       }
+               }
+
+               R.copy(&ECP2::mul4(&mut Q,&u));
+
+       } else {
+               R.copy(&P.mul(e));
+       }
+       return R;
+}
+
+/* f=f^e */
+/* Note that this method requires a lot of RAM! Better to use compressed XTR 
method, see FP4.java */
+pub fn gtpow(d: &mut FP12,e: &mut BIG) -> FP12 {
+       let mut r=FP12::new();
+       if rom::USE_GS_GT {
+               let mut 
g:[FP12;4]=[FP12::new(),FP12::new(),FP12::new(),FP12::new()];
+               let mut f = 
FP2::new_bigs(&BIG::new_ints(&rom::CURVE_FRA),&BIG::new_ints(&rom::CURVE_FRB));
+               let q=BIG::new_ints(&rom::CURVE_ORDER);
+               let mut t=BIG::new();
+               let mut u=gs(e);
+               let mut w=FP12::new();
+
+               g[0].copy(&d);
+               for i in 1..4 {
+                       w.copy(&g[i-1]);
+                       g[i].copy(&w);
+                       g[i].frob(&mut f);
+               }
+               for i in 0..4 {
+                       let np=u[i].nbits();
+                       t.copy(&BIG::modneg(&mut u[i],&q));
+                       let nn=t.nbits();
+                       if nn<np {
+                               u[i].copy(&t);
+                               g[i].conj();
+                       }
+               }
+               r.copy(&FP12::pow4(&mut g,&u));
+       } else {
+               r.copy(&d.pow(e));
+       }
+       return r;
+}
+
+/*
+#[allow(non_snake_case)]
+fn main()
+{
+       let mut 
Q=ECP::new_bigs(&BIG::new_ints(&rom::CURVE_GX),&BIG::new_ints(&rom::CURVE_GY));
+       let mut 
P=ECP2::new_fp2s(&FP2::new_bigs(&BIG::new_ints(&rom::CURVE_PXA),&BIG::new_ints(&rom::CURVE_PXB)),&FP2::new_bigs(&BIG::new_ints(&rom::CURVE_PYA),&BIG::new_ints(&rom::CURVE_PYB)));
+
+       let mut r=BIG::new_ints(&rom::CURVE_ORDER);
+       
+       println!("P= {}",P.tostring());
+       println!("Q= {}",Q.tostring());
+
+       //m:=NewBIGint(17)
+
+       let mut e=ate(&mut P,&mut Q);
+       println!("\ne= {}",e.tostring());
+
+       e=fexp(&e);
+
+       for i in 1..10 {
+               e=ate(&mut P,&mut Q);
+               e=fexp(&e);
+       }
+
+
+       //      e=GTpow(e,m);
+
+       println!("\ne= {}",e.tostring());
+
+       
+       fmt.Printf("\n");
+       GLV:=glv(r)
+
+       fmt.Printf("GLV[0]= "+GLV[0].toString())
+       fmt.Printf("\n")
+
+       fmt.Printf("GLV[0]= "+GLV[1].toString())
+       fmt.Printf("\n")
+
+       G:=NewECP(); G.copy(Q)
+       R:=NewECP2(); R.copy(P)
+
+
+       e=ate(R,Q)
+       e=fexp(e)
+
+       e=GTpow(e,xa)
+       fmt.Printf("\ne= "+e.toString());
+       fmt.Printf("\n")
+
+       R=G2mul(R,xa)
+       e=ate(R,G)
+       e=fexp(e)
+
+       fmt.Printf("\ne= "+e.toString())
+       fmt.Printf("\n")
+
+       G=G1mul(G,xa)
+       e=ate(P,G)
+       e=fexp(e)
+       fmt.Printf("\ne= "+e.toString())
+       fmt.Printf("\n") 
+}*/

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/rust/src/rand.rs
----------------------------------------------------------------------
diff --git a/version22/rust/src/rand.rs b/version22/rust/src/rand.rs
new file mode 100644
index 0000000..5cf79ac
--- /dev/null
+++ b/version22/rust/src/rand.rs
@@ -0,0 +1,147 @@
+/*
+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.
+*/
+
+//mod hash256;
+
+use hash256::HASH256;
+
+const RAND_NK: usize=21;
+const RAND_NJ: usize=6;
+const RAND_NV: usize=8;
+
+pub struct RAND {
+       ira: [u32;RAND_NK],  /* random number...   */
+       rndptr: usize,
+       borrow: u32,
+       pool_ptr: usize,
+       pool: [u8;32]
+}
+
+impl RAND {
+
+       pub fn new() -> RAND {
+               RAND {
+                       ira: [0;RAND_NK],
+                       rndptr:0,
+                       borrow: 0,
+                       pool_ptr:0,
+                       pool:[0;32]
+               }
+       }
+
+       pub fn clean(&mut self) {
+               self.pool_ptr=0; self.rndptr=0;
+               for i in 0..32 {self.pool[i]=0}
+               for i in 0..RAND_NK {self.ira[i]=0}
+               self.borrow=0;          
+       }
+
+       fn sbrand(&mut self) -> u32 { /* Marsaglia & Zaman random number 
generator */
+               self.rndptr+=1;
+               if self.rndptr<RAND_NK {return self.ira[self.rndptr]}
+               self.rndptr=0;
+               let mut k=RAND_NK-RAND_NJ;
+               for i in 0..RAND_NK { /* calculate next NK values */
+                       if k==RAND_NK {k=0}
+                       let t=self.ira[k];
+                       let 
pdiff=t.wrapping_sub(self.ira[i]).wrapping_sub(self.borrow);
+                       if pdiff<t {self.borrow=0}
+                       if pdiff>t {self.borrow=1}
+                       self.ira[i]=pdiff;
+                       k+=1;
+               }
+               return self.ira[0];
+       }
+
+       fn sirand(&mut self,seed: u32) {
+               let mut m: u32=1;
+               let mut sd=seed;
+               self.borrow=0;
+               self.rndptr=0;
+               self.ira[0]^=sd;
+               for i in 1..RAND_NK { /* fill initialisation vector */
+                       let inn=(RAND_NV*i)%RAND_NK;
+                       self.ira[inn]^=m;      /* note XOR */
+                       let t=m;
+                       m=sd.wrapping_sub(m);
+                       sd=t;
+               }
+               for _ in 0..10000 {self.sbrand();} /* "warm-up" & stir the 
generator */
+       }
+
+       fn fill_pool(&mut self) {
+               let mut sh=HASH256::new();
+               for _ in 0..128 {sh.process((self.sbrand()&0xff) as u8)}
+               let w=sh.hash();
+               for i in 0..32 {self.pool[i]=w[i]}
+               self.pool_ptr=0;
+       }
+
+       fn pack(b: [u8;4]) -> u32 { /* pack 4 bytes into a 32-bit Word */
+               return ((((b[3] as u32))&0xff)<<24)|(((b[2] as 
u32)&0xff)<<16)|(((b[1] as u32)&0xff)<<8)|((b[0] as u32)&0xff);
+       }
+
+/* Initialize RNG with some real entropy from some external source */
+       pub fn seed(&mut self,rawlen: usize,raw: &[u8]) { /* initialise from at 
least 128 byte string of raw random entropy */
+               let mut b: [u8;4]=[0;4];
+               let mut sh=HASH256::new();
+               self.pool_ptr=0;
+
+               for i in 0..RAND_NK {self.ira[i]=0}
+               if rawlen>0 {
+                       for i in 0..rawlen {
+                               sh.process(raw[i]);
+                       }
+                       let digest=sh.hash();
+
+/* initialise PRNG from distilled randomness */
+
+                       for i in 0..8  {
+                               b[0]=digest[4*i]; b[1]=digest[4*i+1]; 
b[2]=digest[4*i+2]; b[3]=digest[4*i+3];
+                               self.sirand(RAND::pack(b));
+                       }
+               }
+               self.fill_pool();
+       }       
+
+/* get random byte */
+       pub fn getbyte(&mut self) -> u8 { 
+               let r=self.pool[self.pool_ptr];
+               self.pool_ptr+=1;
+               if self.pool_ptr>=32 {self.fill_pool()}
+               return (r&0xff) as u8;
+       }
+}
+
+/* test main program */
+/*
+fn main() {
+       let mut raw : [u8;100]=[0;100];
+       let mut rng=RAND::new();
+
+       rng.clean();
+       for i in 0..100 {raw[i]=i as u8}
+
+       rng.seed(100,&raw);
+ 
+       for _ in 0..1000 {
+               print!("{:03} ",rng.getbyte());
+       }
+}
+*/

Reply via email to