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 2020/05/05 06:39:23 UTC

[incubator-milagro-crypto-rust] 37/44: Merge develop and fix conflicts

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 40b9037be7d7fe1abe6d376b153997d68599285d
Merge: cab5914 d6bd914
Author: Kirk Baird <ba...@outlook.com>
AuthorDate: Wed Apr 22 10:21:13 2020 +1000

    Merge develop and fix conflicts
    
    Signed-off-by: Kirk Baird <ba...@outlook.com>

 Cargo.lock                                         | 662 +++++++++++++++++++++
 Cargo.toml                                         |  16 +-
 src/big.rs                                         |  11 +-
 src/bls381.rs                                      | 424 +++++++++++++
 src/bls381/iso.rs                                  | 335 +++++++++++
 src/dbig.rs                                        |  21 +-
 src/ecp.rs                                         |  23 +
 src/ecp2.rs                                        |  45 +-
 src/errors.rs                                      |   4 +
 src/fp.rs                                          |  74 ++-
 src/fp2.rs                                         |  23 +
 src/hash256.rs                                     | 266 ++++++++-
 src/hash384.rs                                     | 228 +++++--
 src/hash512.rs                                     | 296 ++++++++-
 src/hash_to_curve.rs                               | 307 ++++++++++
 src/lib.rs                                         |  45 +-
 src/roms/{rom_bls381_32.rs => rom_bls381g1_32.rs}  |  36 +-
 src/roms/{rom_bls381_64.rs => rom_bls381g1_64.rs}  |  38 +-
 src/roms/{rom_bls381_32.rs => rom_bls381g2_32.rs}  |  38 +-
 src/roms/{rom_bls381_64.rs => rom_bls381g2_64.rs}  |  38 +-
 .../BLS12381G1_XMD:SHA-256_SSWU_NU_.json           |  77 +++
 .../BLS12381G1_XMD:SHA-256_SSWU_RO_.json           |  97 +++
 .../BLS12381G1_XMD:SHA-256_SVDW_NU_.json           |  77 +++
 .../BLS12381G1_XMD:SHA-256_SVDW_RO_.json           |  97 +++
 .../BLS12381G2_XMD:SHA-256_SSWU_NU_.json           |  77 +++
 .../BLS12381G2_XMD:SHA-256_SSWU_RO_.json           |  97 +++
 .../BLS12381G2_XMD:SHA-256_SVDW_NU_.json           |  77 +++
 .../BLS12381G2_XMD:SHA-256_SVDW_RO_.json           |  97 +++
 src/test_utils/mod.rs                              |  20 +
 src/test_utils/test_vector_structs.rs              |  44 ++
 30 files changed, 3542 insertions(+), 148 deletions(-)

