You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@milagro.apache.org by km...@apache.org on 2019/12/13 16:34:13 UTC

[incubator-milagro-crypto-rust] 15/18: Duplicate tests in cargo test

This is an automated email from the ASF dual-hosted git repository.

kmccusker pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-crypto-rust.git

commit de198225b44463a96b48e3bc6b5fc4494e86628d
Author: Kirk Baird <ba...@outlook.com>
AuthorDate: Fri Dec 13 17:18:41 2019 +1100

    Duplicate tests in cargo test
    
    Signed-off-by: Kirk Baird <ba...@outlook.com>
---
 tests/test_all.rs | 1473 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/test_bls.rs |  190 +++++++
 tests/test_nhs.rs |   71 +++
 3 files changed, 1734 insertions(+)

diff --git a/tests/test_all.rs b/tests/test_all.rs
new file mode 100644
index 0000000..c543dac
--- /dev/null
+++ b/tests/test_all.rs
@@ -0,0 +1,1473 @@
+/*
+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.
+*/
+
+extern crate amcl;
+
+use std::io;
+use std::str;
+
+use amcl::rand::RAND;
+use amcl::types::CurveType;
+
+pub fn printbinary(array: &[u8]) {
+    for i in 0..array.len() {
+        print!("{:02X}", array[i])
+    }
+    println!("")
+}
+
+fn create_rng() -> RAND {
+    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);
+    rng
+}
+
+#[test]
+fn ecdh_ed25519() {
+    //use amcl::ed25519;
+    use amcl::ed25519::ecdh;
+    use amcl::ed25519::ecp;
+
+    let mut rng = create_rng();
+
+    let pw = "M0ng00se";
+    let pp: &[u8] = b"M0ng00se";
+    const EFS: usize = ecdh::EFS;
+    const EGS: usize = ecdh::EGS;
+    const EAS: usize = ecp::AESKEY;
+
+    let sha = ecp::HASH_TYPE;
+    let mut salt: [u8; 8] = [0; 8];
+    let mut s1: [u8; EGS] = [0; EGS];
+    let mut w0: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+    let mut w1: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+    let mut z0: [u8; EFS] = [0; EFS];
+    let mut z1: [u8; EFS] = [0; EFS];
+    let mut key: [u8; EAS] = [0; EAS];
+    let mut cs: [u8; EGS] = [0; EGS];
+    let mut ds: [u8; EGS] = [0; EGS];
+    let mut m: Vec<u8> = vec![0; 32]; // array that could be of any length. So use heap.
+    let mut p1: [u8; 3] = [0; 3];
+    let mut p2: [u8; 4] = [0; 4];
+    let mut v: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+    let mut t: [u8; 12] = [0; 12];
+
+    for i in 0..8 {
+        salt[i] = (i + 1) as u8
+    } // set Salt
+
+    println!("\nTesting ECDH/ECDSA/ECIES");
+    println!("Alice's Passphrase= {}", pw);
+
+    let mut s0: [u8; EFS] = [0; EGS];
+    ecdh::pbkdf2(sha, pp, &salt, 1000, EGS, &mut s0);
+
+    print!("Alice's private key= 0x");
+    printbinary(&s0);
+
+    /* Generate Key pair S/W */
+    ecdh::key_pair_generate(None, &mut s0, &mut w0);
+
+    print!("Alice's public key= 0x");
+    printbinary(&w0);
+
+    let mut res = ecdh::public_key_validate(&w0);
+    if res != 0 {
+        println!("ECP Public Key is invalid!");
+        return;
+    }
+
+    /* Random private key for other party */
+    ecdh::key_pair_generate(Some(&mut rng), &mut s1, &mut w1);
+
+    print!("Servers private key= 0x");
+    printbinary(&s1);
+
+    print!("Servers public key= 0x");
+    printbinary(&w1);
+
+    res = ecdh::public_key_validate(&w1);
+    if res != 0 {
+        println!("ECP Public Key is invalid!");
+        return;
+    }
+    /* Calculate common key using DH - IEEE 1363 method */
+
+    ecdh::ecpsvdp_dh(&s0, &w1, &mut z0);
+    ecdh::ecpsvdp_dh(&s1, &w0, &mut z1);
+
+    let mut same = true;
+    for i in 0..EFS {
+        if z0[i] != z1[i] {
+            same = false
+        }
+    }
+
+    if !same {
+        println!("*** ECPSVDP-DH Failed");
+        return;
+    }
+
+    ecdh::kdf2(sha, &z0, None, EAS, &mut key);
+
+    print!("Alice's DH Key=  0x");
+    printbinary(&key);
+    print!("Servers DH Key=  0x");
+    printbinary(&key);
+
+    if ecp::CURVETYPE != CurveType::Montgomery {
+        for i in 0..17 {
+            m[i] = i as u8
+        }
+
+        println!("Testing ECIES");
+
+        p1[0] = 0x0;
+        p1[1] = 0x1;
+        p1[2] = 0x2;
+        p2[0] = 0x0;
+        p2[1] = 0x1;
+        p2[2] = 0x2;
+        p2[3] = 0x3;
+
+        let cc = ecdh::ecies_encrypt(sha, &p1, &p2, &mut rng, &w1, &m[0..17], &mut v, &mut t);
+
+        if let Some(mut c) = cc {
+            println!("Ciphertext= ");
+            print!("V= 0x");
+            printbinary(&v);
+            print!("C= 0x");
+            printbinary(&c);
+            print!("T= 0x");
+            printbinary(&t);
+
+            let mm = ecdh::ecies_decrypt(sha, &p1, &p2, &v, &mut c, &t, &s1);
+            if let Some(rm) = mm {
+                println!("Decryption succeeded");
+                print!("Message is 0x");
+                printbinary(&rm);
+            } else {
+                println!("*** ECIES Decryption Failed");
+                return;
+            }
+        } else {
+            println!("*** ECIES Encryption Failed");
+            return;
+        }
+
+        println!("Testing ECDSA");
+
+        if ecdh::ecpsp_dsa(sha, &mut rng, &s0, &m[0..17], &mut cs, &mut ds) != 0 {
+            println!("***ECDSA Signature Failed");
+            return;
+        }
+        println!("Signature= ");
+        print!("C= 0x");
+        printbinary(&cs);
+        print!("D= 0x");
+        printbinary(&ds);
+
+        if ecdh::ecpvp_dsa(sha, &w0, &m[0..17], &cs, &ds) != 0 {
+            println!("***ECDSA Verification Failed");
+            return;
+        } else {
+            println!("ECDSA Signature/Verification succeeded ")
+        }
+    }
+}
+
+#[test]
+fn ecdh_nist256() {
+    use amcl::nist256::ecdh;
+    use amcl::nist256::ecp;
+
+    let mut rng = create_rng();
+
+    let pw = "M0ng00se";
+    let pp: &[u8] = b"M0ng00se";
+    const EFS: usize = ecdh::EFS;
+    const EGS: usize = ecdh::EGS;
+    const EAS: usize = ecp::AESKEY;
+
+    let sha = ecp::HASH_TYPE;
+    let mut salt: [u8; 8] = [0; 8];
+    let mut s1: [u8; EGS] = [0; EGS];
+    let mut w0: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+    let mut w1: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+    let mut z0: [u8; EFS] = [0; EFS];
+    let mut z1: [u8; EFS] = [0; EFS];
+    let mut key: [u8; EAS] = [0; EAS];
+    let mut cs: [u8; EGS] = [0; EGS];
+    let mut ds: [u8; EGS] = [0; EGS];
+    let mut m: Vec<u8> = vec![0; 32]; // array that could be of any length. So use heap.
+    let mut p1: [u8; 3] = [0; 3];
+    let mut p2: [u8; 4] = [0; 4];
+    let mut v: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+    let mut t: [u8; 12] = [0; 12];
+
+    for i in 0..8 {
+        salt[i] = (i + 1) as u8
+    } // set Salt
+
+    println!("\nTesting ECDH/ECDSA/ECIES");
+    println!("Alice's Passphrase= {}", pw);
+
+    let mut s0: [u8; EFS] = [0; EGS];
+    ecdh::pbkdf2(sha, pp, &salt, 1000, EGS, &mut s0);
+
+    print!("Alice's private key= 0x");
+    printbinary(&s0);
+
+    /* Generate Key pair S/W */
+    ecdh::key_pair_generate(None, &mut s0, &mut w0);
+
+    print!("Alice's public key= 0x");
+    printbinary(&w0);
+
+    let mut res = ecdh::public_key_validate(&w0);
+    if res != 0 {
+        println!("ECP Public Key is invalid!");
+        return;
+    }
+
+    /* Random private key for other party */
+    ecdh::key_pair_generate(Some(&mut rng), &mut s1, &mut w1);
+
+    print!("Servers private key= 0x");
+    printbinary(&s1);
+
+    print!("Servers public key= 0x");
+    printbinary(&w1);
+
+    res = ecdh::public_key_validate(&w1);
+    if res != 0 {
+        println!("ECP Public Key is invalid!");
+        return;
+    }
+    /* Calculate common key using DH - IEEE 1363 method */
+
+    ecdh::ecpsvdp_dh(&s0, &w1, &mut z0);
+    ecdh::ecpsvdp_dh(&s1, &w0, &mut z1);
+
+    let mut same = true;
+    for i in 0..EFS {
+        if z0[i] != z1[i] {
+            same = false
+        }
+    }
+
+    if !same {
+        println!("*** ECPSVDP-DH Failed");
+        return;
+    }
+
+    ecdh::kdf2(sha, &z0, None, EAS, &mut key);
+
+    print!("Alice's DH Key=  0x");
+    printbinary(&key);
+    print!("Servers DH Key=  0x");
+    printbinary(&key);
+
+    if ecp::CURVETYPE != CurveType::Montgomery {
+        for i in 0..17 {
+            m[i] = i as u8
+        }
+
+        println!("Testing ECIES");
+
+        p1[0] = 0x0;
+        p1[1] = 0x1;
+        p1[2] = 0x2;
+        p2[0] = 0x0;
+        p2[1] = 0x1;
+        p2[2] = 0x2;
+        p2[3] = 0x3;
+
+        let cc = ecdh::ecies_encrypt(sha, &p1, &p2, &mut rng, &w1, &m[0..17], &mut v, &mut t);
+
+        if let Some(mut c) = cc {
+            println!("Ciphertext= ");
+            print!("V= 0x");
+            printbinary(&v);
+            print!("C= 0x");
+            printbinary(&c);
+            print!("T= 0x");
+            printbinary(&t);
+
+            let mm = ecdh::ecies_decrypt(sha, &p1, &p2, &v, &mut c, &t, &s1);
+            if let Some(rm) = mm {
+                println!("Decryption succeeded");
+                print!("Message is 0x");
+                printbinary(&rm);
+            } else {
+                println!("*** ECIES Decryption Failed");
+                return;
+            }
+        } else {
+            println!("*** ECIES Encryption Failed");
+            return;
+        }
+
+        println!("Testing ECDSA");
+
+        if ecdh::ecpsp_dsa(sha, &mut rng, &s0, &m[0..17], &mut cs, &mut ds) != 0 {
+            println!("***ECDSA Signature Failed");
+            return;
+        }
+        println!("Signature= ");
+        print!("C= 0x");
+        printbinary(&cs);
+        print!("D= 0x");
+        printbinary(&ds);
+
+        if ecdh::ecpvp_dsa(sha, &w0, &m[0..17], &cs, &ds) != 0 {
+            println!("***ECDSA Verification Failed");
+            return;
+        } else {
+            println!("ECDSA Signature/Verification succeeded ")
+        }
+    }
+}
+
+#[test]
+fn ecdh_goldilocks() {
+    use amcl::goldilocks::ecdh;
+    use amcl::goldilocks::ecp;
+
+    let mut rng = create_rng();
+
+    let pw = "M0ng00se";
+    let pp: &[u8] = b"M0ng00se";
+    const EFS: usize = ecdh::EFS;
+    const EGS: usize = ecdh::EGS;
+    const EAS: usize = ecp::AESKEY;
+
+    let sha = ecp::HASH_TYPE;
+    let mut salt: [u8; 8] = [0; 8];
+    let mut s1: [u8; EGS] = [0; EGS];
+    let mut w0: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+    let mut w1: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+    let mut z0: [u8; EFS] = [0; EFS];
+    let mut z1: [u8; EFS] = [0; EFS];
+    let mut key: [u8; EAS] = [0; EAS];
+    let mut cs: [u8; EGS] = [0; EGS];
+    let mut ds: [u8; EGS] = [0; EGS];
+    let mut m: Vec<u8> = vec![0; 32]; // array that could be of any length. So use heap.
+    let mut p1: [u8; 3] = [0; 3];
+    let mut p2: [u8; 4] = [0; 4];
+    let mut v: [u8; 2 * EFS + 1] = [0; 2 * EFS + 1];
+    let mut t: [u8; 12] = [0; 12];
+
+    for i in 0..8 {
+        salt[i] = (i + 1) as u8
+    } // set Salt
+
+    println!("\nTesting ECDH/ECDSA/ECIES");
+    println!("Alice's Passphrase= {}", pw);
+
+    let mut s0: [u8; EFS] = [0; EGS];
+    ecdh::pbkdf2(sha, pp, &salt, 1000, EGS, &mut s0);
+
+    print!("Alice's private key= 0x");
+    printbinary(&s0);
+
+    /* Generate Key pair S/W */
+    ecdh::key_pair_generate(None, &mut s0, &mut w0);
+
+    print!("Alice's public key= 0x");
+    printbinary(&w0);
+
+    let mut res = ecdh::public_key_validate(&w0);
+    if res != 0 {
+        println!("ECP Public Key is invalid!");
+        return;
+    }
+
+    /* Random private key for other party */
+    ecdh::key_pair_generate(Some(&mut rng), &mut s1, &mut w1);
+
+    print!("Servers private key= 0x");
+    printbinary(&s1);
+
+    print!("Servers public key= 0x");
+    printbinary(&w1);
+
+    res = ecdh::public_key_validate(&w1);
+    if res != 0 {
+        println!("ECP Public Key is invalid!");
+        return;
+    }
+    /* Calculate common key using DH - IEEE 1363 method */
+
+    ecdh::ecpsvdp_dh(&s0, &w1, &mut z0);
+    ecdh::ecpsvdp_dh(&s1, &w0, &mut z1);
+
+    let mut same = true;
+    for i in 0..EFS {
+        if z0[i] != z1[i] {
+            same = false
+        }
+    }
+
+    if !same {
+        println!("*** ECPSVDP-DH Failed");
+        return;
+    }
+
+    ecdh::kdf2(sha, &z0, None, EAS, &mut key);
+
+    print!("Alice's DH Key=  0x");
+    printbinary(&key);
+    print!("Servers DH Key=  0x");
+    printbinary(&key);
+
+    if ecp::CURVETYPE != CurveType::Montgomery {
+        for i in 0..17 {
+            m[i] = i as u8
+        }
+
+        println!("Testing ECIES");
+
+        p1[0] = 0x0;
+        p1[1] = 0x1;
+        p1[2] = 0x2;
+        p2[0] = 0x0;
+        p2[1] = 0x1;
+        p2[2] = 0x2;
+        p2[3] = 0x3;
+
+        let cc = ecdh::ecies_encrypt(sha, &p1, &p2, &mut rng, &w1, &m[0..17], &mut v, &mut t);
+
+        if let Some(mut c) = cc {
+            println!("Ciphertext= ");
+            print!("V= 0x");
+            printbinary(&v);
+            print!("C= 0x");
+            printbinary(&c);
+            print!("T= 0x");
+            printbinary(&t);
+
+            let mm = ecdh::ecies_decrypt(sha, &p1, &p2, &v, &mut c, &t, &s1);
+            if let Some(rm) = mm {
+                println!("Decryption succeeded");
+                print!("Message is 0x");
+                printbinary(&rm);
+            } else {
+                println!("*** ECIES Decryption Failed");
+                return;
+            }
+        } else {
+            println!("*** ECIES Encryption Failed");
+            return;
+        }
+
+        println!("Testing ECDSA");
+
+        if ecdh::ecpsp_dsa(sha, &mut rng, &s0, &m[0..17], &mut cs, &mut ds) != 0 {
+            println!("***ECDSA Signature Failed");
+            return;
+        }
+        println!("Signature= ");
+        print!("C= 0x");
+        printbinary(&cs);
+        print!("D= 0x");
+        printbinary(&ds);
+
+        if ecdh::ecpvp_dsa(sha, &w0, &m[0..17], &cs, &ds) != 0 {
+            println!("***ECDSA Verification Failed");
+            return;
+        } else {
+            println!("ECDSA Signature/Verification succeeded ")
+        }
+    }
+}
+
+#[test]
+fn mpin_bn254() {
+    use amcl::bn254::ecp;
+    use amcl::bn254::mpin;
+
+    let mut rng = create_rng();
+
+    pub const PERMITS: bool = true;
+    pub const PINERROR: bool = true;
+    pub const FULL: bool = true;
+    //pub const SINGLE_PASS:bool=false;
+
+    const EFS: usize = mpin::EFS;
+    const EGS: usize = mpin::EGS;
+
+    let mut s: [u8; EGS] = [0; EGS];
+    const RM: usize = EFS as usize;
+    let mut hcid: [u8; RM] = [0; RM];
+    let mut hsid: [u8; RM] = [0; RM];
+
+    const G1S: usize = 2 * EFS + 1; /* Group 1 Size */
+    const G2S: usize = 4 * EFS; /* Group 2 Size */
+    const EAS: usize = ecp::AESKEY;
+
+    let mut sst: [u8; G2S] = [0; G2S];
+    let mut token: [u8; G1S] = [0; G1S];
+    let mut permit: [u8; G1S] = [0; G1S];
+    let mut g1: [u8; 12 * EFS] = [0; 12 * EFS];
+    let mut g2: [u8; 12 * EFS] = [0; 12 * EFS];
+    let mut xid: [u8; G1S] = [0; G1S];
+    let mut xcid: [u8; G1S] = [0; G1S];
+    let mut x: [u8; EGS] = [0; EGS];
+    let mut y: [u8; EGS] = [0; EGS];
+    let mut sec: [u8; G1S] = [0; G1S];
+    let mut r: [u8; EGS] = [0; EGS];
+    let mut z: [u8; G1S] = [0; G1S];
+    let mut hid: [u8; G1S] = [0; G1S];
+    let mut htid: [u8; G1S] = [0; G1S];
+    let mut rhid: [u8; G1S] = [0; G1S];
+    let mut w: [u8; EGS] = [0; EGS];
+    let mut t: [u8; G1S] = [0; G1S];
+    let mut e: [u8; 12 * EFS] = [0; 12 * EFS];
+    let mut f: [u8; 12 * EFS] = [0; 12 * EFS];
+    let mut h: [u8; RM] = [0; RM];
+    let mut ck: [u8; EAS] = [0; EAS];
+    let mut sk: [u8; EAS] = [0; EAS];
+
+    let sha = ecp::HASH_TYPE;
+
+    println!("\nTesting MPIN - PIN is 1234");
+    /* Trusted Authority set-up */
+
+    mpin::random_generate(&mut rng, &mut s);
+    print!("Master Secret s: 0x");
+    printbinary(&s);
+
+    /* Create Client Identity */
+    let name = "testUser@miracl.com";
+    let client_id = name.as_bytes();
+
+    print!("Client ID= ");
+    printbinary(&client_id);
+
+    mpin::hash_id(sha, &client_id, &mut hcid); /* Either Client or TA calculates Hash(ID) - you decide! */
+
+    /* Client and Server are issued secrets by DTA */
+    mpin::get_server_secret(&s, &mut sst);
+    print!("Server Secret SS: 0x");
+    printbinary(&sst);
+
+    mpin::get_client_secret(&mut s, &hcid, &mut token);
+    print!("Client Secret CS: 0x");
+    printbinary(&token);
+
+    /* Client extracts PIN from secret to create Token */
+    let pin: i32 = 1234;
+    println!("Client extracts PIN= {}", pin);
+    let mut rtn = mpin::extract_pin(sha, &client_id, pin, &mut token);
+    if rtn != 0 {
+        println!("FAILURE: EXTRACT_PIN rtn: {}", rtn);
+    }
+
+    print!("Client Token TK: 0x");
+    printbinary(&token);
+
+    if FULL {
+        mpin::precompute(&token, &hcid, &mut g1, &mut g2);
+    }
+
+    let mut date = 0;
+    if PERMITS {
+        date = mpin::today();
+        /* Client gets "Time Token" permit from DTA */
+
+        mpin::get_client_permit(sha, date, &s, &hcid, &mut permit);
+        print!("Time Permit TP: 0x");
+        printbinary(&permit);
+
+        /* This encoding makes Time permit look random - Elligator squared */
+        mpin::encoding(&mut rng, &mut permit);
+        print!("Encoded Time Permit TP: 0x");
+        printbinary(&permit);
+        mpin::decoding(&mut permit);
+        print!("Decoded Time Permit TP: 0x");
+        printbinary(&permit);
+    }
+
+    print!("\nPIN= ");
+    let _ = io::Write::flush(&mut io::stdout());
+    let mut input_text = String::new();
+    let _ = io::stdin().read_line(&mut input_text);
+
+    let pin = input_text.trim().parse::<usize>().unwrap();
+
+    println!("MPIN Multi Pass");
+    /* Send U=x.ID to server, and recreate secret from token and pin */
+    rtn = mpin::client_1(
+        sha,
+        date,
+        &client_id,
+        Some(&mut rng),
+        &mut x,
+        pin,
+        &token,
+        &mut sec,
+        Some(&mut xid[..]),
+        Some(&mut xcid[..]),
+        Some(&permit[..]),
+    );
+    if rtn != 0 {
+        println!("FAILURE: CLIENT_1 rtn: {}", rtn);
+    }
+
+    if FULL {
+        mpin::hash_id(sha, &client_id, &mut hcid);
+        mpin::get_g1_multiple(Some(&mut rng), 1, &mut r, &hcid, &mut z); /* Also Send Z=r.ID to Server, remember random r */
+    }
+
+    /* Server calculates H(ID) and H(T|H(ID)) (if time mpin::PERMITS enabled), and maps them to points on the curve HID and HTID resp. */
+
+    mpin::server_1(sha, date, &client_id, &mut hid, Some(&mut htid[..]));
+
+    if date != 0 {
+        rhid.clone_from_slice(&htid[..]);
+    } else {
+        rhid.clone_from_slice(&hid[..]);
+    }
+
+    /* Server generates Random number Y and sends it to Client */
+    mpin::random_generate(&mut rng, &mut y);
+
+    if FULL {
+        mpin::hash_id(sha, &client_id, &mut hsid);
+        mpin::get_g1_multiple(Some(&mut rng), 0, &mut w, &rhid, &mut 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, &mut sec);
+    if rtn != 0 {
+        println!("FAILURE: CLIENT_2 rtn: {}", rtn);
+    }
+
+    /* 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 */
+
+    if !PINERROR {
+        rtn = mpin::server_2(
+            date,
+            &hid,
+            Some(&htid[..]),
+            &y,
+            &sst,
+            Some(&xid[..]),
+            Some(&xcid[..]),
+            &sec,
+            None,
+            None,
+        );
+    } else {
+        rtn = mpin::server_2(
+            date,
+            &hid,
+            Some(&htid[..]),
+            &y,
+            &sst,
+            Some(&xid[..]),
+            Some(&xcid[..]),
+            &sec,
+            Some(&mut e),
+            Some(&mut f),
+        );
+    }
+
+    if rtn == mpin::BAD_PIN {
+        println!("Server says - Bad Pin. I don't know you. Feck off.");
+        if PINERROR {
+            let err = mpin::kangaroo(&e, &f);
+            if err != 0 {
+                println!("(Client PIN is out by {})", err)
+            }
+        }
+        return;
+    } else {
+        println!("Server says - PIN is good! You really are {}", name);
+    }
+
+    if FULL {
+        let mut pxcid = None;
+        if PERMITS {
+            pxcid = Some(&xcid[..])
+        };
+
+        mpin::hash_all(sha, &hcid, &xid, pxcid, &sec, &y, &z, &t, &mut h);
+        mpin::client_key(sha, &g1, &g2, pin, &r, &x, &h, &t, &mut ck);
+        print!("Client Key =  0x");
+        printbinary(&ck);
+
+        mpin::hash_all(sha, &hsid, &xid, pxcid, &sec, &y, &z, &t, &mut h);
+        mpin::server_key(sha, &z, &sst, &w, &h, &hid, &xid, pxcid, &mut sk);
+        print!("Server Key =  0x");
+        printbinary(&sk);
+    }
+}
+
+#[test]
+fn mpin_bls383() {
+    //use amcl::bls383;
+    use amcl::bls383::ecp;
+    use amcl::bls383::mpin;
+
+    let mut rng = create_rng();
+
+    pub const PERMITS: bool = true;
+    pub const PINERROR: bool = true;
+    pub const FULL: bool = true;
+    //pub const SINGLE_PASS:bool=false;
+
+    const EFS: usize = mpin::EFS;
+    const EGS: usize = mpin::EGS;
+
+    let mut s: [u8; EGS] = [0; EGS];
+    const RM: usize = EFS as usize;
+    let mut hcid: [u8; RM] = [0; RM];
+    let mut hsid: [u8; RM] = [0; RM];
+
+    const G1S: usize = 2 * EFS + 1; /* Group 1 Size */
+    const G2S: usize = 4 * EFS; /* Group 2 Size */
+    const EAS: usize = ecp::AESKEY;
+
+    let mut sst: [u8; G2S] = [0; G2S];
+    let mut token: [u8; G1S] = [0; G1S];
+    let mut permit: [u8; G1S] = [0; G1S];
+    let mut g1: [u8; 12 * EFS] = [0; 12 * EFS];
+    let mut g2: [u8; 12 * EFS] = [0; 12 * EFS];
+    let mut xid: [u8; G1S] = [0; G1S];
+    let mut xcid: [u8; G1S] = [0; G1S];
+    let mut x: [u8; EGS] = [0; EGS];
+    let mut y: [u8; EGS] = [0; EGS];
+    let mut sec: [u8; G1S] = [0; G1S];
+    let mut r: [u8; EGS] = [0; EGS];
+    let mut z: [u8; G1S] = [0; G1S];
+    let mut hid: [u8; G1S] = [0; G1S];
+    let mut htid: [u8; G1S] = [0; G1S];
+    let mut rhid: [u8; G1S] = [0; G1S];
+    let mut w: [u8; EGS] = [0; EGS];
+    let mut t: [u8; G1S] = [0; G1S];
+    let mut e: [u8; 12 * EFS] = [0; 12 * EFS];
+    let mut f: [u8; 12 * EFS] = [0; 12 * EFS];
+    let mut h: [u8; RM] = [0; RM];
+    let mut ck: [u8; EAS] = [0; EAS];
+    let mut sk: [u8; EAS] = [0; EAS];
+
+    let sha = ecp::HASH_TYPE;
+
+    println!("\nTesting MPIN - PIN is 1234");
+    /* Trusted Authority set-up */
+
+    mpin::random_generate(&mut rng, &mut s);
+    print!("Master Secret s: 0x");
+    printbinary(&s);
+
+    /* Create Client Identity */
+    let name = "testUser@miracl.com";
+    let client_id = name.as_bytes();
+
+    print!("Client ID= ");
+    printbinary(&client_id);
+
+    mpin::hash_id(sha, &client_id, &mut hcid); /* Either Client or TA calculates Hash(ID) - you decide! */
+
+    /* Client and Server are issued secrets by DTA */
+    mpin::get_server_secret(&s, &mut sst);
+    print!("Server Secret SS: 0x");
+    printbinary(&sst);
+
+    mpin::get_client_secret(&mut s, &hcid, &mut token);
+    print!("Client Secret CS: 0x");
+    printbinary(&token);
+
+    /* Client extracts PIN from secret to create Token */
+    let pin: i32 = 1234;
+    println!("Client extracts PIN= {}", pin);
+    let mut rtn = mpin::extract_pin(sha, &client_id, pin, &mut token);
+    if rtn != 0 {
+        println!("FAILURE: EXTRACT_PIN rtn: {}", rtn);
+    }
+
+    print!("Client Token TK: 0x");
+    printbinary(&token);
+
+    if FULL {
+        mpin::precompute(&token, &hcid, &mut g1, &mut g2);
+    }
+
+    let mut date = 0;
+    if PERMITS {
+        date = mpin::today();
+        /* Client gets "Time Token" permit from DTA */
+
+        mpin::get_client_permit(sha, date, &s, &hcid, &mut permit);
+        print!("Time Permit TP: 0x");
+        printbinary(&permit);
+
+        /* This encoding makes Time permit look random - Elligator squared */
+        mpin::encoding(&mut rng, &mut permit);
+        print!("Encoded Time Permit TP: 0x");
+        printbinary(&permit);
+        mpin::decoding(&mut permit);
+        print!("Decoded Time Permit TP: 0x");
+        printbinary(&permit);
+    }
+
+    print!("\nPIN= ");
+    let _ = io::Write::flush(&mut io::stdout());
+    let mut input_text = String::new();
+    let _ = io::stdin().read_line(&mut input_text);
+
+    let pin = input_text.trim().parse::<usize>().unwrap();
+
+    println!("MPIN Multi Pass");
+    /* Send U=x.ID to server, and recreate secret from token and pin */
+    rtn = mpin::client_1(
+        sha,
+        date,
+        &client_id,
+        Some(&mut rng),
+        &mut x,
+        pin,
+        &token,
+        &mut sec,
+        Some(&mut xid[..]),
+        Some(&mut xcid[..]),
+        Some(&permit[..]),
+    );
+    if rtn != 0 {
+        println!("FAILURE: CLIENT_1 rtn: {}", rtn);
+    }
+
+    if FULL {
+        mpin::hash_id(sha, &client_id, &mut hcid);
+        mpin::get_g1_multiple(Some(&mut rng), 1, &mut r, &hcid, &mut z); /* Also Send Z=r.ID to Server, remember random r */
+    }
+
+    /* Server calculates H(ID) and H(T|H(ID)) (if time mpin::PERMITS enabled), and maps them to points on the curve HID and HTID resp. */
+
+    mpin::server_1(sha, date, &client_id, &mut hid, Some(&mut htid[..]));
+
+    if date != 0 {
+        rhid.clone_from_slice(&htid[..]);
+    } else {
+        rhid.clone_from_slice(&hid[..]);
+    }
+
+    /* Server generates Random number Y and sends it to Client */
+    mpin::random_generate(&mut rng, &mut y);
+
+    if FULL {
+        mpin::hash_id(sha, &client_id, &mut hsid);
+        mpin::get_g1_multiple(Some(&mut rng), 0, &mut w, &rhid, &mut 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, &mut sec);
+    if rtn != 0 {
+        println!("FAILURE: CLIENT_2 rtn: {}", rtn);
+    }
+
+    /* 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 */
+
+    if !PINERROR {
+        rtn = mpin::server_2(
+            date,
+            &hid,
+            Some(&htid[..]),
+            &y,
+            &sst,
+            Some(&xid[..]),
+            Some(&xcid[..]),
+            &sec,
+            None,
+            None,
+        );
+    } else {
+        rtn = mpin::server_2(
+            date,
+            &hid,
+            Some(&htid[..]),
+            &y,
+            &sst,
+            Some(&xid[..]),
+            Some(&xcid[..]),
+            &sec,
+            Some(&mut e),
+            Some(&mut f),
+        );
+    }
+
+    if rtn == mpin::BAD_PIN {
+        println!("Server says - Bad Pin. I don't know you. Feck off.");
+        if PINERROR {
+            let err = mpin::kangaroo(&e, &f);
+            if err != 0 {
+                println!("(Client PIN is out by {})", err)
+            }
+        }
+        return;
+    } else {
+        println!("Server says - PIN is good! You really are {}", name);
+    }
+
+    if FULL {
+        let mut pxcid = None;
+        if PERMITS {
+            pxcid = Some(&xcid[..])
+        };
+
+        mpin::hash_all(sha, &hcid, &xid, pxcid, &sec, &y, &z, &t, &mut h);
+        mpin::client_key(sha, &g1, &g2, pin, &r, &x, &h, &t, &mut ck);
+        print!("Client Key =  0x");
+        printbinary(&ck);
+
+        mpin::hash_all(sha, &hsid, &xid, pxcid, &sec, &y, &z, &t, &mut h);
+        mpin::server_key(sha, &z, &sst, &w, &h, &hid, &xid, pxcid, &mut sk);
+        print!("Server Key =  0x");
+        printbinary(&sk);
+    }
+}
+
+#[test]
+fn mpin_bls24() {
+    //use amcl::bls24;
+    use amcl::bls24::ecp;
+    use amcl::bls24::mpin192;
+
+    let mut rng = create_rng();
+
+    pub const PERMITS: bool = true;
+    pub const PINERROR: bool = true;
+    pub const FULL: bool = true;
+    //pub const SINGLE_PASS:bool=false;
+
+    const EFS: usize = mpin192::EFS;
+    const EGS: usize = mpin192::EGS;
+
+    let mut s: [u8; EGS] = [0; EGS];
+    const RM: usize = EFS as usize;
+    let mut hcid: [u8; RM] = [0; RM];
+    let mut hsid: [u8; RM] = [0; RM];
+
+    const G1S: usize = 2 * EFS + 1; /* Group 1 Size */
+    const G2S: usize = 8 * EFS; /* Group 2 Size */
+    const EAS: usize = ecp::AESKEY;
+
+    let mut sst: [u8; G2S] = [0; G2S];
+    let mut token: [u8; G1S] = [0; G1S];
+    let mut permit: [u8; G1S] = [0; G1S];
+    let mut g1: [u8; 24 * EFS] = [0; 24 * EFS];
+    let mut g2: [u8; 24 * EFS] = [0; 24 * EFS];
+    let mut xid: [u8; G1S] = [0; G1S];
+    let mut xcid: [u8; G1S] = [0; G1S];
+    let mut x: [u8; EGS] = [0; EGS];
+    let mut y: [u8; EGS] = [0; EGS];
+    let mut sec: [u8; G1S] = [0; G1S];
+    let mut r: [u8; EGS] = [0; EGS];
+    let mut z: [u8; G1S] = [0; G1S];
+    let mut hid: [u8; G1S] = [0; G1S];
+    let mut htid: [u8; G1S] = [0; G1S];
+    let mut rhid: [u8; G1S] = [0; G1S];
+    let mut w: [u8; EGS] = [0; EGS];
+    let mut t: [u8; G1S] = [0; G1S];
+    let mut e: [u8; 24 * EFS] = [0; 24 * EFS];
+    let mut f: [u8; 24 * EFS] = [0; 24 * EFS];
+    let mut h: [u8; RM] = [0; RM];
+    let mut ck: [u8; EAS] = [0; EAS];
+    let mut sk: [u8; EAS] = [0; EAS];
+
+    let sha = ecp::HASH_TYPE;
+
+    println!("\nTesting MPIN - PIN is 1234");
+    /* Trusted Authority set-up */
+
+    mpin192::random_generate(&mut rng, &mut s);
+    print!("Master Secret s: 0x");
+    printbinary(&s);
+
+    /* Create Client Identity */
+    let name = "testUser@miracl.com";
+    let client_id = name.as_bytes();
+
+    print!("Client ID= ");
+    printbinary(&client_id);
+
+    mpin192::hash_id(sha, &client_id, &mut hcid); /* Either Client or TA calculates Hash(ID) - you decide! */
+
+    /* Client and Server are issued secrets by DTA */
+    mpin192::get_server_secret(&s, &mut sst);
+    print!("Server Secret SS: 0x");
+    printbinary(&sst);
+
+    mpin192::get_client_secret(&mut s, &hcid, &mut token);
+    print!("Client Secret CS: 0x");
+    printbinary(&token);
+
+    /* Client extracts PIN from secret to create Token */
+    let pin: i32 = 1234;
+    println!("Client extracts PIN= {}", pin);
+    let mut rtn = mpin192::extract_pin(sha, &client_id, pin, &mut token);
+    if rtn != 0 {
+        println!("FAILURE: EXTRACT_PIN rtn: {}", rtn);
+    }
+
+    print!("Client Token TK: 0x");
+    printbinary(&token);
+
+    if FULL {
+        mpin192::precompute(&token, &hcid, &mut g1, &mut g2);
+    }
+
+    let mut date = 0;
+    if PERMITS {
+        date = mpin192::today();
+        /* Client gets "Time Token" permit from DTA */
+
+        mpin192::get_client_permit(sha, date, &s, &hcid, &mut permit);
+        print!("Time Permit TP: 0x");
+        printbinary(&permit);
+
+        /* This encoding makes Time permit look random - Elligator squared */
+        mpin192::encoding(&mut rng, &mut permit);
+        print!("Encoded Time Permit TP: 0x");
+        printbinary(&permit);
+        mpin192::decoding(&mut permit);
+        print!("Decoded Time Permit TP: 0x");
+        printbinary(&permit);
+    }
+
+    print!("\nPIN= ");
+    let _ = io::Write::flush(&mut io::stdout());
+    let mut input_text = String::new();
+    let _ = io::stdin().read_line(&mut input_text);
+
+    let pin = input_text.trim().parse::<usize>().unwrap();
+
+    println!("MPIN Multi Pass");
+    /* Send U=x.ID to server, and recreate secret from token and pin */
+    rtn = mpin192::client_1(
+        sha,
+        date,
+        &client_id,
+        Some(&mut rng),
+        &mut x,
+        pin,
+        &token,
+        &mut sec,
+        Some(&mut xid[..]),
+        Some(&mut xcid[..]),
+        Some(&permit[..]),
+    );
+    if rtn != 0 {
+        println!("FAILURE: CLIENT_1 rtn: {}", rtn);
+    }
+
+    if FULL {
+        mpin192::hash_id(sha, &client_id, &mut hcid);
+        mpin192::get_g1_multiple(Some(&mut rng), 1, &mut r, &hcid, &mut z); /* Also Send Z=r.ID to Server, remember random r */
+    }
+
+    /* Server calculates H(ID) and H(T|H(ID)) (if time mpin192::PERMITS enabled), and maps them to points on the curve HID and HTID resp. */
+
+    mpin192::server_1(sha, date, &client_id, &mut hid, Some(&mut htid[..]));
+
+    if date != 0 {
+        rhid.clone_from_slice(&htid[..]);
+    } else {
+        rhid.clone_from_slice(&hid[..]);
+    }
+
+    /* Server generates Random number Y and sends it to Client */
+    mpin192::random_generate(&mut rng, &mut y);
+
+    if FULL {
+        mpin192::hash_id(sha, &client_id, &mut hsid);
+        mpin192::get_g1_multiple(Some(&mut rng), 0, &mut w, &rhid, &mut 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 = mpin192::client_2(&x, &y, &mut sec);
+    if rtn != 0 {
+        println!("FAILURE: CLIENT_2 rtn: {}", rtn);
+    }
+
+    /* 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 */
+
+    if !PINERROR {
+        rtn = mpin192::server_2(
+            date,
+            &hid,
+            Some(&htid[..]),
+            &y,
+            &sst,
+            Some(&xid[..]),
+            Some(&xcid[..]),
+            &sec,
+            None,
+            None,
+        );
+    } else {
+        rtn = mpin192::server_2(
+            date,
+            &hid,
+            Some(&htid[..]),
+            &y,
+            &sst,
+            Some(&xid[..]),
+            Some(&xcid[..]),
+            &sec,
+            Some(&mut e),
+            Some(&mut f),
+        );
+    }
+
+    if rtn == mpin192::BAD_PIN {
+        println!("Server says - Bad Pin. I don't know you. Feck off.");
+        if PINERROR {
+            let err = mpin192::kangaroo(&e, &f);
+            if err != 0 {
+                println!("(Client PIN is out by {})", err)
+            }
+        }
+        return;
+    } else {
+        println!("Server says - PIN is good! You really are {}", name);
+    }
+
+    if FULL {
+        let mut pxcid = None;
+        if PERMITS {
+            pxcid = Some(&xcid[..])
+        };
+
+        mpin192::hash_all(sha, &hcid, &xid, pxcid, &sec, &y, &z, &t, &mut h);
+        mpin192::client_key(sha, &g1, &g2, pin, &r, &x, &h, &t, &mut ck);
+        print!("Client Key =  0x");
+        printbinary(&ck);
+
+        mpin192::hash_all(sha, &hsid, &xid, pxcid, &sec, &y, &z, &t, &mut h);
+        mpin192::server_key(sha, &z, &sst, &w, &h, &hid, &xid, pxcid, &mut sk);
+        print!("Server Key =  0x");
+        printbinary(&sk);
+    }
+}
+
+#[test]
+fn mpin_bls48() {
+    //use amcl::bls48;
+    use amcl::bls48::ecp;
+    use amcl::bls48::mpin256;
+
+    let mut rng = create_rng();
+
+    pub const PERMITS: bool = true;
+    pub const PINERROR: bool = true;
+    pub const FULL: bool = true;
+    //pub const SINGLE_PASS:bool=false;
+
+    const EFS: usize = mpin256::EFS;
+    const EGS: usize = mpin256::EGS;
+
+    let mut s: [u8; EGS] = [0; EGS];
+    const RM: usize = EFS as usize;
+    let mut hcid: [u8; RM] = [0; RM];
+    let mut hsid: [u8; RM] = [0; RM];
+
+    const G1S: usize = 2 * EFS + 1; /* Group 1 Size */
+    const G2S: usize = 16 * EFS; /* Group 2 Size */
+    const EAS: usize = ecp::AESKEY;
+
+    let mut sst: [u8; G2S] = [0; G2S];
+    let mut token: [u8; G1S] = [0; G1S];
+    let mut permit: [u8; G1S] = [0; G1S];
+    let mut g1: [u8; 48 * EFS] = [0; 48 * EFS];
+    let mut g2: [u8; 48 * EFS] = [0; 48 * EFS];
+    let mut xid: [u8; G1S] = [0; G1S];
+    let mut xcid: [u8; G1S] = [0; G1S];
+    let mut x: [u8; EGS] = [0; EGS];
+    let mut y: [u8; EGS] = [0; EGS];
+    let mut sec: [u8; G1S] = [0; G1S];
+    let mut r: [u8; EGS] = [0; EGS];
+    let mut z: [u8; G1S] = [0; G1S];
+    let mut hid: [u8; G1S] = [0; G1S];
+    let mut htid: [u8; G1S] = [0; G1S];
+    let mut rhid: [u8; G1S] = [0; G1S];
+    let mut w: [u8; EGS] = [0; EGS];
+    let mut t: [u8; G1S] = [0; G1S];
+    let mut e: [u8; 48 * EFS] = [0; 48 * EFS];
+    let mut f: [u8; 48 * EFS] = [0; 48 * EFS];
+    let mut h: [u8; RM] = [0; RM];
+    let mut ck: [u8; EAS] = [0; EAS];
+    let mut sk: [u8; EAS] = [0; EAS];
+
+    let sha = ecp::HASH_TYPE;
+
+    println!("\nTesting MPIN - PIN is 1234");
+    /* Trusted Authority set-up */
+
+    mpin256::random_generate(&mut rng, &mut s);
+    print!("Master Secret s: 0x");
+    printbinary(&s);
+
+    /* Create Client Identity */
+    let name = "testUser@miracl.com";
+    let client_id = name.as_bytes();
+
+    print!("Client ID= ");
+    printbinary(&client_id);
+
+    mpin256::hash_id(sha, &client_id, &mut hcid); /* Either Client or TA calculates Hash(ID) - you decide! */
+
+    /* Client and Server are issued secrets by DTA */
+    mpin256::get_server_secret(&s, &mut sst);
+    print!("Server Secret SS: 0x");
+    printbinary(&sst);
+
+    mpin256::get_client_secret(&mut s, &hcid, &mut token);
+    print!("Client Secret CS: 0x");
+    printbinary(&token);
+
+    /* Client extracts PIN from secret to create Token */
+    let pin: i32 = 1234;
+    println!("Client extracts PIN= {}", pin);
+    let mut rtn = mpin256::extract_pin(sha, &client_id, pin, &mut token);
+    if rtn != 0 {
+        println!("FAILURE: EXTRACT_PIN rtn: {}", rtn);
+    }
+
+    print!("Client Token TK: 0x");
+    printbinary(&token);
+
+    if FULL {
+        mpin256::precompute(&token, &hcid, &mut g1, &mut g2);
+    }
+
+    let mut date = 0;
+    if PERMITS {
+        date = mpin256::today();
+        /* Client gets "Time Token" permit from DTA */
+
+        mpin256::get_client_permit(sha, date, &s, &hcid, &mut permit);
+        print!("Time Permit TP: 0x");
+        printbinary(&permit);
+
+        /* This encoding makes Time permit look random - Elligator squared */
+        mpin256::encoding(&mut rng, &mut permit);
+        print!("Encoded Time Permit TP: 0x");
+        printbinary(&permit);
+        mpin256::decoding(&mut permit);
+        print!("Decoded Time Permit TP: 0x");
+        printbinary(&permit);
+    }
+
+    print!("\nPIN= ");
+    let _ = io::Write::flush(&mut io::stdout());
+    let mut input_text = String::new();
+    let _ = io::stdin().read_line(&mut input_text);
+
+    let pin = input_text.trim().parse::<usize>().unwrap();
+
+    println!("MPIN Multi Pass");
+    /* Send U=x.ID to server, and recreate secret from token and pin */
+    rtn = mpin256::client_1(
+        sha,
+        date,
+        &client_id,
+        Some(&mut rng),
+        &mut x,
+        pin,
+        &token,
+        &mut sec,
+        Some(&mut xid[..]),
+        Some(&mut xcid[..]),
+        Some(&permit[..]),
+    );
+    if rtn != 0 {
+        println!("FAILURE: CLIENT_1 rtn: {}", rtn);
+    }
+
+    if FULL {
+        mpin256::hash_id(sha, &client_id, &mut hcid);
+        mpin256::get_g1_multiple(Some(&mut rng), 1, &mut r, &hcid, &mut z); /* Also Send Z=r.ID to Server, remember random r */
+    }
+
+    /* Server calculates H(ID) and H(T|H(ID)) (if time mpin256::PERMITS enabled), and maps them to points on the curve HID and HTID resp. */
+
+    mpin256::server_1(sha, date, &client_id, &mut hid, Some(&mut htid[..]));
+
+    if date != 0 {
+        rhid.clone_from_slice(&htid[..]);
+    } else {
+        rhid.clone_from_slice(&hid[..]);
+    }
+
+    /* Server generates Random number Y and sends it to Client */
+    mpin256::random_generate(&mut rng, &mut y);
+
+    if FULL {
+        mpin256::hash_id(sha, &client_id, &mut hsid);
+        mpin256::get_g1_multiple(Some(&mut rng), 0, &mut w, &rhid, &mut 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 = mpin256::client_2(&x, &y, &mut sec);
+    if rtn != 0 {
+        println!("FAILURE: CLIENT_2 rtn: {}", rtn);
+    }
+
+    /* 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 */
+
+    if !PINERROR {
+        rtn = mpin256::server_2(
+            date,
+            &hid,
+            Some(&htid[..]),
+            &y,
+            &sst,
+            Some(&xid[..]),
+            Some(&xcid[..]),
+            &sec,
+            None,
+            None,
+        );
+    } else {
+        rtn = mpin256::server_2(
+            date,
+            &hid,
+            Some(&htid[..]),
+            &y,
+            &sst,
+            Some(&xid[..]),
+            Some(&xcid[..]),
+            &sec,
+            Some(&mut e),
+            Some(&mut f),
+        );
+    }
+
+    if rtn == mpin256::BAD_PIN {
+        println!("Server says - Bad Pin. I don't know you. Feck off.");
+        if PINERROR {
+            let err = mpin256::kangaroo(&e, &f);
+            if err != 0 {
+                println!("(Client PIN is out by {})", err)
+            }
+        }
+        return;
+    } else {
+        println!("Server says - PIN is good! You really are {}", name);
+    }
+
+    if FULL {
+        let mut pxcid = None;
+        if PERMITS {
+            pxcid = Some(&xcid[..])
+        };
+
+        mpin256::hash_all(sha, &hcid, &xid, pxcid, &sec, &y, &z, &t, &mut h);
+        mpin256::client_key(sha, &g1, &g2, pin, &r, &x, &h, &t, &mut ck);
+        print!("Client Key =  0x");
+        printbinary(&ck);
+
+        mpin256::hash_all(sha, &hsid, &xid, pxcid, &sec, &y, &z, &t, &mut h);
+        mpin256::server_key(sha, &z, &sst, &w, &h, &hid, &xid, pxcid, &mut sk);
+        print!("Server Key =  0x");
+        printbinary(&sk);
+    }
+}
+
+#[test]
+fn rsa_2048() {
+    //use amcl::rsa2048;
+    use amcl::rsa2048::ff;
+    use amcl::rsa2048::rsa;
+
+    let mut rng = create_rng();
+
+    let sha = rsa::HASH_TYPE;
+    let message: &[u8] = b"Hello World\n";
+    const RFS: usize = rsa::RFS;
+
+    let mut pbc = rsa::new_public_key(ff::FFLEN);
+    let mut prv = rsa::new_private_key(ff::HFLEN);
+
+    let mut ml: [u8; RFS] = [0; RFS];
+    let mut ms: [u8; RFS] = [0; RFS];
+    let mut c: [u8; RFS] = [0; RFS];
+    let mut s: [u8; RFS] = [0; RFS];
+    let mut e: [u8; RFS] = [0; RFS];
+
+    println!("\nTesting RSA");
+    println!("Generating public/private key pair");
+    rsa::key_pair(&mut rng, 65537, &mut prv, &mut pbc);
+
+    println!("Encrypting test string\n");
+    rsa::oaep_encode(sha, &message, &mut rng, None, &mut e); /* OAEP encode message M to E  */
+
+    rsa::encrypt(&pbc, &e, &mut c); /* encrypt encoded message */
+    print!("Ciphertext= 0x");
+    printbinary(&c);
+
+    println!("Decrypting test string");
+    rsa::decrypt(&prv, &c, &mut ml);
+    let mlen = rsa::oaep_decode(sha, None, &mut ml); /* OAEP decode message  */
+
+    let mess = str::from_utf8(&ml[0..mlen]).unwrap();
+    print!("{}", &mess);
+
+    println!("Signing message");
+    rsa::pkcs15(sha, message, &mut c);
+
+    rsa::decrypt(&prv, &c, &mut s); /* create signature in S */
+
+    print!("Signature= 0x");
+    printbinary(&s);
+
+    rsa::encrypt(&pbc, &s, &mut ms);
+
+    let mut cmp = true;
+    if c.len() != ms.len() {
+        cmp = false;
+    } else {
+        for j in 0..c.len() {
+            if c[j] != ms[j] {
+                cmp = false
+            }
+        }
+    }
+    if cmp {
+        println!("Signature is valid");
+    } else {
+        println!("Signature is INVALID");
+    }
+
+    rsa::private_key_kill(&mut prv);
+}
diff --git a/tests/test_bls.rs b/tests/test_bls.rs
new file mode 100644
index 0000000..20cf73b
--- /dev/null
+++ b/tests/test_bls.rs
@@ -0,0 +1,190 @@
+/*
+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.
+*/
+
+extern crate amcl;
+
+use amcl::rand::RAND;
+
+pub fn printbinary(array: &[u8]) {
+    for i in 0..array.len() {
+        print!("{:02X}", array[i])
+    }
+    println!("")
+}
+
+fn create_rng() -> RAND {
+    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);
+    rng
+}
+
+#[test]
+fn bls_bn254() {
+    use amcl::bn254::bls;
+
+    let mut rng = create_rng();
+
+    const BFS: usize = bls::BFS;
+    const BGS: usize = bls::BGS;
+
+    let mut s: [u8; BGS] = [0; BGS];
+
+    const G1S: usize = BFS + 1; /* Group 1 Size */
+    const G2S: usize = 4 * BFS; /* Group 2 Size */
+
+    let mut w: [u8; G2S] = [0; G2S];
+    let mut sig: [u8; G1S] = [0; G1S];
+
+    let m = String::from("This is a test message");
+
+    bls::key_pair_generate(&mut rng, &mut s, &mut w);
+    print!("Private key : 0x");
+    printbinary(&s);
+    print!("Public  key : 0x");
+    printbinary(&w);
+
+    bls::sign(&mut sig, &m, &s);
+    print!("Signature : 0x");
+    printbinary(&sig);
+
+    let res = bls::verify(&sig, &m, &w);
+    if res == 0 {
+        println!("Signature is OK");
+    } else {
+        println!("Signature is *NOT* OK");
+    }
+}
+
+#[test]
+fn bls_bls383() {
+    use amcl::bls383::bls;
+
+    let mut rng = create_rng();
+
+    const BFS: usize = bls::BFS;
+    const BGS: usize = bls::BGS;
+
+    let mut s: [u8; BGS] = [0; BGS];
+
+    const G1S: usize = BFS + 1; /* Group 1 Size */
+    const G2S: usize = 4 * BFS; /* Group 2 Size */
+
+    let mut w: [u8; G2S] = [0; G2S];
+    let mut sig: [u8; G1S] = [0; G1S];
+
+    let m = String::from("This is a test message");
+
+    bls::key_pair_generate(&mut rng, &mut s, &mut w);
+    print!("Private key : 0x");
+    printbinary(&s);
+    print!("Public  key : 0x");
+    printbinary(&w);
+
+    bls::sign(&mut sig, &m, &s);
+    print!("Signature : 0x");
+    printbinary(&sig);
+
+    let res = bls::verify(&sig, &m, &w);
+    if res == 0 {
+        println!("Signature is OK");
+    } else {
+        println!("Signature is *NOT* OK");
+    }
+}
+
+#[test]
+fn bls_bls24() {
+    use amcl::bls24::bls192;
+
+    let mut rng = create_rng();
+
+    const BFS: usize = bls192::BFS;
+    const BGS: usize = bls192::BGS;
+
+    let mut s: [u8; BGS] = [0; BGS];
+
+    const G1S: usize = BFS + 1; /* Group 1 Size */
+    const G2S: usize = 8 * BFS; /* Group 2 Size */
+
+    let mut w: [u8; G2S] = [0; G2S];
+    let mut sig: [u8; G1S] = [0; G1S];
+
+    let m = String::from("This is a test message");
+
+    bls192::key_pair_generate(&mut rng, &mut s, &mut w);
+    print!("Private key : 0x");
+    printbinary(&s);
+    print!("Public  key : 0x");
+    printbinary(&w);
+
+    bls192::sign(&mut sig, &m, &s);
+    print!("Signature : 0x");
+    printbinary(&sig);
+
+    let res = bls192::verify(&sig, &m, &w);
+    if res == 0 {
+        println!("Signature is OK");
+    } else {
+        println!("Signature is *NOT* OK");
+    }
+}
+
+#[test]
+fn bls_bls48() {
+    use amcl::bls48::bls256;
+
+    let mut rng = create_rng();
+
+    const BFS: usize = bls256::BFS;
+    const BGS: usize = bls256::BGS;
+
+    let mut s: [u8; BGS] = [0; BGS];
+
+    const G1S: usize = BFS + 1; /* Group 1 Size */
+    const G2S: usize = 16 * BFS; /* Group 2 Size */
+
+    let mut w: [u8; G2S] = [0; G2S];
+    let mut sig: [u8; G1S] = [0; G1S];
+
+    let m = String::from("This is a test message");
+
+    bls256::key_pair_generate(&mut rng, &mut s, &mut w);
+    print!("Private key : 0x");
+    printbinary(&s);
+    print!("Public  key : 0x");
+    printbinary(&w);
+
+    bls256::sign(&mut sig, &m, &s);
+    print!("Signature : 0x");
+    printbinary(&sig);
+
+    let res = bls256::verify(&sig, &m, &w);
+    if res == 0 {
+        println!("Signature is OK");
+    } else {
+        println!("Signature is *NOT* OK");
+    }
+}
diff --git a/tests/test_nhs.rs b/tests/test_nhs.rs
new file mode 100644
index 0000000..f272291
--- /dev/null
+++ b/tests/test_nhs.rs
@@ -0,0 +1,71 @@
+/*
+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.
+*/
+
+// Tests NewHope Simple API
+
+// See https://eprint.iacr.org/2016/1157 (Alkim, Ducas, Popplemann and Schwabe)
+
+extern crate amcl;
+
+use amcl::nhs;
+use amcl::rand::RAND;
+
+#[test]
+fn test_nhs() {
+    let mut raw: [u8; 100] = [0; 100];
+
+    let mut srng = RAND::new();
+    srng.clean();
+    for i in 0..100 {
+        raw[i] = (i + 1) as u8
+    }
+
+    srng.seed(100, &raw);
+
+    let mut crng = RAND::new();
+    crng.clean();
+    for i in 0..100 {
+        raw[i] = (i + 2) as u8
+    }
+
+    crng.seed(100, &raw);
+
+    let mut ss: [u8; 1792] = [0; 1792];
+    let mut sb: [u8; 1824] = [0; 1824];
+    let mut uc: [u8; 2176] = [0; 2176];
+
+    let mut keya: [u8; 32] = [0; 32];
+    let mut keyb: [u8; 32] = [0; 32];
+
+    nhs::server_1(&mut srng, &mut sb, &mut ss);
+
+    nhs::client(&mut crng, &sb, &mut uc, &mut keyb);
+
+    nhs::server_2(&ss, &uc, &mut keya);
+
+    for i in 0..keya.len() {
+        print!("{:02X}", keya[i]);
+    }
+    println!("");
+
+    for i in 0..keyb.len() {
+        print!("{:02X}", keyb[i]);
+    }
+    println!("");
+}