diff --cc src/bls381.rs
index 0000000,de56701..f03576d
mode 000000,100644..100644
--- a/src/bls381.rs
+++ b/src/bls381.rs
@@@ -1,0 -1,424 +1,424 @@@
+ /*
+ 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.
+ */
+ 
+ /// BLS12-381
+ ///
+ /// An implementation of BLS12-381 as specified by the following standard:
+ /// https://github.com/cfrg/draft-irtf-cfrg-bls-signature
+ pub mod iso;
+ 
+ use self::iso::{iso11_to_ecp, iso3_to_ecp2};
+ use super::big::Big;
+ use super::ecp::ECP;
+ use super::ecp2::ECP2;
+ use super::fp::FP;
+ use super::fp2::FP2;
+ use super::hash_to_curve::*;
+ use super::pair;
+ use super::rom::*;
+ 
+ use rand::RAND;
+ use sha3::SHA3;
+ use sha3::SHAKE256;
+ use std::str;
+ 
+ // BLS API Functions
+ pub const BFS: usize = MODBYTES as usize;
+ pub const BGS: usize = MODBYTES as usize;
+ pub const BLS_OK: isize = 0;
+ pub const BLS_FAIL: isize = -1;
+ 
+ // Hash a message to an ECP point, using SHA3
+ #[allow(non_snake_case)]
+ fn bls_hashit(m: &str) -> ECP {
+     let mut sh = SHA3::new(SHAKE256);
+     let mut hm: [u8; BFS] = [0; BFS];
+     let t = m.as_bytes();
+     for i in 0..m.len() {
+         sh.process(t[i]);
+     }
+     sh.shake(&mut hm, BFS);
+     let P = ECP::mapit(&hm);
+     P
+ }
+ 
+ /// Generate key pair, private key s, public key w
+ pub fn key_pair_generate(mut rng: &mut RAND, s: &mut [u8], w: &mut [u8]) -> isize {
+     let q = Big::new_ints(&CURVE_ORDER);
+     let g = ECP2::generator();
+     let sc = Big::randomnum(&q, &mut rng);
+     sc.tobytes(s);
+     pair::g2mul(&g, &sc).tobytes(w);
+     BLS_OK
+ }
+ 
+ /// Sign message m using private key s to produce signature sig.
+ pub fn sign(sig: &mut [u8], m: &str, s: &[u8]) -> isize {
+     let d = bls_hashit(m);
+     let mut sc = Big::frombytes(&s);
+     pair::g1mul(&d, &mut sc).tobytes(sig, true);
+     BLS_OK
+ }
+ 
+ /// Verify signature given message m, the signature sig, and the public key w
+ pub fn verify(sig: &[u8], m: &str, w: &[u8]) -> isize {
+     let hm = bls_hashit(m);
+     let mut d = ECP::frombytes(&sig);
+     let g = ECP2::generator();
+     let pk = ECP2::frombytes(&w);
+     d.neg();
+ 
+     // Use new multi-pairing mechanism
+     let mut r = pair::initmp();
+     pair::another(&mut r, &g, &d);
+     pair::another(&mut r, &pk, &hm);
+     let mut v = pair::miller(&r);
+ 
+     //.. or alternatively
+     //    let mut v = pair::ate2(&g, &d, &pk, &hm);
+ 
+     v = pair::fexp(&v);
+     if v.isunity() {
+         return BLS_OK;
+     }
+     BLS_FAIL
+ }
+ 
+ /*************************************************************************************************
+ * Functions for hashing to curve when signatures are on ECP
+ *************************************************************************************************/
+ /// Hash to Curve
+ ///
+ /// Takes a message as input and converts it to a Curve Point
+ /// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-3
+ pub fn hash_to_curve_g1(msg: &[u8]) -> ECP {
+     let u =
+         hash_to_field_fp(msg, 2, DST).expect("hash to field should not fail for given parameters");
 -    let mut q0 = map_to_curve_g1(u[0]);
 -    let q1 = map_to_curve_g1(u[1]);
++    let mut q0 = map_to_curve_g1(u[0].clone());
++    let q1 = map_to_curve_g1(u[1].clone());
+     q0.add(&q1);
+     let p = q0.mul(&H_EFF_G1);
+     p
+ }
+ 
+ // Simplified SWU for Pairing-Friendly Curves
+ //
+ // Take a field point and map it to a Curve Point.
+ // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-6.6.2
+ fn map_to_curve_g1(u: FP) -> ECP {
+     let (x, y) = simplified_swu_fp(u);
+     iso11_to_ecp(&x, &y)
+ }
+ 
+ /*************************************************************************************************
+ * Functions for hashing to curve when signatures are on ECP2
+ *************************************************************************************************/
+ /// Hash to Curve
+ ///
+ /// Takes a message as input and converts it to a Curve Point
+ /// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-3
+ pub fn hash_to_curve_g2(msg: &[u8]) -> ECP2 {
+     let u =
+         hash_to_field_fp2(msg, 2, DST).expect("hash to field should not fail for given parameters");
 -    let mut q0 = map_to_curve_g2(u[0]);
 -    let q1 = map_to_curve_g2(u[1]);
++    let mut q0 = map_to_curve_g2(u[0].clone());
++    let q1 = map_to_curve_g2(u[1].clone());
+     q0.add(&q1);
+     q0.clear_cofactor();
+     q0
+ }
+ 
+ // Simplified SWU for Pairing-Friendly Curves
+ //
+ // Take a field point and map it to a Curve Point.
+ // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-6.6.2
+ fn map_to_curve_g2(u: FP2) -> ECP2 {
+     let (x, y) = simplified_swu_fp2(u);
+     iso3_to_ecp2(&x, &y)
+ }
+ 
+ #[cfg(test)]
+ mod tests {
+     use super::*;
+     use crate::test_utils::*;
+ 
+     // The following tests were exported from
+     // https://github.com/kwantam/bls_sigs_ref/tree/master/python-impl
+     // Format: [(input, output)]
+     // input: [u0_a, u0_b, u1_a, u1_b]
+     // output: [x_a, x_b, y_a, y_b]
+     pub const TESTS: [([&str; 4], [&str; 4]); 4] =
+         [
+             // Test 0
+             (
+                 // Input
+                 [
+                     "004ad233c619209060e40059b81e4c1f92796b05aa1bc6358d65e53dc0d657dfbc713d4030b0b6d9234a6634fd1944e7",
+                     "0e2386c82713441bc3b06a460bd81850f4bf376ea89c80b18c0881e855c58dc8e83b2fd23af983f4786508e30c42af01",
+                     "08a6a75e0a8d32f1e096f29047ea879dd34a5504218d7ce92c32c244786822fb73fbf708d167ad86537468249ec6df48",
+                     "07016d0e5e13cd65780042c6f7b4c74ae1c58da438c99582696818b5c229895b893318dcb87d2a65e557d4ebeb408b70"
+                 ],
+                 // Output
+                 [
+                     "04861c41efcc5fc56e62273692b48da25d950d2a0aaffb34eff80e8dbdc2d41ca38555ceb8554368436aea47d16056b5",
+                     "09db5217528c55d982cf05fc54242bdcd25f1ebb73372e00e16d8e0f19dc3aeabdeef2d42d693405a04c37d60961526a",
+                     "177d05b95e7879a7ddbd83c15114b5a4e9846fde72b2263072dc9e60db548ccbadaacb92cc4952d4f47425fe3c5e0172",
+                     "0fc82c99b928ed9df12a74f9215c3df8ae1e9a3fa54c00897889296890b23a0edcbb9653f9170bf715f882b35c0b4647"
+                 ]
+             ),
+             // Test 1
+             (
+                 // Input
+                 [
+                     "083c57b3ee2ecba5bbf874bb03897827f949096efceea00f002c979de7e5e9429fcf1f3323d4c8c548cd6f8ecb1a5c1d",
+                     "0344fdfe8e1401867a275b3bef7e6ec52450968ab8a1293938fe3d5712dda67c85afeb91d85ab83fcdbebba4dc913e44",
+                     "1361b5ee134c6bee4e287e63f852b6e48546dcf0684af7cf3e7653a3427a609f769ce4d9d99a638b6ae432130fa43104",
+                     "18425b12c2ab5de136eb493b88ca950a45cab942505b5dd59a8b3ae8ec34c40ada65ff2719b1fcda9769fb22882002f9"
+                 ],
+                 // Output
+                 [
+                     "15f7a5c1168ad5ab67ff285c80fa8dd932ca88d9f8b3803c6c7b1f525d2dd5d01f2418259ae167c17c514d55e4707ddb",
+                     "04378269c7364a6cefcdafdb87b004d3ebf6853f46687e46f29f23196d47a176c6f858be34c9f9a3608c74e804f6c686",
+                     "023d9d46abe82bc0ac7c104d9519c037ff72893b8371d72ab92378f60a2361d7171df6b33500828c88923ddb1aab7fa5",
+                     "1015adfeece3613836bf82541ea560c701e197b3d081e2c242b217d809f4ac0ca787b402537a66c0d1f6b76e1b19e94b"
+                 ]
+             ),
+             // Test 2
+             (
+                 // Input
+                 [
+                     "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+                     "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+                     "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+                     "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+                 ],
+                 // Output
+                 [
+                     "19da1b4d47efeeb154f8968b43da2125376e0999ba722141419b03fd857490562fa42a5d0973956d1932dd20c1e0a284",
+                     "18426da25dadd359adfda64fbaddac4414da2a841cb467935289877db450fac424361efb2e7fb141b7b98e6b2f888aef",
+                     "0c2f8d431770d9be9b087c36fc5b66bb83ce6372669f48294193ef646105e0f21d17b134e7d1ad9c18f54b81f6a3707b",
+                     "03257c3be77016e69b75905a97871008a6dfd2e324a6748c48d3304380156987bd0905991824936fcfe34ab25c3b6caa"
+                 ]
+             ),
+             // Test 3
+             (
+                 // Input
+                 [
+                     "05495a3dfa360cb809c1904530db1986aea4bf356e634b40b51e0ee5fcb6cb75085a72a0626873a426470067627c6418",
+                     "11e63b587bedb59c2140518565950bdf881d75c0cccdcedcd9f4b71f2cfede3e5fdbe0261b015562d5edeaa11b7b2b76",
+                     "116c87bbeece66871eb6c2a51bc4327b10ffe470b49c28ef8eef624da766caa2cc9ff6c7042b26b2efd3404f5a81a140",
+                     "010450a90c17ba2997b645ef340fb5b207d6c915b34a93d93e75ee905d6d203d4aac046e10bd4d94a215604ade7afa8e"
+                 ],
+                 // Output
+                 [
+                     "0f1614a6e91c3e00799098fded2f2cfd72cb585cbdaec41b478509913c6772266a764f00b24a7f99607948a4b69b4d8f",
+                     "13ca2148705ca7ba49c92ab8985d7babcc8afc6bf8e397fb829f5fe3f49e51c41332ba4389f5ba66667310b22bea16c9",
+                     "026a743ee00eec8c7ef63351f4a3b26b2f029c10130385efc56ce53d0788db32ff5296ab77f9c389bd196cce8fc1e888",
+                     "0d458d80897e922f3e7e15cfa66a0d3645d95788bddb7478af3f1b5ca662c348b0e9ffdb88fabfdb74f103fea0c2d793"
+                 ]
+             )
+         ];
+ 
+     #[test]
+     fn test_map_to_curve_g2() {
+         // Only run when signatures are on G2
+         if BLS_SIG_G1 {
+             return;
+         }
+ 
+         for test in &TESTS {
+             // Input u0 and u1
+             let a = Big::frombytes(&hex::decode(test.0[0]).unwrap());
+             let b = Big::frombytes(&hex::decode(test.0[1]).unwrap());
 -            let u0 = FP2::new_bigs(&a, &b);
++            let u0 = FP2::new_bigs(a, b);
+             let a = Big::frombytes(&hex::decode(test.0[2]).unwrap());
+             let b = Big::frombytes(&hex::decode(test.0[3]).unwrap());
 -            let u1 = FP2::new_bigs(&a, &b);
++            let u1 = FP2::new_bigs(a, b);
+ 
+             // Map to Curve
+             let (iso3_0_x, iso3_0_y) = simplified_swu_fp2(u0);
+             let (iso3_1_x, iso3_1_y) = simplified_swu_fp2(u1);
+ 
+             // 3-Isogeny Map
+             let mut q0 = iso3_to_ecp2(&iso3_0_x, &iso3_0_y);
+             let q1 = iso3_to_ecp2(&iso3_1_x, &iso3_1_y);
+             q0.add(&q1);
+ 
+             // Clear Cofactor
+             q0.clear_cofactor();
+ 
+             // Check expected values
+             let a = Big::frombytes(&hex::decode(test.1[0]).unwrap());
+             let b = Big::frombytes(&hex::decode(test.1[1]).unwrap());
 -            let check_x = FP2::new_bigs(&a, &b);
++            let check_x = FP2::new_bigs(a, b);
+             let a = Big::frombytes(&hex::decode(test.1[2]).unwrap());
+             let b = Big::frombytes(&hex::decode(test.1[3]).unwrap());
 -            let check_y = FP2::new_bigs(&a, &b);
 -            let check_e = ECP2::new_fp2s(&check_x, &check_y);
++            let check_y = FP2::new_bigs(a, b);
++            let check_e = ECP2::new_fp2s(check_x, check_y);
+ 
+             assert!(q0.equals(&check_e));
+         }
+     }
+ 
+     #[test]
+     #[cfg(feature = "bls381g2")]
+     fn test_hash_to_curve_g2() {
+         // Only run when signatures are on G2
+         if BLS_SIG_G1 {
+             return;
+         }
+ 
+         // Read hash to curve test vector
+         let reader = json_reader(H2C_SUITE);
+         let test_vectors: Bls12381Ro = serde_json::from_reader(reader).unwrap();
+ 
+         // Iterate through each individual case
+         for case in test_vectors.vectors {
+             // Execute hash to curve
+             let u = hash_to_field_fp2(case.msg.as_bytes(), 2, test_vectors.dst.as_bytes()).unwrap();
 -            let q0 = map_to_curve_g2(u[0]);
 -            let q1 = map_to_curve_g2(u[1]);
++            let q0 = map_to_curve_g2(u[0].clone());
++            let q1 = map_to_curve_g2(u[1].clone());
+             let mut r = q0.clone();
+             r.add(&q1);
+             let mut p = r.clone();
+             p.clear_cofactor();
+ 
+             // Verify hash to curve outputs
+             // Check u
+             assert_eq!(case.u.len(), u.len());
+             for (i, u_str) in case.u.iter().enumerate() {
+                 // Convert case 'u[i]' to FP2
+                 let u_str_parts: Vec<&str> = u_str.split(',').collect();
+                 let a = Big::frombytes(&hex::decode(&u_str_parts[0].get(2..).unwrap()).unwrap());
+                 let b = Big::frombytes(&hex::decode(&u_str_parts[1].get(2..).unwrap()).unwrap());
 -                let expected_u_i = FP2::new_bigs(&a, &b);
++                let expected_u_i = FP2::new_bigs(a, b);
+ 
+                 // Verify u[i]
+                 assert_eq!(expected_u_i, u[i]);
+             }
+ 
+             // Check Q0
+             let x_str_parts: Vec<&str> = case.Q0.x.split(',').collect();
+             let a = Big::frombytes(&hex::decode(&x_str_parts[0].get(2..).unwrap()).unwrap());
+             let b = Big::frombytes(&hex::decode(&x_str_parts[1].get(2..).unwrap()).unwrap());
 -            let expected_x = FP2::new_bigs(&a, &b);
++            let expected_x = FP2::new_bigs(a, b);
+ 
+             let y_str_parts: Vec<&str> = case.Q0.y.split(',').collect();
+             let a = Big::frombytes(&hex::decode(&y_str_parts[0].get(2..).unwrap()).unwrap());
+             let b = Big::frombytes(&hex::decode(&y_str_parts[1].get(2..).unwrap()).unwrap());
 -            let expected_y = FP2::new_bigs(&a, &b);
++            let expected_y = FP2::new_bigs(a, b);
+ 
 -            let expected_q0 = ECP2::new_fp2s(&expected_x, &expected_y);
++            let expected_q0 = ECP2::new_fp2s(expected_x, expected_y);
+             assert_eq!(expected_q0, q0);
+ 
+             // Check Q1
+             let x_str_parts: Vec<&str> = case.Q1.x.split(',').collect();
+             let a = Big::frombytes(&hex::decode(&x_str_parts[0].get(2..).unwrap()).unwrap());
+             let b = Big::frombytes(&hex::decode(&x_str_parts[1].get(2..).unwrap()).unwrap());
 -            let expected_x = FP2::new_bigs(&a, &b);
++            let expected_x = FP2::new_bigs(a, b);
+ 
+             let y_str_parts: Vec<&str> = case.Q1.y.split(',').collect();
+             let a = Big::frombytes(&hex::decode(&y_str_parts[0].get(2..).unwrap()).unwrap());
+             let b = Big::frombytes(&hex::decode(&y_str_parts[1].get(2..).unwrap()).unwrap());
 -            let expected_y = FP2::new_bigs(&a, &b);
++            let expected_y = FP2::new_bigs(a, b);
+ 
 -            let expected_q1 = ECP2::new_fp2s(&expected_x, &expected_y);
++            let expected_q1 = ECP2::new_fp2s(expected_x, expected_y);
+             assert_eq!(expected_q1, q1);
+ 
+             // Check P
+             let x_str_parts: Vec<&str> = case.P.x.split(',').collect();
+             let a = Big::frombytes(&hex::decode(&x_str_parts[0].get(2..).unwrap()).unwrap());
+             let b = Big::frombytes(&hex::decode(&x_str_parts[1].get(2..).unwrap()).unwrap());
 -            let expected_x = FP2::new_bigs(&a, &b);
++            let expected_x = FP2::new_bigs(a, b);
+ 
+             let y_str_parts: Vec<&str> = case.P.y.split(',').collect();
+             let a = Big::frombytes(&hex::decode(&y_str_parts[0].get(2..).unwrap()).unwrap());
+             let b = Big::frombytes(&hex::decode(&y_str_parts[1].get(2..).unwrap()).unwrap());
 -            let expected_y = FP2::new_bigs(&a, &b);
++            let expected_y = FP2::new_bigs(a, b);
+ 
 -            let expected_p = ECP2::new_fp2s(&expected_x, &expected_y);
++            let expected_p = ECP2::new_fp2s(expected_x, expected_y);
+             assert_eq!(expected_p, p);
+         }
+     }
+ 
+     #[test]
+     #[cfg(feature = "bls381g1")]
+     fn test_hash_to_curve_g1() {
+         // Only run when signatures are on G2
+         if !BLS_SIG_G1 {
+             return;
+         }
+ 
+         // Read hash to curve test vector
+         let reader = json_reader(H2C_SUITE);
+         let test_vectors: Bls12381Ro = serde_json::from_reader(reader).unwrap();
+ 
+         // Iterate through each individual case
+         for case in test_vectors.vectors {
+             // Execute hash to curve
+             let u = hash_to_field_fp(case.msg.as_bytes(), 2, test_vectors.dst.as_bytes()).unwrap();
 -            let q0 = map_to_curve_g1(u[0]);
 -            let q1 = map_to_curve_g1(u[1]);
++            let q0 = map_to_curve_g1(u[0].clone());
++            let q1 = map_to_curve_g1(u[1].clone());
+             let mut r = q0.clone();
+             r.add(&q1);
+             let p = r.mul(&H_EFF_G1);
+ 
+             // Verify hash to curve outputs
+             // Check u
+             assert_eq!(case.u.len(), u.len());
+             for (i, u_str) in case.u.iter().enumerate() {
+                 // Convert case 'u[i]' to FP
+                 let a = Big::frombytes(&hex::decode(&u_str.get(2..).unwrap()).unwrap());
 -                let expected_u_i = FP::new_big(&a);
++                let expected_u_i = FP::new_big(a);
+ 
+                 // Verify u[i]
+                 assert_eq!(expected_u_i, u[i]);
+             }
+ 
+             // Check Q0
+             let a = Big::frombytes(&hex::decode(&case.Q0.x.get(2..).unwrap()).unwrap());
 -            let expected_x = FP::new_big(&a);
++            let expected_x = FP::new_big(a);
+ 
+             let a = Big::frombytes(&hex::decode(&case.Q0.y.get(2..).unwrap()).unwrap());
 -            let expected_y = FP::new_big(&a);
++            let expected_y = FP::new_big(a);
+ 
+             let expected_q0 = ECP::new_fps(expected_x, expected_y);
+             assert_eq!(expected_q0, q0);
+ 
+             // Check Q1
+             let a = Big::frombytes(&hex::decode(&case.Q1.x.get(2..).unwrap()).unwrap());
 -            let expected_x = FP::new_big(&a);
++            let expected_x = FP::new_big(a);
+ 
+             let a = Big::frombytes(&hex::decode(&case.Q1.y.get(2..).unwrap()).unwrap());
 -            let expected_y = FP::new_big(&a);
++            let expected_y = FP::new_big(a);
+ 
+             let expected_q1 = ECP::new_fps(expected_x, expected_y);
+             assert_eq!(expected_q1, q1);
+ 
+             // Check P
+             let a = Big::frombytes(&hex::decode(&case.P.x.get(2..).unwrap()).unwrap());
 -            let expected_x = FP::new_big(&a);
++            let expected_x = FP::new_big(a);
+ 
+             let a = Big::frombytes(&hex::decode(&case.P.y.get(2..).unwrap()).unwrap());
 -            let expected_y = FP::new_big(&a);
++            let expected_y = FP::new_big(a);
+ 
+             let expected_p = ECP::new_fps(expected_x, expected_y);
+             assert_eq!(expected_p, p);
+         }
+     }
+ }
diff --cc src/bls381/iso.rs
index 0000000,b00fb3d..bbf4f82
mode 000000,100644..100644
--- a/src/bls381/iso.rs
+++ b/src/bls381/iso.rs
@@@ -1,0 -1,335 +1,335 @@@
+ /*
+ 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 super::super::big::Big;
+ use super::super::ecp::ECP;
+ use super::super::ecp2::ECP2;
+ use super::super::fp::FP;
+ use super::super::fp2::FP2;
+ 
+ /**************************************************
+ * 3-Isogeny Constants
+ **************************************************/
+ lazy_static! {
+     // ISO-3 Mapping values
+     pub static ref ISO3_XNUM: [FP2; 4] = [
+         FP2::new_bigs(
 -            &Big::frombytes(&hex::decode("05c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6").unwrap()),
 -            &Big::frombytes(&hex::decode("05c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6").unwrap())
++            Big::frombytes(&hex::decode("05c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6").unwrap()),
++            Big::frombytes(&hex::decode("05c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6").unwrap())
+         ),
+         FP2::new_bigs(
 -            &Big::new(),
 -            &Big::frombytes(&hex::decode("11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71a").unwrap())
++            Big::new(),
++            Big::frombytes(&hex::decode("11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71a").unwrap())
+         ),
+         FP2::new_bigs(
 -            &Big::frombytes(&hex::decode("11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71e").unwrap()),
 -            &Big::frombytes(&hex::decode("08ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38d").unwrap())
++            Big::frombytes(&hex::decode("11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71e").unwrap()),
++            Big::frombytes(&hex::decode("08ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38d").unwrap())
+         ),
+         FP2::new_bigs(
 -            &Big::frombytes(&hex::decode("171d6541fa38ccfaed6dea691f5fb614cb14b4e7f4e810aa22d6108f142b85757098e38d0f671c7188e2aaaaaaaa5ed1").unwrap()),
 -            &Big::new()
++            Big::frombytes(&hex::decode("171d6541fa38ccfaed6dea691f5fb614cb14b4e7f4e810aa22d6108f142b85757098e38d0f671c7188e2aaaaaaaa5ed1").unwrap()),
++            Big::new()
+         )
+     ];
+     pub static ref ISO3_XDEN: [FP2; 4] = [
+         FP2::new_bigs(
 -            &Big::new(),
 -            &Big::frombytes(&hex::decode("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa63").unwrap())
++            Big::new(),
++            Big::frombytes(&hex::decode("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa63").unwrap())
+         ),
+         FP2::new_bigs(
 -            &Big::new_int(12),
 -            &Big::frombytes(&hex::decode("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa9f").unwrap())
++            Big::new_int(12),
++            Big::frombytes(&hex::decode("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa9f").unwrap())
+         ),
+         FP2::new_int(1),
+         FP2::new(),
+     ];
+     pub static ref ISO3_YNUM: [FP2; 4] = [
+         FP2::new_bigs(
 -            &Big::frombytes(&hex::decode("1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706").unwrap()),
 -            &Big::frombytes(&hex::decode("1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706").unwrap())
++            Big::frombytes(&hex::decode("1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706").unwrap()),
++            Big::frombytes(&hex::decode("1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706").unwrap())
+         ),
+         FP2::new_bigs(
 -            &Big::new(),
 -            &Big::frombytes(&hex::decode("05c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97be").unwrap())
++            Big::new(),
++            Big::frombytes(&hex::decode("05c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97be").unwrap())
+         ),
+         FP2::new_bigs(
 -            &Big::frombytes(&hex::decode("11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71c").unwrap()),
 -            &Big::frombytes(&hex::decode("08ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38f").unwrap())
++            Big::frombytes(&hex::decode("11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71c").unwrap()),
++            Big::frombytes(&hex::decode("08ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38f").unwrap())
+         ),
+         FP2::new_bigs(
 -            &Big::frombytes(&hex::decode("124c9ad43b6cf79bfbf7043de3811ad0761b0f37a1e26286b0e977c69aa274524e79097a56dc4bd9e1b371c71c718b10").unwrap()),
 -            &Big::new()
++            Big::frombytes(&hex::decode("124c9ad43b6cf79bfbf7043de3811ad0761b0f37a1e26286b0e977c69aa274524e79097a56dc4bd9e1b371c71c718b10").unwrap()),
++            Big::new()
+         )
+     ];
+     pub static ref ISO3_YDEN: [FP2; 4] = [
+         FP2::new_bigs(
 -            &Big::frombytes(&hex::decode("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb").unwrap()),
 -            &Big::frombytes(&hex::decode("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb").unwrap())
++            Big::frombytes(&hex::decode("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb").unwrap()),
++            Big::frombytes(&hex::decode("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb").unwrap())
+         ),
+         FP2::new_bigs(
 -            &Big::new(),
 -            &Big::frombytes(&hex::decode("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa9d3").unwrap())
++            Big::new(),
++            Big::frombytes(&hex::decode("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa9d3").unwrap())
+         ),
+         FP2::new_bigs(
 -            &Big::new_int(18),
 -            &Big::frombytes(&hex::decode("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa99").unwrap())
++            Big::new_int(18),
++            Big::frombytes(&hex::decode("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa99").unwrap())
+         ),
+         FP2::new_ints(1, 0)
+     ];
+ 
+     // ISO-11 Mapping values
+     pub static ref ISO11_XNUM: [FP; 12] = [
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("11a05f2b1e833340b809101dd99815856b303e88a2d7005ff2627b56cdb4e2c85610c2d5f2e62d6eaeac1662734649b7").unwrap()),
++            Big::frombytes(&hex::decode("11a05f2b1e833340b809101dd99815856b303e88a2d7005ff2627b56cdb4e2c85610c2d5f2e62d6eaeac1662734649b7").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("17294ed3e943ab2f0588bab22147a81c7c17e75b2f6a8417f565e33c70d1e86b4838f2a6f318c356e834eef1b3cb83bb").unwrap())
++            Big::frombytes(&hex::decode("17294ed3e943ab2f0588bab22147a81c7c17e75b2f6a8417f565e33c70d1e86b4838f2a6f318c356e834eef1b3cb83bb").unwrap())
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("0d54005db97678ec1d1048c5d10a9a1bce032473295983e56878e501ec68e25c958c3e3d2a09729fe0179f9dac9edcb0").unwrap()),
++            Big::frombytes(&hex::decode("0d54005db97678ec1d1048c5d10a9a1bce032473295983e56878e501ec68e25c958c3e3d2a09729fe0179f9dac9edcb0").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("1778e7166fcc6db74e0609d307e55412d7f5e4656a8dbf25f1b33289f1b330835336e25ce3107193c5b388641d9b6861").unwrap()),
++            Big::frombytes(&hex::decode("1778e7166fcc6db74e0609d307e55412d7f5e4656a8dbf25f1b33289f1b330835336e25ce3107193c5b388641d9b6861").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("0e99726a3199f4436642b4b3e4118e5499db995a1257fb3f086eeb65982fac18985a286f301e77c451154ce9ac8895d9").unwrap()),
++            Big::frombytes(&hex::decode("0e99726a3199f4436642b4b3e4118e5499db995a1257fb3f086eeb65982fac18985a286f301e77c451154ce9ac8895d9").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("1630c3250d7313ff01d1201bf7a74ab5db3cb17dd952799b9ed3ab9097e68f90a0870d2dcae73d19cd13c1c66f652983").unwrap()),
++            Big::frombytes(&hex::decode("1630c3250d7313ff01d1201bf7a74ab5db3cb17dd952799b9ed3ab9097e68f90a0870d2dcae73d19cd13c1c66f652983").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("0d6ed6553fe44d296a3726c38ae652bfb11586264f0f8ce19008e218f9c86b2a8da25128c1052ecaddd7f225a139ed84").unwrap()),
++            Big::frombytes(&hex::decode("0d6ed6553fe44d296a3726c38ae652bfb11586264f0f8ce19008e218f9c86b2a8da25128c1052ecaddd7f225a139ed84").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("17b81e7701abdbe2e8743884d1117e53356de5ab275b4db1a682c62ef0f2753339b7c8f8c8f475af9ccb5618e3f0c88e").unwrap()),
++            Big::frombytes(&hex::decode("17b81e7701abdbe2e8743884d1117e53356de5ab275b4db1a682c62ef0f2753339b7c8f8c8f475af9ccb5618e3f0c88e").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("080d3cf1f9a78fc47b90b33563be990dc43b756ce79f5574a2c596c928c5d1de4fa295f296b74e956d71986a8497e317").unwrap()),
++            Big::frombytes(&hex::decode("080d3cf1f9a78fc47b90b33563be990dc43b756ce79f5574a2c596c928c5d1de4fa295f296b74e956d71986a8497e317").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("169b1f8e1bcfa7c42e0c37515d138f22dd2ecb803a0c5c99676314baf4bb1b7fa3190b2edc0327797f241067be390c9e").unwrap()),
++            Big::frombytes(&hex::decode("169b1f8e1bcfa7c42e0c37515d138f22dd2ecb803a0c5c99676314baf4bb1b7fa3190b2edc0327797f241067be390c9e").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("10321da079ce07e272d8ec09d2565b0dfa7dccdde6787f96d50af36003b14866f69b771f8c285decca67df3f1605fb7b").unwrap()),
++            Big::frombytes(&hex::decode("10321da079ce07e272d8ec09d2565b0dfa7dccdde6787f96d50af36003b14866f69b771f8c285decca67df3f1605fb7b").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("06e08c248e260e70bd1e962381edee3d31d79d7e22c837bc23c0bf1bc24c6b68c24b1b80b64d391fa9c8ba2e8ba2d229").unwrap()),
++            Big::frombytes(&hex::decode("06e08c248e260e70bd1e962381edee3d31d79d7e22c837bc23c0bf1bc24c6b68c24b1b80b64d391fa9c8ba2e8ba2d229").unwrap()),
+         ),
+     ];
+     pub static ref ISO11_XDEN: [FP; 11] = [
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("08ca8d548cff19ae18b2e62f4bd3fa6f01d5ef4ba35b48ba9c9588617fc8ac62b558d681be343df8993cf9fa40d21b1c").unwrap())
++            Big::frombytes(&hex::decode("08ca8d548cff19ae18b2e62f4bd3fa6f01d5ef4ba35b48ba9c9588617fc8ac62b558d681be343df8993cf9fa40d21b1c").unwrap())
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("12561a5deb559c4348b4711298e536367041e8ca0cf0800c0126c2588c48bf5713daa8846cb026e9e5c8276ec82b3bff").unwrap())
++            Big::frombytes(&hex::decode("12561a5deb559c4348b4711298e536367041e8ca0cf0800c0126c2588c48bf5713daa8846cb026e9e5c8276ec82b3bff").unwrap())
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("0b2962fe57a3225e8137e629bff2991f6f89416f5a718cd1fca64e00b11aceacd6a3d0967c94fedcfcc239ba5cb83e19").unwrap())
++            Big::frombytes(&hex::decode("0b2962fe57a3225e8137e629bff2991f6f89416f5a718cd1fca64e00b11aceacd6a3d0967c94fedcfcc239ba5cb83e19").unwrap())
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("03425581a58ae2fec83aafef7c40eb545b08243f16b1655154cca8abc28d6fd04976d5243eecf5c4130de8938dc62cd8").unwrap())
++            Big::frombytes(&hex::decode("03425581a58ae2fec83aafef7c40eb545b08243f16b1655154cca8abc28d6fd04976d5243eecf5c4130de8938dc62cd8").unwrap())
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("13a8e162022914a80a6f1d5f43e7a07dffdfc759a12062bb8d6b44e833b306da9bd29ba81f35781d539d395b3532a21e").unwrap())
++            Big::frombytes(&hex::decode("13a8e162022914a80a6f1d5f43e7a07dffdfc759a12062bb8d6b44e833b306da9bd29ba81f35781d539d395b3532a21e").unwrap())
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("0e7355f8e4e667b955390f7f0506c6e9395735e9ce9cad4d0a43bcef24b8982f7400d24bc4228f11c02df9a29f6304a5").unwrap())
++            Big::frombytes(&hex::decode("0e7355f8e4e667b955390f7f0506c6e9395735e9ce9cad4d0a43bcef24b8982f7400d24bc4228f11c02df9a29f6304a5").unwrap())
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("0772caacf16936190f3e0c63e0596721570f5799af53a1894e2e073062aede9cea73b3538f0de06cec2574496ee84a3a").unwrap())
++            Big::frombytes(&hex::decode("0772caacf16936190f3e0c63e0596721570f5799af53a1894e2e073062aede9cea73b3538f0de06cec2574496ee84a3a").unwrap())
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("14a7ac2a9d64a8b230b3f5b074cf01996e7f63c21bca68a81996e1cdf9822c580fa5b9489d11e2d311f7d99bbdcc5a5e").unwrap())
++            Big::frombytes(&hex::decode("14a7ac2a9d64a8b230b3f5b074cf01996e7f63c21bca68a81996e1cdf9822c580fa5b9489d11e2d311f7d99bbdcc5a5e").unwrap())
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("0a10ecf6ada54f825e920b3dafc7a3cce07f8d1d7161366b74100da67f39883503826692abba43704776ec3a79a1d641").unwrap())
++            Big::frombytes(&hex::decode("0a10ecf6ada54f825e920b3dafc7a3cce07f8d1d7161366b74100da67f39883503826692abba43704776ec3a79a1d641").unwrap())
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("095fc13ab9e92ad4476d6e3eb3a56680f682b4ee96f7d03776df533978f31c1593174e4b4b7865002d6384d168ecdd0a").unwrap())
++            Big::frombytes(&hex::decode("095fc13ab9e92ad4476d6e3eb3a56680f682b4ee96f7d03776df533978f31c1593174e4b4b7865002d6384d168ecdd0a").unwrap())
+         ),
+         FP::new_int(1),
+     ];
+     pub static ref ISO11_YNUM: [FP; 16] = [
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("090d97c81ba24ee0259d1f094980dcfa11ad138e48a869522b52af6c956543d3cd0c7aee9b3ba3c2be9845719707bb33").unwrap()),
++            Big::frombytes(&hex::decode("090d97c81ba24ee0259d1f094980dcfa11ad138e48a869522b52af6c956543d3cd0c7aee9b3ba3c2be9845719707bb33").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("134996a104ee5811d51036d776fb46831223e96c254f383d0f906343eb67ad34d6c56711962fa8bfe097e75a2e41c696").unwrap()),
++            Big::frombytes(&hex::decode("134996a104ee5811d51036d776fb46831223e96c254f383d0f906343eb67ad34d6c56711962fa8bfe097e75a2e41c696").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("00cc786baa966e66f4a384c86a3b49942552e2d658a31ce2c344be4b91400da7d26d521628b00523b8dfe240c72de1f6").unwrap()),
++            Big::frombytes(&hex::decode("00cc786baa966e66f4a384c86a3b49942552e2d658a31ce2c344be4b91400da7d26d521628b00523b8dfe240c72de1f6").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("01f86376e8981c217898751ad8746757d42aa7b90eeb791c09e4a3ec03251cf9de405aba9ec61deca6355c77b0e5f4cb").unwrap()),
++            Big::frombytes(&hex::decode("01f86376e8981c217898751ad8746757d42aa7b90eeb791c09e4a3ec03251cf9de405aba9ec61deca6355c77b0e5f4cb").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("08cc03fdefe0ff135caf4fe2a21529c4195536fbe3ce50b879833fd221351adc2ee7f8dc099040a841b6daecf2e8fedb").unwrap()),
++            Big::frombytes(&hex::decode("08cc03fdefe0ff135caf4fe2a21529c4195536fbe3ce50b879833fd221351adc2ee7f8dc099040a841b6daecf2e8fedb").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("16603fca40634b6a2211e11db8f0a6a074a7d0d4afadb7bd76505c3d3ad5544e203f6326c95a807299b23ab13633a5f0").unwrap()),
++            Big::frombytes(&hex::decode("16603fca40634b6a2211e11db8f0a6a074a7d0d4afadb7bd76505c3d3ad5544e203f6326c95a807299b23ab13633a5f0").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("04ab0b9bcfac1bbcb2c977d027796b3ce75bb8ca2be184cb5231413c4d634f3747a87ac2460f415ec961f8855fe9d6f2").unwrap()),
++            Big::frombytes(&hex::decode("04ab0b9bcfac1bbcb2c977d027796b3ce75bb8ca2be184cb5231413c4d634f3747a87ac2460f415ec961f8855fe9d6f2").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("0987c8d5333ab86fde9926bd2ca6c674170a05bfe3bdd81ffd038da6c26c842642f64550fedfe935a15e4ca31870fb29").unwrap()),
++            Big::frombytes(&hex::decode("0987c8d5333ab86fde9926bd2ca6c674170a05bfe3bdd81ffd038da6c26c842642f64550fedfe935a15e4ca31870fb29").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("09fc4018bd96684be88c9e221e4da1bb8f3abd16679dc26c1e8b6e6a1f20cabe69d65201c78607a360370e577bdba587").unwrap()),
++            Big::frombytes(&hex::decode("09fc4018bd96684be88c9e221e4da1bb8f3abd16679dc26c1e8b6e6a1f20cabe69d65201c78607a360370e577bdba587").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("0e1bba7a1186bdb5223abde7ada14a23c42a0ca7915af6fe06985e7ed1e4d43b9b3f7055dd4eba6f2bafaaebca731c30").unwrap()),
++            Big::frombytes(&hex::decode("0e1bba7a1186bdb5223abde7ada14a23c42a0ca7915af6fe06985e7ed1e4d43b9b3f7055dd4eba6f2bafaaebca731c30").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("19713e47937cd1be0dfd0b8f1d43fb93cd2fcbcb6caf493fd1183e416389e61031bf3a5cce3fbafce813711ad011c132").unwrap()),
++            Big::frombytes(&hex::decode("19713e47937cd1be0dfd0b8f1d43fb93cd2fcbcb6caf493fd1183e416389e61031bf3a5cce3fbafce813711ad011c132").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("18b46a908f36f6deb918c143fed2edcc523559b8aaf0c2462e6bfe7f911f643249d9cdf41b44d606ce07c8a4d0074d8e").unwrap()),
++            Big::frombytes(&hex::decode("18b46a908f36f6deb918c143fed2edcc523559b8aaf0c2462e6bfe7f911f643249d9cdf41b44d606ce07c8a4d0074d8e").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("0b182cac101b9399d155096004f53f447aa7b12a3426b08ec02710e807b4633f06c851c1919211f20d4c04f00b971ef8").unwrap()),
++            Big::frombytes(&hex::decode("0b182cac101b9399d155096004f53f447aa7b12a3426b08ec02710e807b4633f06c851c1919211f20d4c04f00b971ef8").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("0245a394ad1eca9b72fc00ae7be315dc757b3b080d4c158013e6632d3c40659cc6cf90ad1c232a6442d9d3f5db980133").unwrap()),
++            Big::frombytes(&hex::decode("0245a394ad1eca9b72fc00ae7be315dc757b3b080d4c158013e6632d3c40659cc6cf90ad1c232a6442d9d3f5db980133").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("05c129645e44cf1102a159f748c4a3fc5e673d81d7e86568d9ab0f5d396a7ce46ba1049b6579afb7866b1e715475224b").unwrap()),
++            Big::frombytes(&hex::decode("05c129645e44cf1102a159f748c4a3fc5e673d81d7e86568d9ab0f5d396a7ce46ba1049b6579afb7866b1e715475224b").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("15e6be4e990f03ce4ea50b3b42df2eb5cb181d8f84965a3957add4fa95af01b2b665027efec01c7704b456be69c8b604").unwrap()),
++            Big::frombytes(&hex::decode("15e6be4e990f03ce4ea50b3b42df2eb5cb181d8f84965a3957add4fa95af01b2b665027efec01c7704b456be69c8b604").unwrap()),
+         ),
+     ];
+     pub static ref ISO11_YDEN: [FP; 16] = [
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("16112c4c3a9c98b252181140fad0eae9601a6de578980be6eec3232b5be72e7a07f3688ef60c206d01479253b03663c1").unwrap()),
++            Big::frombytes(&hex::decode("16112c4c3a9c98b252181140fad0eae9601a6de578980be6eec3232b5be72e7a07f3688ef60c206d01479253b03663c1").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("1962d75c2381201e1a0cbd6c43c348b885c84ff731c4d59ca4a10356f453e01f78a4260763529e3532f6102c2e49a03d").unwrap()),
++            Big::frombytes(&hex::decode("1962d75c2381201e1a0cbd6c43c348b885c84ff731c4d59ca4a10356f453e01f78a4260763529e3532f6102c2e49a03d").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("058df3306640da276faaae7d6e8eb15778c4855551ae7f310c35a5dd279cd2eca6757cd636f96f891e2538b53dbf67f2").unwrap()),
++            Big::frombytes(&hex::decode("058df3306640da276faaae7d6e8eb15778c4855551ae7f310c35a5dd279cd2eca6757cd636f96f891e2538b53dbf67f2").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("16b7d288798e5395f20d23bf89edb4d1d115c5dbddbcd30e123da489e726af41727364f2c28297ada8d26d98445f5416").unwrap()),
++            Big::frombytes(&hex::decode("16b7d288798e5395f20d23bf89edb4d1d115c5dbddbcd30e123da489e726af41727364f2c28297ada8d26d98445f5416").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("0be0e079545f43e4b00cc912f8228ddcc6d19c9f0f69bbb0542eda0fc9dec916a20b15dc0fd2ededda39142311a5001d").unwrap()),
++            Big::frombytes(&hex::decode("0be0e079545f43e4b00cc912f8228ddcc6d19c9f0f69bbb0542eda0fc9dec916a20b15dc0fd2ededda39142311a5001d").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("08d9e5297186db2d9fb266eaac783182b70152c65550d881c5ecd87b6f0f5a6449f38db9dfa9cce202c6477faaf9b7ac").unwrap()),
++            Big::frombytes(&hex::decode("08d9e5297186db2d9fb266eaac783182b70152c65550d881c5ecd87b6f0f5a6449f38db9dfa9cce202c6477faaf9b7ac").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("166007c08a99db2fc3ba8734ace9824b5eecfdfa8d0cf8ef5dd365bc400a0051d5fa9c01a58b1fb93d1a1399126a775c").unwrap()),
++            Big::frombytes(&hex::decode("166007c08a99db2fc3ba8734ace9824b5eecfdfa8d0cf8ef5dd365bc400a0051d5fa9c01a58b1fb93d1a1399126a775c").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("16a3ef08be3ea7ea03bcddfabba6ff6ee5a4375efa1f4fd7feb34fd206357132b920f5b00801dee460ee415a15812ed9").unwrap()),
++            Big::frombytes(&hex::decode("16a3ef08be3ea7ea03bcddfabba6ff6ee5a4375efa1f4fd7feb34fd206357132b920f5b00801dee460ee415a15812ed9").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("1866c8ed336c61231a1be54fd1d74cc4f9fb0ce4c6af5920abc5750c4bf39b4852cfe2f7bb9248836b233d9d55535d4a").unwrap()),
++            Big::frombytes(&hex::decode("1866c8ed336c61231a1be54fd1d74cc4f9fb0ce4c6af5920abc5750c4bf39b4852cfe2f7bb9248836b233d9d55535d4a").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("167a55cda70a6e1cea820597d94a84903216f763e13d87bb5308592e7ea7d4fbc7385ea3d529b35e346ef48bb8913f55").unwrap()),
++            Big::frombytes(&hex::decode("167a55cda70a6e1cea820597d94a84903216f763e13d87bb5308592e7ea7d4fbc7385ea3d529b35e346ef48bb8913f55").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("04d2f259eea405bd48f010a01ad2911d9c6dd039bb61a6290e591b36e636a5c871a5c29f4f83060400f8b49cba8f6aa8").unwrap()),
++            Big::frombytes(&hex::decode("04d2f259eea405bd48f010a01ad2911d9c6dd039bb61a6290e591b36e636a5c871a5c29f4f83060400f8b49cba8f6aa8").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("0accbb67481d033ff5852c1e48c50c477f94ff8aefce42d28c0f9a88cea7913516f968986f7ebbea9684b529e2561092").unwrap()),
++            Big::frombytes(&hex::decode("0accbb67481d033ff5852c1e48c50c477f94ff8aefce42d28c0f9a88cea7913516f968986f7ebbea9684b529e2561092").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("0ad6b9514c767fe3c3613144b45f1496543346d98adf02267d5ceef9a00d9b8693000763e3b90ac11e99b138573345cc").unwrap()),
++            Big::frombytes(&hex::decode("0ad6b9514c767fe3c3613144b45f1496543346d98adf02267d5ceef9a00d9b8693000763e3b90ac11e99b138573345cc").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("02660400eb2e4f3b628bdd0d53cd76f2bf565b94e72927c1cb748df27942480e420517bd8714cc80d1fadc1326ed06f7").unwrap()),
++            Big::frombytes(&hex::decode("02660400eb2e4f3b628bdd0d53cd76f2bf565b94e72927c1cb748df27942480e420517bd8714cc80d1fadc1326ed06f7").unwrap()),
+         ),
+         FP::new_big(
 -            &Big::frombytes(&hex::decode("0e0fa1d816ddc03e6b24255e0d7819c171c40f65e273b853324efcd6356caa205ca2f570f13497804415473a1d634b8f").unwrap()),
++            Big::frombytes(&hex::decode("0e0fa1d816ddc03e6b24255e0d7819c171c40f65e273b853324efcd6356caa205ca2f570f13497804415473a1d634b8f").unwrap()),
+         ),
+         FP::new_int(1),
+     ];
+ }
+ 
+ /// Mapping from 11-Isogeny Curve to BLS12-381 ECP
+ ///
+ /// Adjusted from https://eprint.iacr.org/2019/403
+ /// to convert projectives to (XZ, YZ, Z)
+ pub fn iso11_to_ecp(iso_x: &FP, iso_y: &FP) -> ECP {
+     let polynomials_coefficients: [&[FP]; 4] =
+         [&*ISO11_XNUM, &*ISO11_XDEN, &*ISO11_YNUM, &*ISO11_YDEN];
+ 
+     // x-num, x-den, y-num, y-den
+     let mut mapped_vals: [FP; 4] = [FP::new(), FP::new(), FP::new(), FP::new()];
+ 
+     // Horner caculation for evaluating polynomials
+     for (i, coefficients) in polynomials_coefficients[..].iter().enumerate() {
+         mapped_vals[i] = coefficients[coefficients.len() - 1].clone();
+         for k in coefficients.iter().rev().skip(1) {
+             mapped_vals[i].mul(&iso_x);
+             mapped_vals[i].add(&k);
+         }
+     }
+ 
+     // y-num multiplied by y
+     mapped_vals[2].mul(&iso_y);
+ 
+     let mut z = mapped_vals[1].clone(); // x-den
+     z.mul(&mapped_vals[3]); // x-den * y-den
+ 
+     let mut x = mapped_vals[0].clone(); // x-num
+     x.mul(&mapped_vals[3]); // x-num * y-den
+ 
+     let mut y = mapped_vals[2].clone(); // y-num
+     y.mul(&mapped_vals[1]); // y-num * x-den
+ 
+     ECP::new_projective(x, y, z)
+ }
+ 
+ /// Mapping from 3-Isogeny Curve to BLS12-381 ECP2
+ ///
+ /// Adjusted from https://eprint.iacr.org/2019/403
+ /// to convert projectives to (XZ, YZ, Z)
+ pub fn iso3_to_ecp2(iso_x: &FP2, iso_y: &FP2) -> ECP2 {
+     let polynomials_coefficients: [&[FP2; 4]; 4] =
+         [&*ISO3_XNUM, &*ISO3_XDEN, &*ISO3_YNUM, &*ISO3_YDEN];
+ 
+     // x-num, x-den, y-num, y-den
+     let mut mapped_vals: [FP2; 4] = [FP2::new(), FP2::new(), FP2::new(), FP2::new()];
+ 
+     // Horner caculation for evaluating polynomials
+     for (i, coefficients) in polynomials_coefficients[..].iter().enumerate() {
+         mapped_vals[i] = coefficients[coefficients.len() - 1].clone();
+         for k in coefficients.iter().rev().skip(1) {
+             mapped_vals[i].mul(&iso_x);
+             mapped_vals[i].add(&k);
+         }
+     }
+ 
+     // y-num multiplied by y
+     mapped_vals[2].mul(&iso_y);
+ 
+     let mut z = mapped_vals[1].clone(); // x-den
+     z.mul(&mapped_vals[3]); // x-den * y-den
+ 
+     let mut x = mapped_vals[0].clone(); // x-num
+     x.mul(&mapped_vals[3]); // x-num * y-den
+ 
+     let mut y = mapped_vals[2].clone(); // y-num
+     y.mul(&mapped_vals[1]); // y-num * x-den
+ 
+     ECP2::new_projective(x, y, z)
+ }
diff --cc src/dbig.rs
index 6201d72,26b29bd..4fb5f64
--- a/src/dbig.rs
+++ b/src/dbig.rs
@@@ -20,9 -20,9 +20,9 @@@ under the License
  use super::super::arch;
  use super::super::arch::Chunk;
  use super::big;
- use super::big::Big;
+ use super::big::{Big, MODBYTES};
  
 -#[derive(Copy)]
 +#[derive(Clone)]
  pub struct DBig {
      pub w: [Chunk; big::DNLEN],
  }
diff --cc src/ecp2.rs
index f86a005,25f7175..7c18d3c
--- a/src/ecp2.rs
+++ b/src/ecp2.rs
@@@ -696,7 -727,12 +701,12 @@@ impl ECP2 
              x.inc(1);
              x.norm();
          }
+         Q.clear_cofactor();
+         Q
+     }
+ 
+     pub fn clear_cofactor(&mut self) {
 -        let mut X = FP2::new_bigs(&Big::new_ints(&rom::FRA), &Big::new_ints(&rom::FRB));
 +        let mut X = FP2::new_bigs(Big::new_ints(&rom::FRA), Big::new_ints(&rom::FRB));
          if ecp::SEXTIC_TWIST == SexticTwist::MType {
              X.inverse();
              X.norm();
diff --cc src/fp.rs
index 4437d21,f1454c5..058d7a4
--- a/src/fp.rs
+++ b/src/fp.rs
@@@ -116,11 -124,10 +116,10 @@@ impl FP 
              let mut d = DBig::new_scopy(&(self.x));
              return FP::modulo(&mut d);
          }
 -        Big::new_copy(&(self.x))
 +        self.x.clone()
      }
  
-     // reduce a DBig to a Big using the appropriate form of the modulus
-     // dd
+     /// reduce a DBig to a Big using the appropriate form of the modulus
      pub fn modulo(d: &mut DBig) -> Big {
          if MODTYPE == ModType::PseudoMersenne {
              let mut b = Big::new();
@@@ -195,10 -202,10 +194,10 @@@
          self.redc().tostring()
      }
  
-     // reduce this mod Modulus
+     /// reduce this mod Modulus
      pub fn reduce(&mut self) {
          let mut m = Big::new_ints(&rom::MODULUS);
 -        let mut r = Big::new_copy(&m);
 +        let mut r = m.clone();
          let mut sb: usize;
          self.x.norm();
          if self.xes > 16 {
@@@ -222,16 -229,22 +221,16 @@@
          self.xes = 1;
      }
  
-     // test this=0?
+     /// test this=0?
      pub fn iszilch(&self) -> bool {
 -        let mut a = FP::new_copy(self);
 +        let mut a = self.clone();
          a.reduce();
          a.x.iszilch()
      }
  
-     // copy from Big b
 -    /// copy from FP b
 -    pub fn copy(&mut self, b: &FP) {
 -        self.x.copy(&(b.x));
 -        self.xes = b.xes;
 -    }
 -
+     /// copy from Big b
      pub fn bcopy(&mut self, b: &Big) {
 -        self.x.copy(&b);
 +        self.x = b.clone();
          self.nres();
      }
  
@@@ -381,9 -395,9 +381,9 @@@
          }
      }
  
-     // self-=b
+     /// self-=b
      pub fn sub(&mut self, b: &FP) {
 -        let mut n = FP::new_copy(b);
 +        let mut n = b.clone();
          n.neg();
          self.add(&n);
      }
@@@ -578,10 -596,10 +580,10 @@@
          }
      }
  
-     // return TRUE if self==a
+     /// return TRUE if self==a
      pub fn equals(&self, a: &FP) -> bool {
 -        let mut f = FP::new_copy(self);
 -        let mut s = FP::new_copy(a);
 +        let mut f = self.clone();
 +        let mut s = a.clone();
          f.reduce();
          s.reduce();
          if Big::comp(&(f.x), &(s.x)) == 0 {
diff --cc src/fp2.rs
index 84a6c85,12920f4..82a10a9
--- a/src/fp2.rs
+++ b/src/fp2.rs
@@@ -58,32 -58,52 +58,39 @@@ impl FP2 
      }
  
      pub fn new_int(a: isize) -> FP2 {
 -        let mut f = FP2::new();
 -        f.a.copy(&FP::new_int(a));
 -        f.b.zero();
 -        return f;
 +        FP2 {
 +            a: FP::new_int(a),
 +            b: FP::new(),
 +        }
      }
  
+     pub fn new_ints(a: isize, b: isize) -> FP2 {
 -        let mut f = FP2::new();
 -        f.a.copy(&FP::new_int(a));
 -        f.b.copy(&FP::new_int(b));
 -        return f;
 -    }
 -
 -    pub fn new_copy(x: &FP2) -> FP2 {
 -        let mut f = FP2::new();
 -        f.a.copy(&x.a);
 -        f.b.copy(&x.b);
 -        return f;
++        FP2 {
++            a: FP::new_int(a),
++            b: FP::new_int(b),
++        }
+     }
+ 
 -    pub fn new_fps(c: &FP, d: &FP) -> FP2 {
 -        let mut f = FP2::new();
 -        f.a.copy(c);
 -        f.b.copy(d);
 -        return f;
 +    pub fn new_fps(a: FP, b: FP) -> FP2 {
 +        FP2 { a, b }
      }
  
 -    pub fn new_bigs(c: &Big, d: &Big) -> FP2 {
 -        let mut f = FP2::new();
 -        f.a.copy(&FP::new_big(c));
 -        f.b.copy(&FP::new_big(d));
 -        return f;
 +    pub fn new_bigs(c: Big, d: Big) -> FP2 {
 +        FP2 {
 +            a: FP::new_big(c),
 +            b: FP::new_big(d),
 +        }
      }
  
 -    pub fn new_fp(c: &FP) -> FP2 {
 -        let mut f = FP2::new();
 -        f.a.copy(c);
 -        f.b.zero();
 -        return f;
 +    pub fn new_fp(a: FP) -> FP2 {
 +        FP2 { a, b: FP::new() }
      }
  
 -    pub fn new_big(c: &Big) -> FP2 {
 -        let mut f = FP2::new();
 -        f.a.copy(&FP::new_big(c));
 -        f.b.zero();
 -        return f;
 +    pub fn new_big(c: Big) -> FP2 {
 +        FP2 {
 +            a: FP::new_big(c),
 +            b: FP::new(),
 +        }
      }
  
      /* reduce components mod Modulus */
@@@ -377,12 -405,28 +384,28 @@@
      pub fn div_ip(&mut self) {
          let mut t = FP2::new();
          self.norm();
 -        t.a.copy(&self.a);
 +        t.a = self.a.clone();
          t.a.add(&self.b);
 -        t.b.copy(&self.b);
 +        t.b = self.b.clone();
          t.b.sub(&self.a);
          t.norm();
 -        self.copy(&t);
 +        *self = t;
          self.div2();
      }
+ 
+     // ((a + b) , (a - b))
+     pub fn spmt(&mut self) {
+         let b = self.b.clone();
+         self.b = self.a.clone();
+         self.a.add(&b);
+         self.b.sub(&b);
+     }
+ 
+     // b > -b OR if b is 0 then a > -a
+     pub fn is_neg(&mut self) -> bool {
+         if self.b.iszilch() {
+             return self.a.is_neg();
+         }
+         self.b.is_neg()
+     }
  }
diff --cc src/hash_to_curve.rs
index 0000000,fe8d962..8adf370
mode 000000,100644..100644
--- a/src/hash_to_curve.rs
+++ b/src/hash_to_curve.rs
@@@ -1,0 -1,307 +1,307 @@@
+ use super::big::Big;
+ use super::dbig::DBig;
+ use super::fp::FP;
+ use super::fp2::FP2;
+ use super::rom::{
+     HASH_ALGORITHM, HASH_TYPE, L, MODULUS, SSWU_A1, SSWU_A2, SSWU_B1, SSWU_B2, SSWU_Z1, SSWU_Z2,
+     Z_PAD,
+ };
+ 
+ use errors::AmclError;
+ use hash256::HASH256;
+ use hash384::HASH384;
+ use hash512::HASH512;
+ 
+ /// Oversized DST padding
+ pub const OVERSIZED_DST: &[u8] = b"H2C-OVERSIZE-DST-";
+ 
+ #[derive(Copy, Clone)]
+ pub enum HashAlgorithm {
+     Sha256,
+     Sha384,
+     Sha512,
+ }
+ 
+ /// Hash a message
+ pub fn hash(msg: &[u8], hash_function: HashAlgorithm) -> Vec<u8> {
+     match hash_function {
+         HashAlgorithm::Sha256 => {
+             let mut hash = HASH256::new();
+             hash.init();
+             hash.process_array(msg);
+             hash.hash().to_vec()
+         }
+         HashAlgorithm::Sha384 => {
+             let mut hash = HASH384::new();
+             hash.init();
+             hash.process_array(msg);
+             hash.hash().to_vec()
+         }
+         HashAlgorithm::Sha512 => {
+             let mut hash = HASH512::new();
+             hash.init();
+             hash.process_array(msg);
+             hash.hash().to_vec()
+         }
+     }
+ }
+ 
+ // Hash To Field - Fp
+ //
+ // Take a message as bytes and convert it to a Field Point
+ // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2
+ pub fn hash_to_field_fp(msg: &[u8], count: usize, dst: &[u8]) -> Result<Vec<FP>, AmclError> {
+     let m = 1;
+     let p = Big::new_ints(&MODULUS);
+ 
+     let len_in_bytes = count * m * L;
+     let pseudo_random_bytes = expand_message_xmd(msg, len_in_bytes, dst, HASH_ALGORITHM)?;
+ 
+     let mut u: Vec<FP> = Vec::with_capacity(count as usize);
+     for i in 0..count as usize {
+         let elm_offset = L as usize * i * m as usize;
+         let mut dbig = DBig::frombytes(&pseudo_random_bytes[elm_offset..elm_offset + L as usize]);
+         let e: Big = dbig.dmod(&p);
 -        u.push(FP::new_big(&e));
++        u.push(FP::new_big(e));
+     }
+     Ok(u)
+ }
+ 
+ // Hash To Field - Fp2
+ //
+ // Take a message as bytes and convert it to a vector of Field Points with extension degree 2.
+ // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2
+ pub fn hash_to_field_fp2(msg: &[u8], count: usize, dst: &[u8]) -> Result<Vec<FP2>, AmclError> {
+     let m = 2;
+     let p = Big::new_ints(&MODULUS);
+ 
+     let len_in_bytes = count * m * L;
+ 
+     let pseudo_random_bytes = expand_message_xmd(msg, len_in_bytes, dst, HASH_ALGORITHM)?;
+ 
+     let mut u: Vec<FP2> = Vec::with_capacity(count as usize);
+     for i in 0..count as usize {
+         let mut e: Vec<Big> = Vec::with_capacity(m as usize);
+         for j in 0..m as usize {
+             let elm_offset = L as usize * (j + i * m as usize);
+             let mut big =
+                 DBig::frombytes(&pseudo_random_bytes[elm_offset..elm_offset + L as usize]);
+             e.push(big.dmod(&p));
+         }
 -        u.push(FP2::new_bigs(&e[0], &e[1]));
++        u.push(FP2::new_bigs(e[0].clone(), e[1].clone()));
+     }
+     Ok(u)
+ }
+ 
+ // Expand Message XMD
+ //
+ // Take a message and convert it to pseudo random bytes of specified length
+ // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.3.1
+ pub fn expand_message_xmd(
+     msg: &[u8],
+     len_in_bytes: usize,
+     dst: &[u8],
+     hash_algorithm: HashAlgorithm,
+ ) -> Result<Vec<u8>, AmclError> {
+     // ell = ceiling(len_in_bytes / b_in_bytes)
+     let ell = (len_in_bytes + HASH_TYPE - 1) / HASH_TYPE;
+ 
+     // Error if length of output less than 255 bytes
+     if ell >= 255 {
+         return Err(AmclError::HashToFieldError);
+     }
+ 
+     // Create DST prime as (dst.len() || dst)
+     let dst_prime = if dst.len() > 256 {
+         // DST too long, shorten to H("H2C-OVERSIZE-DST-" || dst)
+         let mut tmp = OVERSIZED_DST.to_vec();
+         tmp.extend_from_slice(dst);
+         let mut prime = vec![32u8; 1];
+         prime.append(&mut hash(&tmp, hash_algorithm));
+         prime
+     } else {
+         // DST correct size, prepend length as a single byte
+         let mut prime = vec![dst.len() as u8; 1];
+         prime.extend_from_slice(dst);
+         prime
+     };
+ 
+     let mut pseudo_random_bytes: Vec<u8> = vec![];
+     let mut b: Vec<Vec<u8>> = vec![vec![]; 2];
+ 
+     // Set b[0] to H(Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime)
+     let mut tmp = Z_PAD.to_vec();
+     tmp.extend_from_slice(msg);
+     let l_i_b_str: &[u8] = &(len_in_bytes as u16).to_be_bytes();
+     tmp.extend_from_slice(l_i_b_str);
+     tmp.push(0u8);
+     tmp.extend_from_slice(&dst_prime);
+     b[0] = hash(&tmp, hash_algorithm);
+ 
+     // Set b[1] to H(b_0 || I2OSP(1, 1) || DST_prime)
+     tmp = b[0].clone();
+     tmp.push(1u8);
+     tmp.extend_from_slice(&dst_prime);
+     b[1] = hash(&tmp, hash_algorithm);
+ 
+     pseudo_random_bytes.extend_from_slice(&b[1]);
+ 
+     for i in 2..=ell {
+         // Set b[i] to H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime)
+         tmp = b[0]
+             .iter()
+             .enumerate()
+             .map(|(j, b_0)| {
+                 // Perform strxor(b[0], b[i-1])
+                 b_0 ^ b[i - 1][j] // b[i].len() will all be 32 bytes as they are SHA256 output.
+             })
+             .collect();
+         tmp.push(i as u8); // i < 256
+         tmp.extend_from_slice(&dst_prime);
+         b.push(hash(&tmp, hash_algorithm));
+ 
+         pseudo_random_bytes.extend_from_slice(&b[i]);
+     }
+ 
+     // Take required length
+     Ok(pseudo_random_bytes[..len_in_bytes as usize].to_vec())
+ }
+ 
+ // Simplified Shallue-van de Woestijne-Ulas Method - Fp
+ //
+ // Returns projectives as (XZ, YZ, Z)
+ // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-6.6.2
+ pub fn simplified_swu_fp(u: FP) -> (FP, FP) {
+     // tmp1 = Z * u^2
+     // tv1 = 1 / (Z^2 * u^4 + Z * u^2)
+     let mut tmp1 = u.clone();
+     let is_neg_u = tmp1.is_neg();
+     tmp1.sqr();
+     tmp1.mul(&SSWU_Z1);
+     let mut tv1 = tmp1.clone();
+     tv1.sqr();
+     tv1.add(&tmp1);
+     tv1.inverse();
+ 
+     // x = (-B / A) * (1 + tv1)
+     let mut x = tv1.clone();
+     x.add(&FP::new_int(1));
+     x.mul(&SSWU_B1); // b * (Z^2 * u^4 + Z * u^2 + 1)
+     x.neg();
+     let mut a_inverse = SSWU_A1.clone();
+     a_inverse.inverse();
+     x.mul(&a_inverse);
+ 
+     // Deal with case where Z^2 * u^4 + Z * u^2 == 0
+     if tv1.iszilch() {
+         // x = B / (Z * A)
+         x = SSWU_Z1.clone();
+         x.inverse();
+         x.mul(&SSWU_B1);
+         x.mul(&a_inverse);
+     }
+ 
+     // gx = x^3 + A * x + B
+     let mut gx = x.clone();
+     gx.sqr();
+     gx.add(&SSWU_A1);
+     gx.mul(&x);
+     gx.add(&SSWU_B1);
+ 
+     // y = sqrt(gx)
+     let mut y = gx.clone();
+     let mut y = y.sqrt();
+ 
+     // Check y is valid square root
+     let mut y2 = y.clone();
+     y2.sqr();
+     if !gx.equals(&y2) {
+         // x = x * Z^2 * u
+         x.mul(&tmp1);
+ 
+         // gx = x^3 + A * x + B
+         let mut gx = x.clone();
+         gx.sqr();
+         gx.add(&SSWU_A1);
+         gx.mul(&x);
+         gx.add(&SSWU_B1);
+ 
+         y = gx.sqrt();
+         y2 = y.clone();
+         y2.sqr();
+         assert_eq!(gx, y2, "Hash to Curve SSWU failure - no square roots");
+     }
+ 
+     // Negate y if y and t are opposite in sign
+     if is_neg_u != y.is_neg() {
+         y.neg();
+     }
+ 
+     (x, y)
+ }
+ 
+ // Simplified Shallue-van de Woestijne-Ulas Method - Fp2
+ //
+ // Returns projectives as (X, Y)
+ // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-6.6.2
+ pub fn simplified_swu_fp2(u: FP2) -> (FP2, FP2) {
+     // tmp1 = Z * u^2
+     // tv1 = 1 / (Z^2 * u^4 + Z * u^2)
+     let mut tmp1 = u.clone();
+     let is_neg_u = tmp1.is_neg();
+     tmp1.sqr();
+     tmp1.mul(&SSWU_Z2);
+     let mut tv1 = tmp1.clone();
+     tv1.sqr();
+     tv1.add(&tmp1);
+     tv1.inverse();
+ 
+     // x = (-B / A) * (1 + tv1)
+     let mut x = tv1.clone();
+     x.add(&FP2::new_ints(1, 0));
+     x.mul(&SSWU_B2); // b * (Z^2 * u^4 + Z * u^2 + 1)
+     x.neg();
+     let mut a_inverse = SSWU_A2.clone();
+     a_inverse.inverse();
+     x.mul(&a_inverse);
+ 
+     // Deal with case where Z^2 * u^4 + Z * u^2 == 0
+     if tv1.iszilch() {
+         // x = B / (Z * A)
+         x = SSWU_Z2.clone();
+         x.inverse();
+         x.mul(&SSWU_B2);
+         x.mul(&a_inverse);
+     }
+ 
+     // gx = x^3 + A * x + B
+     let mut gx = x.clone();
+     gx.sqr();
+     gx.add(&SSWU_A2);
+     gx.mul(&x);
+     gx.add(&SSWU_B2);
+ 
+     // y = sqrt(gx)
+     let mut y = gx.clone();
+     if !y.sqrt() {
+         // x = x * Z^2 * u
+         x.mul(&tmp1);
+ 
+         // gx = x^3 + A * x + B
+         let mut gx = x.clone();
+         gx.sqr();
+         gx.add(&SSWU_A2);
+         gx.mul(&x);
+         gx.add(&SSWU_B2);
+ 
+         y = gx;
+         assert!(y.sqrt(), "Hash to Curve SSWU failure - no square roots");
+     }
+ 
+     // Negate y if y and t are opposite in sign
+     if is_neg_u != y.is_neg() {
+         y.neg();
+     }
+ 
+     (x, y)
+ }
diff --cc src/roms/rom_bls381g1_32.rs
index e282e9d,f72806d..0add498
--- a/src/roms/rom_bls381g1_32.rs
+++ b/src/roms/rom_bls381g1_32.rs
@@@ -205,5 -208,34 +208,34 @@@ pub const CURVE_PAIRING_TYPE: CurvePair
  pub const SEXTIC_TWIST: SexticTwist = SexticTwist::MType;
  pub const ATE_BITS: usize = 65;
  pub const SIGN_OF_X: SignOfX = SignOfX::NegativeX;
- pub const HASH_TYPE: usize = 32;
+ pub const HASH_ALGORITHM: HashAlgorithm = HashAlgorithm::Sha256; // Hash algorithm for hash to curve
+ pub const HASH_TYPE: usize = 32; // Output size of hash algorithm
  pub const AESKEY: usize = 16;
+ 
+ /// Signatures on G1: true, Signatures on G2: false
+ pub const BLS_SIG_G1: bool = true;
+ 
+ // BLS Standard Constants
+ /// L = ceil(ceil(log2(Q) + 128) / 8)
+ pub const L: usize = 64;
+ /// Hash to Curve Suite
+ pub const H2C_SUITE: &str = "BLS12381G1_XMD:SHA-256_SSWU_RO_";
+ /// Domain Separation Tag
+ pub const DST: &[u8] = b"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_POP_";
+ /// Z_PAD is a vector of zeros of length equal to the hash block size (64).
+ pub const Z_PAD: [u8; 64] = [0u8; 64];
+ 
+ lazy_static! {
+     // G1 h_eff
+     pub static ref H_EFF_G1: Big = Big::frombytes(&mut hex::decode("d201000000010001").unwrap());
+ 
+     // Curve parameters of G2 ISO-3: y^2 = x^3 + ax + b
 -    pub static ref SSWU_A1: FP = FP::new_big(&Big::frombytes(&hex::decode("00144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d").unwrap()));
 -    pub static ref SSWU_B1: FP = FP::new_big(&Big::frombytes(&hex::decode("12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0").unwrap()));
++    pub static ref SSWU_A1: FP = FP::new_big(Big::frombytes(&hex::decode("00144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d").unwrap()));
++    pub static ref SSWU_B1: FP = FP::new_big(Big::frombytes(&hex::decode("12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0").unwrap()));
+     pub static ref SSWU_Z1: FP = FP::new_int(11);
+ 
+     // Curve parameters of G2 ISO-3: y^2 = x^3 + ax + b
+     pub static ref SSWU_A2: FP2 = FP2::new_ints(0, 240);
+     pub static ref SSWU_B2: FP2 = FP2::new_ints(1012, 1012);
+     pub static ref SSWU_Z2: FP2 = FP2::new_ints(-2, -1);
+ }
diff --cc src/roms/rom_bls381g1_64.rs
index 4d95fdb,51bd4b9..7032be0
--- a/src/roms/rom_bls381g1_64.rs
+++ b/src/roms/rom_bls381g1_64.rs
@@@ -207,5 -210,36 +210,36 @@@ pub const CURVE_PAIRING_TYPE: CurvePair
  pub const SEXTIC_TWIST: SexticTwist = SexticTwist::MType;
  pub const ATE_BITS: usize = 65;
  pub const SIGN_OF_X: SignOfX = SignOfX::NegativeX;
- pub const HASH_TYPE: usize = 32;
+ pub const HASH_ALGORITHM: HashAlgorithm = HashAlgorithm::Sha256; // Hash algorithm for hash to curve
+ pub const HASH_TYPE: usize = 32; // Output size of hash algorithm
  pub const AESKEY: usize = 16;
+ 
+ /// Signatures on G1: true, Signatures on G2: false
+ pub const BLS_SIG_G1: bool = true;
+ 
+ // BLS Standard Constants
+ /// L = ceil(ceil(log2(Q) + 128) / 8)
+ pub const L: usize = 64;
+ /// b_in_bytes = ceil(b / 8), where b is bits outputted from SHA256
+ pub const B_IN_BYTES: usize = 32;
+ /// Hash to Curve Suite
+ pub const H2C_SUITE: &str = "BLS12381G1_XMD:SHA-256_SSWU_RO_";
+ /// Domain Separation Tag
+ pub const DST: &[u8] = b"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_POP_";
+ /// Z_PAD is a vector of zeros of length equal to the hash block size (64).
+ pub const Z_PAD: [u8; 64] = [0u8; 64];
+ 
+ lazy_static! {
+     // G1 h_eff
+     pub static ref H_EFF_G1: Big = Big::frombytes(&mut hex::decode("d201000000010001").unwrap());
+ 
+     // Curve parameters of G2 ISO-3: y^2 = x^3 + ax + b
 -    pub static ref SSWU_A1: FP = FP::new_big(&Big::frombytes(&hex::decode("00144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d").unwrap()));
 -    pub static ref SSWU_B1: FP = FP::new_big(&Big::frombytes(&hex::decode("12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0").unwrap()));
++    pub static ref SSWU_A1: FP = FP::new_big(Big::frombytes(&hex::decode("00144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d").unwrap()));
++    pub static ref SSWU_B1: FP = FP::new_big(Big::frombytes(&hex::decode("12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0").unwrap()));
+     pub static ref SSWU_Z1: FP = FP::new_int(11);
+ 
+     // Curve parameters of G2 ISO-3: y^2 = x^3 + ax + b
+     pub static ref SSWU_A2: FP2 = FP2::new_ints(0, 240);
+     pub static ref SSWU_B2: FP2 = FP2::new_ints(1012, 1012);
+     pub static ref SSWU_Z2: FP2 = FP2::new_ints(-2, -1);
+ }
diff --cc src/roms/rom_bls381g2_32.rs
index e282e9d,af198a8..538e470
--- a/src/roms/rom_bls381g2_32.rs
+++ b/src/roms/rom_bls381g2_32.rs
@@@ -205,5 -208,36 +208,36 @@@ pub const CURVE_PAIRING_TYPE: CurvePair
  pub const SEXTIC_TWIST: SexticTwist = SexticTwist::MType;
  pub const ATE_BITS: usize = 65;
  pub const SIGN_OF_X: SignOfX = SignOfX::NegativeX;
- pub const HASH_TYPE: usize = 32;
+ pub const HASH_ALGORITHM: HashAlgorithm = HashAlgorithm::Sha256; // Hash algorithm for hash to curve
+ pub const HASH_TYPE: usize = 32; // Output size of hash algorithm
  pub const AESKEY: usize = 16;
+ 
+ /// Signatures on G1: true, Signatures on G2: false
+ pub const BLS_SIG_G1: bool = false;
+ 
+ // BLS Standard Constants
+ /// L = ceil(ceil(log2(Q) + 128) / 8)
+ pub const L: usize = 64;
+ /// b_in_bytes = ceil(b / 8), where b is bits outputted from SHA256
+ pub const B_IN_BYTES: usize = 32;
+ /// Hash to Curve Suite
+ pub const H2C_SUITE: &str = "BLS12381G2_XMD:SHA-256_SSWU_RO_";
+ /// Domain Separation Tag
+ pub const DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_";
+ /// Z_PAD is a vector of zeros of length equal to the hash block size (64).
+ pub const Z_PAD: [u8; 64] = [0u8; 64];
+ 
+ lazy_static! {
+     // G1 h_eff
+     pub static ref H_EFF_G1: Big = Big::frombytes(&mut hex::decode("d201000000010001").unwrap());
+ 
+     // Curve parameters of G2 ISO-3: y^2 = x^3 + ax + b
 -    pub static ref SSWU_A1: FP = FP::new_big(&Big::frombytes(&hex::decode("00144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d").unwrap()));
 -    pub static ref SSWU_B1: FP = FP::new_big(&Big::frombytes(&hex::decode("12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0").unwrap()));
++    pub static ref SSWU_A1: FP = FP::new_big(Big::frombytes(&hex::decode("00144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d").unwrap()));
++    pub static ref SSWU_B1: FP = FP::new_big(Big::frombytes(&hex::decode("12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0").unwrap()));
+     pub static ref SSWU_Z1: FP = FP::new_int(11);
+ 
+     // Curve parameters of G2 ISO-3: y^2 = x^3 + ax + b
+     pub static ref SSWU_A2: FP2 = FP2::new_ints(0, 240);
+     pub static ref SSWU_B2: FP2 = FP2::new_ints(1012, 1012);
+     pub static ref SSWU_Z2: FP2 = FP2::new_ints(-2, -1);
+ }
diff --cc src/roms/rom_bls381g2_64.rs
index 4d95fdb,e3d6815..5b8968a
--- a/src/roms/rom_bls381g2_64.rs
+++ b/src/roms/rom_bls381g2_64.rs
@@@ -207,5 -210,36 +210,36 @@@ pub const CURVE_PAIRING_TYPE: CurvePair
  pub const SEXTIC_TWIST: SexticTwist = SexticTwist::MType;
  pub const ATE_BITS: usize = 65;
  pub const SIGN_OF_X: SignOfX = SignOfX::NegativeX;
- pub const HASH_TYPE: usize = 32;
+ pub const HASH_ALGORITHM: HashAlgorithm = HashAlgorithm::Sha256; // Hash algorithm for hash to curve
+ pub const HASH_TYPE: usize = 32; // Output size of hash algorithm
  pub const AESKEY: usize = 16;
+ 
+ /// Signatures on G1: true, Signatures on G2: false
+ pub const BLS_SIG_G1: bool = false;
+ 
+ // BLS Standard Constants
+ /// L = ceil(ceil(log2(Q) + 128) / 8)
+ pub const L: usize = 64;
+ /// b_in_bytes = ceil(b / 8), where b is bits outputted from SHA256
+ pub const B_IN_BYTES: usize = 32;
+ /// Hash to Curve Suite
+ pub const H2C_SUITE: &str = "BLS12381G2_XMD:SHA-256_SSWU_RO_";
+ /// Domain Separation Tag
+ pub const DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_";
+ /// Z_PAD is a vector of zeros of length equal to the hash block size (64).
+ pub const Z_PAD: [u8; 64] = [0u8; 64];
+ 
+ lazy_static! {
+     // G1 h_eff
+     pub static ref H_EFF_G1: Big = Big::frombytes(&mut hex::decode("d201000000010001").unwrap());
+ 
+     // Curve parameters of G2 ISO-3: y^2 = x^3 + ax + b
 -    pub static ref SSWU_A1: FP = FP::new_big(&Big::frombytes(&hex::decode("00144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d").unwrap()));
 -    pub static ref SSWU_B1: FP = FP::new_big(&Big::frombytes(&hex::decode("12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0").unwrap()));
++    pub static ref SSWU_A1: FP = FP::new_big(Big::frombytes(&hex::decode("00144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d").unwrap()));
++    pub static ref SSWU_B1: FP = FP::new_big(Big::frombytes(&hex::decode("12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0").unwrap()));
+     pub static ref SSWU_Z1: FP = FP::new_int(11);
+ 
+     // Curve parameters of G2 ISO-3: y^2 = x^3 + ax + b
+     pub static ref SSWU_A2: FP2 = FP2::new_ints(0, 240);
+     pub static ref SSWU_B2: FP2 = FP2::new_ints(1012, 1012);
+     pub static ref SSWU_Z2: FP2 = FP2::new_ints(-2, -1);
+ }