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/06/18 18:12:17 UTC

[incubator-milagro-crypto-js] 01/01: resync code to golden repo

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

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

commit f33178ad58b8380d47dbc9151b69ebab09e50e40
Author: Kealan McCusker <ke...@gmail.com>
AuthorDate: Tue Jun 18 19:11:57 2019 +0100

    resync code to golden repo
---
 .travis.yml                                        |  22 +-
 LICENSE                                            | 404 +++++++-------
 README.md                                          |  59 +-
 VERSION                                            |   2 +-
 examples/browser/example_BLS.html                  | 249 +++++++++
 ...le_DVS_BN254CX.html => example_DVS_BLS383.html} |   4 +-
 ...IST521.html => example_ECC_BLS383_NIST521.html} |   4 +-
 ..._MPIN_BN254CX.html => example_MPIN_BLS383.html} |   4 +-
 ..._BN254CX.html => example_MPIN_FULL_BLS383.html} |   4 +-
 ...54CX.html => example_MPIN_ONE_PASS_BLS383.html} |   4 +-
 ...TP_BN254CX.html => example_MPIN_TP_BLS383.html} |   4 +-
 ...xample_DVS_BN254CX.js => example_DVS_BLS383.js} |   2 +-
 ...54_NIST521.js => example_ECC_BLS383_NIST521.js} |   4 +-
 ...mple_MPIN_BN254CX.js => example_MPIN_BLS383.js} |   2 +-
 ...FULL_BN254CX.js => example_MPIN_FULL_BLS383.js} |   2 +-
 ..._BN254CX.js => example_MPIN_ONE_PASS_BLS383.js} |   2 +-
 examples/node/example_MPIN_TP_BN254CX.js           | 173 ------
 package.json                                       |  11 +-
 src/aes.js                                         |  47 +-
 src/big.js                                         |  73 ++-
 src/bls.js                                         | 127 +++++
 src/bls192.js                                      | 126 +++++
 src/bls256.js                                      | 129 +++++
 src/ctx.js                                         |  94 +++-
 src/ecdh.js                                        |  44 +-
 src/ecp.js                                         | 206 ++++---
 src/ecp2.js                                        |  90 +--
 src/ecp4.js                                        |  84 +--
 src/ecp8.js                                        |  96 ++--
 src/ff.js                                          |  21 +-
 src/fp.js                                          | 249 +++++++--
 src/fp12.js                                        | 554 ++++++++++++++-----
 src/fp16.js                                        |  77 +--
 src/fp2.js                                         |  11 +-
 src/fp24.js                                        | 583 ++++++++++++++------
 src/fp4.js                                         |  84 +--
 src/fp48.js                                        | 609 +++++++++++++++------
 src/fp8.js                                         |  76 +--
 src/gcm.js                                         |  50 +-
 src/hash256.js                                     |  19 +-
 src/hash384.js                                     |  19 +-
 src/hash512.js                                     |  18 +-
 src/mpin.js                                        |  34 +-
 src/mpin192.js                                     |   9 +-
 src/mpin256.js                                     |   9 +-
 src/pair.js                                        | 300 ++++++----
 src/pair192.js                                     | 191 +++++--
 src/pair256.js                                     | 199 +++++--
 src/rand.js                                        |  28 +-
 src/rsa.js                                         |   3 +-
 src/sha3.js                                        |  28 +-
 test/test_BIG.js                                   |   4 +-
 test/test_DVS.js                                   |   5 +-
 test/test_FP12_js                                  | 206 +++++++
 test/test_FP16_js                                  | 249 +++++++++
 test/test_FP24_js                                  | 235 ++++++++
 test/test_FP2_js                                   | 164 ++++++
 test/test_FP48_js                                  | 246 +++++++++
 test/test_FP4_js                                   | 257 +++++++++
 test/test_FP8_js                                   | 291 ++++++++++
 test/test_FP_js                                    | 146 +++++
 test/test_MPIN.js                                  |   4 +-
 test/test_RSA2048.js                               |   4 +-
 test/test_RSA3072.js                               |   4 +-
 test/test_RSA4096.js                               |   4 +-
 65 files changed, 5296 insertions(+), 1766 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 7673e7b..152fd6b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,26 +1,16 @@
 language: node_js
 
 node_js:
-  - "node"
+  - "8"
 
-sudo: required
-dist: trusty
+before_install:
+  - npm update
 
-group: edge
-
-branches:
-  except:
-    - release
-
-before_script:
-    - npm install chai
-    - npm install -g mocha
-    - npm install -g coveralls
-    - npm install -g istanbul
-    - npm install -g nyc
+install:
+  - npm install
 
 script:
   - npm run coverage
 
 after_success:
-  - npm run report
\ No newline at end of file
+  - npm run report
diff --git a/LICENSE b/LICENSE
index 19efef5..9b5e401 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,202 +1,202 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright 2016 MIRACL UK Ltd
-
-   Licensed 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.
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
\ No newline at end of file
diff --git a/README.md b/README.md
index 3a422fd..2f9d191 100644
--- a/README.md
+++ b/README.md
@@ -1,31 +1,39 @@
 # MCJS - *Milagro Crypto JavaScript*
 
-[![Master Branch](https://img.shields.io/badge/-master:-gray.svg)](https://github.com/milagro-crypto/milagro-crypto-js/tree/master)
-[![Master Build Status](https://secure.travis-ci.org/milagro-crypto/milagro-crypto-js.png?branch=master)](https://travis-ci.org/milagro-crypto/milagro-crypto-js?branch=master)
-[![Coverage Status](https://coveralls.io/repos/github/milagro-crypto/milagro-crypto-js/badge.svg?branch=master)](https://coveralls.io/github/milagro-crypto/milagro-crypto-js?branch=master)
+[![Master Branch](https://img.shields.io/badge/-master:-gray.svg)](https://github.com/apache/incubator-milagro-crypto-js/tree/master)
+[![Master Build Status](https://secure.travis-ci.org/apache/incubator-milagro-crypto-js.png?branch=master)](https://travis-ci.org/apache/incubator-milagro-crypto-js?branch=master)
+[![Master Coverage Status](https://coveralls.io/repos/github/apache/incubator-milagro-crypto-js/badge.svg?branch=master)](https://coveralls.io/github/apache/incubator-milagro-crypto-js?branch=master)
+
+[![Develop Branch](https://img.shields.io/badge/-develop:-gray.svg)](https://github.com/apache/incubator-milagro-crypto-js/tree/develop)
+[![Develop Build Status](https://secure.travis-ci.org/apache/incubator-milagro-crypto-js.png?branch=develop)](https://travis-ci.org/apache/incubator-milagro-crypto-js?branch=develop)
+[![Develop Coverage Status](https://coveralls.io/repos/github/apache/incubator-milagro-crypto-js/badge.svg?branch=develop)](https://coveralls.io/github/apache/incubator-milagro-crypto-js?branch=develop)
 
 
 * **category**:    Library
 * **copyright**:   2019 The Apache Software Foundation
 * **license**:     ASL 2.0 - http://www.apache.org/licenses/LICENSE-2.0
-* **link**:        https://github.com/apache/incubator-milagro-javascript
-* **introduction**: [AMCL.pdf](doc/AMCL.pdf)
+* **link**:        https://github.com/apache/incubator-milagro-crypto-js
 
 ## Description
 
 *MCJS - Milagro Crypto JavaScript*
 
-* MCJS is a standards compliant JavaScript cryptographic library with no external dependencies except for the random seed source.
-
-* MCJS is a refactor of the *JavaScript* code of [AMCL](https://github.com/miracl/amcl). For a detailed explanation about this library please read: [doc/AMCL.pdf](doc/AMCL.pdf). For info about the refactoring process contact support@miracl.com.
+* MCJS is a standards compliant JavaScript cryptographic library with no
+external dependencies except for the random seed source.
 
-* MCJS supports the standards for RSA, ECDH, ECIES, ECDSA and M-PIN, AES-GCM encryption/decryption, SHA256, SHA384, SHA512 and SHA3 hash functions and a cryptographically secure random number generator. Furthermore we recently added New Hope, a post-quantum key exchange.
+* MCJS supports the standards for RSA, ECDH, ECIES, ECDSA and M-PIN, AES-GCM
+encryption/decryption, SHA256, SHA384, SHA512 and SHA3 hash functions and a
+cryptographically secure random number generator. Furthermore we recently
+added New Hope, a post-quantum key exchange.
 
-* MCJS is [Node.js](https://nodejs.org/en/) compatible and browser compatible (see some examples below).
+* MCJS is [Node.js](https://nodejs.org/en/) compatible and browser compatible
+(see some examples below).
 
 ## Install and run  tests
 
-[Node.js](https://nodejs.org/en/) (minimum v6.9.5) and [npm](https://www.npmjs.com/) are required in order to build the library and run the tests. Install also the node.js modules required with the command
+[Node.js](https://nodejs.org/en/) (minimum v6.9.5) and
+[npm](https://www.npmjs.com/) are required in order to build the library and
+run the tests. Install also the node.js modules required with the command
 
 ```
 npm install
@@ -39,7 +47,8 @@ npm test
 
 ## Quick Start
 #### Elliptic Curves
-Suppose you want to implement ECDH with NIST256 elliptic curve. First you need to initialize the context:
+Suppose you want to implement ECDH with NIST256 elliptic curve. First you need
+to initialize the context:
 
 ```
 var CTX = require("milagro-crypto-js");
@@ -51,7 +60,8 @@ then you can call the functions as follows:
 ctx.ECDH.KEY_PAIR_GENERATE(...);
 ctx.ECDH.ECPSVDP_DH(...);
 ```
-If you need to use more than one elliptic curve in the same script you only need to initialize two different contexts, for example
+If you need to use more than one elliptic curve in the same script you only
+need to initialize two different contexts, for example
 ```
 var ctx1 = new CTX("NIST256");
 var ctx2 = new CTX("C25519");
@@ -86,7 +96,8 @@ var ctx = new CTX();
 
 ## Run examples
 
-[Node.js](https://nodejs.org/en/) examples are provided - please see `./examples/node`. Use the following command to run an example
+[Node.js](https://nodejs.org/en/) examples are provided - please see
+`./examples/node`. Use the following command to run an example
 
 ```
 node ./examples/node/example_ECC_NIST256.js
@@ -94,15 +105,27 @@ node ./examples/node/example_ECC_NIST256.js
 
 #### Browsers
 
-The library source code is browser compatible. The browser examples are locates in `./examples/browser`.
+The library source code is browser compatible. The browser examples are locates
+in `./examples/browser`.
 
-## Contributors ##
+## Contributors 
 
-The following people have contributed to milagro-crypto-c
+The following people have contributed to milagro-crypto-js
 
 - Mike Scott
 - Kealan McCusker
 - Alessandro Budroni
 - Samuele Andreoli
 
-Please add yourself here if you make or have made a contribution.
\ No newline at end of file
+Please add yourself here if you make or have made a contribution.
+
+## Making a Contribution
+
+1.  [Check for open issues](https://github.com/apache/incubator-milagro-crypto-js/issues) or start a discussion around a feature idea or a bug by sending a
+mail to dev@milagro.incubator.apache.org
+2.  Fork the repository to start making your changes. Please use the
+"development" branch as a basis.
+3.  Write a test which shows that the bug was fixed or that the feature works
+as expected.
+4.  Make a pull request with a reference to the issue
+
diff --git a/VERSION b/VERSION
index 9575d51..6e8bf73 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.6.1
+0.1.0
diff --git a/examples/browser/example_BLS.html b/examples/browser/example_BLS.html
new file mode 100644
index 0000000..5c19a78
--- /dev/null
+++ b/examples/browser/example_BLS.html
@@ -0,0 +1,249 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>JavaScript Test BLS</title>
+</head>
+<body>
+<h1>JavaScript Test BLS Example</h1>
+<script src="src/rand.js"></script>
+<script src="src/rom_curve.js"></script>
+<script src="src/rom_field.js"></script>
+<script src="src/uint64.js"></script>
+<script src="src/aes.js"></script>
+<script src="src/big.js"></script>
+<script src="src/gcm.js"></script>
+<script src="src/hash256.js"></script>
+<script src="src/hash384.js"></script>
+<script src="src/hash512.js"></script>
+<script src="src/sha3.js"></script>
+<script src="src/nhs.js"></script>
+<script src="src/fp.js"></script>
+<script src="src/fp2.js"></script>
+<script src="src/fp4.js"></script>
+<script src="src/fp12.js"></script>
+<script src="src/ff.js"></script>
+<script src="src/rsa.js"></script>
+<script src="src/ecp.js"></script>
+<script src="src/ecp2.js"></script>
+<script src="src/ecdh.js"></script>
+<script src="src/pair.js"></script>
+<script src="src/bls.js"></script>
+<script src="src/mpin.js"></script>
+<script src="src/ctx.js"></script>
+
+<script src="src/fp8.js"></script>
+<script src="src/fp16.js"></script>
+<script src="src/fp24.js"></script>
+<script src="src/fp48.js"></script>
+<script src="src/ecp4.js"></script>
+<script src="src/ecp8.js"></script>
+<script src="src/pair192.js"></script>
+<script src="src/pair256.js"></script>
+<script src="src/mpin192.js"></script>
+<script src="src/mpin256.js"></script>
+<script src="src/bls192.js"></script>
+<script src="src/bls256.js"></script>
+
+
+<p><a id="myLink4" href="#" onclick="location.reload(false);bn254();">BN254 254-bit k=12 Pairing-Friendly BN Curve Boneh-Lynn-Shacham</a></p>
+<p><a id="myLink5" href="#" onclick="location.reload(false);bls383();">BLS383 383-bit k=12 Pairing-Friendly BLS Curve Boneh-Lynn-Shacham</a></p>
+<p><a id="myLink6" href="#" onclick="location.reload(false);bls24();">BLS24 479-bit k=24 Pairing-Friendly BLS Curve Boneh-Lynn-Shacham</a></p>
+<p><a id="myLink7" href="#" onclick="location.reload(false);bls48();">BLS48 556-bit k=48 Pairing-Friendly BLS Curve Boneh-Lynn-Shacham</a></p>
+
+
+<script>
+
+
+/* Test BLS signature */
+
+// BN254 context
+function bn254() {
+	var ctx = new CTX('BN254');
+	mywindow=window.open();
+
+	mywindow.document.write("<br> BN254 Pairing-Friendly Curve "+  "<br>");
+
+	var i,res;
+	var result;
+
+	var BGS=ctx.BLS.BGS;
+	var BFS=ctx.BLS.BFS;
+
+	var G1S=BFS+1; // Group 1 Size 
+	var G2S=4*BFS; // Group 2 Size 
+
+	var S=[];
+	var W=[];
+	var SIG=[];
+
+	var RAW=[];
+	var rng=new ctx.RAND();
+
+	rng.clean();
+	for (i=0;i<100;i++) RAW[i]=i;
+
+	rng.seed(100,RAW);
+
+	mywindow.document.write ("Testing BLS code <br>");
+	var mess="This is a test message";
+
+	ctx.BLS.KeyPairGenerate(rng,S,W);
+	mywindow.document.write("Private key : 0x"+ctx.BLS.bytestostring(S) + "<br>");
+	mywindow.document.write("Public  key : 0x"+ctx.BLS.bytestostring(W) + "<br>");
+
+	ctx.BLS.sign(SIG,mess,S);
+	mywindow.document.write("Signature : 0x"+ctx.BLS.bytestostring(SIG) + "<br>");
+
+	var res=ctx.BLS.verify(SIG,mess,W);
+
+	if (res==0)
+		mywindow.document.write("Signature is OK" + "<br>");
+	else
+		mywindow.document.write("Signature is *NOT* OK"  + "<br>");
+
+}
+
+// BLS383 context
+function bls383() {
+	var ctx = new CTX('BLS383');
+	mywindow=window.open();
+
+	mywindow.document.write("<br> BLS383 Pairing-Friendly Curve "+  "<br>");
+
+	var i,res;
+	var result;
+
+	var BGS=ctx.BLS.BGS;
+	var BFS=ctx.BLS.BFS;
+
+	var G1S=BFS+1; /* Group 1 Size */
+	var G2S=4*BFS; /* Group 2 Size */
+
+	var S=[];
+	var W=[];
+	var SIG=[];
+
+	var RAW=[];
+	var rng=new ctx.RAND();
+
+	rng.clean();
+	for (i=0;i<100;i++) RAW[i]=i;
+
+	rng.seed(100,RAW);
+
+	mywindow.document.write ("Testing BLS code <br>");
+	var mess="This is a test message";
+
+	ctx.BLS.KeyPairGenerate(rng,S,W);
+	mywindow.document.write("Private key : 0x"+ctx.BLS.bytestostring(S) + "<br>");
+	mywindow.document.write("Public  key : 0x"+ctx.BLS.bytestostring(W) + "<br>");
+
+	ctx.BLS.sign(SIG,mess,S);
+	mywindow.document.write("Signature : 0x"+ctx.BLS.bytestostring(SIG) + "<br>");
+
+	var res=ctx.BLS.verify(SIG,mess,W);
+
+	if (res==0)
+		mywindow.document.write("Signature is OK" + "<br>");
+	else
+		mywindow.document.write("Signature is *NOT* OK"  + "<br>");
+ 
+}
+
+// BLS24 context
+function bls24() {
+	var ctx = new CTX('BLS24');
+	mywindow=window.open();
+
+	mywindow.document.write("<br> BLS24 Pairing-Friendly Curve "+  "<br>");
+
+	var i,res;
+	var result;
+
+	var BGS=ctx.BLS192.BGS;
+	var BFS=ctx.BLS192.BFS;
+
+	var G1S=BFS+1; /* Group 1 Size */
+	var G2S=4*BFS; /* Group 2 Size */
+
+	var S=[];
+	var W=[];
+	var SIG=[];
+
+	var RAW=[];
+	var rng=new ctx.RAND();
+
+	rng.clean();
+	for (i=0;i<100;i++) RAW[i]=i;
+
+	rng.seed(100,RAW);
+
+	mywindow.document.write ("Testing BLS code <br>");
+	var mess="This is a test message";
+
+	ctx.BLS192.KeyPairGenerate(rng,S,W);
+	mywindow.document.write("Private key : 0x"+ctx.BLS192.bytestostring(S) + "<br>");
+	mywindow.document.write("Public  key : 0x"+ctx.BLS192.bytestostring(W) + "<br>");
+
+	ctx.BLS192.sign(SIG,mess,S);
+	mywindow.document.write("Signature : 0x"+ctx.BLS192.bytestostring(SIG) + "<br>");
+
+	var res=ctx.BLS192.verify(SIG,mess,W);
+
+	if (res==0)
+		mywindow.document.write("Signature is OK" + "<br>");
+	else
+		mywindow.document.write("Signature is *NOT* OK"  + "<br>");
+ 
+}
+
+// BLS48 context
+function bls48() {
+	var ctx = new CTX('BLS48');
+	mywindow=window.open();
+
+	mywindow.document.write("<br> BLS48 Pairing-Friendly Curve "+  "<br>");
+
+	var i,res;
+	var result;
+
+	var BGS=ctx.BLS256.BGS;
+	var BFS=ctx.BLS256.BFS;
+
+	var G1S=BFS+1; /* Group 1 Size */
+	var G2S=4*BFS; /* Group 2 Size */
+
+	var S=[];
+	var W=[];
+	var SIG=[];
+
+	var RAW=[];
+	var rng=new ctx.RAND();
+
+	rng.clean();
+	for (i=0;i<100;i++) RAW[i]=i;
+
+	rng.seed(100,RAW);
+
+	mywindow.document.write ("Testing BLS code <br>");
+	var mess="This is a test message";
+
+	ctx.BLS256.KeyPairGenerate(rng,S,W);
+	mywindow.document.write("Private key : 0x"+ctx.BLS256.bytestostring(S) + "<br>");
+	mywindow.document.write("Public  key : 0x"+ctx.BLS256.bytestostring(W) + "<br>");
+
+	ctx.BLS256.sign(SIG,mess,S);
+	mywindow.document.write("Signature : 0x"+ctx.BLS256.bytestostring(SIG) + "<br>");
+
+	var res=ctx.BLS256.verify(SIG,mess,W);
+
+	if (res==0)
+		mywindow.document.write("Signature is OK" + "<br>");
+	else
+		mywindow.document.write("Signature is *NOT* OK"  + "<br>");
+ 
+}
+
+</script>
+</body>
+</html>
diff --git a/examples/browser/example_DVS_BN254CX.html b/examples/browser/example_DVS_BLS383.html
similarity index 98%
rename from examples/browser/example_DVS_BN254CX.html
rename to examples/browser/example_DVS_BLS383.html
index c8d6322..d5c0183 100644
--- a/examples/browser/example_DVS_BN254CX.html
+++ b/examples/browser/example_DVS_BLS383.html
@@ -55,7 +55,7 @@ under the License.
 /* Test DVS - test driver and function exerciser for Designated Verifier Signature API Functions */
 
 
-var ctx = new CTX("BN254CX");
+var ctx = new CTX("BLS383");
 
 var RAW = [];
 var rng = new ctx.RAND();
@@ -87,7 +87,7 @@ ctx.MPIN.RANDOM_GENERATE(rng, S);
 console.log("M-Pin Master Secret s: 0x" + ctx.MPIN.bytestostring(S));
 
 /* Create Client Identity */
-var IDstr = "testuser@miracl.com";
+var IDstr = "testuser@milagro.com";
 var CLIENT_ID = ctx.MPIN.stringtobytes(IDstr);
 
 console.log("Client ID= " + ctx.MPIN.bytestostring(CLIENT_ID));
diff --git a/examples/browser/example_ECC_BN254_NIST521.html b/examples/browser/example_ECC_BLS383_NIST521.html
similarity index 98%
rename from examples/browser/example_ECC_BN254_NIST521.html
rename to examples/browser/example_ECC_BLS383_NIST521.html
index b46d2f8..ea61f8e 100644
--- a/examples/browser/example_ECC_BN254_NIST521.html
+++ b/examples/browser/example_ECC_BLS383_NIST521.html
@@ -56,10 +56,10 @@ under the License.
 /* Test ECC - test driver and function exerciser for ECDH/ECIES/ECDSA API Functions */
 
 
-var ctx1 = new CTX("BN254");
+var ctx1 = new CTX("BLS383");
 var ctx2 = new CTX("NIST521");
 
-console.log("Start testing BN254");
+console.log("Start testing BLS383");
 
 var pp = "M0ng00se",
     res,
diff --git a/examples/browser/example_MPIN_BN254CX.html b/examples/browser/example_MPIN_BLS383.html
similarity index 99%
rename from examples/browser/example_MPIN_BN254CX.html
rename to examples/browser/example_MPIN_BLS383.html
index d1e9fa5..6ca6b73 100644
--- a/examples/browser/example_MPIN_BN254CX.html
+++ b/examples/browser/example_MPIN_BLS383.html
@@ -55,7 +55,7 @@ under the License.
 /* Test MPIN - test driver and function exerciser for MPIN API Functions */
 
 
-var ctx = new CTX("BN254CX");
+var ctx = new CTX("BLS383");
 
 /* Test M-Pin */
 
@@ -95,7 +95,7 @@ ctx.MPIN.RANDOM_GENERATE(rng, S);
 console.log("M-Pin Master Secret s: 0x" + ctx.MPIN.bytestostring(S));
 
 /* Create Client Identity */
-var IDstr = "testUser@miracl.com";
+var IDstr = "testUser@milagro.com";
 var CLIENT_ID = ctx.MPIN.stringtobytes(IDstr);
 HCID = ctx.MPIN.HASH_ID(sha, CLIENT_ID); /* Either Client or TA calculates Hash(ID) - you decide! */
 
diff --git a/examples/browser/example_MPIN_FULL_BN254CX.html b/examples/browser/example_MPIN_FULL_BLS383.html
similarity index 99%
rename from examples/browser/example_MPIN_FULL_BN254CX.html
rename to examples/browser/example_MPIN_FULL_BLS383.html
index b6b82bf..9a572bb 100644
--- a/examples/browser/example_MPIN_FULL_BN254CX.html
+++ b/examples/browser/example_MPIN_FULL_BLS383.html
@@ -55,7 +55,7 @@ under the License.
 /* Test MPIN - test driver and function exerciser for MPIN API Functions */
 
 
-var ctx = new CTX("BN254CX");
+var ctx = new CTX("BLS383");
 
 /* Test M-Pin */
 
@@ -107,7 +107,7 @@ ctx.MPIN.RANDOM_GENERATE(rng, S);
 console.log("M-Pin Master Secret s: 0x" + ctx.MPIN.bytestostring(S));
 
 /* Create Client Identity */
-var IDstr = "testUser@miracl.com";
+var IDstr = "testUser@milagro.com";
 var CLIENT_ID = ctx.MPIN.stringtobytes(IDstr);
 HCID = ctx.MPIN.HASH_ID(sha, CLIENT_ID); /* Either Client or TA calculates Hash(ID) - you decide! */
 
diff --git a/examples/browser/example_MPIN_ONE_PASS_BN254CX.html b/examples/browser/example_MPIN_ONE_PASS_BLS383.html
similarity index 98%
rename from examples/browser/example_MPIN_ONE_PASS_BN254CX.html
rename to examples/browser/example_MPIN_ONE_PASS_BLS383.html
index 24163e2..a798a31 100644
--- a/examples/browser/example_MPIN_ONE_PASS_BN254CX.html
+++ b/examples/browser/example_MPIN_ONE_PASS_BLS383.html
@@ -55,7 +55,7 @@ under the License.
 /* Test MPIN - test driver and function exerciser for MPIN API Functions */
 
 
-var ctx = new CTX("BN254CX");
+var ctx = new CTX("BLS383");
 
 /* Test M-Pin */
 
@@ -106,7 +106,7 @@ ctx.MPIN.RANDOM_GENERATE(rng, S);
 console.log("M-Pin Master Secret s: 0x" + ctx.MPIN.bytestostring(S));
 
 /* Create Client Identity */
-var IDstr = "testUser@miracl.com";
+var IDstr = "testUser@milagro.com";
 var CLIENT_ID = ctx.MPIN.stringtobytes(IDstr);
 HCID = ctx.MPIN.HASH_ID(sha, CLIENT_ID); /* Either Client or TA calculates Hash(ID) - you decide! */
 
diff --git a/examples/browser/example_MPIN_TP_BN254CX.html b/examples/browser/example_MPIN_TP_BLS383.html
similarity index 98%
rename from examples/browser/example_MPIN_TP_BN254CX.html
rename to examples/browser/example_MPIN_TP_BLS383.html
index 1bed73b..8f8c1d2 100644
--- a/examples/browser/example_MPIN_TP_BN254CX.html
+++ b/examples/browser/example_MPIN_TP_BLS383.html
@@ -55,7 +55,7 @@ under the License.
 /* Test MPIN - test driver and function exerciser for MPIN API Functions */
 
 
-var ctx = new CTX("BN254CX");
+var ctx = new CTX("BLS383");
 
 /* Test M-Pin */
 
@@ -95,7 +95,7 @@ ctx.MPIN.RANDOM_GENERATE(rng, S);
 console.log("M-Pin Master Secret s: 0x" + ctx.MPIN.bytestostring(S));
 
 /* Create Client Identity */
-var IDstr = "testUser@miracl.com";
+var IDstr = "testUser@milagro.com";
 var CLIENT_ID = ctx.MPIN.stringtobytes(IDstr);
 HCID = ctx.MPIN.HASH_ID(sha, CLIENT_ID); /* Either Client or TA calculates Hash(ID) - you decide! */
 
diff --git a/examples/node/example_DVS_BN254CX.js b/examples/node/example_DVS_BLS383.js
similarity index 99%
rename from examples/node/example_DVS_BN254CX.js
rename to examples/node/example_DVS_BLS383.js
index c33c68f..da1c66d 100644
--- a/examples/node/example_DVS_BN254CX.js
+++ b/examples/node/example_DVS_BLS383.js
@@ -53,7 +53,7 @@ ctx.MPIN.RANDOM_GENERATE(rng, S);
 console.log("M-Pin Master Secret s: 0x" + ctx.MPIN.bytestostring(S));
 
 /* Create Client Identity */
-var IDstr = "testuser@miracl.com";
+var IDstr = "testuser@milagro.com";
 var CLIENT_ID = ctx.MPIN.stringtobytes(IDstr);
 
 console.log("Client ID= " + ctx.MPIN.bytestostring(CLIENT_ID));
diff --git a/examples/node/example_ECC_BN254_NIST521.js b/examples/node/example_ECC_BLS383_NIST521.js
similarity index 98%
rename from examples/node/example_ECC_BN254_NIST521.js
rename to examples/node/example_ECC_BLS383_NIST521.js
index 10d812f..6a5e82f 100644
--- a/examples/node/example_ECC_BN254_NIST521.js
+++ b/examples/node/example_ECC_BLS383_NIST521.js
@@ -22,10 +22,10 @@ under the License.
 
 var CTX = require("../../index");
 
-var ctx1 = new CTX("BN254");
+var ctx1 = new CTX("BLS383");
 var ctx2 = new CTX("NIST521");
 
-console.log("Start testing BN254");
+console.log("Start testing BLS383");
 
 var pp = "M0ng00se",
     res,
diff --git a/examples/node/example_MPIN_BN254CX.js b/examples/node/example_MPIN_BLS383.js
similarity index 99%
rename from examples/node/example_MPIN_BN254CX.js
rename to examples/node/example_MPIN_BLS383.js
index f4defdc..26acda7 100644
--- a/examples/node/example_MPIN_BN254CX.js
+++ b/examples/node/example_MPIN_BLS383.js
@@ -61,7 +61,7 @@ ctx.MPIN.RANDOM_GENERATE(rng, S);
 console.log("M-Pin Master Secret s: 0x" + ctx.MPIN.bytestostring(S));
 
 /* Create Client Identity */
-var IDstr = "testUser@miracl.com";
+var IDstr = "testUser@milagro.com";
 var CLIENT_ID = ctx.MPIN.stringtobytes(IDstr);
 HCID = ctx.MPIN.HASH_ID(sha, CLIENT_ID); /* Either Client or TA calculates Hash(ID) - you decide! */
 
diff --git a/examples/node/example_MPIN_FULL_BN254CX.js b/examples/node/example_MPIN_FULL_BLS383.js
similarity index 99%
rename from examples/node/example_MPIN_FULL_BN254CX.js
rename to examples/node/example_MPIN_FULL_BLS383.js
index 7788672..7e689b3 100644
--- a/examples/node/example_MPIN_FULL_BN254CX.js
+++ b/examples/node/example_MPIN_FULL_BLS383.js
@@ -73,7 +73,7 @@ ctx.MPIN.RANDOM_GENERATE(rng, S);
 console.log("M-Pin Master Secret s: 0x" + ctx.MPIN.bytestostring(S));
 
 /* Create Client Identity */
-var IDstr = "testUser@miracl.com";
+var IDstr = "testUser@milagro.com";
 var CLIENT_ID = ctx.MPIN.stringtobytes(IDstr);
 HCID = ctx.MPIN.HASH_ID(sha, CLIENT_ID); /* Either Client or TA calculates Hash(ID) - you decide! */
 
diff --git a/examples/node/example_MPIN_ONE_PASS_BN254CX.js b/examples/node/example_MPIN_ONE_PASS_BLS383.js
similarity index 99%
rename from examples/node/example_MPIN_ONE_PASS_BN254CX.js
rename to examples/node/example_MPIN_ONE_PASS_BLS383.js
index a4b999b..c6f6b9f 100644
--- a/examples/node/example_MPIN_ONE_PASS_BN254CX.js
+++ b/examples/node/example_MPIN_ONE_PASS_BLS383.js
@@ -72,7 +72,7 @@ ctx.MPIN.RANDOM_GENERATE(rng, S);
 console.log("M-Pin Master Secret s: 0x" + ctx.MPIN.bytestostring(S));
 
 /* Create Client Identity */
-var IDstr = "testUser@miracl.com";
+var IDstr = "testUser@milagro.com";
 var CLIENT_ID = ctx.MPIN.stringtobytes(IDstr);
 HCID = ctx.MPIN.HASH_ID(sha, CLIENT_ID); /* Either Client or TA calculates Hash(ID) - you decide! */
 
diff --git a/examples/node/example_MPIN_TP_BN254CX.js b/examples/node/example_MPIN_TP_BN254CX.js
deleted file mode 100644
index 43bae9e..0000000
--- a/examples/node/example_MPIN_TP_BN254CX.js
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
-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.
-*/
-
-/* Test MPIN - test driver and function exerciser for MPIN API Functions */
-
-var CTX = require("../../index");
-
-var ctx = new CTX("BN254CX");
-
-/* Test M-Pin */
-
-var RAW = [];
-var i;
-
-var rng = new ctx.RAND();
-rng.clean();
-for (i = 0; i < 100; i++) {
-    RAW[i] = i;
-}
-
-rng.seed(100, RAW);
-
-var sha = ctx.ECP.HASH_TYPE;
-
-var S = [];
-var SST = [];
-var TOKEN = [];
-var PERMIT = [];
-var SEC = [];
-var xID = [];
-var xCID = [];
-var X = [];
-var Y = [];
-var E = [];
-var F = [];
-var HCID = [];
-var HID = [];
-var HTID = [];
-
-/* Set configuration */
-var PINERROR = true;
-
-/* Trusted Authority set-up */
-ctx.MPIN.RANDOM_GENERATE(rng, S);
-console.log("M-Pin Master Secret s: 0x" + ctx.MPIN.bytestostring(S));
-
-/* Create Client Identity */
-var IDstr = "testUser@miracl.com";
-var CLIENT_ID = ctx.MPIN.stringtobytes(IDstr);
-HCID = ctx.MPIN.HASH_ID(sha, CLIENT_ID); /* Either Client or TA calculates Hash(ID) - you decide! */
-
-console.log("Client ID= " + ctx.MPIN.bytestostring(CLIENT_ID));
-
-/* Client and Server are issued secrets by DTA */
-ctx.MPIN.GET_SERVER_SECRET(S, SST);
-console.log("Server Secret SS: 0x" + ctx.MPIN.bytestostring(SST));
-
-ctx.MPIN.GET_CLIENT_SECRET(S, HCID, TOKEN);
-console.log("Client Secret CS: 0x" + ctx.MPIN.bytestostring(TOKEN));
-
-/* Client extracts PIN from secret to create Token */
-var pin = 1234;
-console.log("Client extracts PIN= " + pin);
-var rtn = ctx.MPIN.EXTRACT_PIN(sha, CLIENT_ID, pin, TOKEN);
-if (rtn != 0) {
-    console.log("Failed to extract PIN ");
-}
-
-console.log("Client Token TK: 0x" + ctx.MPIN.bytestostring(TOKEN));
-
-var date = ctx.MPIN.today();
-/* Client gets "Time Token" permit from DTA */
-ctx.MPIN.GET_CLIENT_PERMIT(sha, date, S, HCID, PERMIT);
-console.log("Time Permit TP: 0x" + ctx.MPIN.bytestostring(PERMIT));
-
-/* This encoding makes Time permit look ctx.RANDom - Elligator squared */
-ctx.MPIN.ENCODING(rng, PERMIT);
-console.log("Encoded Time Permit TP: 0x" + ctx.MPIN.bytestostring(PERMIT));
-ctx.MPIN.DECODING(PERMIT);
-console.log("Decoded Time Permit TP: 0x" + ctx.MPIN.bytestostring(PERMIT));
-
-pin = 1234;
-
-/* Set date=0 and PERMIT=null if time permits not in use
-
-Client First pass: Inputs CLIENT_ID, optional RNG, pin, TOKEN and PERMIT. Output xID = x.H(CLIENT_ID) and re-combined secret SEC
-If PERMITS are is use, then date!=0 and PERMIT is added to secret and xCID = x.(H(CLIENT_ID)+H_T(date|H(CLIENT_ID)))
-ctx.RANDom value x is supplied externally if RNG=null, otherwise generated and passed out by RNG
-
-If Time Permits OFF set xCID = null, HTID=null and use xID and HID only
-If Time permits are ON, AND pin error detection is required then all of xID, xCID, HID and HTID are required
-If Time permits are ON, AND pin error detection is NOT required, set xID=null, HID=null and use xCID and HTID only.
-
-
-*/
-var pxID = xID;
-var pxCID = xCID;
-var pHID = HID;
-var pHTID = HTID;
-var pE = E;
-var pF = F;
-var pPERMIT = PERMIT;
-
-if (date != 0) {
-    if (!PINERROR) {
-        pxID = null;
-        //	pHID=null;
-    }
-} else {
-    pPERMIT = null;
-    pxCID = null;
-    pHTID = null;
-}
-if (!PINERROR) {
-    pE = null;
-    pF = null;
-}
-
-console.log("MPIN Multi Pass ");
-rtn = ctx.MPIN.CLIENT_1(sha, date, CLIENT_ID, rng, X, pin, TOKEN, SEC, pxID, pxCID, pPERMIT);
-if (rtn != 0) {
-    console.error("FAILURE: CLIENT_1 rtn: " + rtn);
-    process.exit(-1);
-}
-/* Server calculates H(ID) and H(T|H(ID)) (if time permits enabled), and maps them to points on the curve HID and HTID resp. */
-ctx.MPIN.SERVER_1(sha, date, CLIENT_ID, pHID, pHTID);
-
-/* Server generates ctx.RANDom number Y and sends it to Client */
-ctx.MPIN.RANDOM_GENERATE(rng, Y);
-
-/* Client Second Pass: Inputs Client secret SEC, x and y. Outputs -(x+y)*SEC */
-rtn = ctx.MPIN.CLIENT_2(X, Y, SEC);
-if (rtn != 0) {
-    console.error("FAILURE: CLIENT_2 rtn: " + rtn);
-    process.exit(-1);
-}
-/* Server Second pass. Inputs hashed client id, ctx.RANDom Y, -(x+y)*SEC, xID and xCID and Server secret SST. E and F help kangaroos to find error. */
-/* If PIN error not required, set E and F = NULL */
-rtn = ctx.MPIN.SERVER_2(date, pHID, pHTID, Y, SST, pxID, pxCID, SEC, pE, pF);
-
-if (rtn != 0) {
-    console.error("FAILURE: SERVER_1 rtn: " + rtn);
-    process.exit(-1);
-}
-if (rtn == ctx.MPIN.BAD_PIN) {
-    console.log("Server says - Bad Pin.");
-    if (PINERROR) {
-        var err = ctx.MPIN.KANGAROO(E, F);
-        if (err != 0) {
-            console.log("(Client PIN is out by " + err + ")");
-        }
-    }
-} else {
-    console.log("Server says - PIN is good! You really are " + IDstr);
-}
-
-console.log("SUCCESS");
diff --git a/package.json b/package.json
index cc80f77..1894815 100644
--- a/package.json
+++ b/package.json
@@ -1,10 +1,9 @@
 {
   "name": "milagro-crypto-js",
-  "version": "3.6.0",
-  "description": "Crypto Library in Javascript - Refact of Apache Milagro Crypto Library",
+  "version": "0.1.0",
+  "description": "Apache Milagro Crypto Javascript Library",
   "main": "index.js",
   "directories": {
-    "doc": "doc",
     "example": "examples",
     "test": "test"
   },
@@ -16,7 +15,7 @@
   },
   "repository": {
     "type": "git",
-    "url": "git+https://github.com/miracl/milagro-crypto-js.git"
+    "url": "git+https://github.com/apache/incubator-milagro-crypto-js.git"
   },
   "keywords": [
     "pairing",
@@ -27,9 +26,9 @@
   "author": "Michael Scott, Alessandro Budroni, Kealan McCusker",
   "license": "Apache-2.0",
   "bugs": {
-    "url": "https://github.com/miracl/milagro-crypto-js/issues"
+    "url": "https://github.com/apache/incubator-milagro-crypto-js/issues"
   },
-  "homepage": "https://github.com/miracl/milagro-crypto-js#readme",
+  "homepage": "https://github.com/apache/incubator-milagro-crypto-js#readme",
   "devDependencies": {
     "chai": "^3.5.0",
     "coveralls": "^3.0.2",
diff --git a/src/aes.js b/src/aes.js
index 43fe9aa..73f8425 100644
--- a/src/aes.js
+++ b/src/aes.js
@@ -47,8 +47,8 @@ var AES = function() {
     AES.CTR16 = 45;
 
     AES.prototype = {
-        /* reset cipher - mode or iv */
-        reset: function(m, iv) {
+        /* reset cipher */
+        reset: function(m, iv) { /* reset mode, or reset iv */
             var i;
 
             this.mode = m;
@@ -88,7 +88,7 @@ var AES = function() {
         },
 
         /* Initialise cipher */
-        init: function(m, nk, key, iv) {
+        init: function(m, nk, key, iv) { /* Key=16 bytes */
             /* Key Scheduler. Create expanded encryption key */
             var CipherKey = [],
                 b = [],
@@ -122,11 +122,26 @@ var AES = function() {
 
             for (j = nk, k = 0; j < N; j += nk, k++) {
                 this.fkey[j] = this.fkey[j - nk] ^ AES.SubByte(AES.ROTL24(this.fkey[j - 1])) ^ (AES.rco[k]) & 0xff;
-                for (i = 1; i < nk && (i + j) < N; i++) {
-                    this.fkey[i + j] = this.fkey[i + j - nk] ^ this.fkey[i + j - 1];
-                }
+
+				if (nk<=6)
+				{
+					for (i = 1; i < nk && (i + j) < N; i++) {
+						this.fkey[i + j] = this.fkey[i + j - nk] ^ this.fkey[i + j - 1];
+					}
+				} else {
+					for (i = 1; i < 4 && (i + j) < N; i++) {
+						this.fkey[i + j] = this.fkey[i + j - nk] ^ this.fkey[i + j - 1];
+					}
+					if ((j + 4) < N) {
+						this.fkey[j + 4] = this.fkey[j + 4 - nk] ^ AES.SubByte(this.fkey[j + 3]);
+					}
+					for (i = 5; i < nk && (i + j) < N; i++) {
+						this.fkey[i + j] = this.fkey[i + j - nk] ^ this.fkey[i + j - 1];
+					}
+				}
             }
 
+
             /* now for the expanded decrypt key in reverse order */
 
             for (j = 0; j < 4; j++) {
@@ -447,7 +462,7 @@ var AES = function() {
         },
 
         /* Clean up and delete left-overs */
-        end: function() {
+        end: function() { // clean up
             var i;
 
             for (i = 0; i < 4 * (this.Nr + 1); i++) {
@@ -474,13 +489,11 @@ var AES = function() {
         return (((x) << 24) | ((x) >>> 8));
     };
 
-    /* pack 4 bytes into a 32-bit Word */
-    AES.pack = function(b) {
+    AES.pack = function(b) { /* pack 4 bytes into a 32-bit Word */
         return (((b[3]) & 0xff) << 24) | ((b[2] & 0xff) << 16) | ((b[1] & 0xff) << 8) | (b[0] & 0xff);
     };
 
-    /* unpack bytes from a word */
-    AES.unpack = function(a) {
+    AES.unpack = function(a) { /* unpack bytes from a word */
         var b = [];
         b[0] = (a & 0xff);
         b[1] = ((a >>> 8) & 0xff);
@@ -489,8 +502,7 @@ var AES = function() {
         return b;
     };
 
-    /* x.y= AntiLog(Log(x) + Log(y)) */
-    AES.bmul = function(x, y) {
+    AES.bmul = function(x, y) { /* x.y= AntiLog(Log(x) + Log(y)) */
         var ix = (x & 0xff),
             iy = (y & 0xff),
             lx = (AES.ltab[ix]) & 0xff,
@@ -514,16 +526,14 @@ var AES = function() {
         return AES.pack(b);
     };
 
-    /* dot product of two 4-byte arrays */
-    AES.product = function(x, y) {
+    AES.product = function(x, y) { /* dot product of two 4-byte arrays */
         var xb = AES.unpack(x),
             yb = AES.unpack(y);
 
         return (AES.bmul(xb[0], yb[0]) ^ AES.bmul(xb[1], yb[1]) ^ AES.bmul(xb[2], yb[2]) ^ AES.bmul(xb[3], yb[3])) & 0xff;
     };
 
-    /* matrix Multiplication */
-    AES.InvMixCol = function(x) {
+    AES.InvMixCol = function(x) { /* matrix Multiplication */
         var b = [],
             y, m;
 
@@ -540,8 +550,7 @@ var AES = function() {
         return y;
     };
 
-    /* Inverse Coefficients */
-    AES.InCo = [0xB, 0xD, 0x9, 0xE];
+    AES.InCo = [0xB, 0xD, 0x9, 0xE]; /* Inverse Coefficients */
     AES.rco = [1, 2, 4, 8, 16, 32, 64, 128, 27, 54, 108, 216, 171, 77, 154, 47];
 
     AES.ptab = [
diff --git a/src/big.js b/src/big.js
index 0cf67b6..f680841 100644
--- a/src/big.js
+++ b/src/big.js
@@ -202,8 +202,7 @@ BIG = function(ctx) {
         fshr: function(k) {
             var r, i;
 
-            /* shifted out part */
-            r = this.w[0] & ((1 << k) - 1);
+            r = this.w[0] & ((1 << k) - 1); /* shifted out part */
 
             for (i = 0; i < BIG.NLEN - 1; i++) {
                 this.w[i] = (this.w[i] >> k) | ((this.w[i + 1] << (BIG.BASEBITS - k)) & BIG.BMASK);
@@ -245,8 +244,7 @@ BIG = function(ctx) {
 
             this.w[0] = (this.w[0] << k) & BIG.BMASK;
 
-            /* return excess - only used in ff.js */
-            return (this.w[BIG.NLEN - 1] >> ((8 * BIG.MODBYTES) % BIG.BASEBITS));
+            return (this.w[BIG.NLEN - 1] >> ((8 * BIG.MODBYTES) % BIG.BASEBITS)); /* return excess - only used in FF.java */
         },
 
         /* General shift left by k bits */
@@ -279,9 +277,10 @@ BIG = function(ctx) {
             var k = BIG.NLEN - 1,
                 bts, c;
 
-            this.norm();
+			var t=new BIG(0); t.copy(this);
+            t.norm();
 
-            while (k >= 0 && this.w[k] === 0) {
+            while (k >= 0 && t.w[k] === 0) {
                 k--;
             }
 
@@ -290,7 +289,7 @@ BIG = function(ctx) {
             }
 
             bts = BIG.BASEBITS * k;
-            c = this.w[k];
+            c = t.w[k];
 
             while (c !== 0) {
                 c = Math.floor(c / 2);
@@ -427,8 +426,8 @@ BIG = function(ctx) {
             var c = new BIG(0),
                 i;
 
-            this.norm();
             c.copy(this);
+			c.norm();
 
             for (i = BIG.MODBYTES - 1; i >= 0; i--) {
                 b[i + n] = c.w[0] & 0xff;
@@ -550,9 +549,10 @@ BIG = function(ctx) {
         },
 
         /* reduce this mod m */
-        mod: function(m) {
+        mod: function(m1) {
             var k = 0,
                 r = new BIG(0);
+			var m=new BIG(0); m.copy(m1);
 
             this.norm();
 
@@ -577,12 +577,13 @@ BIG = function(ctx) {
             }
         },
         /* this/=m */
-        div: function(m) {
+        div: function(m1) {
             var k = 0,
                 d = 0,
                 e = new BIG(1),
                 b = new BIG(0),
                 r = new BIG(0);
+			var m=new BIG(0); m.copy(m1);
 
             this.norm();
             b.copy(this);
@@ -761,12 +762,13 @@ BIG = function(ctx) {
         },
 
         /* return this^e mod m */
-        powmod: function(e, m) {
+        powmod: function(e1, m) {
             var a = new BIG(1),
                 z = new BIG(0),
                 s = new BIG(0),
                 bt;
 
+			var e=new BIG(0); e.copy(e1);
             this.norm();
             e.norm();
             z.copy(e);
@@ -790,6 +792,23 @@ BIG = function(ctx) {
         }
     };
 
+	BIG.ssn = function(r,a,m) {
+		var n=BIG.NLEN-1;
+		m.w[0]=(m.w[0]>>1)|((m.w[1]<<(BIG.BASEBITS-1))&BIG.BMASK);
+		r.w[0]=a.w[0]-m.w[0];
+		var carry=r.w[0]>>BIG.BASEBITS;
+		r.w[0]&=BIG.BMASK;
+		for (var i=1;i<n;i++) {
+			m.w[i]=(m.w[i]>>1)|((m.w[i+1]<<(BIG.BASEBITS-1))&BIG.BMASK);
+			r.w[i]=a.w[i]-m.w[i]+carry;
+			carry=r.w[i]>>BIG.BASEBITS;
+			r.w[i]&=BIG.BMASK;
+		}
+		m.w[n]>>=1;
+		r.w[n]=a.w[n]-m.w[n]+carry;
+		return ((r.w[n]>>(BIG.CHUNK-1))&1);
+	};
+
     /* convert from byte array to BIG */
     BIG.frombytearray = function(b, n) {
         var m = new BIG(0),
@@ -861,7 +880,7 @@ BIG = function(ctx) {
 
             b = r & 1;
             m.shl(1);
-            m.w[0] += b;
+            m.w[0] += b; // m.inc(b);
             j++;
             j &= 7;
         }
@@ -897,7 +916,7 @@ BIG = function(ctx) {
     /* return a*b as ctx.DBIG */
     BIG.mul = function(a, b) {
         var c = new ctx.DBIG(0),
-            d = [],
+            d = new Array(BIG.NLEN), //[],
             n, s, t, i, k, co;
 
         for (i = 0; i < BIG.NLEN; i++) {
@@ -940,7 +959,7 @@ BIG = function(ctx) {
     BIG.sqr = function(a) {
         var c = new ctx.DBIG(0),
             n, t, j, i, co;
-
+ 
         c.w[0] = a.w[0] * a.w[0];
 
         for (j = 1; j < BIG.NLEN - 1;) {
@@ -999,8 +1018,8 @@ BIG = function(ctx) {
 
     BIG.monty = function(m, nd, d) {
         var b = new BIG(0),
-            v = [],
-            dd = [],
+            v = new Array(BIG.NLEN),
+            dd = new Array(BIG.NLEN),
             s, c, t, i, k;
 
         t = d.w[0];
@@ -1039,9 +1058,10 @@ BIG = function(ctx) {
     };
 
     /* return a*b mod m */
-    BIG.modmul = function(a, b, m) {
+    BIG.modmul = function(a1, b1, m) {
         var d;
-
+		var a=new BIG(0); a.copy(a1);
+		var b=new BIG(0); b.copy(b1);
         a.mod(m);
         b.mod(m);
         d = BIG.mul(a, b);
@@ -1050,9 +1070,9 @@ BIG = function(ctx) {
     };
 
     /* return a^2 mod m */
-    BIG.modsqr = function(a, m) {
+    BIG.modsqr = function(a1, m) {
         var d;
-
+		var a=new BIG(0); a.copy(a1);
         a.mod(m);
         d = BIG.sqr(a);
 
@@ -1060,7 +1080,8 @@ BIG = function(ctx) {
     };
 
     /* return -a mod m */
-    BIG.modneg = function(a, m) {
+    BIG.modneg = function(a1, m) {
+		var a=new BIG(0); a.copy(a1);
         a.mod(m);
         return m.minus(a);
     };
@@ -1114,7 +1135,7 @@ DBIG = function(ctx) {
 
     /* constructor */
     var DBIG = function(x) {
-        this.w = [];
+        this.w = new Array(BIG.DNLEN);
         this.zero();
         this.w[0] = x;
     };
@@ -1266,9 +1287,10 @@ DBIG = function(ctx) {
             var k = ctx.BIG.DNLEN - 1,
                 bts, c;
 
-            this.norm();
+			var t=new DBIG(0); t.copy(this);
+            t.norm();
 
-            while (k >= 0 && this.w[k] === 0) {
+            while (k >= 0 && t.w[k] === 0) {
                 k--;
             }
 
@@ -1277,7 +1299,7 @@ DBIG = function(ctx) {
             }
 
             bts = ctx.BIG.BASEBITS * k;
-            c = this.w[k];
+            c = t.w[k];
 
             while (c !== 0) {
                 c = Math.floor(c / 2);
@@ -1337,7 +1359,6 @@ DBIG = function(ctx) {
                 dr.sub(m);
                 dr.norm();
                 this.cmove(dr, (1 - ((dr.w[ctx.BIG.DNLEN - 1] >> (ctx.BIG.CHUNK - 1)) & 1)));
-
                 k--;
             }
 
diff --git a/src/bls.js b/src/bls.js
new file mode 100644
index 0000000..8149915
--- /dev/null
+++ b/src/bls.js
@@ -0,0 +1,127 @@
+/*
+    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.
+*/
+
+/* BLS API Functions */
+
+var BLS = function(ctx) {
+    "use strict";
+
+    var BLS = {
+        BLS_OK: 0,
+        BLS_FAIL: -1,
+
+        BFS: ctx.BIG.MODBYTES,
+        BGS: ctx.BIG.MODBYTES,
+
+        bytestostring: function(b) {
+            var s = "",
+                len = b.length,
+                ch, i;
+
+            for (i = 0; i < len; i++) {
+                ch = b[i];
+                s += ((ch >>> 4) & 15).toString(16);
+                s += (ch & 15).toString(16);
+
+            }
+
+            return s;
+        },
+
+        stringtobytes: function(s) {
+            var b = [],
+                i;
+
+            for (i = 0; i < s.length; i++) {
+                b.push(s.charCodeAt(i));
+            }
+
+            return b;
+        },
+
+/* hash a message to an ECP point, using SHA3 */
+
+        bls_hashit: function(m) {
+			var sh = new ctx.SHA3(ctx.SHA3.SHAKE256);
+            var hm = [];
+            var t=this.stringtobytes(m);
+			for (var i=0;i<t.length;i++)
+				sh.process(t[i]);
+			sh.shake(hm,this.BFS);
+			var P=ctx.ECP.mapit(hm);
+			return P;
+		},
+
+/* generate key pair, private key S, public key W */
+
+		KeyPairGenerate(rng,S,W) {
+			var G=ctx.ECP2.generator();
+			var q=new ctx.BIG(0);
+			q.rcopy(ctx.ROM_CURVE.CURVE_Order);
+			var s=ctx.BIG.randomnum(q,rng);
+            s.toBytes(S);
+            G = ctx.PAIR.G2mul(G,s);
+
+            G.toBytes(W);  // To use point compression on public keys, change to true 
+			return this.BLS_OK;
+		},
+
+/* Sign message m using private key S to produce signature SIG */
+
+		sign(SIG,m,S) {
+			var D=this.bls_hashit(m);
+			var s=ctx.BIG.fromBytes(S);
+			D=ctx.PAIR.G1mul(D,s);
+			D.toBytes(SIG,true);
+			return this.BLS_OK;
+		},
+
+/* Verify signature given message m, the signature SIG, and the public key W */
+
+		verify(SIG,m,W) {
+			var HM=this.bls_hashit(m);
+			var D=ctx.ECP.fromBytes(SIG);
+			var G=ctx.ECP2.generator();
+			var PK=ctx.ECP2.fromBytes(W);
+			D.neg();
+
+// Use new multi-pairing mechanism 
+			var r=ctx.PAIR.initmp();
+			ctx.PAIR.another(r,G,D);
+			ctx.PAIR.another(r,PK,HM);
+			var v=ctx.PAIR.miller(r);
+
+//.. or alternatively
+//			var v=ctx.PAIR.ate2(G,D,PK,HM);
+
+			v=ctx.PAIR.fexp(v);
+			if (v.isunity())
+				return this.BLS_OK;
+			return this.BLS_FAIL;
+		}
+    };
+
+    return BLS;
+};	
+
+if (typeof module !== "undefined" && typeof module.exports !== "undefined") {
+    module.exports = {
+        BLS: BLS
+    };
+}
diff --git a/src/bls192.js b/src/bls192.js
new file mode 100644
index 0000000..64dbd3c
--- /dev/null
+++ b/src/bls192.js
@@ -0,0 +1,126 @@
+/*
+    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.
+*/
+
+/* BLS API Functions */
+
+var BLS192 = function(ctx) {
+    "use strict";
+
+    var BLS192 = {
+        BLS_OK: 0,
+        BLS_FAIL: -1,
+
+        BFS: ctx.BIG.MODBYTES,
+        BGS: ctx.BIG.MODBYTES,
+
+        bytestostring: function(b) {
+            var s = "",
+                len = b.length,
+                ch, i;
+
+            for (i = 0; i < len; i++) {
+                ch = b[i];
+                s += ((ch >>> 4) & 15).toString(16);
+                s += (ch & 15).toString(16);
+
+            }
+
+            return s;
+        },
+
+        stringtobytes: function(s) {
+            var b = [],
+                i;
+
+            for (i = 0; i < s.length; i++) {
+                b.push(s.charCodeAt(i));
+            }
+
+            return b;
+        },
+
+/* hash a message to an ECP point, using SHA3 */
+
+        bls_hashit: function(m) {
+			var sh = new ctx.SHA3(ctx.SHA3.SHAKE256);
+            var hm = [];
+            var t=this.stringtobytes(m);
+			for (var i=0;i<t.length;i++)
+				sh.process(t[i]);
+			sh.shake(hm,this.BFS);
+			var P=ctx.ECP.mapit(hm);
+			return P;
+		},
+
+/* generate key pair, private key S, public key W */
+
+		KeyPairGenerate(rng,S,W) {
+			var G=ctx.ECP4.generator();
+			var q=new ctx.BIG(0);
+			q.rcopy(ctx.ROM_CURVE.CURVE_Order);
+			var s=ctx.BIG.randomnum(q,rng);
+            s.toBytes(S);
+            G = ctx.PAIR192.G2mul(G,s);
+            G.toBytes(W);  // To use point compression on public keys, change to true 
+			return this.BLS_OK;
+
+		},
+
+/* Sign message m using private key S to produce signature SIG */
+
+		sign(SIG,m,S) {
+			var D=this.bls_hashit(m);
+			var s=ctx.BIG.fromBytes(S);
+			D=ctx.PAIR192.G1mul(D,s);
+			D.toBytes(SIG,true);
+			return this.BLS_OK;
+		},
+
+/* Verify signature given message m, the signature SIG, and the public key W */
+
+		verify(SIG,m,W) {
+			var HM=this.bls_hashit(m);
+			var D=ctx.ECP.fromBytes(SIG);
+			var G=ctx.ECP4.generator();
+			var PK=ctx.ECP4.fromBytes(W);
+			D.neg();
+
+// Use new multi-pairing mechanism 
+			var r=ctx.PAIR192.initmp();
+			ctx.PAIR192.another(r,G,D);
+			ctx.PAIR192.another(r,PK,HM);
+			var v=ctx.PAIR192.miller(r);
+
+//.. or alternatively
+//			var v=ctx.PAIR192.ate2(G,D,PK,HM);
+			v=ctx.PAIR192.fexp(v);
+			if (v.isunity())
+				return this.BLS_OK;
+			return this.BLS_FAIL;
+		}
+    };
+
+    return BLS192;
+};	
+
+if (typeof module !== "undefined" && typeof module.exports !== "undefined") {
+    module.exports = {
+        BLS192: BLS192
+    };
+}
diff --git a/src/bls256.js b/src/bls256.js
new file mode 100644
index 0000000..a154fe4
--- /dev/null
+++ b/src/bls256.js
@@ -0,0 +1,129 @@
+/*
+    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.
+*/
+
+/* BLS API Functions */
+
+var BLS256 = function(ctx) {
+    "use strict";
+
+    var BLS256 = {
+        BLS_OK: 0,
+        BLS_FAIL: -1,
+
+        BFS: ctx.BIG.MODBYTES,
+        BGS: ctx.BIG.MODBYTES,
+
+        bytestostring: function(b) {
+            var s = "",
+                len = b.length,
+                ch, i;
+
+            for (i = 0; i < len; i++) {
+                ch = b[i];
+                s += ((ch >>> 4) & 15).toString(16);
+                s += (ch & 15).toString(16);
+
+            }
+
+            return s;
+        },
+
+        stringtobytes: function(s) {
+            var b = [],
+                i;
+
+            for (i = 0; i < s.length; i++) {
+                b.push(s.charCodeAt(i));
+            }
+
+            return b;
+        },
+
+/* hash a message to an ECP point, using SHA3 */
+
+        bls_hashit: function(m) {
+			var sh = new ctx.SHA3(ctx.SHA3.SHAKE256);
+            var hm = [];
+            var t=this.stringtobytes(m);
+			for (var i=0;i<t.length;i++)
+				sh.process(t[i]);
+			sh.shake(hm,this.BFS);
+			var P=ctx.ECP.mapit(hm);
+			return P;
+		},
+
+/* generate key pair, private key S, public key W */
+
+		KeyPairGenerate(rng,S,W) {
+			var G=ctx.ECP8.generator();
+			var q=new ctx.BIG(0);
+			q.rcopy(ctx.ROM_CURVE.CURVE_Order);
+			var s=ctx.BIG.randomnum(q,rng);
+            s.toBytes(S);
+            G = ctx.PAIR256.G2mul(G,s);
+            G.toBytes(W);  // To use point compression on public keys, change to true 
+			return this.BLS_OK;
+
+		},
+
+/* Sign message m using private key S to produce signature SIG */
+
+		sign(SIG,m,S) {
+			var D=this.bls_hashit(m);
+			var s=ctx.BIG.fromBytes(S);
+			D=ctx.PAIR256.G1mul(D,s);
+			D.toBytes(SIG,true);
+			return this.BLS_OK;
+		},
+
+/* Verify signature given message m, the signature SIG, and the public key W */
+
+		verify(SIG,m,W) {
+			var HM=this.bls_hashit(m);
+			var D=ctx.ECP.fromBytes(SIG);
+			var G=ctx.ECP8.generator();
+			var PK=ctx.ECP8.fromBytes(W);
+			D.neg();
+
+// Use new multi-pairing mechanism 
+			var r=ctx.PAIR256.initmp();
+			ctx.PAIR256.another(r,G,D);
+			ctx.PAIR256.another(r,PK,HM);
+			var v=ctx.PAIR256.miller(r);
+
+//.. or alternatively
+//			var v=ctx.PAIR256.ate2(G,D,PK,HM);
+
+			v=ctx.PAIR256.fexp(v);
+			if (v.isunity())
+				return this.BLS_OK;
+			return this.BLS_FAIL;
+		}
+    };
+
+    return BLS256;
+};
+
+if (typeof module !== "undefined" && typeof module.exports !== "undefined") {
+    module.exports = {
+        BLS256: BLS256
+    };
+}
+
+		
diff --git a/src/ctx.js b/src/ctx.js
index 0513b31..3af2784 100644
--- a/src/ctx.js
+++ b/src/ctx.js
@@ -24,37 +24,24 @@ var CTX = function(input_parameter) {
         CTXLIST,
         prepareModule;
 
-    /**
-     * Config fields:
-     *  NB   : Number of bytes in Modulus
-     *  BASE : Number base as power of 2
-     *  NBT  : Number of bits in Modulus
-     *  M8   : Modulus mod 8
-     *  MT   : Modulus Type (Pseudo-Mersenne,...)
-     *  CT   : Curve Type (Weierstrass,...)
-     *  PF   : Pairing Friendly
-     *  ST   : Sextic Twist Type
-     *  SX   : Sign of x parameter
-     *  HT   : Hash output size
-     *  AK   : AES key size
-     */
-
     CTXLIST = {
         "ED25519": {
             "BITS": "256",
             "FIELD": "25519",
             "CURVE": "ED25519",
-            "@NB": 32,
-            "@BASE": 24,
-            "@NBT": 255,
-            "@M8": 5,
-            "@MT": 1,
-            "@CT": 1,
-            "@PF": 0,
-            "@ST": 0,
-            "@SX": 0,
-            "@HT": 32,
-            "@AK": 16
+            "@NB": 32,      /* Number of bytes in Modulus */
+            "@BASE": 24,    /* Number base as power of 2 */
+            "@NBT": 255,    /* Number of bits in modulus */
+            "@M8": 5,       /* Modulus mod 8 */
+            "@MT": 1,       /* Modulus Type (pseudo-mersenne,...) */
+            "@CT": 1,       /* Curve Type (Weierstrass,...) */
+            "@PF": 0,       /* Pairing Friendly */
+            "@ST": 0,       /* Sextic Twist Type */
+            "@SX": 0,       /* Sign of x parameter */
+            "@AB": 0,       /* ATE parameter size */
+            "@HT": 32,      /* Hash output size */
+            "@SH": 9,       /* Maximum field excess */
+            "@AK": 16       /* AES key size */
         },
 
         "C25519": {
@@ -70,7 +57,9 @@ var CTX = function(input_parameter) {
             "@PF": 0,
             "@ST": 0,
             "@SX": 0,
+            "@AB": 0,
             "@HT": 32,
+	    "@SH": 9, 
             "@AK": 16
         },
 
@@ -88,7 +77,9 @@ var CTX = function(input_parameter) {
             "@PF": 0,
             "@ST": 0,
             "@SX": 0,
+            "@AB": 0,
             "@HT": 32,
+	    "@SH": 8, 
             "@AK": 16
         },
 
@@ -105,7 +96,9 @@ var CTX = function(input_parameter) {
             "@PF": 0,
             "@ST": 0,
             "@SX": 0,
+            "@AB": 0,
             "@HT": 32,
+	    "@SH": 8, 
             "@AK": 16
         },
 
@@ -122,7 +115,9 @@ var CTX = function(input_parameter) {
             "@PF": 0,
             "@ST": 0,
             "@SX": 0,
+            "@AB": 0,
             "@HT": 48,
+	    "@SH": 7, 
             "@AK": 24
         },
 
@@ -139,7 +134,9 @@ var CTX = function(input_parameter) {
             "@PF": 0,
             "@ST": 0,
             "@SX": 0,
+            "@AB": 0,
             "@HT": 32,
+	    "@SH": 8, 
             "@AK": 16
         },
 
@@ -156,7 +153,9 @@ var CTX = function(input_parameter) {
             "@PF": 0,
             "@ST": 0,
             "@SX": 0,
+            "@AB": 0,
             "@HT": 32,
+	    "@SH": 8, 
             "@AK": 16
         },
 
@@ -173,7 +172,9 @@ var CTX = function(input_parameter) {
             "@PF": 0,
             "@ST": 0,
             "@SX": 0,
+            "@AB": 0,
             "@HT": 48,
+	    "@SH": 9, 
             "@AK": 24
         },
 
@@ -190,7 +191,9 @@ var CTX = function(input_parameter) {
             "@PF": 0,
             "@ST": 0,
             "@SX": 0,
+            "@AB": 0,
             "@HT": 64,
+	    "@SH": 11, 
             "@AK": 32
         },
 
@@ -207,7 +210,9 @@ var CTX = function(input_parameter) {
             "@PF": 0,
             "@ST": 0,
             "@SX": 0,
+            "@AB": 0,
             "@HT": 64,
+	    "@SH": 4, 
             "@AK": 32
         },
 
@@ -224,7 +229,9 @@ var CTX = function(input_parameter) {
             "@PF": 0,
             "@ST": 0,
             "@SX": 0,
+            "@AB": 0,
             "@HT": 64,
+	    "@SH": 8, 
             "@AK": 32
         },
 
@@ -241,7 +248,9 @@ var CTX = function(input_parameter) {
             "@PF": 0,
             "@ST": 0,
             "@SX": 0,
+            "@AB": 0,
             "@HT": 32,
+	    "@SH": 8, 
             "@AK": 16
         },
 
@@ -258,7 +267,9 @@ var CTX = function(input_parameter) {
             "@PF": 0,
             "@ST": 0,
             "@SX": 0,
+            "@AB": 0,
             "@HT": 32,
+	    "@SH": 8, 
             "@AK": 16
         },
 
@@ -275,7 +286,9 @@ var CTX = function(input_parameter) {
             "@PF": 0,
             "@ST": 0,
             "@SX": 0,
+            "@AB": 0,
             "@HT": 48,
+	    "@SH": 7, 
             "@AK": 24
         },
 
@@ -292,7 +305,9 @@ var CTX = function(input_parameter) {
             "@PF": 0,
             "@ST": 0,
             "@SX": 0,
+            "@AB": 0,
             "@HT": 48,
+	    "@SH": 7, 
             "@AK": 24
         },
 
@@ -309,7 +324,9 @@ var CTX = function(input_parameter) {
             "@PF": 0,
             "@ST": 0,
             "@SX": 0,
+            "@AB": 0,
             "@HT": 64,
+	    "@SH": 11, 
             "@AK": 32
         },
 
@@ -326,7 +343,9 @@ var CTX = function(input_parameter) {
             "@PF": 0,
             "@ST": 0,
             "@SX": 0,
+            "@AB": 0,
             "@HT": 64,
+	    "@SH": 11, 
             "@AK": 32
         },
 
@@ -343,7 +362,9 @@ var CTX = function(input_parameter) {
             "@PF": 1,
             "@ST": 1,
             "@SX": 1,
+            "@AB": 66,
             "@HT": 32,
+	    "@SH": 8, 
             "@AK": 16
         },
 
@@ -360,7 +381,9 @@ var CTX = function(input_parameter) {
             "@PF": 1,
             "@ST": 1,
             "@SX": 0,
+            "@AB": 130,
             "@HT": 32,
+	    "@SH": 11, 
             "@AK": 16
         },
 
@@ -377,7 +400,9 @@ var CTX = function(input_parameter) {
             "@PF": 1,
             "@ST": 0,
             "@SX": 1,
+            "@AB": 66,
             "@HT": 32,
+	    "@SH": 10, 
             "@AK": 16
         },
 
@@ -394,7 +419,9 @@ var CTX = function(input_parameter) {
             "@PF": 1,
             "@ST": 0,
             "@SX": 1,
+            "@AB": 66,
             "@HT": 32,
+	    "@SH": 10, 
             "@AK": 16
         },
 
@@ -411,7 +438,9 @@ var CTX = function(input_parameter) {
             "@PF": 2,
             "@ST": 1,
             "@SX": 0,
+            "@AB": 65,
             "@HT": 32,
+	    "@SH": 8, 
             "@AK": 16
         },
 
@@ -428,7 +457,9 @@ var CTX = function(input_parameter) {
             "@PF": 3,
             "@ST": 1,
             "@SX": 0,
+            "@AB": 49,
             "@HT": 48,
+	    "@SH": 4, 
             "@AK": 24
         },
 
@@ -445,7 +476,9 @@ var CTX = function(input_parameter) {
             "@PF": 4,
             "@ST": 1,
             "@SX": 0,
+            "@AB": 32,
             "@HT": 64,
+	    "@SH": 11, 
             "@AK": 32
         },
 
@@ -462,7 +495,9 @@ var CTX = function(input_parameter) {
             "@PF": 2,
             "@ST": 1,
             "@SX": 1,
+            "@AB": 65,
             "@HT": 32,
+	    "@SH": 10, 
             "@AK": 16
         },
 
@@ -479,7 +514,9 @@ var CTX = function(input_parameter) {
             "@PF": 2,
             "@ST": 1,
             "@SX": 1,
+            "@AB": 78,
             "@HT": 32,
+	    "@SH": 11, 
             "@AK": 16
         },
 
@@ -532,7 +569,6 @@ var CTX = function(input_parameter) {
     prepareModule("HASH512");
     prepareModule("SHA3");
     prepareModule("RAND");
-    prepareModule("NHS");
 
     if (typeof input_parameter === "undefined") {
         return;
@@ -570,6 +606,8 @@ var CTX = function(input_parameter) {
             prepareModule("ECP2");
             prepareModule("PAIR");
             prepareModule("MPIN");
+	    prepareModule("BLS");
+
         }
 
         if (ctx.config["@PF"] == 3) {
@@ -580,6 +618,7 @@ var CTX = function(input_parameter) {
             prepareModule("ECP4");
             prepareModule("PAIR192");
             prepareModule("MPIN192");
+            prepareModule("BLS192");
         }
 
         if (ctx.config["@PF"] == 4) {
@@ -591,6 +630,7 @@ var CTX = function(input_parameter) {
             prepareModule("ECP8");
             prepareModule("PAIR256");
             prepareModule("MPIN256");
+            prepareModule("BLS256");
         }
 
         return;
diff --git a/src/ecdh.js b/src/ecdh.js
index 6abba53..416c74c 100644
--- a/src/ecdh.js
+++ b/src/ecdh.js
@@ -57,7 +57,8 @@ var ECDH = function(ctx) {
 
             for (i = 0; i < len; i++) {
                 ch = b[i];
-                s += String.fromCharCode(ch);
+                s += ((ch >>> 4) & 15).toString(16);
+                s += (ch & 15).toString(16);
             }
 
             return s;
@@ -76,7 +77,7 @@ var ECDH = function(ctx) {
 
         hashit: function(sha, A, n, B, pad) {
             var R = [],
-                H, W, i;
+                H, W, i, len;
 
             if (sha == this.SHA256) {
                 H = new ctx.HASH256();
@@ -104,16 +105,18 @@ var ECDH = function(ctx) {
 
             W = [];
 
-            if (sha >= pad) {
-                for (i = 0; i < pad; i++) {
+            len = pad; 
+
+            if (sha >= len) {
+                for (i = 0; i < len; i++) {
                     W[i] = R[i];
                 }
             } else {
                 for (i = 0; i < sha; i++) {
-                    W[i + pad - sha] = R[i];
+                    W[i + len - sha] = R[i];
                 }
 
-                for (i = 0; i < pad - sha; i++) {
+                for (i = 0; i < len - sha; i++) {
                     W[i] = 0;
                 }
             }
@@ -261,6 +264,7 @@ var ECDH = function(ctx) {
 
             K0 = new Array(b);
 
+            //b=K0.length;
             if (olen < 4) {
                 return 0;
             }
@@ -424,6 +428,7 @@ var ECDH = function(ctx) {
         KEY_PAIR_GENERATE: function(RNG, S, W) {
             var res = 0,
                 r, s, G, WP;
+            // var T=[];
 
             G = ctx.ECP.generator();
 
@@ -440,7 +445,7 @@ var ECDH = function(ctx) {
             s.toBytes(S);
 
             WP = G.mul(s);
-            WP.toBytes(W,false);
+            WP.toBytes(W,false);  // To use point compression on public keys, change to true 
 
             return res;
         },
@@ -536,7 +541,7 @@ var ECDH = function(ctx) {
 
             do {
                 u = ctx.BIG.randomnum(r, RNG);
-                w = ctx.BIG.randomnum(r, RNG);
+                w = ctx.BIG.randomnum(r, RNG);  /* side channel masking */
                 V.copy(G);
                 V = V.mul(u);
                 vx = V.getX();
@@ -666,6 +671,16 @@ var ECDH = function(ctx) {
             return C;
         },
 
+		ncomp: function(T1,T2,n) {
+			var res=0;
+			for (var i=0;i<n;i++)
+			{
+				res|=(T1[i]^T2[i]);
+			}
+			if (res==0) return true;
+			return false;
+		},
+
         ECIES_DECRYPT: function(sha, P1, P2, V, C, T, U) {
             var Z = [],
                 VZ = [],
@@ -716,16 +731,9 @@ var ECDH = function(ctx) {
 
             this.HMAC(sha, AC, K2, TAG);
 
-            same = true;
-            for (i = 0; i < T.length; i++) {
-                if (T[i] != TAG[i]) {
-                    same = false;
-                }
-            }
-
-            if (!same) {
-                return [];
-            }
+			if (!this.ncomp(T,TAG,T.length)) {
+				return [];
+			}
 
             return M;
         }
diff --git a/src/ecp.js b/src/ecp.js
index ba045fd..97c2918 100644
--- a/src/ecp.js
+++ b/src/ecp.js
@@ -48,6 +48,7 @@ var ECP = function(ctx) {
     ECP.CURVE_PAIRING_TYPE = ctx.config["@PF"];
     ECP.SEXTIC_TWIST = ctx.config["@ST"];
     ECP.SIGN_OF_X = ctx.config["@SX"];
+    ECP.ATE_BITS = ctx.config["@AB"];
 
     ECP.HASH_TYPE = ctx.config["@HT"];
     ECP.AESKEY = ctx.config["@AK"];
@@ -55,11 +56,14 @@ var ECP = function(ctx) {
     ECP.prototype = {
         /* test this=O point-at-infinity */
         is_infinity: function() {
+  
             this.x.reduce();
             this.z.reduce();
 
             if (ECP.CURVETYPE == ECP.EDWARDS) {
+
                 this.y.reduce();
+
                 return (this.x.iszilch() && this.y.equals(this.z));
             } else if (ECP.CURVETYPE == ECP.WEIERSTRASS) {
                 this.y.reduce();
@@ -73,20 +77,24 @@ var ECP = function(ctx) {
 
         /* conditional swap of this and Q dependant on d */
         cswap: function(Q, d) {
+
             this.x.cswap(Q.x, d);
             if (ECP.CURVETYPE != ECP.MONTGOMERY) {
                 this.y.cswap(Q.y, d);
             }
             this.z.cswap(Q.z, d);
+
         },
 
         /* conditional move of Q to P dependant on d */
         cmove: function(Q, d) {
+
             this.x.cmove(Q.x, d);
             if (ECP.CURVETYPE != ECP.MONTGOMERY) {
                 this.y.cmove(Q.y, d);
             }
             this.z.cmove(Q.z, d);
+
         },
 
         /* Constant time select from pre-computed table */
@@ -191,12 +199,14 @@ var ECP = function(ctx) {
             this.y = new ctx.FP(0);
             this.y.bcopy(iy);
             this.z = new ctx.FP(1);
+			this.x.norm();
             rhs = ECP.RHS(this.x);
 
             if (ECP.CURVETYPE == ECP.MONTGOMERY) {
                 if (rhs.jacobi() != 1) {
                     this.inf();
                 }
+ 
             } else {
                 y2 = new ctx.FP(0);
                 y2.copy(this.y);
@@ -214,6 +224,7 @@ var ECP = function(ctx) {
 
             this.x = new ctx.FP(0);
             this.x.bcopy(ix);
+			this.x.norm();
             rhs = ECP.RHS(this.x);
             this.z = new ctx.FP(1);
 
@@ -234,6 +245,7 @@ var ECP = function(ctx) {
 
             this.x = new ctx.FP(0);
             this.x.bcopy(ix);
+			this.x.norm();
             rhs = ECP.RHS(this.x);
             this.z = new ctx.FP(1);
 
@@ -278,19 +290,18 @@ var ECP = function(ctx) {
 
         /* extract x as ctx.BIG */
         getX: function() {
-            this.affine();
-            return this.x.redc();
+			var W=new ECP(); W.copy(this); W.affine();
+            return W.x.redc();
         },
 
         /* extract y as ctx.BIG */
         getY: function() {
-            this.affine();
-            return this.y.redc();
+			var W=new ECP(); W.copy(this); W.affine();
+            return W.y.redc();
         },
 
         /* get sign of Y */
         getS: function() {
-            this.affine();
             var y = this.getY();
             return y.parity();
         },
@@ -311,42 +322,50 @@ var ECP = function(ctx) {
         },
 
         /* convert to byte array */
-        toBytes: function(b) {
+        toBytes: function(b,compress) {
             var t = [],
                 i;
-
-            if (ECP.CURVETYPE != ECP.MONTGOMERY) {
-                b[0] = 0x04;
-            } else {
-                b[0] = 0x02;
-            }
-
-            this.affine();
-            this.x.redc().toBytes(t);
+			var W=new ECP(); W.copy(this);
+            W.affine();
+            W.x.redc().toBytes(t);
 
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 1] = t[i];
             }
 
-            if (ECP.CURVETYPE != ECP.MONTGOMERY) {
-                this.y.redc().toBytes(t);
-                for (i = 0; i < ctx.BIG.MODBYTES; i++) {
-                    b[i + ctx.BIG.MODBYTES + 1] = t[i];
+            if (ECP.CURVETYPE == ECP.MONTGOMERY) {
+                b[0] = 0x06;
+                return;
+            }
+
+            if (compress) {
+                b[0]=0x02;
+                if (W.y.redc().parity()==1) {
+                    b[0]=0x03;
                 }
+                return;
+            }
+
+            b[0]=0x04;
+
+            W.y.redc().toBytes(t);
+            for (i = 0; i < ctx.BIG.MODBYTES; i++) {
+                b[i + ctx.BIG.MODBYTES + 1] = t[i];
             }
         },
         /* convert to hex string */
         toString: function() {
-            if (this.is_infinity()) {
+			var W=new ECP(); W.copy(this);
+            if (W.is_infinity()) {
                 return "infinity";
             }
 
-            this.affine();
+            W.affine();
 
             if (ECP.CURVETYPE == ECP.MONTGOMERY) {
-                return "(" + this.x.redc().toString() + ")";
+                return "(" + W.x.redc().toString() + ")";
             } else {
-                return "(" + this.x.redc().toString() + "," + this.y.redc().toString() + ")";
+                return "(" + W.x.redc().toString() + "," + W.y.redc().toString() + ")";
             }
         },
 
@@ -360,13 +379,13 @@ var ECP = function(ctx) {
 
                 if (ctx.ROM_CURVE.CURVE_A == 0) {
                     t0 = new ctx.FP(0);
-                    t0.copy(this.y);
+                    t0.copy(this.y);                    
                     t0.sqr();
                     t1 = new ctx.FP(0);
-                    t1.copy(this.y);
+                    t1.copy(this.y); 
                     t1.mul(this.z);
                     t2 = new ctx.FP(0);
-                    t2.copy(this.z);
+                    t2.copy(this.z); 
                     t2.sqr();
 
                     this.z.copy(t0);
@@ -379,10 +398,10 @@ var ECP = function(ctx) {
                     t2.imul(3 * ctx.ROM_CURVE.CURVE_B_I);
 
                     x3 = new ctx.FP(0);
-                    x3.copy(t2);
+                    x3.copy(t2); 
                     x3.mul(this.z);
                     y3 = new ctx.FP(0);
-                    y3.copy(t0);
+                    y3.copy(t0); 
                     y3.add(t2);
                     y3.norm();
                     this.z.mul(t1);
@@ -405,21 +424,23 @@ var ECP = function(ctx) {
                     this.y.norm();
                 } else {
                     t0 = new ctx.FP(0);
-                    t0.copy(this.x);
+                    t0.copy(this.x); 
                     t1 = new ctx.FP(0);
-                    t1.copy(this.y);
+                    t1.copy(this.y); 
                     t2 = new ctx.FP(0);
-                    t2.copy(this.z);
+                    t2.copy(this.z); 
                     t3 = new ctx.FP(0);
-                    t3.copy(this.x);
+                    t3.copy(this.x); 
                     z3 = new ctx.FP(0);
-                    z3.copy(this.z);
-                    y3 = new ctx.FP(0);
-                    x3 = new ctx.FP(0);
-                    b = new ctx.FP(0);
+                    z3.copy(this.z); 
+                    y3 = new ctx.FP(0); 
+                    x3 = new ctx.FP(0); 
+                    b = new ctx.FP(0); 
+                    
                     if (ctx.ROM_CURVE.CURVE_B_I == 0) {
                         b.rcopy(ctx.ROM_CURVE.CURVE_B);
                     }
+                   
                     t0.sqr(); //1    x^2
                     t1.sqr(); //2    y^2
                     t2.sqr(); //3
@@ -452,8 +473,8 @@ var ECP = function(ctx) {
                     y3.mul(x3); //14
                     x3.mul(t3); //15
                     t3.copy(t2);
-                    t3.add(t2); //16
-                    t2.add(t3); //17
+                    t3.add(t2);  //16
+                    t2.add(t3);  //17
 
                     if (ctx.ROM_CURVE.CURVE_B_I == 0) {
                         z3.mul(b); //18
@@ -489,6 +510,7 @@ var ECP = function(ctx) {
                     t1.norm(); //33
                     z3.copy(t0);
                     z3.mul(t1); //34
+                  
                     this.x.copy(x3);
                     this.x.norm();
                     this.y.copy(y3);
@@ -500,12 +522,13 @@ var ECP = function(ctx) {
 
             if (ECP.CURVETYPE == ECP.EDWARDS) {
                 C = new ctx.FP(0);
-                C.copy(this.x);
+                C.copy(this.x); 
                 D = new ctx.FP(0);
-                D.copy(this.y);
+                D.copy(this.y); 
                 H = new ctx.FP(0);
-                H.copy(this.z);
-                J = new ctx.FP(0);
+                H.copy(this.z); 
+                J = new ctx.FP(0); 
+               
                 this.x.mul(this.y);
                 this.x.add(this.x);
                 this.x.norm();
@@ -536,12 +559,12 @@ var ECP = function(ctx) {
 
             if (ECP.CURVETYPE == ECP.MONTGOMERY) {
                 A = new ctx.FP(0);
-                A.copy(this.x);
+                A.copy(this.x); 
                 B = new ctx.FP(0);
-                B.copy(this.x);
-                AA = new ctx.FP(0);
-                BB = new ctx.FP(0);
-                C = new ctx.FP(0);
+                B.copy(this.x); 
+                AA = new ctx.FP(0); 
+                BB = new ctx.FP(0); 
+                C = new ctx.FP(0); 
 
                 A.add(this.z);
                 A.norm();
@@ -579,20 +602,20 @@ var ECP = function(ctx) {
 
                     b = 3 * ctx.ROM_CURVE.CURVE_B_I;
                     t0 = new ctx.FP(0);
-                    t0.copy(this.x);
+                    t0.copy(this.x); 
                     t0.mul(Q.x);
                     t1 = new ctx.FP(0);
-                    t1.copy(this.y);
+                    t1.copy(this.y); 
                     t1.mul(Q.y);
                     t2 = new ctx.FP(0);
-                    t2.copy(this.z);
+                    t2.copy(this.z); 
                     t2.mul(Q.z);
                     t3 = new ctx.FP(0);
-                    t3.copy(this.x);
+                    t3.copy(this.x); 
                     t3.add(this.y);
                     t3.norm();
                     t4 = new ctx.FP(0);
-                    t4.copy(Q.x);
+                    t4.copy(Q.x); 
                     t4.add(Q.y);
                     t4.norm();
                     t3.mul(t4);
@@ -605,7 +628,7 @@ var ECP = function(ctx) {
                     t4.add(this.z);
                     t4.norm();
                     x3 = new ctx.FP(0);
-                    x3.copy(Q.y);
+                    x3.copy(Q.y); 
                     x3.add(Q.z);
                     x3.norm();
 
@@ -619,7 +642,7 @@ var ECP = function(ctx) {
                     x3.add(this.z);
                     x3.norm();
                     y3 = new ctx.FP(0);
-                    y3.copy(Q.x);
+                    y3.copy(Q.x); 
                     y3.add(Q.z);
                     y3.norm();
                     x3.mul(y3);
@@ -634,7 +657,7 @@ var ECP = function(ctx) {
                     t2.imul(b);
 
                     z3 = new ctx.FP(0);
-                    z3.copy(t1);
+                    z3.copy(t1); 
                     z3.add(t2);
                     z3.norm();
                     t1.sub(t2);
@@ -661,21 +684,21 @@ var ECP = function(ctx) {
                     this.z.norm();
                 } else {
                     t0 = new ctx.FP(0);
-                    t0.copy(this.x);
+                    t0.copy(this.x); 
                     t1 = new ctx.FP(0);
-                    t1.copy(this.y);
+                    t1.copy(this.y); 
                     t2 = new ctx.FP(0);
-                    t2.copy(this.z);
+                    t2.copy(this.z); 
                     t3 = new ctx.FP(0);
-                    t3.copy(this.x);
+                    t3.copy(this.x); 
                     t4 = new ctx.FP(0);
-                    t4.copy(Q.x);
-                    z3 = new ctx.FP(0);
+                    t4.copy(Q.x); 
+                    z3 = new ctx.FP(0); 
                     y3 = new ctx.FP(0);
-                    y3.copy(Q.x);
+                    y3.copy(Q.x); 
                     x3 = new ctx.FP(0);
-                    x3.copy(Q.y);
-                    b = new ctx.FP(0);
+                    x3.copy(Q.y); 
+                    b = new ctx.FP(0); 
 
                     if (ctx.ROM_CURVE.CURVE_B_I == 0) {
                         b.rcopy(ctx.ROM_CURVE.CURVE_B);
@@ -690,7 +713,7 @@ var ECP = function(ctx) {
                     t4.norm(); //5
                     t3.mul(t4); //6
                     t4.copy(t0);
-                    t4.add(t1); //7
+                    t4.add(t1);  //7
                     t3.sub(t4);
                     t3.norm(); //8
                     t4.copy(this.y);
@@ -728,9 +751,9 @@ var ECP = function(ctx) {
                     x3.sub(z3);
                     x3.norm(); //20
                     z3.copy(x3);
-                    z3.add(x3); //21
+                    z3.add(x3);  //21
 
-                    x3.add(z3); //22
+                    x3.add(z3);  //22
                     z3.copy(t1);
                     z3.sub(x3);
                     z3.norm(); //23
@@ -747,7 +770,7 @@ var ECP = function(ctx) {
                     t1.add(t2); //26
                     t2.add(t1); //27
 
-                    y3.sub(t2); //28
+                    y3.sub(t2);  //28
 
                     y3.sub(t0);
                     y3.norm(); //29
@@ -773,7 +796,8 @@ var ECP = function(ctx) {
                     z3.mul(t4); //41
                     t1.copy(t3);
                     t1.mul(t0); //42
-                    z3.add(t1);
+                    z3.add(t1); 
+           
                     this.x.copy(x3);
                     this.x.norm();
                     this.y.copy(y3);
@@ -785,15 +809,15 @@ var ECP = function(ctx) {
 
             if (ECP.CURVETYPE == ECP.EDWARDS) {
                 A = new ctx.FP(0);
-                A.copy(this.z);
-                B = new ctx.FP(0);
+                A.copy(this.z); 
+                B = new ctx.FP(0); 
                 C = new ctx.FP(0);
-                C.copy(this.x);
+                C.copy(this.x); 
                 D = new ctx.FP(0);
-                D.copy(this.y);
-                E = new ctx.FP(0);
-                F = new ctx.FP(0);
-                G = new ctx.FP(0);
+                D.copy(this.y); 
+                E = new ctx.FP(0); 
+                F = new ctx.FP(0); 
+                G = new ctx.FP(0); 
 
                 A.mul(Q.z); //A=2
                 B.copy(A);
@@ -900,13 +924,15 @@ var ECP = function(ctx) {
             this.x.copy(A);
             this.z.copy(W.x);
             this.z.mul(B);
+
+            //  this.x.norm();
         },
 
         /* this-=Q */
         sub: function(Q) {
-            Q.neg();
-            this.add(Q);
-            Q.neg();
+			var NQ = new ECP(); NQ.copy(Q);
+            NQ.neg();
+            this.add(NQ);
         },
 
         /* constant time multiply by small integer of length bts - use ladder */
@@ -947,12 +973,10 @@ var ECP = function(ctx) {
             }
             if (cf==4) {
                 this.dbl(); this.dbl();
-                this.affine();
                 return;
             }
             if (cf==8) {
                 this.dbl(); this.dbl(); this.dbl();
-                this.affine();
                 return;
             }
             c.rcopy(ctx.ROM_CURVE.CURVE_Cof);
@@ -1001,8 +1025,6 @@ var ECP = function(ctx) {
                 W = [];
                 w = [];
 
-                this.affine();
-
                 // precompute table
                 Q.copy(this);
                 Q.dbl();
@@ -1070,9 +1092,6 @@ var ECP = function(ctx) {
                 i, s, ns, nb,
                 a, b;
 
-            this.affine();
-            Q.affine();
-
             te.copy(e);
             tf.copy(f);
 
@@ -1205,6 +1224,11 @@ var ECP = function(ctx) {
             return P;
         }
 
+        if (ECP.CURVETYPE == ECP.MONTGOMERY) {
+            P.setx(px);
+            return P;
+        }
+
         if (b[0] == 0x04) {
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 t[i] = b[i + ctx.BIG.MODBYTES + 1];
@@ -1219,10 +1243,14 @@ var ECP = function(ctx) {
             P.setxy(px, py);
 
             return P;
-        } else {
-            P.setx(px);
+        }
+
+        if (b[0]==0x02 || b[0]==0x03) {
+            P.setxi(px,b[0]&1);
             return P;
         }
+
+        return P;
     };
 
     /* Calculate RHS of curve equation */
@@ -1230,7 +1258,7 @@ var ECP = function(ctx) {
         var r = new ctx.FP(0),
             b, cx, one, x3;
 
-        x.norm();
+        //x.norm();
         r.copy(x);
         r.sqr();
 
diff --git a/src/ecp2.js b/src/ecp2.js
index 77ef534..b8ce9af 100644
--- a/src/ecp2.js
+++ b/src/ecp2.js
@@ -32,6 +32,7 @@ var ECP2 = function(ctx) {
     ECP2.prototype = {
         /* Test this=O? */
         is_infinity: function() {
+
             this.x.reduce();
             this.y.reduce();
             this.z.reduce();
@@ -149,14 +150,14 @@ var ECP2 = function(ctx) {
 
         /* extract affine x as ctx.FP2 */
         getX: function() {
-            this.affine();
-            return this.x;
+			var W=new ECP2(); W.copy(this); W.affine();
+            return W.x;
         },
 
         /* extract affine y as ctx.FP2 */
         getY: function() {
-            this.affine();
-            return this.y;
+			var W=new ECP2(); W.copy(this); W.affine();
+            return W.y;
         },
 
         /* extract projective x */
@@ -178,22 +179,22 @@ var ECP2 = function(ctx) {
         toBytes: function(b) {
             var t = [],
                 i;
-
-            this.affine();
-            this.x.getA().toBytes(t);
+			var W=new ECP2(); W.copy(this);
+            W.affine();
+            W.x.getA().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i] = t[i];
             }
-            this.x.getB().toBytes(t);
+            W.x.getB().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + ctx.BIG.MODBYTES] = t[i];
             }
 
-            this.y.getA().toBytes(t);
+            W.y.getA().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 2 * ctx.BIG.MODBYTES] = t[i];
             }
-            this.y.getB().toBytes(t);
+            W.y.getB().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 3 * ctx.BIG.MODBYTES] = t[i];
             }
@@ -201,11 +202,12 @@ var ECP2 = function(ctx) {
 
         /* convert this to hex string */
         toString: function() {
-            if (this.is_infinity()) {
+			var W=new ECP2(); W.copy(this);
+            if (W.is_infinity()) {
                 return "infinity";
             }
-            this.affine();
-            return "(" + this.x.toString() + "," + this.y.toString() + ")";
+            W.affine();
+            return "(" + W.x.toString() + "," + W.y.toString() + ")";
         },
 
         /* set this=(x,y) */
@@ -215,10 +217,11 @@ var ECP2 = function(ctx) {
             this.x.copy(ix);
             this.y.copy(iy);
             this.z.one();
+			this.x.norm();
 
             rhs = ECP2.RHS(this.x);
 
-            y2 = new ctx.FP2(this.y);
+            y2 = new ctx.FP2(this.y); 
             y2.sqr();
 
             if (!y2.equals(rhs)) {
@@ -232,6 +235,7 @@ var ECP2 = function(ctx) {
 
             this.x.copy(ix);
             this.z.one();
+			this.x.norm();
 
             rhs = ECP2.RHS(this.x);
 
@@ -246,7 +250,7 @@ var ECP2 = function(ctx) {
         frob: function(X) {
             var X2;
 
-            X2 = new ctx.FP2(X);
+            X2 = new ctx.FP2(X); //X2.copy(X);
             X2.sqr();
             this.x.conj();
             this.y.conj();
@@ -262,20 +266,20 @@ var ECP2 = function(ctx) {
             var iy, t0, t1, t2, x3, y3;
 
             iy = new ctx.FP2(0);
-            iy.copy(this.y);
+            iy.copy(this.y); 
             if (ctx.ECP.SEXTIC_TWIST == ctx.ECP.D_TYPE) {
                 iy.mul_ip();
                 iy.norm();
             }
 
             t0 = new ctx.FP2(0);
-            t0.copy(this.y);
+            t0.copy(this.y); 
             t0.sqr();
             if (ctx.ECP.SEXTIC_TWIST == ctx.ECP.D_TYPE) {
                 t0.mul_ip();
             }
             t1 = new ctx.FP2(0);
-            t1.copy(iy);
+            t1.copy(iy); 
             t1.mul(this.z);
             t2 = new ctx.FP2(0);
             t2.copy(this.z);
@@ -295,11 +299,11 @@ var ECP2 = function(ctx) {
             }
 
             x3 = new ctx.FP2(0);
-            x3.copy(t2);
+            x3.copy(t2); 
             x3.mul(this.z);
 
             y3 = new ctx.FP2(0);
-            y3.copy(t0);
+            y3.copy(t0); 
 
             y3.add(t2);
             y3.norm();
@@ -313,7 +317,7 @@ var ECP2 = function(ctx) {
             y3.mul(t0);
             y3.add(x3); //(y^2+3z*2)(y^2-9z^2)+3b.z^2.8y^2
             t1.copy(this.x);
-            t1.mul(iy);
+            t1.mul(iy); //
             this.x.copy(t0);
             this.x.norm();
             this.x.mul(t1);
@@ -333,21 +337,21 @@ var ECP2 = function(ctx) {
 
             b = 3 * ctx.ROM_CURVE.CURVE_B_I;
             t0 = new ctx.FP2(0);
-            t0.copy(this.x);
+            t0.copy(this.x); 
             t0.mul(Q.x); // x.Q.x
             t1 = new ctx.FP2(0);
-            t1.copy(this.y);
+            t1.copy(this.y); 
             t1.mul(Q.y); // y.Q.y
 
             t2 = new ctx.FP2(0);
-            t2.copy(this.z);
+            t2.copy(this.z); 
             t2.mul(Q.z);
             t3 = new ctx.FP2(0);
-            t3.copy(this.x);
+            t3.copy(this.x); 
             t3.add(this.y);
             t3.norm(); //t3=X1+Y1
             t4 = new ctx.FP2(0);
-            t4.copy(Q.x);
+            t4.copy(Q.x); 
             t4.add(Q.y);
             t4.norm(); //t4=X2+Y2
             t3.mul(t4); //t3=(X1+Y1)(X2+Y2)
@@ -365,7 +369,7 @@ var ECP2 = function(ctx) {
             t4.add(this.z);
             t4.norm(); //t4=Y1+Z1
             x3 = new ctx.FP2(0);
-            x3.copy(Q.y);
+            x3.copy(Q.y); 
             x3.add(Q.z);
             x3.norm(); //x3=Y2+Z2
 
@@ -384,7 +388,7 @@ var ECP2 = function(ctx) {
             x3.add(this.z);
             x3.norm(); // x3=X1+Z1
             y3 = new ctx.FP2(0);
-            y3.copy(Q.x);
+            y3.copy(Q.x); 
             y3.add(Q.z);
             y3.norm(); // y3=X2+Z2
             x3.mul(y3); // x3=(X1+Z1)(X2+Z2)
@@ -406,11 +410,11 @@ var ECP2 = function(ctx) {
             t0.norm();
             t2.imul(b);
             if (ctx.ECP.SEXTIC_TWIST == ctx.ECP.M_TYPE) {
-                t2.mul_ip();
+                t2.mul_ip(); t2.norm();
             }
 
             z3 = new ctx.FP2(0);
-            z3.copy(t1);
+            z3.copy(t1); 
             z3.add(t2);
             z3.norm();
             t1.sub(t2);
@@ -446,11 +450,9 @@ var ECP2 = function(ctx) {
         /* this-=Q */
         sub: function(Q) {
             var D;
-
-            Q.neg();
-            D = this.add(Q);
-            Q.neg();
-
+			var NQ=new ECP2(); NQ.copy(Q);
+            NQ.neg();
+            D = this.add(NQ);
             return D;
         },
 
@@ -470,8 +472,6 @@ var ECP2 = function(ctx) {
                 return new ECP2();
             }
 
-            this.affine();
-
             // precompute table
             Q.copy(this);
             Q.dbl();
@@ -557,7 +557,7 @@ var ECP2 = function(ctx) {
         }
         rb = ctx.BIG.fromBytes(t);
 
-        rx = new ctx.FP2(ra, rb);
+        rx = new ctx.FP2(ra, rb); //rx.bset(ra,rb);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = b[i + 2 * ctx.BIG.MODBYTES];
@@ -568,7 +568,7 @@ var ECP2 = function(ctx) {
         }
         rb = ctx.BIG.fromBytes(t);
 
-        ry = new ctx.FP2(ra, rb);
+        ry = new ctx.FP2(ra, rb); //ry.bset(ra,rb);
 
         P = new ECP2();
         P.setxy(rx, ry);
@@ -580,13 +580,13 @@ var ECP2 = function(ctx) {
     ECP2.RHS = function(x) {
         var r, c, b;
 
-        x.norm();
-        r = new ctx.FP2(x);
+        //x.norm();
+        r = new ctx.FP2(x); //r.copy(x);
         r.sqr();
 
         c = new ctx.BIG(0);
         c.rcopy(ctx.ROM_CURVE.CURVE_B);
-        b = new ctx.FP2(c);
+        b = new ctx.FP2(c); //b.bseta(c);
 
         if (ctx.ECP.SEXTIC_TWIST == ctx.ECP.D_TYPE) {
             b.div_ip();
@@ -621,7 +621,7 @@ var ECP2 = function(ctx) {
 
         for (i = 0; i < 4; i++) {
             t[i] = new ctx.BIG(u[i]); t[i].norm();
-            Q[i].affine();
+            //Q[i].affine();
         }
 
         T[0] = new ECP2(); T[0].copy(Q[0]); // Q[0]
@@ -683,6 +683,7 @@ var ECP2 = function(ctx) {
         return P;
     };
 
+
     /* return 1 if b==c, no branching */
     ECP2.teq = function(b, c) {
         var x = b ^ c;
@@ -734,7 +735,7 @@ var ECP2 = function(ctx) {
             K = new ECP2();
             K.copy(T);
             K.dbl();
-            K.add(T);
+            K.add(T); //K.affine();
 
             K.frob(X);
             Q.frob(X);
@@ -748,6 +749,7 @@ var ECP2 = function(ctx) {
         }
 
         if (ctx.ECP.CURVE_PAIRING_TYPE == ctx.ECP.BLS) {
+
             xQ = Q.mul(x);
             x2Q = xQ.mul(x);
 
diff --git a/src/ecp4.js b/src/ecp4.js
index 1292aea..82fbce3 100644
--- a/src/ecp4.js
+++ b/src/ecp4.js
@@ -57,6 +57,7 @@ var ECP4 = function(ctx) {
             this.x.cmove(Q.x, d);
             this.y.cmove(Q.y, d);
             this.z.cmove(Q.z, d);
+
         },
 
         /* Constant time select from pre-computed table */
@@ -140,14 +141,14 @@ var ECP4 = function(ctx) {
 
         /* extract affine x as ctx.FP4 */
         getX: function() {
-            this.affine();
-            return this.x;
+			var W=new ECP4(); W.copy(this); W.affine();
+            return W.x;
         },
 
         /* extract affine y as ctx.FP4 */
         getY: function() {
-            this.affine();
-            return this.y;
+			var W=new ECP4(); W.copy(this); W.affine();
+            return W.y;
         },
 
         /* extract projective x */
@@ -169,39 +170,39 @@ var ECP4 = function(ctx) {
         toBytes: function(b) {
             var t = [],
                 i;
-
-            this.affine();
-            this.x.geta().getA().toBytes(t);
+			var W=new ECP4(); W.copy(this);
+            W.affine();
+            W.x.geta().getA().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i] = t[i];
             }
-            this.x.geta().getB().toBytes(t);
+            W.x.geta().getB().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + ctx.BIG.MODBYTES] = t[i];
             }
-            this.x.getb().getA().toBytes(t);
+            W.x.getb().getA().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 2*ctx.BIG.MODBYTES] = t[i];
             }
-            this.x.getb().getB().toBytes(t);
+            W.x.getb().getB().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 3*ctx.BIG.MODBYTES] = t[i];
             }
 
 
-            this.y.geta().getA().toBytes(t);
+            W.y.geta().getA().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 4 * ctx.BIG.MODBYTES] = t[i];
             }
-            this.y.geta().getB().toBytes(t);
+            W.y.geta().getB().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 5 * ctx.BIG.MODBYTES] = t[i];
             }
-            this.y.getb().getA().toBytes(t);
+            W.y.getb().getA().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 6 * ctx.BIG.MODBYTES] = t[i];
             }
-            this.y.getb().getB().toBytes(t);
+            W.y.getb().getB().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 7 * ctx.BIG.MODBYTES] = t[i];
             }
@@ -209,11 +210,12 @@ var ECP4 = function(ctx) {
 
         /* convert this to hex string */
         toString: function() {
-            if (this.is_infinity()) {
+			var W=new ECP4(); W.copy(this);
+            if (W.is_infinity()) {
                 return "infinity";
             }
-            this.affine();
-            return "(" + this.x.toString() + "," + this.y.toString() + ")";
+            W.affine();
+            return "(" + W.x.toString() + "," + W.y.toString() + ")";
         },
 
         /* set this=(x,y) */
@@ -223,15 +225,17 @@ var ECP4 = function(ctx) {
             this.x.copy(ix);
             this.y.copy(iy);
             this.z.one();
+			this.x.norm();
 
             rhs = ECP4.RHS(this.x);
 
-            y2 = new ctx.FP4(this.y);
+            y2 = new ctx.FP4(this.y); //y2.copy(this.y);
             y2.sqr();
 
             if (!y2.equals(rhs)) {
                 this.inf();
             }
+
         },
 
         /* set this=(x,.) */
@@ -240,7 +244,7 @@ var ECP4 = function(ctx) {
 
             this.x.copy(ix);
             this.z.one();
-
+			this.x.norm();
             rhs = ECP4.RHS(this.x);
 
             if (rhs.sqrt()) {
@@ -313,7 +317,7 @@ var ECP4 = function(ctx) {
             y3.mul(t0);
             y3.add(x3); //(y^2+3z*2)(y^2-9z^2)+3b.z^2.8y^2
             t1.copy(this.x);
-            t1.mul(iy);
+            t1.mul(iy); //
             this.x.copy(t0);
             this.x.norm();
             this.x.mul(t1);
@@ -362,7 +366,7 @@ var ECP4 = function(ctx) {
             x3.norm(); //x3=Y2+Z2
 
             t4.mul(x3); //t4=(Y1+Z1)(Y2+Z2)
-            x3.copy(t1);
+            x3.copy(t1); //
             x3.add(t2); //X3=Y1.Y2+Z1.Z2
 
             t4.sub(x3);
@@ -432,11 +436,9 @@ var ECP4 = function(ctx) {
         /* this-=Q */
         sub: function(Q) {
             var D;
-
-            Q.neg();
-            D = this.add(Q);
-            Q.neg();
-
+			var NQ=new ECP4(); NQ.copy(Q);
+            NQ.neg();
+            D = this.add(NQ);
             return D;
         },
 
@@ -456,8 +458,6 @@ var ECP4 = function(ctx) {
                 return new ECP4();
             }
 
-            this.affine();
-
             // precompute table
             Q.copy(this);
             Q.dbl();
@@ -567,7 +567,7 @@ var ECP4 = function(ctx) {
         rb = ctx.BIG.fromBytes(t);
         rb4=new ctx.FP2(ra,rb);
 
-        rx = new ctx.FP4(ra4, rb4);
+        rx = new ctx.FP4(ra4, rb4); //rx.bset(ra,rb);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = b[i + 4 * ctx.BIG.MODBYTES];
@@ -590,7 +590,7 @@ var ECP4 = function(ctx) {
         rb4=new ctx.FP2(ra,rb);
 
 
-        ry = new ctx.FP4(ra4, rb4);
+        ry = new ctx.FP4(ra4, rb4); //ry.bset(ra,rb);
 
         P = new ECP4();
         P.setxy(rx, ry);
@@ -602,13 +602,13 @@ var ECP4 = function(ctx) {
     ECP4.RHS = function(x) {
         var r, c, b;
 
-        x.norm();
-        r = new ctx.FP4(x);
+        //x.norm();
+        r = new ctx.FP4(x); //r.copy(x);
         r.sqr();
 
         c = new ctx.BIG(0);
         c.rcopy(ctx.ROM_CURVE.CURVE_B);
-        b = new ctx.FP4(c);
+        b = new ctx.FP4(c); //b.bseta(c);
 
         if (ctx.ECP.SEXTIC_TWIST == ctx.ECP.D_TYPE) {
             b.div_i();
@@ -644,17 +644,17 @@ var ECP4 = function(ctx) {
 
         for (i = 0; i < 8; i++) {
             t[i] = new ctx.BIG(u[i]); t[i].norm();
-            Q[i].affine();
+            //Q[i].affine();
         }
 
-        T1[0] = new ECP4(); T1[0].copy(Q[0]);
-        T1[1] = new ECP4(); T1[1].copy(T1[0]); T1[1].add(Q[1]);
-        T1[2] = new ECP4(); T1[2].copy(T1[0]); T1[2].add(Q[2]);
-        T1[3] = new ECP4(); T1[3].copy(T1[1]); T1[3].add(Q[2]);
-        T1[4] = new ECP4(); T1[4].copy(T1[0]); T1[4].add(Q[3]);
-        T1[5] = new ECP4(); T1[5].copy(T1[1]); T1[5].add(Q[3]);
-        T1[6] = new ECP4(); T1[6].copy(T1[2]); T1[6].add(Q[3]);
-        T1[7] = new ECP4(); T1[7].copy(T1[3]); T1[7].add(Q[3]);
+        T1[0] = new ECP4(); T1[0].copy(Q[0]); // Q[0]
+        T1[1] = new ECP4(); T1[1].copy(T1[0]); T1[1].add(Q[1]); // Q[0]+Q[1]
+        T1[2] = new ECP4(); T1[2].copy(T1[0]); T1[2].add(Q[2]); // Q[0]+Q[2]
+        T1[3] = new ECP4(); T1[3].copy(T1[1]); T1[3].add(Q[2]); // Q[0]+Q[1]+Q[2]
+        T1[4] = new ECP4(); T1[4].copy(T1[0]); T1[4].add(Q[3]); // Q[0]+Q[3]
+        T1[5] = new ECP4(); T1[5].copy(T1[1]); T1[5].add(Q[3]); // Q[0]+Q[1]+Q[3]
+        T1[6] = new ECP4(); T1[6].copy(T1[2]); T1[6].add(Q[3]); // Q[0]+Q[2]+Q[3]
+        T1[7] = new ECP4(); T1[7].copy(T1[3]); T1[7].add(Q[3]); // Q[0]+Q[1]+Q[2]+Q[3]
 
         //  Use Frobenius
         for (i=0;i<8;i++) {
diff --git a/src/ecp8.js b/src/ecp8.js
index 9ba464c..593f739 100644
--- a/src/ecp8.js
+++ b/src/ecp8.js
@@ -27,12 +27,12 @@ var ECP8 = function(ctx) {
         this.x = new ctx.FP8(0);
         this.y = new ctx.FP8(1);
         this.z = new ctx.FP8(0);
-        // this.INF = true;
     };
 
     ECP8.prototype = {
         /* Test this=O? */
         is_infinity: function() {
+
             this.x.reduce();
             this.y.reduce();
             this.z.reduce();
@@ -140,14 +140,14 @@ var ECP8 = function(ctx) {
 
         /* extract affine x as ctx.FP8 */
         getX: function() {
-            this.affine();
-            return this.x;
+			var W=new ECP8(); W.copy(this); W.affine();
+            return W.x;
         },
 
         /* extract affine y as ctx.FP8 */
         getY: function() {
-            this.affine();
-            return this.y;
+			var W=new ECP8(); W.copy(this); W.affine();
+            return W.y;
         },
 
         /* extract projective x */
@@ -169,72 +169,72 @@ var ECP8 = function(ctx) {
         toBytes: function(b) {
             var t = [],
                 i;
-
-            this.affine();
-            this.x.geta().geta().getA().toBytes(t);
+			var W=new ECP8(); W.copy(this);
+            W.affine();
+            W.x.geta().geta().getA().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i] = t[i];
             }
-            this.x.geta().geta().getB().toBytes(t);
+            W.x.geta().geta().getB().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + ctx.BIG.MODBYTES] = t[i];
             }
-            this.x.geta().getb().getA().toBytes(t);
+            W.x.geta().getb().getA().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 2*ctx.BIG.MODBYTES] = t[i];
             }
-            this.x.geta().getb().getB().toBytes(t);
+            W.x.geta().getb().getB().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 3*ctx.BIG.MODBYTES] = t[i];
             }
 
-            this.x.getb().geta().getA().toBytes(t);
+            W.x.getb().geta().getA().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 4*ctx.BIG.MODBYTES] = t[i];
             }
-            this.x.getb().geta().getB().toBytes(t);
+            W.x.getb().geta().getB().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 5*ctx.BIG.MODBYTES] = t[i];
             }
-            this.x.getb().getb().getA().toBytes(t);
+            W.x.getb().getb().getA().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 6*ctx.BIG.MODBYTES] = t[i];
             }
-            this.x.getb().getb().getB().toBytes(t);
+            W.x.getb().getb().getB().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 7*ctx.BIG.MODBYTES] = t[i];
             }
 
-            this.y.geta().geta().getA().toBytes(t);
+            W.y.geta().geta().getA().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 8 * ctx.BIG.MODBYTES] = t[i];
             }
-            this.y.geta().geta().getB().toBytes(t);
+            W.y.geta().geta().getB().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 9 * ctx.BIG.MODBYTES] = t[i];
             }
-            this.y.geta().getb().getA().toBytes(t);
+            W.y.geta().getb().getA().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 10 * ctx.BIG.MODBYTES] = t[i];
             }
-            this.y.geta().getb().getB().toBytes(t);
+            W.y.geta().getb().getB().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 11 * ctx.BIG.MODBYTES] = t[i];
             }
 
-            this.y.getb().geta().getA().toBytes(t);
+            W.y.getb().geta().getA().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 12 * ctx.BIG.MODBYTES] = t[i];
             }
-            this.y.getb().geta().getB().toBytes(t);
+            W.y.getb().geta().getB().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 13 * ctx.BIG.MODBYTES] = t[i];
             }
-            this.y.getb().getb().getA().toBytes(t);
+            W.y.getb().getb().getA().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 14 * ctx.BIG.MODBYTES] = t[i];
             }
-            this.y.getb().getb().getB().toBytes(t);
+            W.y.getb().getb().getB().toBytes(t);
             for (i = 0; i < ctx.BIG.MODBYTES; i++) {
                 b[i + 15 * ctx.BIG.MODBYTES] = t[i];
             }
@@ -242,11 +242,12 @@ var ECP8 = function(ctx) {
 
         /* convert this to hex string */
         toString: function() {
-            if (this.is_infinity()) {
+			var W=new ECP8(); W.copy(this);
+            if (W.is_infinity()) {
                 return "infinity";
             }
-            this.affine();
-            return "(" + this.x.toString() + "," + this.y.toString() + ")";
+            W.affine();
+            return "(" + W.x.toString() + "," + W.y.toString() + ")";
         },
 
         /* set this=(x,y) */
@@ -256,10 +257,11 @@ var ECP8 = function(ctx) {
             this.x.copy(ix);
             this.y.copy(iy);
             this.z.one();
+			this.x.norm();
 
             rhs = ECP8.RHS(this.x);
 
-            y2 = new ctx.FP8(this.y);
+            y2 = new ctx.FP8(this.y); //y2.copy(this.y);
             y2.sqr();
 
             if (!y2.equals(rhs)) {
@@ -273,7 +275,7 @@ var ECP8 = function(ctx) {
 
             this.x.copy(ix);
             this.z.one();
-
+			this.x.norm();
             rhs = ECP8.RHS(this.x);
 
             if (rhs.sqrt()) {
@@ -357,7 +359,7 @@ var ECP8 = function(ctx) {
             y3.mul(t0);
             y3.add(x3); //(y^2+3z*2)(y^2-9z^2)+3b.z^2.8y^2
             t1.copy(this.x);
-            t1.mul(iy);
+            t1.mul(iy); //
             this.x.copy(t0);
             this.x.norm();
             this.x.mul(t1);
@@ -406,7 +408,7 @@ var ECP8 = function(ctx) {
             x3.norm(); //x3=Y2+Z2
 
             t4.mul(x3); //t4=(Y1+Z1)(Y2+Z2)
-            x3.copy(t1);
+            x3.copy(t1); //
             x3.add(t2); //X3=Y1.Y2+Z1.Z2
 
             t4.sub(x3);
@@ -476,11 +478,9 @@ var ECP8 = function(ctx) {
         /* this-=Q */
         sub: function(Q) {
             var D;
-
-            Q.neg();
-            D = this.add(Q);
-            Q.neg();
-
+			var NQ=new ECP8(); NQ.copy(Q);
+            NQ.neg();
+            D = this.add(NQ);
             return D;
         },
 
@@ -500,8 +500,6 @@ var ECP8 = function(ctx) {
                 return new ECP8();
             }
 
-            this.affine();
-
             // precompute table
             Q.copy(this);
             Q.dbl();
@@ -661,7 +659,7 @@ var ECP8 = function(ctx) {
 
         rb8=new ctx.FP4(ra4,rb4);
 
-        rx = new ctx.FP8(ra8, rb8);
+        rx = new ctx.FP8(ra8, rb8); //rx.bset(ra,rb);
 
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
@@ -708,7 +706,7 @@ var ECP8 = function(ctx) {
 
         rb8=new ctx.FP4(ra4,rb4);
 
-        ry = new ctx.FP8(ra8, rb8);
+        ry = new ctx.FP8(ra8, rb8); //ry.bset(ra,rb);
 
         P = new ECP8();
         P.setxy(rx, ry);
@@ -720,7 +718,7 @@ var ECP8 = function(ctx) {
     ECP8.RHS = function(x) {
         var r, c, b;
 
-        x.norm();
+        //x.norm();
         r = new ctx.FP8(x); //r.copy(x);
         r.sqr();
 
@@ -768,17 +766,17 @@ var ECP8 = function(ctx) {
 
         for (i = 0; i < 16; i++) {
             t[i] = new ctx.BIG(u[i]); t[i].norm();
-            Q[i].affine();
+            //Q[i].affine();
         }
 
-        T1[0] = new ECP8(); T1[0].copy(Q[0]);
-        T1[1] = new ECP8(); T1[1].copy(T1[0]); T1[1].add(Q[1]);
-        T1[2] = new ECP8(); T1[2].copy(T1[0]); T1[2].add(Q[2]);
-        T1[3] = new ECP8(); T1[3].copy(T1[1]); T1[3].add(Q[2]);
-        T1[4] = new ECP8(); T1[4].copy(T1[0]); T1[4].add(Q[3]);
-        T1[5] = new ECP8(); T1[5].copy(T1[1]); T1[5].add(Q[3]);
-        T1[6] = new ECP8(); T1[6].copy(T1[2]); T1[6].add(Q[3]);
-        T1[7] = new ECP8(); T1[7].copy(T1[3]); T1[7].add(Q[3]);
+        T1[0] = new ECP8(); T1[0].copy(Q[0]); // Q[0]
+        T1[1] = new ECP8(); T1[1].copy(T1[0]); T1[1].add(Q[1]); // Q[0]+Q[1]
+        T1[2] = new ECP8(); T1[2].copy(T1[0]); T1[2].add(Q[2]); // Q[0]+Q[2]
+        T1[3] = new ECP8(); T1[3].copy(T1[1]); T1[3].add(Q[2]); // Q[0]+Q[1]+Q[2]
+        T1[4] = new ECP8(); T1[4].copy(T1[0]); T1[4].add(Q[3]); // Q[0]+Q[3]
+        T1[5] = new ECP8(); T1[5].copy(T1[1]); T1[5].add(Q[3]); // Q[0]+Q[1]+Q[3]
+        T1[6] = new ECP8(); T1[6].copy(T1[2]); T1[6].add(Q[3]); // Q[0]+Q[2]+Q[3]
+        T1[7] = new ECP8(); T1[7].copy(T1[3]); T1[7].add(Q[3]); // Q[0]+Q[1]+Q[2]+Q[3]
 
         //  Use Frobenius
         for (i=0;i<8;i++) {
diff --git a/src/ff.js b/src/ff.js
index b62592e..8bcd3c4 100644
--- a/src/ff.js
+++ b/src/ff.js
@@ -37,8 +37,7 @@ var FF = function(ctx) {
     FF.P_FEXCESS = (1 << (ctx.BIG.BASEBITS * ctx.BIG.NLEN - FF.P_MBITS - 1));
     FF.P_TBITS = (FF.P_MBITS % ctx.BIG.BASEBITS);
     FF.FF_BITS = (ctx.BIG.BIGBITS * FF.FFLEN);
-    /* Useful for half-size RSA private key operations */
-    FF.HFLEN = (FF.FFLEN / 2);
+    FF.HFLEN = (FF.FFLEN / 2); /* Useful for half-size RSA private key operations */
 
     FF.prototype = {
         /* set to zero */
@@ -205,8 +204,7 @@ var FF = function(ctx) {
             var trunc = false,
                 i, carry;
 
-            /* -v n signals to do truncation */
-            if (n < 0) {
+            if (n < 0) { /* -v n signals to do truncation */
                 n = -n;
                 trunc = true;
             }
@@ -328,12 +326,10 @@ var FF = function(ctx) {
             this.rnorm(vp + nd2, n);
         },
 
-        /* Calculates Least Significant bottom half of x*y */
-        karmul_lower: function(vp, x, xp, y, yp, t, tp, n) {
+        karmul_lower: function(vp, x, xp, y, yp, t, tp, n) { /* Calculates Least Significant bottom half of x*y */
             var nd2;
 
-            /* only calculate bottom half of product */
-            if (n === 1) {
+            if (n === 1) { /* only calculate bottom half of product */
                 this.v[vp].copy(ctx.BIG.smul(x.v[xp], y.v[yp]));
 
                 return;
@@ -350,8 +346,7 @@ var FF = function(ctx) {
             this.rnorm(vp + nd2, -nd2); /* truncate it */
         },
 
-        /* Calculates Most Significant upper half of x*y, given lower part */
-        karmul_upper: function(x, y, t, n) {
+        karmul_upper: function(x, y, t, n) { /* Calculates Most Significant upper half of x*y, given lower part */
             var nd2;
 
             nd2 = n / 2;
@@ -409,9 +404,8 @@ var FF = function(ctx) {
             }
         },
 
-        /* /Fast Karatsuba Montgomery reduction
-         * return This mod modulus, N is modulus, ND is Montgomery Constant */
-        reduce: function(N, ND) {
+        /* return This mod modulus, N is modulus, ND is Montgomery Constant */
+        reduce: function(N, ND) { /* fast karatsuba Montgomery reduction */
             var n = N.length,
                 t = new FF(2 * n),
                 r = new FF(n),
@@ -1006,6 +1000,7 @@ var FF = function(ctx) {
     return FF;
 };
 
+
 if (typeof module !== "undefined" && typeof module.exports !== "undefined") {
     module.exports = {
         FF: FF
diff --git a/src/fp.js b/src/fp.js
index 05beedb..ebb0d74 100644
--- a/src/fp.js
+++ b/src/fp.js
@@ -30,7 +30,9 @@ var FP = function(ctx) {
             this.XES = x.XES;
         } else {
             this.f = new ctx.BIG(x);
-            this.nres();
+			this.XES = 1;
+			if (!this.f.iszilch())
+				this.nres();
         }
     };
 
@@ -39,11 +41,17 @@ var FP = function(ctx) {
     FP.GENERALISED_MERSENNE = 2;
     FP.MONTGOMERY_FRIENDLY = 3;
 
+	FP.ZERO = 0;
+	FP.ONE = 1;
+	FP.SPARSER = 2;
+	FP.SPARSE = 3;
+	FP.DENSE= 4;
+
     FP.MODBITS = ctx.config["@NBT"];
     FP.MOD8 = ctx.config["@M8"];
     FP.MODTYPE = ctx.config["@MT"];
 
-    FP.FEXCESS = (1 << ctx.config["@SH"]); // 2^(BASEBITS*NLEN-MODBITS)
+    FP.FEXCESS = ((1 << ctx.config["@SH"])-1); // 2^(BASEBITS*NLEN-MODBITS)-1
     FP.OMASK = (-1) << FP.TBITS;
     FP.TBITS = FP.MODBITS % ctx.BIG.BASEBITS;
     FP.TMASK = (1 << FP.TBITS) - 1;
@@ -136,22 +144,48 @@ var FP = function(ctx) {
 
         /* test this=0 */
         iszilch: function() {
-            this.reduce();
-            return this.f.iszilch();
+			var c=new FP(0); c.copy(this);
+            c.reduce();
+            return c.f.iszilch();
         },
 
         /* reduce this mod Modulus */
         reduce: function() {
-            var p = new ctx.BIG(0);
-            p.rcopy(ctx.ROM_FIELD.Modulus);
-            this.f.mod(p);
+            var q,carry,sr,sb,m = new ctx.BIG(0);
+            m.rcopy(ctx.ROM_FIELD.Modulus);
+			var r = new ctx.BIG(0);
+            r.rcopy(ctx.ROM_FIELD.Modulus);
+			this.f.norm();
+
+			if (this.XES>16)
+			{
+				q=FP.quo(this.f,m);
+				carry=r.pmul(q);
+				r.w[ctx.BIG.NLEN-1]+=(carry<<ctx.BIG.BASEBITS); // correction - put any carry out back in again
+				this.f.sub(r);
+				this.f.norm();
+				sb=2;
+			}
+			else {
+					sb=FP.logb2(this.XES-1);
+			}
+			m.fshl(sb);
+
+			while (sb>0)
+			{
+// constant time...
+				sr=ctx.BIG.ssn(r,this.f,m);  // optimized combined shift, subtract and norm
+				this.f.cmove(r,1-sr);
+				sb--;
+			}			
+
             this.XES = 1;
         },
 
         /* set this=1 */
         one: function() {
             this.f.one();
-            return this.nres();
+            this.nres();
         },
 
         /* normalise this */
@@ -242,7 +276,7 @@ var FP = function(ctx) {
             sb = FP.logb2(this.XES - 1);
 
             m.fshl(sb);
-            this.XES = (1 << sb);
+            this.XES = (1 << sb)+1;
             this.f.rsub(m);
 
             if (this.XES > FP.FEXCESS) {
@@ -290,23 +324,144 @@ var FP = function(ctx) {
             return this;
         },
 
+// return this^(p-3)/4 or this^(p-5)/8
+// See https://eprint.iacr.org/2018/1038
+		fpow: function() {
+			var i,j,k,bw,w,c,nw,lo,m,n;
+			var xp=[];
+			var ac=[1,2,3,6,12,15,30,60,120,240,255];
+// phase 1
+			
+			xp[0]=new FP(this);	// 1 
+			xp[1]=new FP(this); xp[1].sqr(); // 2
+			xp[2]=new FP(xp[1]); xp[2].mul(this);  //3
+			xp[3]=new FP(xp[2]); xp[3].sqr();  // 6 
+			xp[4]=new FP(xp[3]); xp[4].sqr();  // 12
+			xp[5]=new FP(xp[4]); xp[5].mul(xp[2]);  // 15
+			xp[6]=new FP(xp[5]); xp[6].sqr();  // 30
+			xp[7]=new FP(xp[6]); xp[7].sqr();  // 60
+			xp[8]=new FP(xp[7]); xp[8].sqr();  // 120
+			xp[9]=new FP(xp[8]); xp[9].sqr();  // 240
+			xp[10]=new FP(xp[9]); xp[10].mul(xp[5]);  // 255		
+			
+
+			n=FP.MODBITS;
+			if (FP.MODTYPE == FP.GENERALISED_MERSENNE)   // Goldilocks ONLY
+				n/=2;
+			if (FP.MOD8==5)
+			{
+				n-=3;
+				c=(ctx.ROM_FIELD.MConst+5)/8;
+			} else {
+				n-=2;
+				c=(ctx.ROM_FIELD.MConst+3)/4;
+			}
+
+			bw=0; w=1; while (w<c) {w*=2; bw+=1;}
+			k=w-c;
+
+			i=10; var key=new FP(0);
+			if (k!=0)
+			{
+				while (ac[i]>k) i--;
+				key.copy(xp[i]); 
+				k-=ac[i];
+			}
+			while (k!=0)
+			{
+				i--;
+				if (ac[i]>k) continue;
+				key.mul(xp[i]);
+				k-=ac[i]; 
+			}
+
+// phase 2 
+			xp[1].copy(xp[2]);
+			xp[2].copy(xp[5]);
+			xp[3].copy(xp[10]);
+	
+			j=3; m=8;
+			nw=n-bw;
+			var t=new FP(0);
+			while (2*m<nw)
+			{
+				t.copy(xp[j++]);
+				for (i=0;i<m;i++)
+					t.sqr(); 
+				xp[j].copy(xp[j-1]);
+				xp[j].mul(t);
+				m*=2;
+			}
+			lo=nw-m;
+			var r=new FP(xp[j]);
+
+			while (lo!=0)
+			{
+				m/=2; j--;
+				if (lo<m) continue;
+				lo-=m;
+				t.copy(r);
+				for (i=0;i<m;i++)
+					t.sqr();
+				r.copy(t);
+				r.mul(xp[j]);
+			}
+
+// phase 3
+			if (bw!=0)
+			{
+				for (i=0;i<bw;i++ )
+					r.sqr();
+				r.mul(key); 
+			}
+
+			if (FP.MODTYPE == FP.GENERALISED_MERSENNE)   // Goldilocks ONLY
+			{
+				key.copy(r);
+				r.sqr();
+				r.mul(this);
+				for (i=0;i<n+1;i++)
+					r.sqr();
+				r.mul(key);
+			}
+			return r;
+		},
+
         /* this=1/this mod Modulus */
         inverse: function() {
-            var m2=new ctx.BIG(0);
-
-            m2.rcopy(ctx.ROM_FIELD.Modulus);
-            m2.dec(2); m2.norm();
-            this.copy(this.pow(m2));
-            return this;
 
+			if (FP.MODTYPE == FP.PSEUDO_MERSENNE || FP.MODTYPE == FP.GENERALISED_MERSENNE)
+			{
+				var y=this.fpow();
+				if (FP.MOD8==5)
+				{
+					var t=new FP(this);
+					t.sqr();
+					this.mul(t);
+					y.sqr();
+
+				} 
+				y.sqr();
+				y.sqr();
+				this.mul(y);
+				return this;
+			} else {
+				var m2=new ctx.BIG(0);
+				m2.rcopy(ctx.ROM_FIELD.Modulus);
+				m2.dec(2); m2.norm();
+				this.copy(this.pow(m2));
+				return this;
+			}
         },
 
         /* return TRUE if this==a */
         equals: function(a) {
-            a.reduce();
-            this.reduce();
+			var ft=new FP(0); ft.copy(this);
+			var sd=new FP(0); sd.copy(a);
+            ft.reduce();
+            sd.reduce();
 
-            if (ctx.BIG.comp(a.f, this.f) === 0) {
+            if (ctx.BIG.comp(ft.f, sd.f) === 0) {
                 return true;
             }
 
@@ -319,7 +474,7 @@ var FP = function(ctx) {
                 tb=[],
                 t=new ctx.BIG(e),
                 nb, lsbs, r;
-
+			this.norm();
             t.norm();
             nb= 1 + Math.floor((t.nbits() + 3) / 4);
 
@@ -360,21 +515,23 @@ var FP = function(ctx) {
 
         /* return sqrt(this) mod Modulus */
         sqrt: function() {
-            var b = new ctx.BIG(0),
-                i, v, r;
+            var i, v, r;
 
             this.reduce();
-
-            b.rcopy(ctx.ROM_FIELD.Modulus);
-
             if (FP.MOD8 == 5) {
-                b.dec(5);
-                b.norm();
-                b.shr(3);
                 i = new FP(0);
                 i.copy(this);
                 i.f.shl(1);
-                v = i.pow(b);
+				if (FP.MODTYPE == FP.PSEUDO_MERSENNE || FP.MODTYPE == FP.GENERALISED_MERSENNE) {
+					v=i.fpow();
+				} else {
+					var b = new ctx.BIG(0);
+					b.rcopy(ctx.ROM_FIELD.Modulus);
+					b.dec(5);
+					b.norm();
+					b.shr(3);
+					v = i.pow(b);
+				}
                 i.mul(v);
                 i.mul(v);
                 i.f.dec(1);
@@ -386,11 +543,18 @@ var FP = function(ctx) {
 
                 return r;
             } else {
-                b.inc(1);
-                b.norm();
-                b.shr(2);
-
-                return this.pow(b);
+				if (FP.MODTYPE == FP.PSEUDO_MERSENNE || FP.MODTYPE == FP.GENERALISED_MERSENNE) {
+					var r=this.fpow();
+					r.mul(this);
+					return r;
+				} else {
+					var b = new ctx.BIG(0);
+					b.rcopy(ctx.ROM_FIELD.Modulus);
+					b.inc(1);
+					b.norm();
+					b.shr(2);
+					return this.pow(b);
+				}
             }
         }
 
@@ -412,6 +576,20 @@ var FP = function(ctx) {
         return r;
     };
 
+	FP.quo = function(n,m) {
+		var num,den,hb=ctx.BIG.CHUNK>>1;
+		if (FP.TBITS<hb)
+		{
+			var sh=hb-FP.TBITS;
+			num=(n.w[ctx.BIG.NLEN-1]<<sh)|(n.w[ctx.BIG.NLEN-2]>>(ctx.BIG.BASEBITS-sh));
+			den=(m.w[ctx.BIG.NLEN-1]<<sh)|(m.w[ctx.BIG.NLEN-2]>>(ctx.BIG.BASEBITS-sh));
+		} else {
+			num=n.w[ctx.BIG.NLEN-1];
+			den=m.w[ctx.BIG.NLEN-1];			
+		}
+		return Math.floor(num/(den+1))
+	};
+
     /* reduce a ctx.DBIG to a ctx.BIG using a "special" modulus */
     FP.mod = function(d) {
         var b = new ctx.BIG(0),
@@ -433,6 +611,7 @@ var FP = function(ctx) {
             tw = t.w[ctx.BIG.NLEN - 1];
             t.w[ctx.BIG.NLEN - 1] &= FP.TMASK;
             t.inc(ctx.ROM_FIELD.MConst * ((tw >> FP.TBITS) + (v << (ctx.BIG.BASEBITS - FP.TBITS))));
+            //      b.add(t);
             t.norm();
 
             return t;
@@ -450,8 +629,7 @@ var FP = function(ctx) {
             b.norm();
         }
 
-        // GoldiLocks Only
-        if (FP.MODTYPE == FP.GENERALISED_MERSENNE) {
+        if (FP.MODTYPE == FP.GENERALISED_MERSENNE) { // GoldiLocks Only
             t = d.split(FP.MODBITS);
             b.hcopy(d);
             b.add(t);
@@ -465,6 +643,7 @@ var FP = function(ctx) {
 
             b.add(tt);
             b.add(lo);
+            //b.norm();
             tt.shl(FP.MODBITS / 2);
             b.add(tt);
 
diff --git a/src/fp12.js b/src/fp12.js
index 8955650..aa29a39 100644
--- a/src/fp12.js
+++ b/src/fp12.js
@@ -27,13 +27,30 @@ var FP12 = function(ctx) {
     /* general purpose constructor */
     var FP12 = function(d, e, f) {
         if (d instanceof FP12) {
+            // ignore e, d, which are assumed be undefined in this case
             this.a = new ctx.FP4(d.a);
             this.b = new ctx.FP4(d.b);
             this.c = new ctx.FP4(d.c);
-        } else {
+            this.stype=ctx.FP.DENSE;
+        } else if (typeof d !== "undefined" && typeof e !== "undefined" && typeof f !== "undefined") {
+            // all 3 components set to (can be anything that the FP4 constructor supports)
             this.a = new ctx.FP4(d);
             this.b = new ctx.FP4(e);
             this.c = new ctx.FP4(f);
+            this.stype=ctx.FP.DENSE;
+        } else if (typeof d === "number") {
+            // first component is number
+            this.a = new ctx.FP4(d);
+            this.b = new ctx.FP4(0);
+            this.c = new ctx.FP4(0);
+            if (d==1) this.stype=ctx.FP.ONE;
+            else this.stype=ctx.FP.SPARSER;
+        } else {
+            // other cases, including `new ctx.FP12()` fall back to zero
+            this.a = new ctx.FP4(0);
+            this.b = new ctx.FP4(0);
+            this.c = new ctx.FP4(0);
+            this.stype=ctx.FP.ZERO;
         }
     };
 
@@ -54,7 +71,6 @@ var FP12 = function(ctx) {
 
         /* test x==0 ? */
         iszilch: function() {
-            this.reduce();
             return (this.a.iszilch() && this.b.iszilch() && this.c.iszilch());
         },
 
@@ -70,6 +86,8 @@ var FP12 = function(ctx) {
             this.a.cmove(g.a, d);
             this.b.cmove(g.b, d);
             this.c.cmove(g.c, d);
+			d=~(d-1);
+			this.stype^=(this.stype^g.stype)&d;
         },
 
 
@@ -82,7 +100,7 @@ var FP12 = function(ctx) {
             babs = (b ^ m) - m;
             babs = (babs - 1) / 2;
 
-            this.cmove(g[0], FP12.teq(babs, 0));
+            this.cmove(g[0], FP12.teq(babs, 0)); // conditional move
             this.cmove(g[1], FP12.teq(babs, 1));
             this.cmove(g[2], FP12.teq(babs, 2));
             this.cmove(g[3], FP12.teq(babs, 3));
@@ -96,6 +114,14 @@ var FP12 = function(ctx) {
             this.cmove(invf, (m & 1));
         },
 
+		settype: function(w) {
+			this.stype=w;
+		},
+
+		gettype: function() {
+			return this.stype;
+		},
+
         /* extract a from this */
         geta: function() {
             return this.a;
@@ -121,6 +147,7 @@ var FP12 = function(ctx) {
             this.a.copy(x.a);
             this.b.copy(x.b);
             this.c.copy(x.c);
+			this.stype=x.stype;
         },
 
         /* set this=1 */
@@ -128,6 +155,15 @@ var FP12 = function(ctx) {
             this.a.one();
             this.b.zero();
             this.c.zero();
+			this.stype=ctx.FP.ONE;
+        },
+
+        /* set this=0 */
+        zero: function() {
+            this.a.zero();
+            this.b.zero();
+            this.c.zero();
+			this.stype=ctx.FP.ZERO;
         },
 
         /* this=conj(this) */
@@ -142,6 +178,7 @@ var FP12 = function(ctx) {
             this.a.copy(d);
             this.b.copy(e);
             this.c.copy(f);
+			this.stype=ctx.FP.DENSE;
         },
 
         /* set this from one ctx.FP4 */
@@ -149,13 +186,14 @@ var FP12 = function(ctx) {
             this.a.copy(d);
             this.b.zero();
             this.c.zero();
+			this.stype=ctx.FP.SPARSER
         },
 
         /* Granger-Scott Unitary Squaring */
         usqr: function() {
-            var A = new ctx.FP4(this.a),
-                B = new ctx.FP4(this.c),
-                C = new ctx.FP4(this.b),
+            var A = new ctx.FP4(this.a), 
+                B = new ctx.FP4(this.c), 
+                C = new ctx.FP4(this.b), 
                 D = new ctx.FP4(0);
 
             this.a.sqr();
@@ -186,19 +224,23 @@ var FP12 = function(ctx) {
             this.c.add(this.c);
             this.b.add(B);
             this.c.add(C);
+			this.stype=ctx.FP.DENSE;
             this.reduce();
         },
 
         /* Chung-Hasan SQR2 method from http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf */
         sqr: function() {
-            var A = new ctx.FP4(this.a),
-                B = new ctx.FP4(this.b),
-                C = new ctx.FP4(this.c),
-                D = new ctx.FP4(this.a);
+			if (this.stype==ctx.FP.ONE)
+				return;
+
+            var A = new ctx.FP4(this.a), 
+                B = new ctx.FP4(this.b), 
+                C = new ctx.FP4(this.c), 
+                D = new ctx.FP4(this.a); 
 
             A.sqr();
             B.mul(this.c);
-            B.add(B);
+            B.add(B); 
             C.sqr();
             D.mul(this.b);
             D.add(D);
@@ -221,18 +263,21 @@ var FP12 = function(ctx) {
             this.b.copy(C);
             this.b.add(D);
             this.c.add(A);
-
+			if (this.stype==ctx.FP.SPARSER)
+				this.stype=ctx.FP.SPARSE;
+			else
+				this.stype=ctx.FP.DENSE;
             this.norm();
         },
 
         /* FP12 full multiplication this=this*y */
         mul: function(y) {
-            var z0 = new ctx.FP4(this.a),
+            var z0 = new ctx.FP4(this.a), 
                 z1 = new ctx.FP4(0),
-                z2 = new ctx.FP4(this.b),
+                z2 = new ctx.FP4(this.b), 
                 z3 = new ctx.FP4(0),
-                t0 = new ctx.FP4(this.a),
-                t1 = new ctx.FP4(y.a);
+                t0 = new ctx.FP4(this.a), 
+                t1 = new ctx.FP4(y.a); 
 
             z0.mul(y.a);
             z2.mul(y.b);
@@ -292,117 +337,323 @@ var FP12 = function(ctx) {
             z3.times_i();
             this.a.copy(z0);
             this.a.add(z3);
-
+			this.stype=ctx.FP.DENSE;
             this.norm();
         },
 
-        /* Special case this*=y that arises from special form of ATE pairing line function */
-        smul: function(y, twist) {
-            var z0, z1, z2, z3, t0, t1;
-
-            if (twist == ctx.ECP.D_TYPE) {
-
-                z0 = new ctx.FP4(this.a);
-                z2 = new ctx.FP4(this.b);
-                z3 = new ctx.FP4(this.b);
-                t0 = new ctx.FP4(0);
-                t1 = new ctx.FP4(y.a);
-
-                z0.mul(y.a);
-                z2.pmul(y.b.real());
-                this.b.add(this.a);
-                t1.real().add(y.b.real());
-
-                this.b.norm();
-                t1.norm();
-
-                this.b.mul(t1);
-                z3.add(this.c);
-                z3.norm();
-                z3.pmul(y.b.real());
-
-                t0.copy(z0);
-                t0.neg();
-                t1.copy(z2);
-                t1.neg();
-
-                this.b.add(t0);
-
-                this.b.add(t1);
-                z3.add(t1);
-                z2.add(t0);
-
-                t0.copy(this.a);
-                t0.add(this.c);
-                t0.norm();
-                t0.mul(y.a);
-                this.c.copy(z2);
-                this.c.add(t0);
-
-                z3.times_i();
-                this.a.copy(z0);
-                this.a.add(z3);
-            }
-
-            if (twist == ctx.ECP.M_TYPE) {
-                z0=new ctx.FP4(this.a);
-                z1=new ctx.FP4(0);
-                z2=new ctx.FP4(0);
-                z3=new ctx.FP4(0);
-                t0=new ctx.FP4(this.a);
-                t1=new ctx.FP4(0);
-
-                z0.mul(y.a);
-                t0.add(this.b);
-                t0.norm();
-
-                z1.copy(t0); z1.mul(y.a);
-                t0.copy(this.b); t0.add(this.c);
-                t0.norm();
-
-                z3.copy(t0);
-                z3.pmul(y.c.getb());
-                z3.times_i();
-
-                t0.copy(z0); t0.neg();
-
-                z1.add(t0);
-                this.b.copy(z1);
-                z2.copy(t0);
-
-                t0.copy(this.a); t0.add(this.c);
-                t1.copy(y.a); t1.add(y.c);
-
-                t0.norm();
-                t1.norm();
-
-                t0.mul(t1);
-                z2.add(t0);
-
-                t0.copy(this.c);
-
-                t0.pmul(y.c.getb());
-                t0.times_i();
-
-                t1.copy(t0); t1.neg();
-
-                this.c.copy(z2); this.c.add(t1);
-                z3.add(t1);
-                t0.times_i();
-                this.b.add(t0);
-                z3.norm();
-                z3.times_i();
-                this.a.copy(z0); this.a.add(z3);
-            }
-
-            this.norm();
-        },
+/* FP12 multiplication w=w*y */
+/* catering for special case that arises from special form of ATE pairing line function */
+/* w and y are both sparser line functions - cost = 6m */ 
+		smul: function(y) {
+			if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.D_TYPE)
+			{	
+				var w1=new ctx.FP2(this.a.geta());
+				var w2=new ctx.FP2(this.a.getb());
+				var w3=new ctx.FP2(this.b.geta());
+
+				w1.mul(y.a.geta());
+				w2.mul(y.a.getb());
+				w3.mul(y.b.geta());
+
+				var ta=new ctx.FP2(this.a.geta());
+				var tb=new ctx.FP2(y.a.geta());
+				ta.add(this.a.getb()); ta.norm();
+				tb.add(y.a.getb()); tb.norm();
+				var tc=new ctx.FP2(ta);
+				tc.mul(tb);
+				var t=new ctx.FP2(w1);
+				t.add(w2);
+				t.neg();
+				tc.add(t);
+
+				ta.copy(this.a.geta()); ta.add(this.b.geta()); ta.norm();
+				tb.copy(y.a.geta()); tb.add(y.b.geta()); tb.norm();
+				var td=new ctx.FP2(ta);
+				td.mul(tb);
+				t.copy(w1);
+				t.add(w3);
+				t.neg();
+				td.add(t);
+
+				ta.copy(this.a.getb()); ta.add(this.b.geta()); ta.norm();
+				tb.copy(y.a.getb()); tb.add(y.b.geta()); tb.norm();
+				var te=new ctx.FP2(ta);
+				te.mul(tb);
+				t.copy(w2);
+				t.add(w3);
+				t.neg();
+				te.add(t);
+
+				w2.mul_ip();
+				w1.add(w2);
+
+				this.a.geta().copy(w1); this.a.getb().copy(tc);
+				this.b.geta().copy(td); this.b.getb().copy(te);
+				this.c.geta().copy(w3); this.c.getb().zero();
+
+				this.a.norm();
+				this.b.norm();
+
+			} else {
+				var w1=new ctx.FP2(this.a.geta());
+				var w2=new ctx.FP2(this.a.getb());
+				var w3=new ctx.FP2(this.c.getb());
+
+				w1.mul(y.a.geta());
+				w2.mul(y.a.getb());
+				w3.mul(y.c.getb());
+
+				var ta=new ctx.FP2(this.a.geta());
+				var tb=new ctx.FP2(y.a.geta());
+				ta.add(this.a.getb()); ta.norm();
+				tb.add(y.a.getb()); tb.norm();
+				var tc=new ctx.FP2(ta);
+				tc.mul(tb);
+				var t=new ctx.FP2(w1);
+				t.add(w2);
+				t.neg();
+				tc.add(t);
+
+				ta.copy(this.a.geta()); ta.add(this.c.getb()); ta.norm();
+				tb.copy(y.a.geta()); tb.add(y.c.getb()); tb.norm();
+				var td=new ctx.FP2(ta);
+				td.mul(tb);
+				t.copy(w1);
+				t.add(w3);
+				t.neg();
+				td.add(t);
+
+				ta.copy(this.a.getb()); ta.add(this.c.getb()); ta.norm();
+				tb.copy(y.a.getb()); tb.add(y.c.getb()); tb.norm();
+				var te=new ctx.FP2(ta);
+				te.mul(tb);
+				t.copy(w2);
+				t.add(w3);
+				t.neg();
+				te.add(t);
+
+				w2.mul_ip();
+				w1.add(w2);
+				this.a.geta().copy(w1); this.a.getb().copy(tc);
+
+				w3.mul_ip();
+				w3.norm();
+				this.b.geta().zero(); this.b.getb().copy(w3);
+
+				te.norm();
+				te.mul_ip();
+				this.c.geta().copy(te);
+				this.c.getb().copy(td);
+
+				this.a.norm();
+				this.c.norm();
+
+			}
+			this.stype=ctx.FP.SPARSE;
+		},
+
+/* FP12 full multiplication w=w*y */
+/* Supports sparse multiplicands */
+/* Usually w is denser than y */
+		ssmul: function(y) {
+			if (this.stype==ctx.FP.ONE)
+			{
+				this.copy(y);
+				return;
+			}
+			if (y.stype==ctx.FP.ONE)
+				return;
+
+			if (y.stype>=ctx.FP.SPARSE)
+			{
+				var z0=new ctx.FP4(this.a);
+				var z1=new ctx.FP4(0);
+				var z2=new ctx.FP4(0);
+				var z3=new ctx.FP4(0);
+				z0.mul(y.a);
+
+				if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.M_TYPE)
+				{
+					if (y.stype==ctx.FP.SPARSE || this.stype==ctx.FP.SPARSE)
+					{
+						z2.getb().copy(this.b.getb());
+						z2.getb().mul(y.b.getb());
+						z2.geta().zero();
+						if (y.stype!=ctx.FP.SPARSE)
+						{
+							z2.geta().copy(this.b.getb());
+							z2.geta().mul(y.b.geta());
+						}
+						if (this.stype!=ctx.FP.SPARSE)
+						{
+							z2.geta().copy(this.b.geta());
+							z2.geta().mul(y.b.getb());
+						}
+						z2.times_i();
+					} else {
+						z2.copy(this.b);
+						z2.mul(y.b);
+					}
+				} else {
+					z2.copy(this.b);
+					z2.mul(y.b);
+				}
+				var t0=new ctx.FP4(this.a);
+				var t1=new ctx.FP4(y.a);
+				t0.add(this.b); t0.norm();
+				t1.add(y.b); t1.norm();
+
+				z1.copy(t0); z1.mul(t1);
+				t0.copy(this.b); t0.add(this.c); t0.norm();
+				t1.copy(y.b); t1.add(y.c); t1.norm();
+
+				z3.copy(t0); z3.mul(t1);
+
+				t0.copy(z0); t0.neg();
+				t1.copy(z2); t1.neg();
+
+				z1.add(t0);
+				this.b.copy(z1); this.b.add(t1);
+
+				z3.add(t1);
+				z2.add(t0);
+
+				t0.copy(this.a); t0.add(this.c); t0.norm();
+				t1.copy(y.a); t1.add(y.c); t1.norm();
+	
+				t0.mul(t1);
+				z2.add(t0);
+
+				if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.D_TYPE)
+				{
+					if (y.stype==ctx.FP.SPARSE || this.stype==ctx.FP.SPARSE)
+					{
+						t0.geta().copy(this.c.geta());
+						t0.geta().mul(y.c.geta());
+						t0.getb().zero();
+						if (y.stype!=ctx.FP.SPARSE)
+						{
+							t0.getb().copy(this.c.geta());
+							t0.getb().mul(y.c.getb());
+						}
+						if (this.stype!=ctx.FP.SPARSE)
+						{
+							t0.getb().copy(this.c.getb());
+							t0.getb().mul(y.c.geta());
+						}
+					} else {
+						t0.copy(this.c);
+						t0.mul(y.c);
+					}
+				} else {
+					t0.copy(this.c);
+					t0.mul(y.c);
+				}
+				t1.copy(t0); t1.neg();
+
+				this.c.copy(z2); this.c.add(t1);
+				z3.add(t1);
+				t0.times_i();
+				this.b.add(t0);
+				z3.norm();
+				z3.times_i();
+				this.a.copy(z0); this.a.add(z3);
+			} else {
+				if (this.stype==ctx.FP.SPARSER)
+				{
+					this.smul(y);
+					return;
+				}
+				if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.D_TYPE)
+				{ // dense by sparser - 13m 
+					var z0=new ctx.FP4(this.a);
+					var z2=new ctx.FP4(this.b);
+					var z3=new ctx.FP4(this.b);
+					var t0=new ctx.FP4(0);
+					var t1=new ctx.FP4(y.a);
+					z0.mul(y.a);
+					z2.pmul(y.b.real());
+					this.b.add(this.a);
+					t1.real().add(y.b.real());
+
+					t1.norm();
+					this.b.norm();
+					this.b.mul(t1);
+					z3.add(this.c);
+					z3.norm();
+					z3.pmul(y.b.real());
+
+					t0.copy(z0); t0.neg();
+					t1.copy(z2); t1.neg();
+
+					this.b.add(t0);
+
+					this.b.add(t1);
+					z3.add(t1);
+					z2.add(t0);
+
+					t0.copy(this.a); t0.add(this.c); t0.norm();
+					z3.norm();
+					t0.mul(y.a);
+					this.c.copy(z2); this.c.add(t0);
+
+					z3.times_i();
+					this.a.copy(z0); this.a.add(z3);
+				}
+				if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.M_TYPE)
+				{
+					var z0=new ctx.FP4(this.a);
+					var z1=new ctx.FP4(0);
+					var z2=new ctx.FP4(0);
+					var z3=new ctx.FP4(0);
+					var t0=new ctx.FP4(this.a);
+					var t1=new ctx.FP4(0);
+		
+					z0.mul(y.a);
+					t0.add(this.b); t0.norm();
+
+					z1.copy(t0); z1.mul(y.a);
+					t0.copy(this.b); t0.add(this.c);
+					t0.norm();
+
+					z3.copy(t0); 
+					z3.pmul(y.c.getb());
+					z3.times_i();
+
+					t0.copy(z0); t0.neg();
+					z1.add(t0);
+					this.b.copy(z1); 
+					z2.copy(t0);
+
+					t0.copy(this.a); t0.add(this.c); t0.norm();
+					t1.copy(y.a); t1.add(y.c); t1.norm();
+
+					t0.mul(t1);
+					z2.add(t0);
+					t0.copy(this.c); 
+			
+					t0.pmul(y.c.getb());
+					t0.times_i();
+					t1.copy(t0); t1.neg();
+
+					this.c.copy(z2); this.c.add(t1);
+					z3.add(t1);
+					t0.times_i();
+					this.b.add(t0);
+					z3.norm();
+					z3.times_i();
+					this.a.copy(z0); this.a.add(z3);
+				}	
+			}
+			this.stype=ctx.FP.DENSE;
+			this.norm();
+		},
 
         /* this=1/this */
         inverse: function() {
-            var f0 = new ctx.FP4(this.a),
-                f1 = new ctx.FP4(this.b),
-                f2 = new ctx.FP4(this.a),
+            var f0 = new ctx.FP4(this.a), 
+                f1 = new ctx.FP4(this.b), 
+                f2 = new ctx.FP4(this.a), 
                 f3 = new ctx.FP4(0);
 
             f0.sqr();
@@ -442,6 +693,7 @@ var FP12 = function(ctx) {
             this.b.mul(f3);
             this.c.copy(f2);
             this.c.mul(f3);
+			this.stype=ctx.FP.DENSE;
         },
 
         /* this=this^p, where p=Modulus, using Frobenius */
@@ -458,6 +710,7 @@ var FP12 = function(ctx) {
 
             this.b.pmul(f);
             this.c.pmul(f2);
+			this.stype=ctx.FP.DENSE;
         },
 
         /* trace function */
@@ -535,29 +788,29 @@ var FP12 = function(ctx) {
 
         /* set this=this^e */
         pow: function(e) {
-            var e3, w, nb, i, bt;
-
-            this.norm();
-            e.norm();
-
-            e3 = new ctx.BIG(e);
+            var e1, e3, w, nb, i, bt, sf;
+			e1 = new ctx.BIG(e);
+			e1.norm();
+            e3 = new ctx.BIG(e1);
             e3.pmul(3);
             e3.norm();
 
-            w = new FP12(this);
+			sf = new FP12(this);
+			sf.norm();
+            w = new FP12(sf); 
             nb = e3.nbits();
 
             for (i = nb - 2; i >= 1; i--) {
                 w.usqr();
-                bt = e3.bit(i) - e.bit(i);
+                bt = e3.bit(i) - e1.bit(i);
 
                 if (bt == 1) {
-                    w.mul(this);
+                    w.mul(sf);
                 }
                 if (bt == -1) {
-                    this.conj();
-                    w.mul(this);
-                    this.conj();
+                    sf.conj();
+                    w.mul(sf);
+                    sf.conj();
                 }
             }
             w.reduce();
@@ -642,7 +895,7 @@ var FP12 = function(ctx) {
             t[i] = w[i + ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); 
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 2 * ctx.BIG.MODBYTES];
@@ -652,9 +905,9 @@ var FP12 = function(ctx) {
             t[i] = w[i + 3 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        d = new ctx.FP2(a, b);
+        d = new ctx.FP2(a, b); 
 
-        e = new ctx.FP4(c, d);
+        e = new ctx.FP4(c, d); 
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 4 * ctx.BIG.MODBYTES];
@@ -664,7 +917,7 @@ var FP12 = function(ctx) {
             t[i] = w[i + 5 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); 
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 6 * ctx.BIG.MODBYTES];
@@ -676,7 +929,7 @@ var FP12 = function(ctx) {
         b = ctx.BIG.fromBytes(t);
         d = new ctx.FP2(a, b);
 
-        f = new ctx.FP4(c, d);
+        f = new ctx.FP4(c, d); 
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 8 * ctx.BIG.MODBYTES];
@@ -686,7 +939,7 @@ var FP12 = function(ctx) {
             t[i] = w[i + 9 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); 
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 10 * ctx.BIG.MODBYTES];
@@ -696,11 +949,11 @@ var FP12 = function(ctx) {
             t[i] = w[i + 11 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        d = new ctx.FP2(a, b);
+        d = new ctx.FP2(a, b); 
 
-        g = new ctx.FP4(c, d);
+        g = new ctx.FP4(c, d); 
 
-        r = new FP12(e, f, g);
+        r = new FP12(e, f, g); 
 
         return r;
     };
@@ -731,14 +984,14 @@ var FP12 = function(ctx) {
             t[i] = new ctx.BIG(u[i]); t[i].norm();
         }
 
-        g[0] = new FP12(q[0]);
-        g[1] = new FP12(g[0]); g[1].mul(q[1]);
-        g[2] = new FP12(g[0]); g[2].mul(q[2]);
-        g[3] = new FP12(g[1]); g[3].mul(q[2]);
-        g[4] = new FP12(q[0]); g[4].mul(q[3]);
-        g[5] = new FP12(g[1]); g[5].mul(q[3]);
-        g[6] = new FP12(g[2]); g[6].mul(q[3]);
-        g[7] = new FP12(g[3]); g[7].mul(q[3]);
+        g[0] = new FP12(q[0]);  // q[0]
+        g[1] = new FP12(g[0]); g[1].mul(q[1]);  // q[0].q[1]
+        g[2] = new FP12(g[0]); g[2].mul(q[2]);  // q[0].q[2]
+        g[3] = new FP12(g[1]); g[3].mul(q[2]);  // q[0].q[1].q[2]
+        g[4] = new FP12(q[0]); g[4].mul(q[3]);  // q[0].q[3]
+        g[5] = new FP12(g[1]); g[5].mul(q[3]);  // q[0].q[1].q[3]
+        g[6] = new FP12(g[2]); g[6].mul(q[3]);  // q[0].q[2].q[3]
+        g[7] = new FP12(g[3]); g[7].mul(q[3]);  // q[0].q[1].q[2].q[3]
 
         // Make it odd
         pb=1-t[0].parity();
@@ -794,6 +1047,7 @@ var FP12 = function(ctx) {
     return FP12;
 };
 
+
 if (typeof module !== "undefined" && typeof module.exports !== "undefined") {
     module.exports = {
         FP12: FP12
diff --git a/src/fp16.js b/src/fp16.js
index d700dfc..14d10e8 100644
--- a/src/fp16.js
+++ b/src/fp16.js
@@ -50,7 +50,6 @@ var FP16 = function(ctx) {
 
         /* test this==0 ? */
         iszilch: function() {
-            this.reduce();
             return (this.a.iszilch() && this.b.iszilch());
         },
 
@@ -122,13 +121,13 @@ var FP16 = function(ctx) {
 
         /* this=-this */
         neg: function() {
-            var m = new ctx.FP8(this.a),
+            var m = new ctx.FP8(this.a), 
                 t = new ctx.FP8(0);
 
             this.norm();
-
             m.add(this.b);
             m.neg();
+ 
             t.copy(m);
             t.add(this.b);
             this.b.copy(m);
@@ -157,7 +156,7 @@ var FP16 = function(ctx) {
 
         /* this-=x */
         sub: function(x) {
-            var m = new FP16(x);
+            var m = new FP16(x); 
             m.neg();
             this.add(m);
         },
@@ -182,9 +181,9 @@ var FP16 = function(ctx) {
 
         /* this*=this */
         sqr: function() {
-            var t1 = new ctx.FP8(this.a),
-                t2 = new ctx.FP8(this.b),
-                t3 = new ctx.FP8(this.a);
+            var t1 = new ctx.FP8(this.a), 
+                t2 = new ctx.FP8(this.b), 
+                t3 = new ctx.FP8(this.a); 
 
             t3.mul(this.b);
             t1.add(this.b);
@@ -214,10 +213,10 @@ var FP16 = function(ctx) {
         /* this*=y */
         mul: function(y) {
 
-            var t1 = new ctx.FP8(this.a),
-                t2 = new ctx.FP8(this.b),
+            var t1 = new ctx.FP8(this.a), 
+                t2 = new ctx.FP8(this.b), 
                 t3 = new ctx.FP8(0),
-                t4 = new ctx.FP8(this.b);
+                t4 = new ctx.FP8(this.b); 
 
             t1.mul(y.a);
             t2.mul(y.b);
@@ -253,10 +252,10 @@ var FP16 = function(ctx) {
 
         /* this=1/this */
         inverse: function() {
-            this.norm();
+            //this.norm();
 
-            var t1 = new ctx.FP8(this.a),
-                t2 = new ctx.FP8(this.b);
+            var t1 = new ctx.FP8(this.a), 
+                t2 = new ctx.FP8(this.b); 
 
             t1.sqr();
             t2.sqr();
@@ -304,14 +303,13 @@ var FP16 = function(ctx) {
 
         /* this=this^e */
         pow: function(e) {
-            this.norm();
-            e.norm();
-
-            var w = new FP16(this),
-                z = new ctx.BIG(e),
+            
+            var w = new FP16(this), 
+                z = new ctx.BIG(e), 
                 r = new FP16(1),
                 bt;
-
+			w.norm();
+			z.norm();
             for (;;) {
                 bt = z.parity();
                 z.fshr(1);
@@ -333,8 +331,8 @@ var FP16 = function(ctx) {
 
         /* XTR xtr_a function */
         xtr_A: function(w, y, z) {
-            var r = new FP16(w),
-                t = new FP16(w);
+            var r = new FP16(w), 
+                t = new FP16(w); 
 
             r.sub(y);
             r.norm();
@@ -353,18 +351,20 @@ var FP16 = function(ctx) {
 
         /* XTR xtr_d function */
         xtr_D: function() {
-            var w = new FP16(this);
+            var w = new FP16(this); 
             this.sqr();
             w.conj();
-            w.add(w);
+            w.add(w); 
             this.sub(w);
             this.reduce();
         },
 
         /* r=x^n using XTR method on traces of FP12s */
         xtr_pow: function(n) {
+			var sf = new FP16(this);
+			sf.norm();
             var a = new FP16(3),
-                b = new FP16(this),
+                b = new FP16(sf),
                 c = new FP16(b),
                 t = new FP16(0),
                 r = new FP16(0),
@@ -372,10 +372,10 @@ var FP16 = function(ctx) {
 
             c.xtr_D();
 
-            n.norm();
+            
             par = n.parity();
             v = new ctx.BIG(n);
-
+			v.norm();
             v.fshr(1);
 
             if (par === 0) {
@@ -387,10 +387,10 @@ var FP16 = function(ctx) {
             for (i = nb - 1; i >= 0; i--) {
                 if (v.bit(i) != 1) {
                     t.copy(b);
-                    this.conj();
+                    sf.conj();
                     c.conj();
-                    b.xtr_A(a, this, c);
-                    this.conj();
+                    b.xtr_A(a, sf, c);
+                    sf.conj();
                     c.copy(t);
                     c.xtr_D();
                     a.xtr_D();
@@ -399,7 +399,7 @@ var FP16 = function(ctx) {
                     t.conj();
                     a.copy(b);
                     a.xtr_D();
-                    b.xtr_A(c, this, t);
+                    b.xtr_A(c, sf, t);
                     c.xtr_D();
                 }
             }
@@ -416,21 +416,22 @@ var FP16 = function(ctx) {
 
         /* r=ck^a.cl^n using XTR double exponentiation method on traces of FP12s. See Stam thesis. */
         xtr_pow2: function(ck, ckml, ckm2l, a, b) {
-            a.norm();
-            b.norm();
 
-            var e = new ctx.BIG(a),
-                d = new ctx.BIG(b),
+            var e = new ctx.BIG(a), 
+                d = new ctx.BIG(b), 
                 w = new ctx.BIG(0),
-                cu = new FP16(ck),
-                cv = new FP16(this),
-                cumv = new FP16(ckml),
-                cum2v = new FP16(ckm2l),
+                cu = new FP16(ck), 
+                cv = new FP16(this), 
+                cumv = new FP16(ckml), 
+                cum2v = new FP16(ckm2l), 
                 r = new FP16(0),
                 t = new FP16(0),
                 f2 = 0,
                 i;
 
+            d.norm();
+            e.norm();
+
             while (d.parity() === 0 && e.parity() === 0) {
                 d.fshr(1);
                 e.fshr(1);
diff --git a/src/fp2.js b/src/fp2.js
index 695fa9d..d2d1a50 100644
--- a/src/fp2.js
+++ b/src/fp2.js
@@ -50,7 +50,6 @@ var FP2 = function(ctx) {
 
         /* test this=0 ? */
         iszilch: function() {
-            this.reduce();
             return (this.a.iszilch() && this.b.iszilch());
         },
 
@@ -151,7 +150,7 @@ var FP2 = function(ctx) {
 
         /* this-=x */
         sub: function(x) {
-            var m = new FP2(x);
+            var m = new FP2(x); 
             m.neg();
             this.add(m);
         },
@@ -180,7 +179,6 @@ var FP2 = function(ctx) {
                 mb = new ctx.FP(this.b);
 
             w1.add(this.b);
-
             w3.add(this.a);
             w3.norm();
             this.b.mul(w3);
@@ -317,7 +315,7 @@ var FP2 = function(ctx) {
 
         /* this*=sqrt(-1) */
         times_i: function() {
-            var z = new ctx.FP(this.a);
+            var z = new ctx.FP(this.a); //z.copy(this.a);
             this.a.copy(this.b);
             this.a.neg();
             this.b.copy(z);
@@ -326,13 +324,14 @@ var FP2 = function(ctx) {
         /* w*=(1+sqrt(-1)) */
         /* where X*2-(1+sqrt(-1)) is irreducible for FP4, assumes p=3 mod 8 */
         mul_ip: function() {
-            var t = new FP2(this),
+            var t = new FP2(this), 
                 z = new ctx.FP(this.a);
 
             this.a.copy(this.b);
             this.a.neg();
             this.b.copy(z);
             this.add(t);
+            //      this.norm();
         },
 
         div_ip2: function() {
@@ -364,7 +363,7 @@ var FP2 = function(ctx) {
             this.norm();
 
             var r = new FP2(1),
-                x = new FP2(this),
+                x = new FP2(this), 
                 bt;
 
             e.norm();
diff --git a/src/fp24.js b/src/fp24.js
index 43bc85a..50cd3d2 100644
--- a/src/fp24.js
+++ b/src/fp24.js
@@ -26,15 +26,27 @@ var FP24 = function(ctx) {
 
     /* general purpose constructor */
     var FP24 = function(d, e, f) {
-        if (d instanceof FP24) {
-            this.a = new ctx.FP8(d.a);
-            this.b = new ctx.FP8(d.b);
-            this.c = new ctx.FP8(d.c);
-        } else {
-            this.a = new ctx.FP8(d);
-            this.b = new ctx.FP8(e);
-            this.c = new ctx.FP8(f);
-        }
+		if (!isNaN(d))
+		{
+			this.a = new ctx.FP8(d);
+			this.b = new ctx.FP8(0);
+			this.c = new ctx.FP8(0);
+			if (d==1) this.stype=ctx.FP.ONE;
+			else this.stype=ctx.FP.SPARSER;
+		}
+		else
+		{
+			if (d instanceof FP24) {
+				this.a = new ctx.FP8(d.a);
+				this.b = new ctx.FP8(d.b);
+				this.c = new ctx.FP8(d.c);
+			} else {
+				this.a = new ctx.FP8(d);
+				this.b = new ctx.FP8(e);
+				this.c = new ctx.FP8(f);
+			}
+			this.stype=ctx.FP.DENSE;
+		}
     };
 
     FP24.prototype = {
@@ -54,7 +66,6 @@ var FP24 = function(ctx) {
 
         /* test x==0 ? */
         iszilch: function() {
-            this.reduce();
             return (this.a.iszilch() && this.b.iszilch() && this.c.iszilch());
         },
 
@@ -69,6 +80,8 @@ var FP24 = function(ctx) {
             this.a.cmove(g.a, d);
             this.b.cmove(g.b, d);
             this.c.cmove(g.c, d);
+			d=~(d-1);
+			this.stype^=(this.stype^g.stype)&d;
         },
 
         /* Constant time select from pre-computed table */
@@ -80,7 +93,7 @@ var FP24 = function(ctx) {
             babs = (b ^ m) - m;
             babs = (babs - 1) / 2;
 
-            this.cmove(g[0], FP24.teq(babs, 0));
+            this.cmove(g[0], FP24.teq(babs, 0)); // conditional move
             this.cmove(g[1], FP24.teq(babs, 1));
             this.cmove(g[2], FP24.teq(babs, 2));
             this.cmove(g[3], FP24.teq(babs, 3));
@@ -93,7 +106,14 @@ var FP24 = function(ctx) {
             invf.conj();
             this.cmove(invf, (m & 1));
         },
-
+		
+		settype: function(w) {
+			this.stype=w;
+		},
+
+		gettype: function() {
+			return this.stype;
+		},
         /* extract a from this */
         geta: function() {
             return this.a;
@@ -119,6 +139,7 @@ var FP24 = function(ctx) {
             this.a.copy(x.a);
             this.b.copy(x.b);
             this.c.copy(x.c);
+			this.stype=x.stype;
         },
 
         /* set this=1 */
@@ -126,6 +147,15 @@ var FP24 = function(ctx) {
             this.a.one();
             this.b.zero();
             this.c.zero();
+			this.stype=ctx.FP.ONE;
+        },
+
+        /* set this=0 */
+        zero: function() {
+            this.a.zero();
+            this.b.zero();
+            this.c.zero();
+			this.stype=ctx.FP.ZERO;
         },
 
         /* this=conj(this) */
@@ -140,6 +170,7 @@ var FP24 = function(ctx) {
             this.a.copy(d);
             this.b.copy(e);
             this.c.copy(f);
+			this.stype=ctx.FP.DENSE;
         },
 
         /* set this from one ctx.FP8 */
@@ -147,13 +178,14 @@ var FP24 = function(ctx) {
             this.a.copy(d);
             this.b.zero();
             this.c.zero();
+			this.stype=ctx.FP.SPARSER
         },
 
         /* Granger-Scott Unitary Squaring */
         usqr: function() {
-            var A = new ctx.FP8(this.a),
-                B = new ctx.FP8(this.c),
-                C = new ctx.FP8(this.b),
+            var A = new ctx.FP8(this.a), 
+                B = new ctx.FP8(this.c), 
+                C = new ctx.FP8(this.b), 
                 D = new ctx.FP8(0);
 
             this.a.sqr();
@@ -184,19 +216,23 @@ var FP24 = function(ctx) {
             this.c.add(this.c);
             this.b.add(B);
             this.c.add(C);
+			this.stype=ctx.FP.DENSE;
             this.reduce();
         },
 
         /* Chung-Hasan SQR2 method from http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf */
         sqr: function() {
-            var A = new ctx.FP8(this.a),
-                B = new ctx.FP8(this.b),
-                C = new ctx.FP8(this.c),
-                D = new ctx.FP8(this.a);
+			if (this.stype==ctx.FP.ONE)
+				return;
+
+            var A = new ctx.FP8(this.a), 
+                B = new ctx.FP8(this.b), 
+                C = new ctx.FP8(this.c), 
+                D = new ctx.FP8(this.a); 
 
             A.sqr();
             B.mul(this.c);
-            B.add(B);
+            B.add(B); 
             C.sqr();
             D.mul(this.b);
             D.add(D);
@@ -219,18 +255,21 @@ var FP24 = function(ctx) {
             this.b.copy(C);
             this.b.add(D);
             this.c.add(A);
-
+			if (this.stype==ctx.FP.SPARSER)
+				this.stype=ctx.FP.SPARSE;
+			else
+				this.stype=ctx.FP.DENSE;
             this.norm();
         },
 
         /* FP24 full multiplication this=this*y */
         mul: function(y) {
-            var z0 = new ctx.FP8(this.a),
+            var z0 = new ctx.FP8(this.a), 
                 z1 = new ctx.FP8(0),
-                z2 = new ctx.FP8(this.b),
+                z2 = new ctx.FP8(this.b), 
                 z3 = new ctx.FP8(0),
-                t0 = new ctx.FP8(this.a),
-                t1 = new ctx.FP8(y.a);
+                t0 = new ctx.FP8(this.a), 
+                t1 = new ctx.FP8(y.a); 
 
             z0.mul(y.a);
             z2.mul(y.b);
@@ -287,119 +326,327 @@ var FP24 = function(ctx) {
             z3.add(t1);
             t0.times_i();
             this.b.add(t0);
+            // z3.norm();
             z3.times_i();
             this.a.copy(z0);
             this.a.add(z3);
-
+			this.stype=ctx.FP.DENSE;
             this.norm();
         },
 
-        /* Special case this*=y that arises from special form of ATE pairing line function */
-        smul: function(y, twist) {
-            var z0, z1, z2, z3, t0, t1;
-
-            if (twist == ctx.ECP.D_TYPE) {
-                z0 = new ctx.FP8(this.a);
-                z2 = new ctx.FP8(this.b);
-                z3 = new ctx.FP8(this.b);
-                t0 = new ctx.FP8(0);
-                t1 = new ctx.FP8(y.a);
-
-                z0.mul(y.a);
-                z2.pmul(y.b.real());
-                this.b.add(this.a);
-                t1.real().add(y.b.real());
-
-                this.b.norm();
-                t1.norm();
-
-                this.b.mul(t1);
-                z3.add(this.c);
-                z3.norm();
-                z3.pmul(y.b.real());
-
-                t0.copy(z0);
-                t0.neg();
-                t1.copy(z2);
-                t1.neg();
-
-                this.b.add(t0);
-
-                this.b.add(t1);
-                z3.add(t1);
-                z2.add(t0);
-
-                t0.copy(this.a);
-                t0.add(this.c);
-                t0.norm();
-                t0.mul(y.a);
-                this.c.copy(z2);
-                this.c.add(t0);
-
-                z3.times_i();
-                this.a.copy(z0);
-                this.a.add(z3);
-            }
-
-            if (twist == ctx.ECP.M_TYPE) {
-                z0=new ctx.FP8(this.a);
-                z1=new ctx.FP8(0);
-                z2=new ctx.FP8(0);
-                z3=new ctx.FP8(0);
-                t0=new ctx.FP8(this.a);
-                t1=new ctx.FP8(0);
-
-                z0.mul(y.a);
-                t0.add(this.b);
-                t0.norm();
-
-                z1.copy(t0); z1.mul(y.a);
-                t0.copy(this.b); t0.add(this.c);
-                t0.norm();
-
-                z3.copy(t0);
-                z3.pmul(y.c.getb());
-                z3.times_i();
-
-                t0.copy(z0); t0.neg();
-
-                z1.add(t0);
-                this.b.copy(z1);
-                z2.copy(t0);
-
-                t0.copy(this.a); t0.add(this.c);
-                t1.copy(y.a); t1.add(y.c);
-
-                t0.norm();
-                t1.norm();
-
-                t0.mul(t1);
-                z2.add(t0);
-
-                t0.copy(this.c);
-
-                t0.pmul(y.c.getb());
-                t0.times_i();
-
-                t1.copy(t0); t1.neg();
-
-                this.c.copy(z2); this.c.add(t1);
-                z3.add(t1);
-                t0.times_i();
-                this.b.add(t0);
-                z3.norm();
-                z3.times_i();
-                this.a.copy(z0); this.a.add(z3);
-            }
-
-            this.norm();
-        },
+/* FP24 multiplication w=w*y */
+/* catering for special case that arises from special form of ATE pairing line function */
+/* w and y are both sparser line functions - cost = 6m */ 
+		smul: function(y) {
+			if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.D_TYPE)
+			{	
+				var w1=new ctx.FP4(this.a.geta());
+				var w2=new ctx.FP4(this.a.getb());
+				var w3=new ctx.FP4(this.b.geta());
+
+				w1.mul(y.a.geta());
+				w2.mul(y.a.getb());
+				w3.mul(y.b.geta());
+
+				var ta=new ctx.FP4(this.a.geta());
+				var tb=new ctx.FP4(y.a.geta());
+				ta.add(this.a.getb()); ta.norm();
+				tb.add(y.a.getb()); tb.norm();
+				var tc=new ctx.FP4(ta);
+				tc.mul(tb);
+				var t=new ctx.FP4(w1);
+				t.add(w2);
+				t.neg();
+				tc.add(t);
+
+				ta.copy(this.a.geta()); ta.add(this.b.geta()); ta.norm();
+				tb.copy(y.a.geta()); tb.add(y.b.geta()); tb.norm();
+				var td=new ctx.FP4(ta);
+				td.mul(tb);
+				t.copy(w1);
+				t.add(w3);
+				t.neg();
+				td.add(t);
+
+				ta.copy(this.a.getb()); ta.add(this.b.geta()); ta.norm();
+				tb.copy(y.a.getb()); tb.add(y.b.geta()); tb.norm();
+				var te=new ctx.FP4(ta);
+				te.mul(tb);
+				t.copy(w2);
+				t.add(w3);
+				t.neg();
+				te.add(t);
+
+				w2.times_i();
+				w1.add(w2);
+
+				this.a.geta().copy(w1); this.a.getb().copy(tc);
+				this.b.geta().copy(td); this.b.getb().copy(te);
+				this.c.geta().copy(w3); this.c.getb().zero();
+
+				this.a.norm();
+				this.b.norm();
+
+			} else {
+				var w1=new ctx.FP4(this.a.geta());
+				var w2=new ctx.FP4(this.a.getb());
+				var w3=new ctx.FP4(this.c.getb());
+
+				w1.mul(y.a.geta());
+				w2.mul(y.a.getb());
+				w3.mul(y.c.getb());
+
+				var ta=new ctx.FP4(this.a.geta());
+				var tb=new ctx.FP4(y.a.geta());
+				ta.add(this.a.getb()); ta.norm();
+				tb.add(y.a.getb()); tb.norm();
+				var tc=new ctx.FP4(ta);
+				tc.mul(tb);
+				var t=new ctx.FP4(w1);
+				t.add(w2);
+				t.neg();
+				tc.add(t);
+
+				ta.copy(this.a.geta()); ta.add(this.c.getb()); ta.norm();
+				tb.copy(y.a.geta()); tb.add(y.c.getb()); tb.norm();
+				var td=new ctx.FP4(ta);
+				td.mul(tb);
+				t.copy(w1);
+				t.add(w3);
+				t.neg();
+				td.add(t);
+
+				ta.copy(this.a.getb()); ta.add(this.c.getb()); ta.norm();
+				tb.copy(y.a.getb()); tb.add(y.c.getb()); tb.norm();
+				var te=new ctx.FP4(ta);
+				te.mul(tb);
+				t.copy(w2);
+				t.add(w3);
+				t.neg();
+				te.add(t);
+
+				w2.times_i();
+				w1.add(w2);
+				this.a.geta().copy(w1); this.a.getb().copy(tc);
+
+				w3.times_i();
+				w3.norm();
+				this.b.geta().zero(); this.b.getb().copy(w3);
+
+				te.norm();
+				te.times_i();
+				this.c.geta().copy(te);
+				this.c.getb().copy(td);
+
+				this.a.norm();
+				this.c.norm();
+
+			}
+			this.stype=ctx.FP.SPARSE;
+		},
+
+/* FP24 full multiplication w=w*y */
+/* Supports sparse multiplicands */
+/* Usually w is denser than y */
+		ssmul: function(y) {
+			if (this.stype==ctx.FP.ONE)
+			{
+				this.copy(y);
+				return;
+			}
+			if (y.stype==ctx.FP.ONE)
+				return;
+
+			if (y.stype>=ctx.FP.SPARSE)
+			{
+				var z0=new ctx.FP8(this.a);
+				var z1=new ctx.FP8(0);
+				var z2=new ctx.FP8(0);
+				var z3=new ctx.FP8(0);
+				z0.mul(y.a);
+
+				if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.M_TYPE)
+				{
+					if (y.stype==ctx.FP.SPARSE || this.stype==ctx.FP.SPARSE)
+					{
+						z2.getb().copy(this.b.getb());
+						z2.getb().mul(y.b.getb());
+						z2.geta().zero();
+						if (y.stype!=ctx.FP.SPARSE)
+						{
+							z2.geta().copy(this.b.getb());
+							z2.geta().mul(y.b.geta());
+						}
+						if (this.stype!=ctx.FP.SPARSE)
+						{
+							z2.geta().copy(this.b.geta());
+							z2.geta().mul(y.b.getb());
+						}
+						z2.times_i();
+					} else {
+						z2.copy(this.b);
+						z2.mul(y.b);
+					}
+				} else {
+					z2.copy(this.b);
+					z2.mul(y.b);
+				}
+				var t0=new ctx.FP8(this.a);
+				var t1=new ctx.FP8(y.a);
+				t0.add(this.b); t0.norm();
+				t1.add(y.b); t1.norm();
+
+				z1.copy(t0); z1.mul(t1);
+				t0.copy(this.b); t0.add(this.c); t0.norm();
+				t1.copy(y.b); t1.add(y.c); t1.norm();
+
+				z3.copy(t0); z3.mul(t1);
+
+				t0.copy(z0); t0.neg();
+				t1.copy(z2); t1.neg();
+
+				z1.add(t0);
+				this.b.copy(z1); this.b.add(t1);
+
+				z3.add(t1);
+				z2.add(t0);
+
+				t0.copy(this.a); t0.add(this.c); t0.norm();
+				t1.copy(y.a); t1.add(y.c); t1.norm();
+	
+				t0.mul(t1);
+				z2.add(t0);
+
+				if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.D_TYPE)
+				{
+					if (y.stype==ctx.FP.SPARSE || this.stype==ctx.FP.SPARSE)
+					{
+						t0.geta().copy(this.c.geta());
+						t0.geta().mul(y.c.geta());
+						t0.getb().zero();
+						if (y.stype!=ctx.FP.SPARSE)
+						{
+							t0.getb().copy(this.c.geta());
+							t0.getb().mul(y.c.getb());
+						}
+						if (this.stype!=ctx.FP.SPARSE)
+						{
+							t0.getb().copy(this.c.getb());
+							t0.getb().mul(y.c.geta());
+						}
+					} else {
+						t0.copy(this.c);
+						t0.mul(y.c);
+					}
+				} else {
+					t0.copy(this.c);
+					t0.mul(y.c);
+				}
+				t1.copy(t0); t1.neg();
+
+				this.c.copy(z2); this.c.add(t1);
+				z3.add(t1);
+				t0.times_i();
+				this.b.add(t0);
+				z3.norm();
+				z3.times_i();
+				this.a.copy(z0); this.a.add(z3);
+			} else {
+				if (this.stype==ctx.FP.SPARSER)
+				{
+					this.smul(y);
+					return;
+				}
+				if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.D_TYPE)
+				{ // dense by sparser - 13m 
+					var z0=new ctx.FP8(this.a);
+					var z2=new ctx.FP8(this.b);
+					var z3=new ctx.FP8(this.b);
+					var t0=new ctx.FP8(0);
+					var t1=new ctx.FP8(y.a);
+					z0.mul(y.a);
+					z2.pmul(y.b.real());
+					this.b.add(this.a);
+					t1.real().add(y.b.real());
+
+					t1.norm();
+					this.b.norm();
+					this.b.mul(t1);
+					z3.add(this.c);
+					z3.norm();
+					z3.pmul(y.b.real());
+
+					t0.copy(z0); t0.neg();
+					t1.copy(z2); t1.neg();
+
+					this.b.add(t0);
+
+					this.b.add(t1);
+					z3.add(t1);
+					z2.add(t0);
+
+					t0.copy(this.a); t0.add(this.c); t0.norm();
+					z3.norm();
+					t0.mul(y.a);
+					this.c.copy(z2); this.c.add(t0);
+
+					z3.times_i();
+					this.a.copy(z0); this.a.add(z3);
+				}
+				if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.M_TYPE)
+				{
+					var z0=new ctx.FP8(this.a);
+					var z1=new ctx.FP8(0);
+					var z2=new ctx.FP8(0);
+					var z3=new ctx.FP8(0);
+					var t0=new ctx.FP8(this.a);
+					var t1=new ctx.FP8(0);
+		
+					z0.mul(y.a);
+					t0.add(this.b); t0.norm();
+
+					z1.copy(t0); z1.mul(y.a);
+					t0.copy(this.b); t0.add(this.c);
+					t0.norm();
+
+					z3.copy(t0); 
+					z3.pmul(y.c.getb());
+					z3.times_i();
+
+					t0.copy(z0); t0.neg();
+					z1.add(t0);
+					this.b.copy(z1); 
+					z2.copy(t0);
+
+					t0.copy(this.a); t0.add(this.c); t0.norm();
+					t1.copy(y.a); t1.add(y.c); t1.norm();
+
+					t0.mul(t1);
+					z2.add(t0);
+					t0.copy(this.c); 
+			
+					t0.pmul(y.c.getb());
+					t0.times_i();
+					t1.copy(t0); t1.neg();
+
+					this.c.copy(z2); this.c.add(t1);
+					z3.add(t1);
+					t0.times_i();
+					this.b.add(t0);
+					z3.norm();
+					z3.times_i();
+					this.a.copy(z0); this.a.add(z3);
+				}	
+			}
+			this.stype=ctx.FP.DENSE;
+			this.norm();
+		},
 
         /* this=1/this */
         inverse: function() {
-            var f0 = new ctx.FP8(this.a),
-                f1 = new ctx.FP8(this.b),
-                f2 = new ctx.FP8(this.a),
+            var f0 = new ctx.FP8(this.a), 
+                f1 = new ctx.FP8(this.b), 
+                f2 = new ctx.FP8(this.a), 
                 f3 = new ctx.FP8(0);
 
             f0.sqr();
@@ -439,6 +686,7 @@ var FP24 = function(ctx) {
             this.b.mul(f3);
             this.c.copy(f2);
             this.c.mul(f3);
+			this.stype=ctx.FP.DENSE;
         },
 
         /* this=this^p, where p=Modulus, using Frobenius */
@@ -460,6 +708,7 @@ var FP24 = function(ctx) {
                 this.b.qmul(f); this.b.times_i2();
                 this.c.qmul(f2); this.c.times_i2(); this.c.times_i2();
             }
+			this.stype=ctx.FP.DENSE;
         },
 
         /* trace function */
@@ -588,29 +837,31 @@ var FP24 = function(ctx) {
 
         /* set this=this^e */
         pow: function(e) {
-            var e3, w, nb, i, bt;
+            var e1, e3, w, nb, i, bt, sf;
 
-            this.norm();
-            e.norm();
+			sf = new FP24(this);
+            sf.norm();
+			e1 = new ctx.BIG(e);
+            e1.norm();
 
-            e3 = new ctx.BIG(e);
+            e3 = new ctx.BIG(e1);
             e3.pmul(3);
             e3.norm();
 
-            w = new FP24(this);
+            w = new FP24(sf);
             nb = e3.nbits();
 
             for (i = nb - 2; i >= 1; i--) {
                 w.usqr();
-                bt = e3.bit(i) - e.bit(i);
+                bt = e3.bit(i) - e1.bit(i);
 
                 if (bt == 1) {
-                    w.mul(this);
+                    w.mul(sf);
                 }
                 if (bt == -1) {
-                    this.conj();
-                    w.mul(this);
-                    this.conj();
+                    sf.conj();
+                    w.mul(sf);
+                    sf.conj();
                 }
             }
             w.reduce();
@@ -695,7 +946,7 @@ var FP24 = function(ctx) {
             t[i] = w[i + ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 2 * ctx.BIG.MODBYTES];
@@ -705,9 +956,9 @@ var FP24 = function(ctx) {
             t[i] = w[i + 3 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        d = new ctx.FP2(a, b);
+        d = new ctx.FP2(a, b); //d.bset(a,b);
 
-        ea = new ctx.FP4(c, d);
+        ea = new ctx.FP4(c, d); //e.set(c,d);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 4 * ctx.BIG.MODBYTES];
@@ -717,7 +968,7 @@ var FP24 = function(ctx) {
             t[i] = w[i + 5 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 6 * ctx.BIG.MODBYTES];
@@ -727,9 +978,9 @@ var FP24 = function(ctx) {
             t[i] = w[i + 7 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        d = new ctx.FP2(a, b);
+        d = new ctx.FP2(a, b); //d.bset(a,b);
 
-        eb = new ctx.FP4(c, d);
+        eb = new ctx.FP4(c, d); //e.set(c,d);
 
         e = new ctx.FP8(ea,eb);
 
@@ -741,7 +992,7 @@ var FP24 = function(ctx) {
             t[i] = w[i + 9 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 10 * ctx.BIG.MODBYTES];
@@ -753,7 +1004,7 @@ var FP24 = function(ctx) {
         b = ctx.BIG.fromBytes(t);
         d = new ctx.FP2(a, b);
 
-        ea = new ctx.FP4(c, d);
+        ea = new ctx.FP4(c, d); //e.set(c,d);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 12 * ctx.BIG.MODBYTES];
@@ -763,7 +1014,7 @@ var FP24 = function(ctx) {
             t[i] = w[i + 13 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 14 * ctx.BIG.MODBYTES];
@@ -775,9 +1026,9 @@ var FP24 = function(ctx) {
         b = ctx.BIG.fromBytes(t);
         d = new ctx.FP2(a, b);
 
-        eb = new ctx.FP4(c, d);
+        eb = new ctx.FP4(c, d); //e.set(c,d);
 
-        f = new ctx.FP8(ea, eb);
+        f = new ctx.FP8(ea, eb); //f.set(c,d);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 16 * ctx.BIG.MODBYTES];
@@ -787,7 +1038,7 @@ var FP24 = function(ctx) {
             t[i] = w[i + 17 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 18 * ctx.BIG.MODBYTES];
@@ -797,9 +1048,9 @@ var FP24 = function(ctx) {
             t[i] = w[i + 19 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        d = new ctx.FP2(a, b);
+        d = new ctx.FP2(a, b); //d.bset(a,b);
 
-        ea = new ctx.FP4(c, d);
+        ea = new ctx.FP4(c, d); //e.set(c,d);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 20 * ctx.BIG.MODBYTES];
@@ -809,7 +1060,7 @@ var FP24 = function(ctx) {
             t[i] = w[i + 21 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 22 * ctx.BIG.MODBYTES];
@@ -819,13 +1070,13 @@ var FP24 = function(ctx) {
             t[i] = w[i + 23 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        d = new ctx.FP2(a, b);
+        d = new ctx.FP2(a, b); //d.bset(a,b);
 
-        eb = new ctx.FP4(c, d);
+        eb = new ctx.FP4(c, d); //e.set(c,d);
 
-        g = new ctx.FP8(ea, eb);
+        g = new ctx.FP8(ea, eb); //g.set(c,d);
 
-        r = new FP24(e, f, g);
+        r = new FP24(e, f, g); //r.set(e,f,g);
 
         return r;
     };
@@ -860,14 +1111,14 @@ var FP24 = function(ctx) {
             t[i] = new ctx.BIG(u[i]); t[i].norm();
         }
 
-        g1[0] = new FP24(q[0]);
-        g1[1] = new FP24(g1[0]); g1[1].mul(q[1]);
-        g1[2] = new FP24(g1[0]); g1[2].mul(q[2]);
-        g1[3] = new FP24(g1[1]); g1[3].mul(q[2]);
-        g1[4] = new FP24(q[0]);  g1[4].mul(q[3]);
-        g1[5] = new FP24(g1[1]); g1[5].mul(q[3]);
-        g1[6] = new FP24(g1[2]); g1[6].mul(q[3]);
-        g1[7] = new FP24(g1[3]); g1[7].mul(q[3]);
+        g1[0] = new FP24(q[0]);  // q[0]
+        g1[1] = new FP24(g1[0]); g1[1].mul(q[1]);   // q[0].q[1]
+        g1[2] = new FP24(g1[0]); g1[2].mul(q[2]);   // q[0].q[2]
+        g1[3] = new FP24(g1[1]); g1[3].mul(q[2]);   // q[0].q[1].q[2]
+        g1[4] = new FP24(q[0]);  g1[4].mul(q[3]);   // q[0].q[3]
+        g1[5] = new FP24(g1[1]); g1[5].mul(q[3]);   // q[0].q[1].q[3]
+        g1[6] = new FP24(g1[2]); g1[6].mul(q[3]);   // q[0].q[2].q[3]
+        g1[7] = new FP24(g1[3]); g1[7].mul(q[3]);   // q[0].q[1].q[2].q[3]
 
         //  Use Frobenius
         fa.rcopy(ctx.ROM_FIELD.Fra);
diff --git a/src/fp4.js b/src/fp4.js
index 5fda45b..12c7c97 100644
--- a/src/fp4.js
+++ b/src/fp4.js
@@ -50,7 +50,6 @@ var FP4 = function(ctx) {
 
         /* test this==0 ? */
         iszilch: function() {
-            this.reduce();
             return (this.a.iszilch() && this.b.iszilch());
         },
 
@@ -123,7 +122,7 @@ var FP4 = function(ctx) {
         /* this=-this */
         neg: function() {
             this.norm();
-            var m = new ctx.FP2(this.a),
+            var m = new ctx.FP2(this.a), 
                 t = new ctx.FP2(0);
 
             m.add(this.b);
@@ -156,7 +155,7 @@ var FP4 = function(ctx) {
 
         /* this-=x */
         sub: function(x) {
-            var m = new FP4(x);
+            var m = new FP4(x); 
             m.neg();
             this.add(m);
         },
@@ -180,9 +179,11 @@ var FP4 = function(ctx) {
 
         /* this*=this */
         sqr: function() {
-            var t1 = new ctx.FP2(this.a),
-                t2 = new ctx.FP2(this.b),
-                t3 = new ctx.FP2(this.a);
+            // this.norm();
+
+            var t1 = new ctx.FP2(this.a), 
+                t2 = new ctx.FP2(this.b), 
+                t3 = new ctx.FP2(this.a); 
 
             t3.mul(this.b);
             t1.add(this.b);
@@ -212,10 +213,12 @@ var FP4 = function(ctx) {
 
         /* this*=y */
         mul: function(y) {
-            var t1 = new ctx.FP2(this.a),
-                t2 = new ctx.FP2(this.b),
+            // this.norm();
+
+            var t1 = new ctx.FP2(this.a), 
+                t2 = new ctx.FP2(this.b), 
                 t3 = new ctx.FP2(0),
-                t4 = new ctx.FP2(this.b);
+                t4 = new ctx.FP2(this.b); 
 
             t1.mul(y.a);
             t2.mul(y.b);
@@ -253,8 +256,8 @@ var FP4 = function(ctx) {
         inverse: function() {
             this.norm();
 
-            var t1 = new ctx.FP2(this.a),
-                t2 = new ctx.FP2(this.b);
+            var t1 = new ctx.FP2(this.a), 
+                t2 = new ctx.FP2(this.b); 
 
             t1.sqr();
             t2.sqr();
@@ -270,8 +273,8 @@ var FP4 = function(ctx) {
 
         /* this*=i where i = sqrt(-1+sqrt(-1)) */
         times_i: function() {
-            var s = new ctx.FP2(this.b),
-                t = new ctx.FP2(this.b);
+            var s = new ctx.FP2(this.b), //s.copy(this.b);
+                t = new ctx.FP2(this.b); //t.copy(this.b);
 
             s.times_i();
             t.add(s);
@@ -289,14 +292,12 @@ var FP4 = function(ctx) {
 
         /* this=this^e */
         pow: function(e) {
-            this.norm();
-            e.norm();
-
-            var w = new FP4(this),
-                z = new ctx.BIG(e),
+            var w = new FP4(this), 
+                z = new ctx.BIG(e), 
                 r = new FP4(1),
                 bt;
-
+			w.norm();
+			z.norm();
             for (;;) {
                 bt = z.parity();
                 z.fshr(1);
@@ -318,9 +319,10 @@ var FP4 = function(ctx) {
 
         /* XTR xtr_a function */
         xtr_A: function(w, y, z) {
-            var r = new FP4(w),
-                t = new FP4(w);
+            var r = new FP4(w), 
+                t = new FP4(w); 
 
+            //y.norm(); // ??
             r.sub(y);
             r.norm();
             r.pmul(this.a);
@@ -338,29 +340,32 @@ var FP4 = function(ctx) {
 
         /* XTR xtr_d function */
         xtr_D: function() {
-            var w = new FP4(this);
+            var w = new FP4(this); 
             this.sqr();
             w.conj();
-            w.add(w);
+            w.add(w); 
             this.sub(w);
             this.reduce();
         },
 
         /* r=x^n using XTR method on traces of FP12s */
         xtr_pow: function(n) {
+			var sf = new FP4(this);
+			sf.norm();
             var a = new FP4(3),
-                b = new FP4(this),
+                b = new FP4(sf),
                 c = new FP4(b),
                 t = new FP4(0),
                 r = new FP4(0),
                 par, v, nb, i;
 
+
             c.xtr_D();
 
-            n.norm();
+            //n.norm();
             par = n.parity();
             v = new ctx.BIG(n);
-
+			v.norm();
             v.fshr(1);
 
             if (par === 0) {
@@ -372,10 +377,10 @@ var FP4 = function(ctx) {
             for (i = nb - 1; i >= 0; i--) {
                 if (v.bit(i) != 1) {
                     t.copy(b);
-                    this.conj();
+                    sf.conj();
                     c.conj();
-                    b.xtr_A(a, this, c);
-                    this.conj();
+                    b.xtr_A(a, sf, c);
+                    sf.conj();
                     c.copy(t);
                     c.xtr_D();
                     a.xtr_D();
@@ -384,7 +389,7 @@ var FP4 = function(ctx) {
                     t.conj();
                     a.copy(b);
                     a.xtr_D();
-                    b.xtr_A(c, this, t);
+                    b.xtr_A(c, sf, t);
                     c.xtr_D();
                 }
             }
@@ -401,21 +406,22 @@ var FP4 = function(ctx) {
 
         /* r=ck^a.cl^n using XTR double exponentiation method on traces of FP12s. See Stam thesis. */
         xtr_pow2: function(ck, ckml, ckm2l, a, b) {
-            a.norm();
-            b.norm();
-
-            var e = new ctx.BIG(a),
-                d = new ctx.BIG(b),
+ 
+            var e = new ctx.BIG(a), 
+                d = new ctx.BIG(b), 
                 w = new ctx.BIG(0),
-                cu = new FP4(ck),
-                cv = new FP4(this),
-                cumv = new FP4(ckml),
-                cum2v = new FP4(ckm2l),
+                cu = new FP4(ck), 
+                cv = new FP4(this), 
+                cumv = new FP4(ckml), 
+                cum2v = new FP4(ckm2l), 
                 r = new FP4(0),
                 t = new FP4(0),
                 f2 = 0,
                 i;
 
+			e.norm();
+			d.norm();
+
             while (d.parity() === 0 && e.parity() === 0) {
                 d.fshr(1);
                 e.fshr(1);
diff --git a/src/fp48.js b/src/fp48.js
index 68b3f4e..58ac47b 100644
--- a/src/fp48.js
+++ b/src/fp48.js
@@ -26,15 +26,27 @@ var FP48 = function(ctx) {
 
     /* general purpose constructor */
     var FP48 = function(d, e, f) {
-        if (d instanceof FP48) {
-            this.a = new ctx.FP16(d.a);
-            this.b = new ctx.FP16(d.b);
-            this.c = new ctx.FP16(d.c);
-        } else {
-            this.a = new ctx.FP16(d);
-            this.b = new ctx.FP16(e);
-            this.c = new ctx.FP16(f);
-        }
+		if (!isNaN(d))
+		{
+			this.a = new ctx.FP16(d);
+			this.b = new ctx.FP16(0);
+			this.c = new ctx.FP16(0);
+			if (d==1) this.stype=ctx.FP.ONE;
+			else this.stype=ctx.FP.SPARSER;
+		}
+		else
+		{
+	        if (d instanceof FP48) {
+		        this.a = new ctx.FP16(d.a);
+			    this.b = new ctx.FP16(d.b);
+				this.c = new ctx.FP16(d.c);
+			} else {
+				this.a = new ctx.FP16(d);
+				this.b = new ctx.FP16(e);
+				this.c = new ctx.FP16(f);
+			}
+			this.stype=ctx.FP.DENSE;
+		}
     };
 
     FP48.prototype = {
@@ -54,7 +66,6 @@ var FP48 = function(ctx) {
 
         /* test x==0 ? */
         iszilch: function() {
-            this.reduce();
             return (this.a.iszilch() && this.b.iszilch() && this.c.iszilch());
         },
 
@@ -69,6 +80,9 @@ var FP48 = function(ctx) {
             this.a.cmove(g.a, d);
             this.b.cmove(g.b, d);
             this.c.cmove(g.c, d);
+			d=~(d-1);
+			this.stype^=(this.stype^g.stype)&d;
+
         },
 
         /* Constant time select from pre-computed table */
@@ -94,6 +108,14 @@ var FP48 = function(ctx) {
             this.cmove(invf, (m & 1));
         },
 
+		settype: function(w) {
+			this.stype=w;
+		},
+
+		gettype: function() {
+			return this.stype;
+		},
+
         /* extract a from this */
         geta: function() {
             return this.a;
@@ -119,6 +141,7 @@ var FP48 = function(ctx) {
             this.a.copy(x.a);
             this.b.copy(x.b);
             this.c.copy(x.c);
+			this.stype=x.stype;
         },
 
         /* set this=1 */
@@ -126,6 +149,15 @@ var FP48 = function(ctx) {
             this.a.one();
             this.b.zero();
             this.c.zero();
+			this.stype=ctx.FP.ONE;
+        },
+
+        /* set this=0 */
+        zero: function() {
+            this.a.zero();
+            this.b.zero();
+            this.c.zero();
+			this.stype=ctx.FP.ZERO;
         },
 
         /* this=conj(this) */
@@ -140,6 +172,7 @@ var FP48 = function(ctx) {
             this.a.copy(d);
             this.b.copy(e);
             this.c.copy(f);
+			this.stype=ctx.FP.DENSE;
         },
 
         /* set this from one ctx.FP16 */
@@ -147,11 +180,12 @@ var FP48 = function(ctx) {
             this.a.copy(d);
             this.b.zero();
             this.c.zero();
+			this.stype=ctx.FP.SPARSER
         },
 
         /* Granger-Scott Unitary Squaring */
         usqr: function() {
-            var A = new ctx.FP16(this.a),
+            var A = new ctx.FP16(this.a), 
                 B = new ctx.FP16(this.c),
                 C = new ctx.FP16(this.b),
                 D = new ctx.FP16(0);
@@ -184,19 +218,23 @@ var FP48 = function(ctx) {
             this.c.add(this.c);
             this.b.add(B);
             this.c.add(C);
+			this.stype=ctx.FP.DENSE;
             this.reduce();
         },
 
         /* Chung-Hasan SQR2 method from http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf */
         sqr: function() {
-            var A = new ctx.FP16(this.a),
-                B = new ctx.FP16(this.b),
-                C = new ctx.FP16(this.c),
-                D = new ctx.FP16(this.a);
+			if (this.stype==ctx.FP.ONE)
+				return;
+
+            var A = new ctx.FP16(this.a), 
+                B = new ctx.FP16(this.b), 
+                C = new ctx.FP16(this.c), 
+                D = new ctx.FP16(this.a); 
 
             A.sqr();
             B.mul(this.c);
-            B.add(B);
+            B.add(B); 
             C.sqr();
             D.mul(this.b);
             D.add(D);
@@ -219,18 +257,21 @@ var FP48 = function(ctx) {
             this.b.copy(C);
             this.b.add(D);
             this.c.add(A);
-
+			if (this.stype==ctx.FP.SPARSER)
+				this.stype=ctx.FP.SPARSE;
+			else
+				this.stype=ctx.FP.DENSE;
             this.norm();
         },
 
         /* FP48 full multiplication this=this*y */
         mul: function(y) {
-            var z0 = new ctx.FP16(this.a),
+            var z0 = new ctx.FP16(this.a), 
                 z1 = new ctx.FP16(0),
-                z2 = new ctx.FP16(this.b),
+                z2 = new ctx.FP16(this.b), 
                 z3 = new ctx.FP16(0),
-                t0 = new ctx.FP16(this.a),
-                t1 = new ctx.FP16(y.a);
+                t0 = new ctx.FP16(this.a), 
+                t1 = new ctx.FP16(y.a); 
 
             z0.mul(y.a);
             z2.mul(y.b);
@@ -287,120 +328,328 @@ var FP48 = function(ctx) {
             z3.add(t1);
             t0.times_i();
             this.b.add(t0);
-            // z3.norm();
+  
             z3.times_i();
             this.a.copy(z0);
             this.a.add(z3);
-
+			this.stype=ctx.FP.DENSE;
             this.norm();
         },
 
-        /* Special case this*=y that arises from special form of ATE pairing line function */
-        smul: function(y, twist) {
-            var z0, z1, z2, z3, t0, t1;
-
-            if (twist == ctx.ECP.D_TYPE) {
-                z0 = new ctx.FP16(this.a),
-                z2 = new ctx.FP16(this.b),
-                z3 = new ctx.FP16(this.b),
-                t0 = new ctx.FP16(0),
-                t1 = new ctx.FP16(y.a);
-
-                z0.mul(y.a);
-                z2.pmul(y.b.real());
-                this.b.add(this.a);
-                t1.real().add(y.b.real());
-
-                this.b.norm();
-                t1.norm();
-
-                this.b.mul(t1);
-                z3.add(this.c);
-                z3.norm();
-                z3.pmul(y.b.real());
-
-                t0.copy(z0);
-                t0.neg();
-                t1.copy(z2);
-                t1.neg();
-
-                this.b.add(t0);
-
-                this.b.add(t1);
-                z3.add(t1);
-                z2.add(t0);
-
-                t0.copy(this.a);
-                t0.add(this.c);
-                t0.norm();
-                t0.mul(y.a);
-                this.c.copy(z2);
-                this.c.add(t0);
-
-                z3.times_i();
-                this.a.copy(z0);
-                this.a.add(z3);
-            }
-
-            if (twist == ctx.ECP.M_TYPE) {
-                z0=new ctx.FP16(this.a);
-                z1=new ctx.FP16(0);
-                z2=new ctx.FP16(0);
-                z3=new ctx.FP16(0);
-                t0=new ctx.FP16(this.a);
-                t1=new ctx.FP16(0);
-
-                z0.mul(y.a);
-                t0.add(this.b);
-                t0.norm();
-
-                z1.copy(t0); z1.mul(y.a);
-                t0.copy(this.b); t0.add(this.c);
-                t0.norm();
-
-                z3.copy(t0);
-                z3.pmul(y.c.getb());
-                z3.times_i();
-
-                t0.copy(z0); t0.neg();
-
-                z1.add(t0);
-                this.b.copy(z1);
-                z2.copy(t0);
+/* FP48 multiplication w=w*y */
+/* catering for special case that arises from special form of ATE pairing line function */
+/* w and y are both sparser line functions - cost = 6m */ 
+		smul: function(y) {
+			if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.D_TYPE)
+			{	
+				var w1=new ctx.FP8(this.a.geta());
+				var w2=new ctx.FP8(this.a.getb());
+				var w3=new ctx.FP8(this.b.geta());
+
+				w1.mul(y.a.geta());
+				w2.mul(y.a.getb());
+				w3.mul(y.b.geta());
+
+				var ta=new ctx.FP8(this.a.geta());
+				var tb=new ctx.FP8(y.a.geta());
+				ta.add(this.a.getb()); ta.norm();
+				tb.add(y.a.getb()); tb.norm();
+				var tc=new ctx.FP8(ta);
+				tc.mul(tb);
+				var t=new ctx.FP8(w1);
+				t.add(w2);
+				t.neg();
+				tc.add(t);
+
+				ta.copy(this.a.geta()); ta.add(this.b.geta()); ta.norm();
+				tb.copy(y.a.geta()); tb.add(y.b.geta()); tb.norm();
+				var td=new ctx.FP8(ta);
+				td.mul(tb);
+				t.copy(w1);
+				t.add(w3);
+				t.neg();
+				td.add(t);
+
+				ta.copy(this.a.getb()); ta.add(this.b.geta()); ta.norm();
+				tb.copy(y.a.getb()); tb.add(y.b.geta()); tb.norm();
+				var te=new ctx.FP8(ta);
+				te.mul(tb);
+				t.copy(w2);
+				t.add(w3);
+				t.neg();
+				te.add(t);
+
+				w2.times_i();
+				w1.add(w2);
+
+				this.a.geta().copy(w1); this.a.getb().copy(tc);
+				this.b.geta().copy(td); this.b.getb().copy(te);
+				this.c.geta().copy(w3); this.c.getb().zero();
+
+				this.a.norm();
+				this.b.norm();
+
+			} else {
+				var w1=new ctx.FP8(this.a.geta());
+				var w2=new ctx.FP8(this.a.getb());
+				var w3=new ctx.FP8(this.c.getb());
+
+				w1.mul(y.a.geta());
+				w2.mul(y.a.getb());
+				w3.mul(y.c.getb());
+
+				var ta=new ctx.FP8(this.a.geta());
+				var tb=new ctx.FP8(y.a.geta());
+				ta.add(this.a.getb()); ta.norm();
+				tb.add(y.a.getb()); tb.norm();
+				var tc=new ctx.FP8(ta);
+				tc.mul(tb);
+				var t=new ctx.FP8(w1);
+				t.add(w2);
+				t.neg();
+				tc.add(t);
+
+				ta.copy(this.a.geta()); ta.add(this.c.getb()); ta.norm();
+				tb.copy(y.a.geta()); tb.add(y.c.getb()); tb.norm();
+				var td=new ctx.FP8(ta);
+				td.mul(tb);
+				t.copy(w1);
+				t.add(w3);
+				t.neg();
+				td.add(t);
+
+				ta.copy(this.a.getb()); ta.add(this.c.getb()); ta.norm();
+				tb.copy(y.a.getb()); tb.add(y.c.getb()); tb.norm();
+				var te=new ctx.FP8(ta);
+				te.mul(tb);
+				t.copy(w2);
+				t.add(w3);
+				t.neg();
+				te.add(t);
+
+				w2.times_i();
+				w1.add(w2);
+				this.a.geta().copy(w1); this.a.getb().copy(tc);
+
+				w3.times_i();
+				w3.norm();
+				this.b.geta().zero(); this.b.getb().copy(w3);
+
+				te.norm();
+				te.times_i();
+				this.c.geta().copy(te);
+				this.c.getb().copy(td);
+
+				this.a.norm();
+				this.c.norm();
+
+			}
+			this.stype=ctx.FP.SPARSE;
+		},
+
+/* FP48 full multiplication w=w*y */
+/* Supports sparse multiplicands */
+/* Usually w is denser than y */
+		ssmul: function(y) {
+			if (this.stype==ctx.FP.ONE)
+			{
+				this.copy(y);
+				return;
+			}
+			if (y.stype==ctx.FP.ONE)
+				return;
+
+			if (y.stype>=ctx.FP.SPARSE)
+			{
+				var z0=new ctx.FP16(this.a);
+				var z1=new ctx.FP16(0);
+				var z2=new ctx.FP16(0);
+				var z3=new ctx.FP16(0);
+				z0.mul(y.a);
+
+				if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.M_TYPE)
+				{
+					if (y.stype==ctx.FP.SPARSE || this.stype==ctx.FP.SPARSE)
+					{
+						z2.getb().copy(this.b.getb());
+						z2.getb().mul(y.b.getb());
+						z2.geta().zero();
+						if (y.stype!=ctx.FP.SPARSE)
+						{
+							z2.geta().copy(this.b.getb());
+							z2.geta().mul(y.b.geta());
+						}
+						if (this.stype!=ctx.FP.SPARSE)
+						{
+							z2.geta().copy(this.b.geta());
+							z2.geta().mul(y.b.getb());
+						}
+						z2.times_i();
+					} else {
+						z2.copy(this.b);
+						z2.mul(y.b);
+					}
+				} else {
+					z2.copy(this.b);
+					z2.mul(y.b);
+				}
+				var t0=new ctx.FP16(this.a);
+				var t1=new ctx.FP16(y.a);
+				t0.add(this.b); t0.norm();
+				t1.add(y.b); t1.norm();
+
+				z1.copy(t0); z1.mul(t1);
+				t0.copy(this.b); t0.add(this.c); t0.norm();
+				t1.copy(y.b); t1.add(y.c); t1.norm();
+
+				z3.copy(t0); z3.mul(t1);
+
+				t0.copy(z0); t0.neg();
+				t1.copy(z2); t1.neg();
+
+				z1.add(t0);
+				this.b.copy(z1); this.b.add(t1);
+
+				z3.add(t1);
+				z2.add(t0);
+
+				t0.copy(this.a); t0.add(this.c); t0.norm();
+				t1.copy(y.a); t1.add(y.c); t1.norm();
+	
+				t0.mul(t1);
+				z2.add(t0);
+
+				if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.D_TYPE)
+				{
+					if (y.stype==ctx.FP.SPARSE || this.stype==ctx.FP.SPARSE)
+					{
+						t0.geta().copy(this.c.geta());
+						t0.geta().mul(y.c.geta());
+						t0.getb().zero();
+						if (y.stype!=ctx.FP.SPARSE)
+						{
+							t0.getb().copy(this.c.geta());
+							t0.getb().mul(y.c.getb());
+						}
+						if (this.stype!=ctx.FP.SPARSE)
+						{
+							t0.getb().copy(this.c.getb());
+							t0.getb().mul(y.c.geta());
+						}
+					} else {
+						t0.copy(this.c);
+						t0.mul(y.c);
+					}
+				} else {
+					t0.copy(this.c);
+					t0.mul(y.c);
+				}
+				t1.copy(t0); t1.neg();
+
+				this.c.copy(z2); this.c.add(t1);
+				z3.add(t1);
+				t0.times_i();
+				this.b.add(t0);
+				z3.norm();
+				z3.times_i();
+				this.a.copy(z0); this.a.add(z3);
+			} else {
+				if (this.stype==ctx.FP.SPARSER)
+				{
+					this.smul(y);
+					return;
+				}
+				if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.D_TYPE)
+				{ // dense by sparser - 13m 
+					var z0=new ctx.FP16(this.a);
+					var z2=new ctx.FP16(this.b);
+					var z3=new ctx.FP16(this.b);
+					var t0=new ctx.FP16(0);
+					var t1=new ctx.FP16(y.a);
+					z0.mul(y.a);
+					z2.pmul(y.b.real());
+					this.b.add(this.a);
+					t1.real().add(y.b.real());
+
+					t1.norm();
+					this.b.norm();
+					this.b.mul(t1);
+					z3.add(this.c);
+					z3.norm();
+					z3.pmul(y.b.real());
+
+					t0.copy(z0); t0.neg();
+					t1.copy(z2); t1.neg();
+
+					this.b.add(t0);
+
+					this.b.add(t1);
+					z3.add(t1);
+					z2.add(t0);
+
+					t0.copy(this.a); t0.add(this.c); t0.norm();
+					z3.norm();
+					t0.mul(y.a);
+					this.c.copy(z2); this.c.add(t0);
+
+					z3.times_i();
+					this.a.copy(z0); this.a.add(z3);
+				}
+				if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.M_TYPE)
+				{
+					var z0=new ctx.FP16(this.a);
+					var z1=new ctx.FP16(0);
+					var z2=new ctx.FP16(0);
+					var z3=new ctx.FP16(0);
+					var t0=new ctx.FP16(this.a);
+					var t1=new ctx.FP16(0);
+		
+					z0.mul(y.a);
+					t0.add(this.b); t0.norm();
+
+					z1.copy(t0); z1.mul(y.a);
+					t0.copy(this.b); t0.add(this.c);
+					t0.norm();
+
+					z3.copy(t0); 
+					z3.pmul(y.c.getb());
+					z3.times_i();
+
+					t0.copy(z0); t0.neg();
+					z1.add(t0);
+					this.b.copy(z1); 
+					z2.copy(t0);
+
+					t0.copy(this.a); t0.add(this.c); t0.norm();
+					t1.copy(y.a); t1.add(y.c); t1.norm();
+
+					t0.mul(t1);
+					z2.add(t0);
+					t0.copy(this.c); 
+			
+					t0.pmul(y.c.getb());
+					t0.times_i();
+					t1.copy(t0); t1.neg();
+
+					this.c.copy(z2); this.c.add(t1);
+					z3.add(t1);
+					t0.times_i();
+					this.b.add(t0);
+					z3.norm();
+					z3.times_i();
+					this.a.copy(z0); this.a.add(z3);
+				}	
+			}
+			this.stype=ctx.FP.DENSE;
+			this.norm();
+		},
 
-                t0.copy(this.a); t0.add(this.c);
-                t1.copy(y.a); t1.add(y.c);
-
-                t0.norm();
-                t1.norm();
-
-                t0.mul(t1);
-                z2.add(t0);
-
-                t0.copy(this.c);
-
-                t0.pmul(y.c.getb());
-                t0.times_i();
-
-                t1.copy(t0); t1.neg();
-
-                this.c.copy(z2); this.c.add(t1);
-                z3.add(t1);
-                t0.times_i();
-                this.b.add(t0);
-                z3.norm();
-                z3.times_i();
-                this.a.copy(z0); this.a.add(z3);
-            }
-
-            this.norm();
-        },
 
         /* this=1/this */
         inverse: function() {
-            var f0 = new ctx.FP16(this.a),
-                f1 = new ctx.FP16(this.b),
-                f2 = new ctx.FP16(this.a),
+            var f0 = new ctx.FP16(this.a), 
+                f1 = new ctx.FP16(this.b), 
+                f2 = new ctx.FP16(this.a), 
                 f3 = new ctx.FP16(0);
 
             f0.sqr();
@@ -440,6 +689,7 @@ var FP48 = function(ctx) {
             this.b.mul(f3);
             this.c.copy(f2);
             this.c.mul(f3);
+			this.stype=ctx.FP.DENSE;
         },
 
         /* this=this^p, where p=Modulus, using Frobenius */
@@ -462,6 +712,7 @@ var FP48 = function(ctx) {
                 this.b.qmul(f); this.b.times_i4(); this.b.times_i2();
                 this.c.qmul(f2); this.c.times_i4(); this.c.times_i4(); this.c.times_i4();
             }
+			this.stype=ctx.FP.DENSE;
         },
 
         /* trace function */
@@ -692,29 +943,31 @@ var FP48 = function(ctx) {
 
         /* set this=this^e */
         pow: function(e) {
-            var e3, w, nb, i, bt;
+            var e1, e3, w, nb, i, bt, sf;
 
-            this.norm();
-            e.norm();
+			sf = new FP48(this);
+            sf.norm();
+			e1 = new ctx.BIG(e);
+            e1.norm();
 
-            e3 = new ctx.BIG(e);
+            e3 = new ctx.BIG(e1);
             e3.pmul(3);
             e3.norm();
 
-            w = new FP48(this);
+            w = new FP48(sf); //w.copy(this);
             nb = e3.nbits();
 
             for (i = nb - 2; i >= 1; i--) {
                 w.usqr();
-                bt = e3.bit(i) - e.bit(i);
+                bt = e3.bit(i) - e1.bit(i);
 
                 if (bt == 1) {
-                    w.mul(this);
+                    w.mul(sf);
                 }
                 if (bt == -1) {
-                    this.conj();
-                    w.mul(this);
-                    this.conj();
+                    sf.conj();
+                    w.mul(sf);
+                    sf.conj();
                 }
             }
             w.reduce();
@@ -799,7 +1052,7 @@ var FP48 = function(ctx) {
             t[i] = w[i + ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 2 * ctx.BIG.MODBYTES];
@@ -809,9 +1062,9 @@ var FP48 = function(ctx) {
             t[i] = w[i + 3 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        d = new ctx.FP2(a, b);
+        d = new ctx.FP2(a, b); //d.bset(a,b);
 
-        ea = new ctx.FP4(c, d);
+        ea = new ctx.FP4(c, d); //e.set(c,d);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 4 * ctx.BIG.MODBYTES];
@@ -821,7 +1074,7 @@ var FP48 = function(ctx) {
             t[i] = w[i + 5 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 6 * ctx.BIG.MODBYTES];
@@ -831,9 +1084,9 @@ var FP48 = function(ctx) {
             t[i] = w[i + 7 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        d = new ctx.FP2(a, b);
+        d = new ctx.FP2(a, b); //d.bset(a,b);
 
-        eb = new ctx.FP4(c, d);
+        eb = new ctx.FP4(c, d); //e.set(c,d);
 
         fa = new ctx.FP8(ea,eb);
 
@@ -845,7 +1098,7 @@ var FP48 = function(ctx) {
             t[i] = w[i + 9 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 10 * ctx.BIG.MODBYTES];
@@ -855,9 +1108,9 @@ var FP48 = function(ctx) {
             t[i] = w[i + 11 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        d = new ctx.FP2(a, b);
+        d = new ctx.FP2(a, b); //d.bset(a,b);
 
-        ea = new ctx.FP4(c, d);
+        ea = new ctx.FP4(c, d); //e.set(c,d);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 12 * ctx.BIG.MODBYTES];
@@ -867,7 +1120,7 @@ var FP48 = function(ctx) {
             t[i] = w[i + 13 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 14 * ctx.BIG.MODBYTES];
@@ -877,9 +1130,9 @@ var FP48 = function(ctx) {
             t[i] = w[i + 15 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        d = new ctx.FP2(a, b);
+        d = new ctx.FP2(a, b); //d.bset(a,b);
 
-        eb = new ctx.FP4(c, d);
+        eb = new ctx.FP4(c, d); //e.set(c,d);
 
         fb = new ctx.FP8(ea,eb);
 
@@ -893,7 +1146,7 @@ var FP48 = function(ctx) {
             t[i] = w[i + 17 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 18 * ctx.BIG.MODBYTES];
@@ -905,7 +1158,7 @@ var FP48 = function(ctx) {
         b = ctx.BIG.fromBytes(t);
         d = new ctx.FP2(a, b);
 
-        ea = new ctx.FP4(c, d);
+        ea = new ctx.FP4(c, d); //e.set(c,d);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 20 * ctx.BIG.MODBYTES];
@@ -915,7 +1168,7 @@ var FP48 = function(ctx) {
             t[i] = w[i + 21 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 22 * ctx.BIG.MODBYTES];
@@ -927,7 +1180,7 @@ var FP48 = function(ctx) {
         b = ctx.BIG.fromBytes(t);
         d = new ctx.FP2(a, b);
 
-        eb = new ctx.FP4(c, d);
+        eb = new ctx.FP4(c, d); //e.set(c,d);
 
         fa = new ctx.FP8(ea,eb);
 
@@ -939,7 +1192,7 @@ var FP48 = function(ctx) {
             t[i] = w[i + 25 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 26 * ctx.BIG.MODBYTES];
@@ -951,7 +1204,7 @@ var FP48 = function(ctx) {
         b = ctx.BIG.fromBytes(t);
         d = new ctx.FP2(a, b);
 
-        ea = new ctx.FP4(c, d);
+        ea = new ctx.FP4(c, d); //e.set(c,d);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 28 * ctx.BIG.MODBYTES];
@@ -961,7 +1214,7 @@ var FP48 = function(ctx) {
             t[i] = w[i + 29 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 30 * ctx.BIG.MODBYTES];
@@ -973,11 +1226,11 @@ var FP48 = function(ctx) {
         b = ctx.BIG.fromBytes(t);
         d = new ctx.FP2(a, b);
 
-        eb = new ctx.FP4(c, d);
+        eb = new ctx.FP4(c, d); //e.set(c,d);
 
         fb = new ctx.FP8(ea,eb);
 
-        f = new ctx.FP16(fa, fb);
+        f = new ctx.FP16(fa, fb); //f.set(c,d);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 32 * ctx.BIG.MODBYTES];
@@ -987,7 +1240,7 @@ var FP48 = function(ctx) {
             t[i] = w[i + 33 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 34 * ctx.BIG.MODBYTES];
@@ -997,9 +1250,9 @@ var FP48 = function(ctx) {
             t[i] = w[i + 35 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        d = new ctx.FP2(a, b);
+        d = new ctx.FP2(a, b); //d.bset(a,b);
 
-        ea = new ctx.FP4(c, d);
+        ea = new ctx.FP4(c, d); //e.set(c,d);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 36 * ctx.BIG.MODBYTES];
@@ -1009,7 +1262,7 @@ var FP48 = function(ctx) {
             t[i] = w[i + 37 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 38 * ctx.BIG.MODBYTES];
@@ -1019,9 +1272,9 @@ var FP48 = function(ctx) {
             t[i] = w[i + 39 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        d = new ctx.FP2(a, b);
+        d = new ctx.FP2(a, b); //d.bset(a,b);
 
-        eb = new ctx.FP4(c, d);
+        eb = new ctx.FP4(c, d); //e.set(c,d);
 
         fa = new ctx.FP8(ea,eb);
 
@@ -1033,7 +1286,7 @@ var FP48 = function(ctx) {
             t[i] = w[i + 41 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 42 * ctx.BIG.MODBYTES];
@@ -1043,9 +1296,9 @@ var FP48 = function(ctx) {
             t[i] = w[i + 43 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        d = new ctx.FP2(a, b);
+        d = new ctx.FP2(a, b); //d.bset(a,b);
 
-        ea = new ctx.FP4(c, d);
+        ea = new ctx.FP4(c, d); //e.set(c,d);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 44 * ctx.BIG.MODBYTES];
@@ -1055,7 +1308,7 @@ var FP48 = function(ctx) {
             t[i] = w[i + 45 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        c = new ctx.FP2(a, b);
+        c = new ctx.FP2(a, b); //c.bset(a,b);
 
         for (i = 0; i < ctx.BIG.MODBYTES; i++) {
             t[i] = w[i + 46 * ctx.BIG.MODBYTES];
@@ -1065,15 +1318,15 @@ var FP48 = function(ctx) {
             t[i] = w[i + 47 * ctx.BIG.MODBYTES];
         }
         b = ctx.BIG.fromBytes(t);
-        d = new ctx.FP2(a, b);
+        d = new ctx.FP2(a, b); //d.bset(a,b);
 
-        eb = new ctx.FP4(c, d);
+        eb = new ctx.FP4(c, d); //e.set(c,d);
 
         fb = new ctx.FP8(ea,eb);
 
-        g = new ctx.FP16(fa, fb);
+        g = new ctx.FP16(fa, fb); //g.set(c,d);
 
-        r = new FP48(e, f, g);
+        r = new FP48(e, f, g); //r.set(e,f,g);
 
         return r;
     };
@@ -1114,14 +1367,14 @@ var FP48 = function(ctx) {
             t[i] = new ctx.BIG(u[i]); t[i].norm();
         }
 
-        g1[0] = new FP48(q[0]);
-        g1[1] = new FP48(g1[0]); g1[1].mul(q[1]);
-        g1[2] = new FP48(g1[0]); g1[2].mul(q[2]);
-        g1[3] = new FP48(g1[1]); g1[3].mul(q[2]);
-        g1[4] = new FP48(q[0]);  g1[4].mul(q[3]);
-        g1[5] = new FP48(g1[1]); g1[5].mul(q[3]);
-        g1[6] = new FP48(g1[2]); g1[6].mul(q[3]);
-        g1[7] = new FP48(g1[3]); g1[7].mul(q[3]);
+        g1[0] = new FP48(q[0]);  // q[0]
+        g1[1] = new FP48(g1[0]); g1[1].mul(q[1]);   // q[0].q[1]
+        g1[2] = new FP48(g1[0]); g1[2].mul(q[2]);   // q[0].q[2]
+        g1[3] = new FP48(g1[1]); g1[3].mul(q[2]);   // q[0].q[1].q[2]
+        g1[4] = new FP48(q[0]);  g1[4].mul(q[3]);   // q[0].q[3]
+        g1[5] = new FP48(g1[1]); g1[5].mul(q[3]);   // q[0].q[1].q[3]
+        g1[6] = new FP48(g1[2]); g1[6].mul(q[3]);   // q[0].q[2].q[3]
+        g1[7] = new FP48(g1[3]); g1[7].mul(q[3]);   // q[0].q[1].q[2].q[3]
 
         //  Use Frobenius
         fa.rcopy(ctx.ROM_FIELD.Fra);
diff --git a/src/fp8.js b/src/fp8.js
index 371d253..21aa7bd 100644
--- a/src/fp8.js
+++ b/src/fp8.js
@@ -50,7 +50,6 @@ var FP8 = function(ctx) {
 
         /* test this==0 ? */
         iszilch: function() {
-            this.reduce();
             return (this.a.iszilch() && this.b.iszilch());
         },
 
@@ -123,7 +122,7 @@ var FP8 = function(ctx) {
         /* this=-this */
         neg: function() {
             this.norm();
-            var m = new ctx.FP4(this.a),
+            var m = new ctx.FP4(this.a), 
                 t = new ctx.FP4(0);
 
             m.add(this.b);
@@ -156,7 +155,7 @@ var FP8 = function(ctx) {
 
         /* this-=x */
         sub: function(x) {
-            var m = new FP8(x);
+            var m = new FP8(x); 
             m.neg();
             this.add(m);
         },
@@ -180,9 +179,9 @@ var FP8 = function(ctx) {
 
         /* this*=this */
         sqr: function() {
-            var t1 = new ctx.FP4(this.a),
-                t2 = new ctx.FP4(this.b),
-                t3 = new ctx.FP4(this.a);
+            var t1 = new ctx.FP4(this.a), 
+                t2 = new ctx.FP4(this.b), 
+                t3 = new ctx.FP4(this.a); 
 
             t3.mul(this.b);
             t1.add(this.b);
@@ -211,10 +210,10 @@ var FP8 = function(ctx) {
 
         /* this*=y */
         mul: function(y) {
-            var t1 = new ctx.FP4(this.a),
-                t2 = new ctx.FP4(this.b),
+            var t1 = new ctx.FP4(this.a), 
+                t2 = new ctx.FP4(this.b), 
                 t3 = new ctx.FP4(0),
-                t4 = new ctx.FP4(this.b);
+                t4 = new ctx.FP4(this.b); 
 
             t1.mul(y.a);
             t2.mul(y.b);
@@ -230,7 +229,7 @@ var FP8 = function(ctx) {
             t3.copy(t1);
             t3.neg();
             t4.add(t3);
-
+ 
             t3.copy(t2);
             t3.neg();
             this.b.copy(t4);
@@ -252,8 +251,8 @@ var FP8 = function(ctx) {
         inverse: function() {
             this.norm();
 
-            var t1 = new ctx.FP4(this.a),
-                t2 = new ctx.FP4(this.b);
+            var t1 = new ctx.FP4(this.a), 
+                t2 = new ctx.FP4(this.b); 
 
             t1.sqr();
             t2.sqr();
@@ -295,14 +294,12 @@ var FP8 = function(ctx) {
 
         /* this=this^e */
         pow: function(e) {
-            this.norm();
-            e.norm();
-
-            var w = new FP8(this),
-                z = new ctx.BIG(e),
+            var w = new FP8(this), 
+                z = new ctx.BIG(e), 
                 r = new FP8(1),
                 bt;
-
+			w.norm();
+			z.norm();
             for (;;) {
                 bt = z.parity();
                 z.fshr(1);
@@ -324,8 +321,8 @@ var FP8 = function(ctx) {
 
         /* XTR xtr_a function */
         xtr_A: function(w, y, z) {
-            var r = new FP8(w),
-                t = new FP8(w);
+            var r = new FP8(w), 
+                t = new FP8(w); 
 
             r.sub(y);
             r.norm();
@@ -344,29 +341,31 @@ var FP8 = function(ctx) {
 
         /* XTR xtr_d function */
         xtr_D: function() {
-            var w = new FP8(this);
+            var w = new FP8(this); //w.copy(this);
             this.sqr();
             w.conj();
-            w.add(w);
+            w.add(w); 
             this.sub(w);
             this.reduce();
         },
 
         /* r=x^n using XTR method on traces of FP12s */
         xtr_pow: function(n) {
+			var sf = new FP8(this);
+			sf.norm();
             var a = new FP8(3),
-                b = new FP8(this),
+                b = new FP8(sf),
                 c = new FP8(b),
                 t = new FP8(0),
                 r = new FP8(0),
                 par, v, nb, i;
-
+	
             c.xtr_D();
 
-            n.norm();
+            
             par = n.parity();
             v = new ctx.BIG(n);
-
+			v.norm();
             v.fshr(1);
 
             if (par === 0) {
@@ -378,10 +377,10 @@ var FP8 = function(ctx) {
             for (i = nb - 1; i >= 0; i--) {
                 if (v.bit(i) != 1) {
                     t.copy(b);
-                    this.conj();
+                    sf.conj();
                     c.conj();
-                    b.xtr_A(a, this, c);
-                    this.conj();
+                    b.xtr_A(a, sf, c);
+                    sf.conj();
                     c.copy(t);
                     c.xtr_D();
                     a.xtr_D();
@@ -390,7 +389,7 @@ var FP8 = function(ctx) {
                     t.conj();
                     a.copy(b);
                     a.xtr_D();
-                    b.xtr_A(c, this, t);
+                    b.xtr_A(c, sf, t);
                     c.xtr_D();
                 }
             }
@@ -407,21 +406,22 @@ var FP8 = function(ctx) {
 
         /* r=ck^a.cl^n using XTR double exponentiation method on traces of FP12s. See Stam thesis. */
         xtr_pow2: function(ck, ckml, ckm2l, a, b) {
-            a.norm();
-            b.norm();
 
-            var e = new ctx.BIG(a),
-                d = new ctx.BIG(b),
+            var e = new ctx.BIG(a), 
+                d = new ctx.BIG(b), 
                 w = new ctx.BIG(0),
-                cu = new FP8(ck),
-                cv = new FP8(this),
-                cumv = new FP8(ckml),
-                cum2v = new FP8(ckm2l),
+                cu = new FP8(ck), 
+                cv = new FP8(this), 
+                cumv = new FP8(ckml), 
+                cum2v = new FP8(ckm2l), 
                 r = new FP8(0),
                 t = new FP8(0),
                 f2 = 0,
                 i;
 
+            e.norm();
+            d.norm();
+
             while (d.parity() === 0 && e.parity() === 0) {
                 d.fshr(1);
                 e.fshr(1);
diff --git a/src/gcm.js b/src/gcm.js
index 1e67c71..0591972 100644
--- a/src/gcm.js
+++ b/src/gcm.js
@@ -41,9 +41,8 @@ var GCM = function(ctx) {
 
     var GCM = function() {
         this.table = new Array(128);
-        /* 2k bytes */
         for (var i = 0; i < 128; i++) {
-            this.table[i] = new Array(4);
+            this.table[i] = new Array(4); /* 2k bytes */
         }
         this.stateX = [];
         this.Y_0 = [];
@@ -83,14 +82,12 @@ var GCM = function(ctx) {
                 }
 
                 if (c !== 0) {
-                    /* irreducible polynomial */
-                    this.table[i][0] ^= 0xE1000000;
+                    this.table[i][0] ^= 0xE1000000; /* irreducible polynomial */
                 }
             }
         },
 
-        /* gf2m mul - Z=H*X mod 2^128 */
-        gf2mul: function() {
+        gf2mul: function() { /* gf2m mul - Z=H*X mod 2^128 */
             var P = [],
                 b = [],
                 i, j, m, k, c;
@@ -124,8 +121,7 @@ var GCM = function(ctx) {
             }
         },
 
-        /* Finish off GHASH */
-        wrap: function() {
+        wrap: function() { /* Finish off GHASH */
             var F = [],
                 L = [],
                 b = [],
@@ -153,8 +149,7 @@ var GCM = function(ctx) {
         },
 
         /* Initialize GCM mode */
-        /* iv size niv is usually 12 bytes (96 bits). ctx.AES key size nk can be 16,24 or 32 bytes */
-        init: function(nk, key, niv, iv) {
+        init: function(nk, key, niv, iv) { /* iv size niv is usually 12 bytes (96 bits). ctx.AES key size nk can be 16,24 or 32 bytes */
             var H = [],
                 b = [],
                 i;
@@ -165,13 +160,11 @@ var GCM = function(ctx) {
             }
 
             this.a.init(ctx.AES.ECB, nk, key, iv);
-            /* E(K,0) */
-            this.a.ecb_encrypt(H);
+            this.a.ecb_encrypt(H); /* E(K,0) */
             this.precompute(H);
 
             this.lenA[0] = this.lenC[0] = this.lenA[1] = this.lenC[1] = 0;
 
-            /* initialize IV */
             if (niv == 12) {
                 for (i = 0; i < 12; i++) {
                     this.a.f[i] = iv[i];
@@ -181,15 +174,14 @@ var GCM = function(ctx) {
                 this.a.f[12] = b[0];
                 this.a.f[13] = b[1];
                 this.a.f[14] = b[2];
-                this.a.f[15] = b[3];
+                this.a.f[15] = b[3]; /* initialise IV */
 
                 for (i = 0; i < 16; i++) {
                     this.Y_0[i] = this.a.f[i];
                 }
             } else {
                 this.status = GCM.ACCEPTING_CIPHER;
-                /* GHASH(H,0,IV) */
-                this.ghash(iv, niv);
+                this.ghash(iv, niv); /* GHASH(H,0,IV) */
                 this.wrap();
 
                 for (i = 0; i < 16; i++) {
@@ -205,8 +197,7 @@ var GCM = function(ctx) {
         },
 
         /* Add Header data - included but not encrypted */
-        /* len is length of header */
-        add_header: function(header, len) {
+        add_header: function(header, len) { /* Add some header. Won't be encrypted, but will be authenticated. len is length of header */
             var i, j = 0;
 
             if (this.status != GCM.ACCEPTING_HEADER) {
@@ -281,7 +272,6 @@ var GCM = function(ctx) {
             }
 
             while (j < len) {
-                /* increment counter */
                 b[0] = this.a.f[12];
                 b[1] = this.a.f[13];
                 b[2] = this.a.f[14];
@@ -292,14 +282,13 @@ var GCM = function(ctx) {
                 this.a.f[12] = b[0];
                 this.a.f[13] = b[1];
                 this.a.f[14] = b[2];
-                this.a.f[15] = b[3];
+                this.a.f[15] = b[3]; /* increment counter */
 
                 for (i = 0; i < 16; i++) {
                     B[i] = this.a.f[i];
                 }
 
-                /* encrypt it  */
-                this.a.ecb_encrypt(B);
+                this.a.ecb_encrypt(B); /* encrypt it  */
 
                 for (i = 0; i < 16 && j < len; i++) {
                     cipher[j] = (plain[j] ^ B[i]);
@@ -339,7 +328,6 @@ var GCM = function(ctx) {
             }
 
             while (j < len) {
-                /* increment counter */
                 b[0] = this.a.f[12];
                 b[1] = this.a.f[13];
                 b[2] = this.a.f[14];
@@ -350,14 +338,13 @@ var GCM = function(ctx) {
                 this.a.f[12] = b[0];
                 this.a.f[13] = b[1];
                 this.a.f[14] = b[2];
-                this.a.f[15] = b[3];
+                this.a.f[15] = b[3]; /* increment counter */
 
                 for (i = 0; i < 16; i++) {
                     B[i] = this.a.f[i];
                 }
 
-                /* encrypt it  */
-                this.a.ecb_encrypt(B);
+                this.a.ecb_encrypt(B); /* encrypt it  */
 
                 for (i = 0; i < 16 && j < len; i++) {
                     oc = cipher[j];
@@ -383,15 +370,14 @@ var GCM = function(ctx) {
         },
 
         /* Finish and extract Tag */
-        finish: function(extract) {
+        finish: function(extract) { /* Finish off GHASH and extract tag (MAC) */
             var tag = [],
                 i;
 
             this.wrap();
             /* extract tag */
             if (extract) {
-                /* E(K,Y0) */
-                this.a.ecb_encrypt(this.Y_0);
+                this.a.ecb_encrypt(this.Y_0); /* E(K,Y0) */
 
                 for (i = 0; i < 16; i++) {
                     this.Y_0[i] ^= this.stateX[i];
@@ -411,13 +397,11 @@ var GCM = function(ctx) {
 
     };
 
-    /* pack 4 bytes into a 32-bit Word */
-    GCM.pack = function(b) {
+    GCM.pack = function(b) { /* pack 4 bytes into a 32-bit Word */
         return (((b[0]) & 0xff) << 24) | ((b[1] & 0xff) << 16) | ((b[2] & 0xff) << 8) | (b[3] & 0xff);
     };
 
-    /* unpack bytes from a word */
-    GCM.unpack = function(a) {
+    GCM.unpack = function(a) { /* unpack bytes from a word */
         var b = [];
 
         b[3] = (a & 0xff);
diff --git a/src/hash256.js b/src/hash256.js
index f08016c..99b36f2 100644
--- a/src/hash256.js
+++ b/src/hash256.js
@@ -28,9 +28,7 @@ var HASH256 = function() {
     };
 
     HASH256.prototype = {
-
-        /* basic transformation step */
-        transform: function() {
+        transform: function() { /* basic transformation step */
             var a, b, c, d, e, f, g, hh, t1, t2, j;
 
             for (j = 16; j < 64; j++) {
@@ -46,8 +44,7 @@ var HASH256 = function() {
             g = this.h[6];
             hh = this.h[7];
 
-            /* 64 times - mush it up */
-            for (j = 0; j < 64; j++) {
+            for (j = 0; j < 64; j++) { /* 64 times - mush it up */
                 t1 = (hh + HASH256.Sig1(e) + HASH256.Ch(e, f, g) + HASH256.HK[j] + this.w[j]) | 0;
                 t2 = (HASH256.Sig0(a) + HASH256.Maj(a, b, c)) | 0;
                 hh = g;
@@ -71,8 +68,8 @@ var HASH256 = function() {
 
         },
 
-        /* Initialize Hash function */
-        init: function() {
+        /* Initialise Hash function */
+        init: function() { /* initialise */
             var i;
 
             for (i = 0; i < 64; i++) {
@@ -90,7 +87,7 @@ var HASH256 = function() {
         },
 
         /* process a single byte */
-        process: function(byt) {
+        process: function(byt) { /* process the next message byte */
             var cnt;
 
             cnt = (this.length[0] >>> 5) % 16;
@@ -123,8 +120,7 @@ var HASH256 = function() {
             this.process(n & 0xff);
         },
 
-        /* pad message and finish - supply digest */
-        hash: function() {
+        hash: function() { /* pad message and finish - supply digest */
             var digest = [],
                 len0, len1, i;
 
@@ -140,8 +136,7 @@ var HASH256 = function() {
             this.w[15] = len0;
             this.transform();
 
-            /* convert to bytes */
-            for (i = 0; i < HASH256.len; i++) {
+            for (i = 0; i < HASH256.len; i++) { /* convert to bytes */
                 digest[i] = ((this.h[i >>> 2] >> (8 * (3 - i % 4))) & 0xff);
             }
             this.init();
diff --git a/src/hash384.js b/src/hash384.js
index 95c2c3e..9c2941d 100644
--- a/src/hash384.js
+++ b/src/hash384.js
@@ -28,9 +28,7 @@ var HASH384 = function(ctx) {
     };
 
     HASH384.prototype = {
-
-        /* basic transformation step */
-        transform: function() {
+        transform: function() { /* basic transformation step */
             var a, b, c, d, e, f, g, hh, t1, t2, j;
 
             for (j = 16; j < 80; j++) {
@@ -46,8 +44,7 @@ var HASH384 = function(ctx) {
             g = this.h[6].copy();
             hh = this.h[7].copy();
 
-            /* 80 times - mush it up */
-            for (j = 0; j < 80; j++) {
+            for (j = 0; j < 80; j++) { /* 80 times - mush it up */
                 t1 = hh.copy();
                 t1.add(HASH384.Sig1(e)).add(HASH384.Ch(e, f, g)).add(HASH384.HK[j]).add(this.w[j]);
 
@@ -76,8 +73,8 @@ var HASH384 = function(ctx) {
             this.h[7].add(hh);
         },
 
-        /* Initialize Hash function */
-        init: function() {
+        /* Initialise Hash function */
+        init: function() { /* initialise */
             var i;
 
             for (i = 0; i < 80; i++) {
@@ -96,7 +93,7 @@ var HASH384 = function(ctx) {
         },
 
         /* process a single byte */
-        process: function(byt) {
+        process: function(byt) { /* process the next message byte */
             var cnt, e;
 
             cnt = (this.length[0].bot >>> 6) % 16;
@@ -131,8 +128,7 @@ var HASH384 = function(ctx) {
             this.process(n & 0xff);
         },
 
-        /* pad message and finish - supply digest */
-        hash: function() {
+        hash: function() { /* pad message and finish - supply digest */
             var digest = [],
                 len0, len1,
                 i;
@@ -148,8 +144,7 @@ var HASH384 = function(ctx) {
             this.w[15] = len0;
             this.transform();
 
-            /* convert to bytes */
-            for (i = 0; i < HASH384.len; i++) {
+            for (i = 0; i < HASH384.len; i++) { /* convert to bytes */
                 digest[i] = HASH384.R(8 * (7 - i % 8), this.h[i >>> 3]).bot & 0xff;
             }
 
diff --git a/src/hash512.js b/src/hash512.js
index 39d58fa..eb468a6 100644
--- a/src/hash512.js
+++ b/src/hash512.js
@@ -29,8 +29,7 @@ var HASH512 = function(ctx) {
 
     HASH512.prototype = {
 
-        /* basic transformation step */
-        transform: function() {
+        transform: function() { /* basic transformation step */
             var a, b, c, d, e, f, g, hh, t1, t2, j;
 
             for (j = 16; j < 80; j++) {
@@ -46,8 +45,7 @@ var HASH512 = function(ctx) {
             g = this.h[6].copy();
             hh = this.h[7].copy();
 
-            /* 80 times - mush it up */
-            for (j = 0; j < 80; j++) {
+            for (j = 0; j < 80; j++) { /* 80 times - mush it up */
                 t1 = hh.copy();
                 t1.add(HASH512.Sig1(e)).add(HASH512.Ch(e, f, g)).add(HASH512.HK[j]).add(this.w[j]);
 
@@ -76,8 +74,8 @@ var HASH512 = function(ctx) {
             this.h[7].add(hh);
         },
 
-        /* Initialize Hash function */
-        init: function() {
+        /* Initialise Hash function */
+        init: function() { /* initialise */
             var i;
 
             for (i = 0; i < 80; i++) {
@@ -97,7 +95,7 @@ var HASH512 = function(ctx) {
         },
 
         /* process a single byte */
-        process: function(byt) {
+        process: function(byt) { /* process the next message byte */
             var cnt, e;
 
             cnt = (this.length[0].bot >>> 6) % 16;
@@ -132,8 +130,7 @@ var HASH512 = function(ctx) {
             this.process(n & 0xff);
         },
 
-        /* pad message and finish - supply digest */
-        hash: function() {
+        hash: function() { /* pad message and finish - supply digest */
             var digest = [],
                 len0, len1, i;
 
@@ -149,8 +146,7 @@ var HASH512 = function(ctx) {
             this.w[15] = len0;
             this.transform();
 
-            /* convert to bytes */
-            for (i = 0; i < HASH512.len; i++) {
+            for (i = 0; i < HASH512.len; i++) { /* convert to bytes */
                 digest[i] = HASH512.R(8 * (7 - i % 8), this.h[i >>> 3]).bot & 0xff;
             }
 
diff --git a/src/mpin.js b/src/mpin.js
index f439773..8988cc5 100644
--- a/src/mpin.js
+++ b/src/mpin.js
@@ -223,7 +223,7 @@ var MPIN = function(ctx) {
                 u.dec(1);
                 u.norm();
                 r++;
-                R.setxi(u, s);
+                R.setxi(u, s); 
                 if (!R.is_infinity()) {
                     break;
                 }
@@ -336,7 +336,7 @@ var MPIN = function(ctx) {
 
             P.add(Q);
 
-            P.toBytes(R);
+            P.toBytes(R,false);
 
             return 0;
         },
@@ -395,7 +395,7 @@ var MPIN = function(ctx) {
             R = R.pinmul(factor, facbits);
             P.sub(R);
 
-            P.toBytes(TOKEN);
+            P.toBytes(TOKEN,false);
 
             return 0;
         },
@@ -416,7 +416,7 @@ var MPIN = function(ctx) {
             R = R.pinmul(factor, facbits);
             P.add(R);
 
-            P.toBytes(TOKEN);
+            P.toBytes(TOKEN,false);
 
             return 0;
         },
@@ -462,7 +462,7 @@ var MPIN = function(ctx) {
                 P = ctx.ECP.mapit(G);
             }
 
-            ctx.PAIR.G1mul(P, x).toBytes(W);
+            ctx.PAIR.G1mul(P, x).toBytes(W,false);
 
             return 0;
         },
@@ -480,7 +480,7 @@ var MPIN = function(ctx) {
                 s = ctx.BIG.fromBytes(S);
 
             P = ctx.PAIR.G1mul(P, s);
-            P.toBytes(CTT);
+            P.toBytes(CTT,false);
 
             return 0;
         },
@@ -491,8 +491,6 @@ var MPIN = function(ctx) {
                 x, P, T, W, h;
 
             r.rcopy(ctx.ROM_CURVE.CURVE_Order);
-
-            //  var q=new ctx.BIG(0); q.rcopy(ctx.ROM_FIELD.Modulus);
             if (rng !== null) {
                 x = ctx.BIG.randomnum(r, rng);
                 x.toBytes(X);
@@ -524,7 +522,7 @@ var MPIN = function(ctx) {
 
                 if (xID != null) {
                     P = ctx.PAIR.G1mul(P, x);
-                    P.toBytes(xID);
+                    P.toBytes(xID,false);
                     W = ctx.PAIR.G1mul(W, x);
                     P.add(W);
                 } else {
@@ -533,16 +531,16 @@ var MPIN = function(ctx) {
                 }
 
                 if (xCID != null) {
-                    P.toBytes(xCID);
+                    P.toBytes(xCID,false);
                 }
             } else {
                 if (xID != null) {
                     P = ctx.PAIR.G1mul(P, x);
-                    P.toBytes(xID);
+                    P.toBytes(xID,false);
                 }
             }
 
-            T.toBytes(SEC);
+            T.toBytes(SEC,false);
 
             return 0;
         },
@@ -566,8 +564,7 @@ var MPIN = function(ctx) {
 
             P = ctx.PAIR.G1mul(P, px);
             P.neg();
-            P.toBytes(SEC);
-
+            P.toBytes(SEC,false);
             return 0;
         },
 
@@ -577,12 +574,12 @@ var MPIN = function(ctx) {
                 P = ctx.ECP.mapit(h),
                 R;
 
-            P.toBytes(HID);
+            P.toBytes(HID,false);
             if (date !== 0) {
                 h = this.hashit(sha, date, h);
                 R = ctx.ECP.mapit(h);
                 P.add(R);
-                P.toBytes(HTID);
+                P.toBytes(HTID,false);
             }
         },
 
@@ -635,7 +632,6 @@ var MPIN = function(ctx) {
 
             P = ctx.PAIR.G1mul(P, y);
             P.add(R);
-            P.affine();
             R = ctx.ECP.fromBytes(mSEC);
             if (R.is_infinity()) {
                 return this.INVALID_POINT;
@@ -661,7 +657,6 @@ var MPIN = function(ctx) {
 
                         P = ctx.PAIR.G1mul(P, y);
                         P.add(R);
-                        P.affine();
                     }
                     g = ctx.PAIR.ate(Q, P);
                     g = ctx.PAIR.fexp(g);
@@ -671,7 +666,6 @@ var MPIN = function(ctx) {
 
                 return this.BAD_PIN;
             }
-
             return 0;
         },
 
@@ -960,7 +954,7 @@ var MPIN = function(ctx) {
             h = ctx.BIG.fromBytes(H);
             A = ctx.PAIR.G1mul(A, h);
             R.add(A);
-            R.affine();
+            //R.affine();
 
             U = ctx.PAIR.G1mul(U, w);
             g = ctx.PAIR.ate(sQ, R);
diff --git a/src/mpin192.js b/src/mpin192.js
index a6b0e06..c198a46 100644
--- a/src/mpin192.js
+++ b/src/mpin192.js
@@ -129,6 +129,7 @@ var MPIN192 = function(ctx) {
                 t[i] = w[i - 7 * this.EFS];
             }
 
+
             U.getX().toBytes(w);
             for (i = 8 * this.EFS; i < 9 * this.EFS; i++) {
                 t[i] = w[i - 8 * this.EFS];
@@ -240,7 +241,7 @@ var MPIN192 = function(ctx) {
                 u.dec(1);
                 u.norm();
                 r++;
-                R.setxi(u, s);
+                R.setxi(u, s); 
                 if (!R.is_infinity()) {
                     break;
                 }
@@ -508,8 +509,6 @@ var MPIN192 = function(ctx) {
                 x, P, T, W, h;
 
             r.rcopy(ctx.ROM_CURVE.CURVE_Order);
-
-            //  var q=new ctx.BIG(0); q.rcopy(ctx.ROM_FIELD.Modulus);
             if (rng !== null) {
                 x = ctx.BIG.randomnum(r, rng);
                 x.toBytes(X);
@@ -652,7 +651,7 @@ var MPIN192 = function(ctx) {
 
             P = ctx.PAIR192.G1mul(P, y);
             P.add(R);
-            P.affine();
+            //P.affine();
             R = ctx.ECP.fromBytes(mSEC);
             if (R.is_infinity()) {
                 return this.INVALID_POINT;
@@ -678,7 +677,6 @@ var MPIN192 = function(ctx) {
 
                         P = ctx.PAIR192.G1mul(P, y);
                         P.add(R);
-                        P.affine();
                     }
                     g = ctx.PAIR192.ate(Q, P);
                     g = ctx.PAIR192.fexp(g);
@@ -977,7 +975,6 @@ var MPIN192 = function(ctx) {
             h = ctx.BIG.fromBytes(H);
             A = ctx.PAIR192.G1mul(A, h);
             R.add(A);
-            R.affine();
 
             U = ctx.PAIR192.G1mul(U, w);
             g = ctx.PAIR192.ate(sQ, R);
diff --git a/src/mpin256.js b/src/mpin256.js
index 15b1041..bf985f7 100644
--- a/src/mpin256.js
+++ b/src/mpin256.js
@@ -275,7 +275,7 @@ var MPIN256 = function(ctx) {
                 u.dec(1);
                 u.norm();
                 r++;
-                R.setxi(u, s); //=new ECP(u,s);
+                R.setxi(u, s); 
                 if (!R.is_infinity()) {
                     break;
                 }
@@ -544,7 +544,6 @@ var MPIN256 = function(ctx) {
 
             r.rcopy(ctx.ROM_CURVE.CURVE_Order);
 
-            //  var q=new ctx.BIG(0); q.rcopy(ctx.ROM_FIELD.Modulus);
             if (rng !== null) {
                 x = ctx.BIG.randomnum(r, rng);
                 x.toBytes(X);
@@ -619,7 +618,7 @@ var MPIN256 = function(ctx) {
             P = ctx.PAIR256.G1mul(P, px);
             P.neg();
             P.toBytes(SEC,false);
-
+ 
             return 0;
         },
 
@@ -687,7 +686,6 @@ var MPIN256 = function(ctx) {
 
             P = ctx.PAIR256.G1mul(P, y);
             P.add(R);
-            P.affine();
             R = ctx.ECP.fromBytes(mSEC);
             if (R.is_infinity()) {
                 return this.INVALID_POINT;
@@ -713,7 +711,6 @@ var MPIN256 = function(ctx) {
 
                         P = ctx.PAIR256.G1mul(P, y);
                         P.add(R);
-                        P.affine();
                     }
                     g = ctx.PAIR256.ate(Q, P);
                     g = ctx.PAIR256.fexp(g);
@@ -958,7 +955,6 @@ var MPIN256 = function(ctx) {
 
             r = new ctx.BIG(0);
             r.rcopy(ctx.ROM_CURVE.CURVE_Order);
-
             z.add(h);
             z.mod(r);
 
@@ -1012,7 +1008,6 @@ var MPIN256 = function(ctx) {
             h = ctx.BIG.fromBytes(H);
             A = ctx.PAIR256.G1mul(A, h);
             R.add(A);
-            R.affine();
 
             U = ctx.PAIR256.G1mul(U, w);
             g = ctx.PAIR256.ate(sQ, R);
diff --git a/src/pair.js b/src/pair.js
index 1a55e54..36e60d0 100644
--- a/src/pair.js
+++ b/src/pair.js
@@ -29,8 +29,7 @@ var PAIR = function(ctx) {
                 X1, Y1, T1, T2,
                 a, b;
 
-            if (A == B) {
-                /* Doubling */
+            if (A == B) { /* Doubling */
                 XX = new ctx.FP2(A.getx());
                 YY = new ctx.FP2(A.gety());
                 ZZ = new ctx.FP2(A.getz());
@@ -77,8 +76,7 @@ var PAIR = function(ctx) {
                 }
 
                 A.dbl();
-            } else {
-                /* Addition */
+            } else { /* Addition */
                 X1 = new ctx.FP2(A.getx()); // X1
                 Y1 = new ctx.FP2(A.gety()); // Y1
                 T1 = new ctx.FP2(A.getz()); // Z1
@@ -124,19 +122,121 @@ var PAIR = function(ctx) {
             }
 
             r.set(a, b, c);
+			r.settype(ctx.FP.SPARSER);
 
             return r;
         },
 
+/* prepare for multi-pairing */
+		initmp: function() {
+			var r=[];
+			for (var i=0;i<ctx.ECP.ATE_BITS;i++)
+				r[i] = new ctx.FP12(1);
+			return r;
+		},
+
+/* basic Miller loop */
+		miller: function(r) {
+			var res=new ctx.FP12(1);
+			for (var i=ctx.ECP.ATE_BITS-1; i>=1; i--)
+			{
+				res.sqr();
+				res.ssmul(r[i]); 
+			}
+
+			if (ctx.ECP.SIGN_OF_X==ctx.ECP.NEGATIVEX)
+				res.conj();
+			res.ssmul(r[0]);
+
+			return res;
+		},
+
+/* Accumulate another set of line functions for n-pairing */
+		another: function(r,P1,Q1) {
+
+			var f;
+			var n=new ctx.BIG(0);
+			var n3=new ctx.BIG(0);
+			var K=new ctx.ECP2();
+			var lv,lv2;
+			var bt;
+
+// P is needed in affine form for line function, Q for (Qx,Qy) extraction
+			var P=new ctx.ECP2(); P.copy(P1); P.affine();
+			var Q=new ctx.ECP(); Q.copy(Q1); Q.affine();
+
+			P.affine();
+			Q.affine();
+
+			if (ctx.ECP.CURVE_PAIRING_TYPE==ctx.ECP.BN)
+			{
+                var fa = new ctx.BIG(0);
+                fa.rcopy(ctx.ROM_FIELD.Fra);
+                var fb = new ctx.BIG(0);
+                fb.rcopy(ctx.ROM_FIELD.Frb);
+                f = new ctx.FP2(fa, fb); 
+				if (ctx.ECP.SEXTIC_TWIST==ctx.ECP.M_TYPE)
+				{
+					f.inverse();
+					f.norm();
+				}
+			}
+
+			var Qx=new ctx.FP(Q.getx());
+			var Qy=new ctx.FP(Q.gety());
+
+			var A=new ctx.ECP2();
+			A.copy(P);
+
+			var MP=new ctx.ECP2();
+			MP.copy(P); MP.neg();
+
+			var nb=PAIR.lbits(n3,n);
+
+			for (var i=nb-2;i>=1;i--)
+			{
+				lv=PAIR.line(A,A,Qx,Qy);
+
+				bt=n3.bit(i)-n.bit(i); 
+				if (bt==1)
+				{
+					lv2=PAIR.line(A,P,Qx,Qy);
+					lv.smul(lv2);
+				}
+				if (bt==-1)
+				{
+					lv2=PAIR.line(A,MP,Qx,Qy);
+					lv.smul(lv2);
+				}
+				r[i].ssmul(lv);
+			}
+
+/* R-ate fixup required for BN curves */
+			if (ctx.ECP.CURVE_PAIRING_TYPE==ctx.ECP.BN)
+			{
+				if (ctx.ECP.SIGN_OF_X==ctx.ECP.NEGATIVEX)
+				{
+					A.neg();
+				}
+				K.copy(P);
+				K.frob(f);
+				lv=PAIR.line(A,K,Qx,Qy);
+				K.frob(f);
+				K.neg();
+				lv2=PAIR.line(A,K,Qx,Qy);
+				lv.smul(lv2);
+				r[0].ssmul(lv);
+			}	 
+		},
+
         /* Optimal R-ate pairing */
-        ate: function(P, Q) {
-            var fa, fb, f, x, n, n3, K, lv,
-                Qx, Qy, A, r, nb, bt,
+        ate: function(P1, Q1) {
+            var fa, fb, f, x, n, n3, K, lv, lv2,
+                Qx, Qy, A, NP, r, nb, bt,
                 i;
 
-            x = new ctx.BIG(0);
-            x.rcopy(ctx.ROM_CURVE.CURVE_Bnx);
-            n = new ctx.BIG(x);
+            n = new ctx.BIG(0);
+			n3 = new ctx.BIG(0);
             K = new ctx.ECP2();
 
             if (ctx.ECP.CURVE_PAIRING_TYPE == ctx.ECP.BN) {
@@ -145,55 +245,44 @@ var PAIR = function(ctx) {
                 fa.rcopy(ctx.ROM_FIELD.Fra);
                 fb = new ctx.BIG(0);
                 fb.rcopy(ctx.ROM_FIELD.Frb);
-                f = new ctx.FP2(fa, fb);
+                f = new ctx.FP2(fa, fb); 
 
                 if (ctx.ECP.SEXTIC_TWIST == ctx.ECP.M_TYPE) {
                     f.inverse();
                     f.norm();
                 }
-
-                n.pmul(6);
-                if (ctx.ECP.SIGN_OF_X == ctx.ECP.POSITIVEX) {
-                    n.inc(2);
-                } else {
-                    n.dec(2);
-                }
-            } else {
-                n.copy(x);
             }
-            n.norm();
 
-            n3 = new ctx.BIG(n);
-            n3.pmul(3);
-            n3.norm();
+			var P=new ctx.ECP2(); P.copy(P1); P.affine();
+			var Q=new ctx.ECP(); Q.copy(Q1); Q.affine();
 
-            Qx = new ctx.FP(Q.getx());
-            Qy = new ctx.FP(Q.gety());
+            Qx = new ctx.FP(Q.getx()); 
+            Qy = new ctx.FP(Q.gety()); 
 
             A = new ctx.ECP2();
             r = new ctx.FP12(1);
-
             A.copy(P);
-            nb = n3.nbits();
+
+			NP = new ctx.ECP2();
+			NP.copy(P);
+			NP.neg();
+
+            nb = PAIR.lbits(n3,n);
 
             for (i = nb - 2; i >= 1; i--) {
                 r.sqr();
                 lv = PAIR.line(A, A, Qx, Qy);
-
-                r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-
                 bt=n3.bit(i)-n.bit(i);
 
                 if (bt == 1) {
-                    lv = PAIR.line(A, P, Qx, Qy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
+                    lv2 = PAIR.line(A, P, Qx, Qy);
+                    lv.smul(lv2);
                 }
                 if (bt == -1) {
-                    P.neg();
-                    lv = PAIR.line(A, P, Qx, Qy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-                    P.neg();
+                    lv2 = PAIR.line(A, NP, Qx, Qy);
+                    lv.smul(lv2);
                 }
+                r.ssmul(lv);
             }
 
             if (ctx.ECP.SIGN_OF_X == ctx.ECP.NEGATIVEX) {
@@ -210,27 +299,25 @@ var PAIR = function(ctx) {
                 K.frob(f);
 
                 lv = PAIR.line(A, K, Qx, Qy);
-                r.smul(lv,ctx.ECP.SEXTIC_TWIST);
                 K.frob(f);
                 K.neg();
-                lv = PAIR.line(A, K, Qx, Qy);
-                r.smul(lv,ctx.ECP.SEXTIC_TWIST);
+                lv2 = PAIR.line(A, K, Qx, Qy);
+				lv.smul(lv2);
+                r.ssmul(lv);
             }
 
             return r;
         },
 
         /* Optimal R-ate double pairing e(P,Q).e(R,S) */
-        ate2: function(P, Q, R, S) {
-            var fa, fb, f, x, n, n3, K, lv,
-                Qx, Qy, Sx, Sy, A, B, r, nb, bt,
+	
+        ate2: function(P1, Q1, R1, S1) {
+            var fa, fb, f, x, n, n3, K, lv, lv2,
+                Qx, Qy, Sx, Sy, A, B, NP,NR,r, nb, bt,
                 i;
 
-
-            x = new ctx.BIG(0);
-            x.rcopy(ctx.ROM_CURVE.CURVE_Bnx);
-
-            n = new ctx.BIG(x);
+            n = new ctx.BIG(0);
+			n3 = new ctx.BIG(0);
             K = new ctx.ECP2();
 
             if (ctx.ECP.CURVE_PAIRING_TYPE == ctx.ECP.BN) {
@@ -244,27 +331,19 @@ var PAIR = function(ctx) {
                     f.inverse();
                     f.norm();
                 }
+            } 
 
-                n.pmul(6);
-                if (ctx.ECP.SIGN_OF_X == ctx.ECP.POSITIVEX) {
-                    n.inc(2);
-                } else {
-                    n.dec(2);
-                }
-            } else {
-                n.copy(x);
-            }
-            n.norm();
+			var P=new ctx.ECP2(); P.copy(P1); P.affine();
+			var Q=new ctx.ECP(); Q.copy(Q1); Q.affine();
+			var R=new ctx.ECP2(); R.copy(R1); R.affine();
+			var S=new ctx.ECP(); S.copy(S1); S.affine();
 
-            n3 = new ctx.BIG(n);
-            n3.pmul(3);
-            n3.norm();
 
-            Qx = new ctx.FP(Q.getx());
-            Qy = new ctx.FP(Q.gety());
+            Qx = new ctx.FP(Q.getx()); 
+            Qy = new ctx.FP(Q.gety()); 
 
-            Sx = new ctx.FP(S.getx());
-            Sy = new ctx.FP(S.gety());
+            Sx = new ctx.FP(S.getx()); 
+            Sy = new ctx.FP(S.gety()); 
 
             A = new ctx.ECP2();
             B = new ctx.ECP2();
@@ -272,32 +351,36 @@ var PAIR = function(ctx) {
 
             A.copy(P);
             B.copy(R);
-            nb = n3.nbits();
+
+			NP = new ctx.ECP2();
+			NP.copy(P);
+			NP.neg();
+			NR = new ctx.ECP2();
+			NR.copy(R);
+			NR.neg();
+
+            nb = PAIR.lbits(n3,n);
 
             for (i = nb - 2; i >= 1; i--) {
                 r.sqr();
                 lv = PAIR.line(A, A, Qx, Qy);
-                r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-                lv = PAIR.line(B, B, Sx, Sy);
-                r.smul(lv,ctx.ECP.SEXTIC_TWIST);
+                lv2 = PAIR.line(B, B, Sx, Sy);
+				lv.smul(lv2);
+                r.ssmul(lv);
 
                 bt=n3.bit(i)-n.bit(i);
 
                 if (bt == 1) {
                     lv = PAIR.line(A, P, Qx, Qy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-                    lv = PAIR.line(B, R, Sx, Sy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
+                    lv2 = PAIR.line(B, R, Sx, Sy);
+					lv.smul(lv2);
+                    r.ssmul(lv);
                 }
                 if (bt == -1) {
-                    P.neg();
-                    lv = PAIR.line(A, P, Qx, Qy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-                    P.neg();
-                    R.neg();
-                    lv = PAIR.line(B, R, Sx, Sy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-                    R.neg();
+                    lv = PAIR.line(A, NP, Qx, Qy);
+                    lv2 = PAIR.line(B, NR, Sx, Sy);
+					lv.smul(lv2);
+                    r.ssmul(lv);
                 }
             }
 
@@ -306,7 +389,7 @@ var PAIR = function(ctx) {
             }
 
 
-            /* R-ate fixup required for BN curves */
+            // R-ate fixup required for BN curves 
             if (ctx.ECP.CURVE_PAIRING_TYPE == ctx.ECP.BN) {
                 if (ctx.ECP.SIGN_OF_X == ctx.ECP.NEGATIVEX) {
                     A.neg();
@@ -316,21 +399,21 @@ var PAIR = function(ctx) {
                 K.frob(f);
 
                 lv = PAIR.line(A, K, Qx, Qy);
-                r.smul(lv,ctx.ECP.SEXTIC_TWIST);
                 K.frob(f);
                 K.neg();
-                lv = PAIR.line(A, K, Qx, Qy);
-                r.smul(lv,ctx.ECP.SEXTIC_TWIST);
+                lv2 = PAIR.line(A, K, Qx, Qy);
+				lv.smul(lv2);
+                r.ssmul(lv);
 
                 K.copy(R);
                 K.frob(f);
 
                 lv = PAIR.line(B, K, Sx, Sy);
-                r.smul(lv,ctx.ECP.SEXTIC_TWIST);
                 K.frob(f);
                 K.neg();
-                lv = PAIR.line(B, K, Sx, Sy);
-                r.smul(lv,ctx.ECP.SEXTIC_TWIST);
+                lv2 = PAIR.line(B, K, Sx, Sy);
+				lv.smul(lv2);
+                r.ssmul(lv);
             }
 
             return r;
@@ -361,17 +444,21 @@ var PAIR = function(ctx) {
             r.frob(f);
             r.frob(f);
             r.mul(lv);
-
+			if (r.isunity())
+			{
+				r.zero();
+				return r;
+			}
             /* Hard part of final exp */
             if (ctx.ECP.CURVE_PAIRING_TYPE == ctx.ECP.BN) {
                 lv.copy(r);
                 lv.frob(f);
-                x0 = new ctx.FP12(lv);
+                x0 = new ctx.FP12(lv); //x0.copy(lv);
                 x0.frob(f);
                 lv.mul(r);
                 x0.mul(lv);
                 x0.frob(f);
-                x1 = new ctx.FP12(r);
+                x1 = new ctx.FP12(r); //x1.copy(r);
                 x1.conj();
 
                 x4 = r.pow(x);
@@ -379,13 +466,13 @@ var PAIR = function(ctx) {
                     x4.conj();
                 }
 
-                x3 = new ctx.FP12(x4);
+                x3 = new ctx.FP12(x4); //x3.copy(x4);
                 x3.frob(f);
                 x2 = x4.pow(x);
                 if (ctx.ECP.SIGN_OF_X == ctx.ECP.POSITIVEX) {
                     x2.conj();
                 }
-                x5 = new ctx.FP12(x2);
+                x5 = new ctx.FP12(x2); /*x5.copy(x2);*/
                 x5.conj();
                 lv = x2.pow(x);
                 if (ctx.ECP.SIGN_OF_X == ctx.ECP.POSITIVEX) {
@@ -478,6 +565,28 @@ var PAIR = function(ctx) {
         }
     };
 
+/* prepare ate parameter, n=6u+2 (BN) or n=u (BLS), n3=3*n */
+	PAIR.lbits = function(n3,n)
+	{
+		n.rcopy(ctx.ROM_CURVE.CURVE_Bnx);
+		if (ctx.ECP.CURVE_PAIRING_TYPE==ctx.ECP.BN)
+		{
+			n.pmul(6);
+			if (ctx.ECP.SIGN_OF_X==ctx.ECP.POSITIVEX)
+			{
+				n.inc(2);
+			} else {
+				n.dec(2);
+			}
+		}
+		
+		n.norm();
+		n3.copy(n);
+		n3.pmul(3);
+		n3.norm();
+		return n3.nbits();
+	},
+
     /* GLV method */
     PAIR.glv = function(e) {
         var u = [],
@@ -508,8 +617,7 @@ var PAIR = function(ctx) {
                     u[i].mod(q);
                 }
             }
-        } else {
-            // -(x^2).P = (Beta.x,y)
+        } else { // -(x^2).P = (Beta.x,y)
             q = new ctx.BIG(0);
             q.rcopy(ctx.ROM_CURVE.CURVE_Order);
             x = new ctx.BIG(0);
@@ -583,11 +691,10 @@ var PAIR = function(ctx) {
         var R, Q, q, bcru, cru, t, u, np, nn;
 
         if (ctx.ROM_CURVE.USE_GLV) {
-            P.affine();
             R = new ctx.ECP();
             R.copy(P);
             Q = new ctx.ECP();
-            Q.copy(P);
+            Q.copy(P); Q.affine();
             q = new ctx.BIG(0);
             q.rcopy(ctx.ROM_CURVE.CURVE_Order);
             bcru = new ctx.BIG(0);
@@ -645,7 +752,6 @@ var PAIR = function(ctx) {
 
             u = PAIR.gs(e);
             t = new ctx.BIG(0);
-            P.affine();
             Q[0] = new ctx.ECP2();
             Q[0].copy(P);
 
diff --git a/src/pair192.js b/src/pair192.js
index 3439804..74e9c72 100644
--- a/src/pair192.js
+++ b/src/pair192.js
@@ -121,51 +121,121 @@ var PAIR192 = function(ctx) {
             }
 
             r.set(a, b, c);
-
+			r.settype(ctx.FP.SPARSER);
             return r;
         },
 
+/* prepare for multi-pairing */
+		initmp: function() {
+			var r=[];
+			for (var i=0;i<ctx.ECP.ATE_BITS;i++)
+				r[i] = new ctx.FP24(1);
+			return r;
+		},
+
+/* basic Miller loop */
+		miller: function(r) {
+			var res=new ctx.FP24(1);
+			for (var i=ctx.ECP.ATE_BITS-1; i>=1; i--)
+			{
+				res.sqr();
+				res.ssmul(r[i]); 
+			}
+
+			if (ctx.ECP.SIGN_OF_X==ctx.ECP.NEGATIVEX)
+				res.conj();
+			res.ssmul(r[0]);
+
+			return res;
+		},
+
+/* Accumulate another set of line functions for n-pairing */
+		another: function(r,P1,Q1) {
+
+			var f;
+			var n=new ctx.BIG(0);
+			var n3=new ctx.BIG(0);
+			var lv,lv2;
+			var bt;
+
+// P is needed in affine form for line function, Q for (Qx,Qy) extraction
+			var P=new ctx.ECP4(); P.copy(P1); P.affine();
+			var Q=new ctx.ECP(); Q.copy(Q1); Q.affine();
+
+			P.affine();
+			Q.affine();
+
+			var Qx=new ctx.FP(Q.getx());
+			var Qy=new ctx.FP(Q.gety());
+
+			var A=new ctx.ECP4();
+			A.copy(P);
+
+			var MP=new ctx.ECP4();
+			MP.copy(P); MP.neg();
+
+			var nb=PAIR192.lbits(n3,n);
+
+			for (var i=nb-2;i>=1;i--)
+			{
+				lv=PAIR192.line(A,A,Qx,Qy);
+
+				bt=n3.bit(i)-n.bit(i); 
+				if (bt==1)
+				{
+					lv2=PAIR192.line(A,P,Qx,Qy);
+					lv.smul(lv2);
+				}
+				if (bt==-1)
+				{
+					lv2=PAIR192.line(A,MP,Qx,Qy);
+					lv.smul(lv2);
+				}
+				r[i].ssmul(lv);
+			} 
+		},
+
+
         /* Optimal R-ate pairing */
-        ate: function(P, Q) {
-            var x, n, n3, lv,
-                Qx, Qy, A, r, nb, bt,
+        ate: function(P1, Q1) {
+            var x, n, n3, lv, lv2,
+                Qx, Qy, A, NP, r, nb, bt,
                 i;
 
-            x = new ctx.BIG(0);
-            x.rcopy(ctx.ROM_CURVE.CURVE_Bnx);
-            n = new ctx.BIG(x);
+            n = new ctx.BIG(0);
+			n3 = new ctx.BIG(0);
 
-            n3 = new ctx.BIG(n);
-            n3.pmul(3);
-            n3.norm();
+			var P=new ctx.ECP4(); P.copy(P1); P.affine();
+			var Q=new ctx.ECP(); Q.copy(Q1); Q.affine();
 
-            Qx = new ctx.FP(Q.getx());
-            Qy = new ctx.FP(Q.gety());
+            Qx = new ctx.FP(Q.getx()); 
+            Qy = new ctx.FP(Q.gety()); 
 
             A = new ctx.ECP4();
             r = new ctx.FP24(1);
 
             A.copy(P);
-            nb = n3.nbits();
+			NP = new ctx.ECP4();
+			NP.copy(P);
+			NP.neg();
+
+
+            nb = PAIR192.lbits(n3,n);
 
             for (i = nb - 2; i >= 1; i--) {
                 r.sqr();
                 lv = PAIR192.line(A, A, Qx, Qy);
-
-                r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-
                 bt=n3.bit(i)-n.bit(i);
 
                 if (bt == 1) {
-                    lv = PAIR192.line(A, P, Qx, Qy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
+                    lv2 = PAIR192.line(A, P, Qx, Qy);
+                    lv.smul(lv2);
                 }
                 if (bt == -1) {
-                    P.neg();
-                    lv = PAIR192.line(A, P, Qx, Qy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-                    P.neg();
+                    lv2 = PAIR192.line(A, NP, Qx, Qy);
+                    lv.smul(lv2);
                 }
+                r.ssmul(lv);
             }
 
             if (ctx.ECP.SIGN_OF_X == ctx.ECP.NEGATIVEX) {
@@ -176,19 +246,20 @@ var PAIR192 = function(ctx) {
         },
 
         /* Optimal R-ate double pairing e(P,Q).e(R,S) */
-        ate2: function(P, Q, R, S) {
-            var x, n, n3, lv,
-                Qx, Qy, Sx, Sy, A, B, r, nb, bt,
+        ate2: function(P1, Q1, R1, S1) {
+            var x, n, n3, lv, lv2,
+                Qx, Qy, Sx, Sy, A, B, NP, NR, r, nb, bt,
                 i;
 
 
-            x = new ctx.BIG(0);
-            x.rcopy(ctx.ROM_CURVE.CURVE_Bnx);
+            n = new ctx.BIG(0);
+			n3 = new ctx.BIG(0);
+
+			var P=new ctx.ECP4(); P.copy(P1); P.affine();
+			var Q=new ctx.ECP(); Q.copy(Q1); Q.affine();
+			var R=new ctx.ECP4(); R.copy(R1); R.affine();
+			var S=new ctx.ECP(); S.copy(S1); S.affine();
 
-            n = new ctx.BIG(x);
-            n3 = new ctx.BIG(n);
-            n3.pmul(3);
-            n3.norm();
 
             Qx = new ctx.FP(Q.getx());
             Qy = new ctx.FP(Q.gety());
@@ -202,32 +273,35 @@ var PAIR192 = function(ctx) {
 
             A.copy(P);
             B.copy(R);
-            nb = n3.nbits();
+			NP = new ctx.ECP4();
+			NP.copy(P);
+			NP.neg();
+			NR = new ctx.ECP4();
+			NR.copy(R);
+			NR.neg();
+
+            nb = PAIR192.lbits(n3,n);
 
             for (i = nb - 2; i >= 1; i--) {
                 r.sqr();
                 lv = PAIR192.line(A, A, Qx, Qy);
-                r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-                lv = PAIR192.line(B, B, Sx, Sy);
-                r.smul(lv,ctx.ECP.SEXTIC_TWIST);
+                lv2 = PAIR192.line(B, B, Sx, Sy);
+				lv.smul(lv2);
+                r.ssmul(lv);
 
                 bt=n3.bit(i)-n.bit(i);
 
                 if (bt == 1) {
                     lv = PAIR192.line(A, P, Qx, Qy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-                    lv = PAIR192.line(B, R, Sx, Sy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
+                    lv2 = PAIR192.line(B, R, Sx, Sy);
+					lv.smul(lv2);
+                    r.ssmul(lv);
                 }
                 if (bt == -1) {
-                    P.neg();
-                    lv = PAIR192.line(A, P, Qx, Qy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-                    P.neg();
-                    R.neg();
-                    lv = PAIR192.line(B, R, Sx, Sy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-                    R.neg();
+                    lv = PAIR192.line(A, NP, Qx, Qy);
+                    lv2 = PAIR192.line(B, NR, Sx, Sy);
+					lv.smul(lv2);
+                    r.ssmul(lv);
                 }
             }
 
@@ -251,17 +325,21 @@ var PAIR192 = function(ctx) {
             x = new ctx.BIG(0);
             x.rcopy(ctx.ROM_CURVE.CURVE_Bnx);
 
-            r = new ctx.FP24(m);
+            r = new ctx.FP24(m); //r.copy(m);
 
             /* Easy part of final exp */
-            lv = new ctx.FP24(r);
+            lv = new ctx.FP24(r); //lv.copy(r);
             lv.inverse();
             r.conj();
             r.mul(lv);
             lv.copy(r);
             r.frob(f,4);
             r.mul(lv);
-
+			if (r.isunity())
+			{
+				r.zero();
+				return r;
+			}
             /* Hard part of final exp */
             // Ghamman & Fouotsa Method
             t7=new ctx.FP24(r); t7.usqr();
@@ -337,6 +415,16 @@ var PAIR192 = function(ctx) {
         }
     };
 
+/* prepare ate parameter, n=6u+2 (BN) or n=u (BLS), n3=3*n */
+	PAIR192.lbits = function(n3,n)
+	{
+		n.rcopy(ctx.ROM_CURVE.CURVE_Bnx);
+		n3.copy(n);
+		n3.pmul(3);
+		n3.norm();
+		return n3.nbits();
+	},
+
     /* GLV method */
     PAIR192.glv = function(e) {
         var u = [],
@@ -391,11 +479,10 @@ var PAIR192 = function(ctx) {
         var R, Q, q, bcru, cru, t, u, np, nn;
 
         if (ctx.ROM_CURVE.USE_GLV) {
-            P.affine();
             R = new ctx.ECP();
             R.copy(P);
             Q = new ctx.ECP();
-            Q.copy(P);
+            Q.copy(P); Q.affine();
             q = new ctx.BIG(0);
             q.rcopy(ctx.ROM_CURVE.CURVE_Order);
             bcru = new ctx.BIG(0);
@@ -444,7 +531,7 @@ var PAIR192 = function(ctx) {
 
             u = PAIR192.gs(e);
             t = new ctx.BIG(0);
-            P.affine();
+          
             Q[0] = new ctx.ECP4();
             Q[0].copy(P);
 
diff --git a/src/pair256.js b/src/pair256.js
index f80234d..5dca245 100644
--- a/src/pair256.js
+++ b/src/pair256.js
@@ -121,51 +121,121 @@ var PAIR256 = function(ctx) {
             }
 
             r.set(a, b, c);
-
+			r.settype(ctx.FP.SPARSER);
             return r;
         },
 
+/* prepare for multi-pairing */
+		initmp: function() {
+			var r=[];
+			for (var i=0;i<ctx.ECP.ATE_BITS;i++)
+				r[i] = new ctx.FP48(1);
+			return r;
+		},
+
+/* basic Miller loop */
+		miller: function(r) {
+			var res=new ctx.FP48(1);
+			for (var i=ctx.ECP.ATE_BITS-1; i>=1; i--)
+			{
+				res.sqr();
+				res.ssmul(r[i]); 
+			}
+
+			if (ctx.ECP.SIGN_OF_X==ctx.ECP.NEGATIVEX)
+				res.conj();
+			res.ssmul(r[0]);
+
+			return res;
+		},
+
+/* Accumulate another set of line functions for n-pairing */
+		another: function(r,P1,Q1) {
+
+			var f;
+			var n=new ctx.BIG(0);
+			var n3=new ctx.BIG(0);
+			var lv,lv2;
+			var bt;
+
+// P is needed in affine form for line function, Q for (Qx,Qy) extraction
+			var P=new ctx.ECP8(); P.copy(P1); P.affine();
+			var Q=new ctx.ECP(); Q.copy(Q1); Q.affine();
+
+			P.affine();
+			Q.affine();
+
+			var Qx=new ctx.FP(Q.getx());
+			var Qy=new ctx.FP(Q.gety());
+
+			var A=new ctx.ECP8();
+			A.copy(P);
+
+			var MP=new ctx.ECP8();
+			MP.copy(P); MP.neg();
+
+			var nb=PAIR256.lbits(n3,n);
+
+			for (var i=nb-2;i>=1;i--)
+			{
+				lv=PAIR256.line(A,A,Qx,Qy);
+
+				bt=n3.bit(i)-n.bit(i); 
+				if (bt==1)
+				{
+					lv2=PAIR256.line(A,P,Qx,Qy);
+					lv.smul(lv2);
+				}
+				if (bt==-1)
+				{
+					lv2=PAIR256.line(A,MP,Qx,Qy);
+					lv.smul(lv2);
+				}
+				r[i].ssmul(lv);
+			} 
+		},
+
+
         /* Optimal R-ate pairing */
-        ate: function(P, Q) {
-            var x, n, n3, lv,
-                Qx, Qy, A, r, nb, bt,
+        ate: function(P1, Q1) {
+            var x, n, n3, lv, lv2,
+                Qx, Qy, A, NP, r, nb, bt,
                 i;
 
-            x = new ctx.BIG(0);
-            x.rcopy(ctx.ROM_CURVE.CURVE_Bnx);
-            n = new ctx.BIG(x);
+            n = new ctx.BIG(0);
+			n3 = new ctx.BIG(0);
 
-            n3 = new ctx.BIG(n);
-            n3.pmul(3);
-            n3.norm();
+			var P=new ctx.ECP8(); P.copy(P1); P.affine();
+			var Q=new ctx.ECP(); Q.copy(Q1); Q.affine();
 
-            Qx = new ctx.FP(Q.getx());
-            Qy = new ctx.FP(Q.gety());
+            Qx = new ctx.FP(Q.getx()); 
+            Qy = new ctx.FP(Q.gety()); 
 
             A = new ctx.ECP8();
             r = new ctx.FP48(1);
 
             A.copy(P);
-            nb = n3.nbits();
+			NP = new ctx.ECP8();
+			NP.copy(P);
+			NP.neg();
+
+
+            nb = PAIR256.lbits(n3,n);
 
             for (i = nb - 2; i >= 1; i--) {
                 r.sqr();
                 lv = PAIR256.line(A, A, Qx, Qy);
-
-                r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-
                 bt=n3.bit(i)-n.bit(i);
 
                 if (bt == 1) {
-                    lv = PAIR256.line(A, P, Qx, Qy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
+                    lv2 = PAIR256.line(A, P, Qx, Qy);
+                    lv.smul(lv2);
                 }
                 if (bt == -1) {
-                    P.neg();
-                    lv = PAIR256.line(A, P, Qx, Qy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-                    P.neg();
+                    lv2 = PAIR256.line(A, NP, Qx, Qy);
+                    lv.smul(lv2);
                 }
+                r.ssmul(lv);
             }
 
             if (ctx.ECP.SIGN_OF_X == ctx.ECP.NEGATIVEX) {
@@ -176,25 +246,25 @@ var PAIR256 = function(ctx) {
         },
 
         /* Optimal R-ate double pairing e(P,Q).e(R,S) */
-        ate2: function(P, Q, R, S) {
-            var x, n, n3, lv,
-                Qx, Qy, Sx, Sy, A, B, r, nb, bt,
+        ate2: function(P1, Q1, R1, S1) {
+            var x, n, n3, lv, lv2,
+                Qx, Qy, Sx, Sy, A, B, NP, NR, r, nb, bt,
                 i;
 
+            n = new ctx.BIG(0);
+			n3 = new ctx.BIG(0);
 
-            x = new ctx.BIG(0);
-            x.rcopy(ctx.ROM_CURVE.CURVE_Bnx);
+			var P=new ctx.ECP8(); P.copy(P1); P.affine();
+			var Q=new ctx.ECP(); Q.copy(Q1); Q.affine();
+			var R=new ctx.ECP8(); R.copy(R1); R.affine();
+			var S=new ctx.ECP(); S.copy(S1); S.affine();
 
-            n = new ctx.BIG(x);
-            n3 = new ctx.BIG(n);
-            n3.pmul(3);
-            n3.norm();
 
-            Qx = new ctx.FP(Q.getx());
-            Qy = new ctx.FP(Q.gety());
+            Qx = new ctx.FP(Q.getx()); 
+            Qy = new ctx.FP(Q.gety()); 
 
-            Sx = new ctx.FP(S.getx());
-            Sy = new ctx.FP(S.gety());
+            Sx = new ctx.FP(S.getx()); 
+            Sy = new ctx.FP(S.gety()); 
 
             A = new ctx.ECP8();
             B = new ctx.ECP8();
@@ -202,32 +272,36 @@ var PAIR256 = function(ctx) {
 
             A.copy(P);
             B.copy(R);
-            nb = n3.nbits();
+			NP = new ctx.ECP8();
+			NP.copy(P);
+			NP.neg();
+			NR = new ctx.ECP8();
+			NR.copy(R);
+			NR.neg();
+
+
+            nb = PAIR256.lbits(n3,n);
 
             for (i = nb - 2; i >= 1; i--) {
                 r.sqr();
                 lv = PAIR256.line(A, A, Qx, Qy);
-                r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-                lv = PAIR256.line(B, B, Sx, Sy);
-                r.smul(lv,ctx.ECP.SEXTIC_TWIST);
+                lv2 = PAIR256.line(B, B, Sx, Sy);
+				lv.smul(lv2);
+                r.ssmul(lv);
 
                 bt=n3.bit(i)-n.bit(i);
 
                 if (bt == 1) {
                     lv = PAIR256.line(A, P, Qx, Qy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-                    lv = PAIR256.line(B, R, Sx, Sy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
+                    lv2 = PAIR256.line(B, R, Sx, Sy);
+					lv.smul(lv2);
+                    r.ssmul(lv);
                 }
                 if (bt == -1) {
-                    P.neg();
-                    lv = PAIR256.line(A, P, Qx, Qy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-                    P.neg();
-                    R.neg();
-                    lv = PAIR256.line(B, R, Sx, Sy);
-                    r.smul(lv,ctx.ECP.SEXTIC_TWIST);
-                    R.neg();
+                    lv = PAIR256.line(A, NP, Qx, Qy);
+                    lv2 = PAIR256.line(B, NR, Sx, Sy);
+					lv.smul(lv2);
+                    r.ssmul(lv);
                 }
             }
 
@@ -251,17 +325,21 @@ var PAIR256 = function(ctx) {
             x = new ctx.BIG(0);
             x.rcopy(ctx.ROM_CURVE.CURVE_Bnx);
 
-            r = new ctx.FP48(m);
+            r = new ctx.FP48(m); //r.copy(m);
 
             /* Easy part of final exp */
-            lv = new ctx.FP48(r);
+            lv = new ctx.FP48(r); //lv.copy(r);
             lv.inverse();
             r.conj();
             r.mul(lv);
             lv.copy(r);
             r.frob(f,8);
             r.mul(lv);
-
+			if (r.isunity())
+			{
+				r.zero();
+				return r;
+			}
             /* Hard part of final exp */
             // Ghamman & Fouotsa Method
             t7=new ctx.FP48(r); t7.usqr();
@@ -408,6 +486,16 @@ var PAIR256 = function(ctx) {
         }
     };
 
+/* prepare ate parameter, n=6u+2 (BN) or n=u (BLS), n3=3*n */
+	PAIR256.lbits = function(n3,n)
+	{
+		n.rcopy(ctx.ROM_CURVE.CURVE_Bnx);
+		n3.copy(n);
+		n3.pmul(3);
+		n3.norm();
+		return n3.nbits();
+	},
+
     /* GLV method */
     PAIR256.glv = function(e) {
         var u = [],
@@ -468,11 +556,10 @@ var PAIR256 = function(ctx) {
         var R, Q, q, bcru, cru, t, u, np, nn;
 
         if (ctx.ROM_CURVE.USE_GLV) {
-            P.affine();
             R = new ctx.ECP();
             R.copy(P);
             Q = new ctx.ECP();
-            Q.copy(P);
+            Q.copy(P); Q.affine();
             q = new ctx.BIG(0);
             q.rcopy(ctx.ROM_CURVE.CURVE_Order);
             bcru = new ctx.BIG(0);
@@ -521,7 +608,7 @@ var PAIR256 = function(ctx) {
 
             u = PAIR256.gs(e);
             t = new ctx.BIG(0);
-            P.affine();
+          
             Q[0] = new ctx.ECP8();
             Q[0].copy(P);
 
diff --git a/src/rand.js b/src/rand.js
index 2b4c4fa..db110b0 100644
--- a/src/rand.js
+++ b/src/rand.js
@@ -33,14 +33,11 @@ var RAND = function(ctx) {
 
     var RAND = function() {
         /* Cryptographically strong pseudo-random number generator */
-        /* random number...   */
-        this.ira = [];
-        /* ...array & pointer */
-        this.rndptr = 0;
+        this.ira = []; /* random number...   */
+        this.rndptr = 0; /* ...array & pointer */
         this.borrow = 0;
         this.pool_ptr = 0;
-        /* random pool */
-        this.pool = [];
+        this.pool = []; /* random pool */
         this.clean();
     };
 
@@ -76,16 +73,14 @@ var RAND = function(ctx) {
 
             this.rndptr = 0;
 
-            /* calculate next NK values */
-            for (i = 0, k = this.NK - this.NJ; i < this.NK; i++, k++) {
+            for (i = 0, k = this.NK - this.NJ; i < this.NK; i++, k++) { /* calculate next NK values */
                 if (k == this.NK) {
                     k = 0;
                 }
 
                 t = this.ira[k] >>> 0;
                 pdiff = (t - this.ira[i] - this.borrow) | 0;
-                /* This is seriously weird stuff. I got to do this to get a proper unsigned comparison... */
-                pdiff >>>= 0;
+                pdiff >>>= 0; /* This is seriously weird shit. I got to do this to get a proper unsigned comparison... */
 
                 if (pdiff < t) {
                     this.borrow = 0;
@@ -110,11 +105,9 @@ var RAND = function(ctx) {
             seed >>>= 0;
             this.ira[0] ^= seed;
 
-            /* fill initialisation vector */
-            for (i = 1; i < this.NK; i++) {
+            for (i = 1; i < this.NK; i++) { /* fill initialisation vector */
                 inn = (this.NV * i) % this.NK;
-                /* note XOR */
-                this.ira[inn] ^= m;
+                this.ira[inn] ^= m; /* note XOR */
                 t = m;
                 m = (seed - m) | 0;
                 seed = t;
@@ -138,8 +131,8 @@ var RAND = function(ctx) {
             this.pool_ptr = 0;
         },
 
-        /* Initialize RNG with some real entropy from some external source - at least 128 byte string */
-        seed: function(rawlen, raw) {
+        /* Initialize RNG with some real entropy from some external source */
+        seed: function(rawlen, raw) { /* initialise from at least 128 byte string of raw random entropy */
             var sh = new ctx.HASH256(),
                 digest = [],
                 b = [],
@@ -183,8 +176,7 @@ var RAND = function(ctx) {
         }
     };
 
-    /* pack 4 bytes into a 32-bit Word */
-    RAND.pack = function(b) {
+    RAND.pack = function(b) { /* pack 4 bytes into a 32-bit Word */
         return (((b[3]) & 0xff) << 24) | ((b[2] & 0xff) << 16) | ((b[1] & 0xff) << 8) | (b[0] & 0xff);
     };
 
diff --git a/src/rsa.js b/src/rsa.js
index 3e4bf9d..d04ba30 100644
--- a/src/rsa.js
+++ b/src/rsa.js
@@ -119,8 +119,7 @@ RSA = function(ctx) {
             return R;
         },
 
-        /* IEEE1363 A16.11/A16.12 more or less */
-        KEY_PAIR: function(rng, e, PRIV, PUB) {
+        KEY_PAIR: function(rng, e, PRIV, PUB) { /* IEEE1363 A16.11/A16.12 more or less */
             var n = PUB.n.length >> 1,
                 t = new ctx.FF(n),
                 p1 = new ctx.FF(n),
diff --git a/src/sha3.js b/src/sha3.js
index 5150750..345de82 100644
--- a/src/sha3.js
+++ b/src/sha3.js
@@ -106,8 +106,8 @@ var SHA3 = function(ctx) {
             }
         },
 
-        /* Initialize Hash function */
-        init: function(olen) {
+        /* Initialise Hash function */
+        init: function(olen) { /* initialise */
             var i, j;
             for (i = 0; i < 5; i++) {
                 this.S[i] = [];
@@ -121,15 +121,14 @@ var SHA3 = function(ctx) {
         },
 
         /* process a single byte */
-        process: function(byt) {
+        process: function(byt) { /* process the next message byte */
             var i, j, k, b, cnt, el;
 
             cnt = (this.length % this.rate);
             b = cnt % 8;
             cnt >>= 3;
             i = cnt % 5;
-            /* process by columns! */
-            j = Math.floor(cnt / 5);
+            j = Math.floor(cnt / 5); /* process by columns! */
 
             el = new ctx.UInt64(0, byt);
             for (k = 0; k < b; k++) {
@@ -183,36 +182,31 @@ var SHA3 = function(ctx) {
                 this.transform();
             }
         },
-        /* pad message and finish - supply digest */
-        hash: function(buff) {
+
+        hash: function(buff) { /* pad message and finish - supply digest */
             var q = this.rate - (this.length % this.rate);
             if (q == 1) {
                 this.process(0x86);
             } else {
-                /* 0x06 for SHA-3 */
-                this.process(0x06);
+                this.process(0x06); /* 0x06 for SHA-3 */
                 while (this.length % this.rate != this.rate - 1) {
                     this.process(0x00);
                 }
-                /* this will force a final transform */
-                this.process(0x80);
+                this.process(0x80); /* this will force a final transform */
             }
             this.squeeze(buff, this.len);
         },
 
-        /* pad message and finish - supply digest */
-        shake: function(buff, olen) {
+        shake: function(buff, olen) { /* pad message and finish - supply digest */
             var q = this.rate - (this.length % this.rate);
             if (q == 1) {
                 this.process(0x9f);
             } else {
-                /* 0x06 for SHA-3 */
-                this.process(0x1f);
+                this.process(0x1f); /* 0x06 for SHA-3 */
                 while (this.length % this.rate != this.rate - 1) {
                     this.process(0x00);
                 }
-                /* this will force a final transform */
-                this.process(0x80);
+                this.process(0x80); /* this will force a final transform */
             }
             this.squeeze(buff, olen);
         }
diff --git a/test/test_BIG.js b/test/test_BIG.js
index 1146b01..0ba368e 100644
--- a/test/test_BIG.js
+++ b/test/test_BIG.js
@@ -250,7 +250,7 @@ all_curves.forEach(function(curve){
 
 			done();
 		});
-
+                /*
 		it('test sum', function(done) {
 			vectors.forEach(function(vector) {
 				var BIG1 = readBIG(vector.BIG1,ctx),
@@ -276,7 +276,7 @@ all_curves.forEach(function(curve){
 
 			done();
 		});
-
+                */
 		it('test modulus this > m', function(done) {
 			vectors.forEach(function(vector) {
 				if(vectors.BIGmod2 !== undefined){
diff --git a/test/test_DVS.js b/test/test_DVS.js
index 2a48373..3f9eeea 100644
--- a/test/test_DVS.js
+++ b/test/test_DVS.js
@@ -23,6 +23,7 @@ var chai = require('chai');
 
 var CTX = require("../index");
 
+// Curves for test
 pf_curves = ['BN254', 'BN254CX', 'BLS381', 'BLS383', 'BLS461', 'FP256BN', 'FP512BN', 'BLS24', 'BLS48'];
 
 var expect = chai.expect;
@@ -38,7 +39,7 @@ pf_curves.forEach(function(curve) {
             MPIN, EGS, EFS, G1S, G2S,
             pin = 1234,
             pin2 = 2345,
-            IDstr = "testuser@miracl.com",
+            IDstr = "testuser@milagro.com",
             message = "Message to sign",
             S = [],
             SST = [],
@@ -134,4 +135,4 @@ pf_curves.forEach(function(curve) {
             done();
         });
     });
-});
\ No newline at end of file
+});
diff --git a/test/test_FP12_js b/test/test_FP12_js
new file mode 100644
index 0000000..49ea61c
--- /dev/null
+++ b/test/test_FP12_js
@@ -0,0 +1,206 @@
+/*
+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.
+*/
+
+
+/* Test FP12 ARITHMETICS - test driver and function exerciser for FP4 API Functions */
+
+var chai = require('chai');
+
+var CTX = require("../index");
+
+var expect = chai.expect;
+
+var pf_curves = ['BN254', 'BN254CX', 'BLS381', 'BLS383', 'BLS461', 'FP256BN', 'FP512BN'];
+
+var readBIG = function(string, ctx) {
+    while (string.length != ctx.BIG.MODBYTES*2){string = "00"+string;}
+    return ctx.BIG.fromBytes(Buffer.from(string, "hex"));
+}
+
+var readFP2 = function(string, ctx) {
+    string = string.split(",");
+    var cox = string[0].slice(1);
+    var coy = string[1].slice(0,-1);
+
+    var x = readBIG(cox,ctx);
+    var y = readBIG(coy,ctx);
+
+    return new ctx.FP2(x,y);;
+}
+
+var readFP4 = function(string, ctx) {
+    var X, Y;
+
+    string = string.split("],[");
+    var cox = string[0].slice(1) + "]";
+    var coy = "[" + string[1].slice(0,-1);
+
+    X = readFP2(cox,ctx);
+    Y = readFP2(coy,ctx);
+
+    return new ctx.FP4(X,Y);
+}
+
+var readFP12= function(string, ctx) {
+    var X,Y,Z;
+
+    string = string.split("]],[[");
+    var cox = string[0].slice(1) + "]]";
+    var coy = "[[" + string[1] + "]]";
+    var coz = "[[" + string[2].slice(0,-1);
+
+    X = readFP4(cox,ctx);
+    Y = readFP4(coy,ctx);
+    Z = readFP4(coz,ctx);
+
+    return new ctx.FP12(X,Y,Z);
+}
+
+describe('TEST FP12 ARITHMETIC', function() {
+
+    pf_curves.forEach(function(curve){
+
+        it('test '+ curve, function(done) {
+            this.timeout(0);
+
+            var ctx = new CTX(curve);
+            var vectors = require('../testVectors/fp12/'+ curve +'.json');
+
+            var Fra = new ctx.FP(0),
+                Frb = new ctx.FP(0),
+                Fr;
+            Fra.rcopy(ctx.ROM_FIELD.Fra);
+            Frb.rcopy(ctx.ROM_FIELD.Frb);
+            Fr = new ctx.FP2(Fra,Frb);
+
+            var i = 0;
+            vectors.forEach(function(vector) {
+                // Generate/read the necessary FP12 and BIGs
+                var fp121,fp122,fp123,fp124,fp12c;
+                fp121 = readFP12(vector.FP121, ctx);
+                fp122 = readFP12(vector.FP122, ctx);
+                if (i===0){
+                    fp123 = readFP12(vector.FP123, ctx);
+                    fp124 = readFP12(vector.FP124, ctx);
+                }
+                    fp12c = readFP12(vector.FP12c, ctx);
+                var BIGsc1,BIGsc2,BIGsc3,BIGsc4,BIGscs,BIGsco;
+                BIGsc1 = readBIG(vector.BIGsc1, ctx);
+                if (i===0){
+                    BIGsc2 = readBIG(vector.BIGsc2, ctx);
+                    BIGsc3 = readBIG(vector.BIGsc3, ctx);
+                    BIGsc4 = readBIG(vector.BIGsc4, ctx);
+                }
+                BIGscs = readBIG(vector.BIGscs, ctx);
+                BIGsco = readBIG(vector.BIGsco, ctx);
+                var a1 = new ctx.FP12(0);
+                var a2 = new ctx.FP12(0);
+
+                // test conjugate of a FP4
+                var fp12conj = readFP12(vector.FP12conj, ctx);
+                a1.copy(fp121);
+                a1.conj();
+                expect(a1.toString()).to.equal(fp12conj.toString());
+
+                // test multiplication and commutativity
+                var fp12mul = readFP12(vector.FP12mul, ctx);
+                a1.copy(fp121);
+                a2.copy(fp122);
+                a1.mul(fp122);
+                a2.mul(fp121);
+                expect(a1.toString()).to.equal(fp12mul.toString());
+                expect(a2.toString()).to.equal(fp12mul.toString());
+
+                // test square
+                var fp12sqr = readFP12(vector.FP12square, ctx);
+                a1.copy(fp121);
+                a1.sqr();
+                expect(a1.toString()).to.equal(fp12sqr.toString());
+
+                // test unitary square
+                var fp12usqr = readFP12(vector.FP12usquare, ctx);
+                a1.copy(fp121);
+                a1.usqr();
+                expect(a1.toString()).to.equal(fp12usqr.toString());
+
+                // test inverse
+                var fp12inv = readFP12(vector.FP12inv, ctx);
+                a1.copy(fp121);
+                a1.inverse();
+                expect(a1.toString()).to.equal(fp12inv.toString());
+
+                // test smultiplication for D-TYPE
+                var fp12smulydtype = readFP12(vector.FP12smulydtype,ctx);
+                var fp12smuldtype = readFP12(vector.FP12smuldtype,ctx);
+                a1.copy(fp121);
+                a1.smul(fp12smulydtype, ctx.ECP.D_TYPE);
+                expect(a1.toString()).to.equal(fp12smuldtype.toString());
+
+                // test smultiplication for M-TYPE
+                var fp12smulymtype = readFP12(vector.FP12smulymtype,ctx);
+                var fp12smulmtype = readFP12(vector.FP12smulmtype,ctx);
+                a1.copy(fp121);
+                a1.smul(fp12smulymtype, ctx.ECP.M_TYPE);
+                expect(a1.toString()).to.equal(fp12smulmtype.toString());
+
+                // test power
+                var fp12pow = readFP12(vector.FP12pow, ctx);
+                a1 = fp121.pow(BIGsc1);
+                expect(a1.toString()).to.equal(fp12pow.toString());
+
+                // test power by small integer
+                var fp12pinpow = readFP12(vector.FP12pinpow, ctx);
+                a1.copy(fp121);
+                a1.pinpow(i+1,10);
+                expect(a1.toString()).to.equal(fp12pinpow.toString());
+                i++;
+
+                // test frobenius
+                var fp12frob = readFP12(vector.FP12frob, ctx);
+                a1.copy(fp121);
+                a1.frob(Fr);
+                expect(a1.toString()).to.equal(fp12frob.toString());
+
+                // test compressed power with big integer
+                var fp12compow = readFP4(vector.FP12compow, ctx);
+                a1 = fp12c.compow(BIGsc1,BIGsco);
+                expect(a1.toString()).to.equal(fp12compow.toString());
+
+                // test compressed power with small integer
+                var fp12compows = readFP4(vector.FP12compows, ctx);
+                a1 = fp12c.compow(BIGscs,BIGsco);
+                expect(a1.toString()).to.equal(fp12compows.toString());
+
+                // test pow4
+                // Executed only once for timing reasons
+                if (i===0) {
+                    var fp12pow4 = readFP12(vector.FP12pow4, ctx);
+                    a1 = ctx.FP12.pow4([fp121,fp122,fp123,fp124],[BIGsc1,BIGsc2,BIGsc3,BIGsc4]);
+                    expect(a1.toString()).to.equal(fp12pow4.toString());
+                }
+
+                //test trace
+                var fp4trace = readFP4(vector.FP4trace, ctx);
+                a1 = fp121.trace();
+                expect(a1.toString()).to.equal(fp4trace.toString());
+            });
+            done();
+        });
+    });
+});
diff --git a/test/test_FP16_js b/test/test_FP16_js
new file mode 100644
index 0000000..7ff7511
--- /dev/null
+++ b/test/test_FP16_js
@@ -0,0 +1,249 @@
+/*
+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.
+*/
+
+
+/* Test FP16 ARITHMETICS - test driver and function exerciser for FP16 API Functions */
+
+var chai = require('chai');
+
+var CTX = require("../index");
+
+var expect = chai.expect;
+
+var pf_curves = ['BLS48'];
+
+var readBIG = function(string, ctx) {
+    while (string.length != ctx.BIG.MODBYTES*2){string = "00"+string;}
+    return ctx.BIG.fromBytes(Buffer.from(string, "hex"));
+}
+
+var readFP2 = function(string, ctx) {
+    string = string.split(",");
+    var cox = string[0].slice(1);
+    var coy = string[1].slice(0,-1);
+
+    var x = readBIG(cox,ctx);
+    var y = readBIG(coy,ctx);
+
+    return new ctx.FP2(x,y);;
+}
+
+var readFP4 = function(string, ctx) {
+    var X, Y;
+
+    string = string.split("],[");
+    var cox = string[0].slice(1) + "]";
+    var coy = "[" + string[1].slice(0,-1);
+
+    X = readFP2(cox,ctx);
+    Y = readFP2(coy,ctx);
+
+    return new ctx.FP4(X,Y);
+}
+
+var readFP8 = function(string, ctx) {
+    var X, Y;
+
+    string = string.split("]],[[");
+    var cox = string[0].slice(1) + "]]";
+    var coy = "[[" + string[1].slice(0,-1);
+
+    X = readFP4(cox,ctx);
+    Y = readFP4(coy,ctx);
+
+    return new ctx.FP8(X,Y);
+}
+
+var readFP16 = function(string, ctx) {
+    var X, Y;
+
+    string = string.split("]]],[[[");
+    var cox = string[0].slice(1) + "]]]";
+    var coy = "[[[" + string[1].slice(0,-1);
+
+    X = readFP8(cox,ctx);
+    Y = readFP8(coy,ctx);
+
+    return new ctx.FP16(X,Y);
+}
+
+describe('TEST FP16 ARITHMETIC', function() {
+
+    pf_curves.forEach(function(curve){
+
+        it('test '+ curve, function(done) {
+            this.timeout(0);
+
+            var ctx = new CTX(curve);
+            var vectors = require('../testVectors/fp16/'+curve+'.json');
+
+            var a1 = new ctx.FP16(0),
+                a2 = new ctx.FP16(0),
+                one = new ctx.FP16(1),
+                zero = new ctx.FP16(0),
+                fp8one = new ctx.FP8(1),
+                fp8zero = new ctx.FP8(0);
+
+            // Test iszilch and isunity
+            expect(zero.iszilch()).to.be.true;
+            expect(one.iszilch()).to.be.false;
+            expect(zero.isunity()).to.be.false;
+            expect(one.isunity()).to.be.true;
+
+            // Test real/isreal
+            expect(one.isreal()).to.be.true;
+            expect(one.real().toString()).to.be.equal(fp8one.toString());
+            one.times_i();
+            expect(one.isreal()).to.be.false;
+            expect(one.real().toString()).to.be.equal(fp8zero.toString());
+
+            // Test set using FP8
+            one.set(fp8one,fp8zero);
+            expect(one.isunity()).to.be.true;
+            one.seta(fp8one);
+            expect(one.isunity()).to.be.true;
+
+            var i=0;
+            vectors.forEach(function(vector){
+
+                // test commutativity of addition
+                var fp161 = readFP16(vector.FP161,ctx);
+                var fp162 = readFP16(vector.FP162,ctx);
+                var fp16add = readFP16(vector.FP16add,ctx);
+
+                a1.copy(fp161);
+                a1.add(fp162);
+                expect(a1.toString()).to.equal(fp16add.toString());
+                a2.copy(fp162);
+                a2.add(fp161);
+                expect(a2.toString()).to.equal(fp16add.toString());
+
+                // test associativity of addition
+                a2.add(fp16add);
+                a1.copy(fp161);
+                a1.add(fp16add);
+                a1.add(fp162);
+                expect(a1.toString()).to.equal(a2.toString());
+
+                // test subtraction
+                var fp16sub = readFP16(vector.FP16sub, ctx);
+                a1.copy(fp161);
+                a1.sub(fp162);
+                expect(a1.toString()).to.equal(fp16sub.toString());
+
+                // test negative of a FP16
+                var fp16neg = readFP16(vector.FP16neg, ctx);
+                a1.copy(fp161);
+                a1.neg();
+                expect(a1.toString()).to.equal(fp16neg.toString());
+
+                // test conjugate of a FP16
+                var fp16conj = readFP16(vector.FP16conj, ctx);
+                a1.copy(fp161);
+                a1.conj();
+                expect(a1.toString()).to.equal(fp16conj.toString());
+
+                // test negative conjugate of a FP16
+                var fp16nconj = readFP16(vector.FP16nconj, ctx);
+                a1.copy(fp161);
+                a1.nconj();
+                expect(a1.toString()).to.equal(fp16nconj.toString());
+
+                // test multiplication by FP2
+                var fp16qmul = readFP16(vector.FP16qmul, ctx);
+                var fp2sc = readFP2(vector.FP2sc, ctx);
+                a1.copy(fp161);
+                a1.qmul(fp2sc);
+                expect(a1.toString()).to.equal(fp16qmul.toString());
+
+                // test multiplication by FP8
+                var fp16pmul = readFP16(vector.FP16pmul, ctx);
+                var fp8sc = readFP8(vector.FP8sc, ctx);
+                a1.copy(fp161);
+                a1.pmul(fp8sc);
+                expect(a1.toString()).to.equal(fp16pmul.toString());
+
+                // test small scalar multiplication
+                var fp16imul = readFP16(vector.FP16imul, ctx);
+                a1.copy(fp161);
+                a1.imul(i);
+                expect(a1.toString()).to.equal(fp16imul.toString());
+                i++;
+
+                // test square
+                var fp16sqr = readFP16(vector.FP16sqr, ctx);
+                a1.copy(fp161);
+                a1.sqr();
+                expect(a1.toString()).to.equal(fp16sqr.toString());
+
+                // test multiplication
+                var fp16mul = readFP16(vector.FP16mul, ctx);
+                a1.copy(fp161);
+                a1.mul(fp162);
+                expect(a1.toString()).to.equal(fp16mul.toString());
+
+                // test power
+                var fp16pow = readFP16(vector.FP16pow, ctx);
+                var BIGsc1 = readBIG(vector.BIGsc1, ctx);
+                a1 = fp161.pow(BIGsc1);
+                expect(a1.toString()).to.equal(fp16pow.toString());
+
+                // test inverse
+                var fp16inv = readFP16(vector.FP16inv, ctx);
+                a1.copy(fp161);
+                a1.inverse();
+                expect(a1.toString()).to.equal(fp16inv.toString());
+
+                // test multiplication by sqrt(1+sqrt(-1))
+                var fp16mulj = readFP16(vector.FP16mulj, ctx);
+                a1.copy(fp161);
+                a1.times_i();
+                expect(a1.toString()).to.equal(fp16mulj.toString());
+
+                // // test the XTR addition function r=w*x-conj(x)*y+z
+                var fp16xtrA = readFP16(vector.FP16xtrA, ctx);
+                a1.copy(fp162);
+                a1.xtr_A(fp161,fp16add,fp16sub);
+                expect(a1.toString()).to.equal(fp16xtrA.toString());
+
+                // test the XTR addition function r=w*x-conj(x)*y+z
+                var fp16xtrD = readFP16(vector.FP16xtrD, ctx);
+                a1.copy(fp161);
+                a1.xtr_D();
+                expect(a1.toString()).to.equal(fp16xtrD.toString());
+
+                // test the XTR single power r=Tr(x^e)
+                var fp16xtrpow = readFP16(vector.FP16xtrpow, ctx);
+                var fp481 = readFP16(vector.FP481, ctx);
+                a1 = fp481.xtr_pow(BIGsc1);
+                expect(a1.toString()).to.equal(fp16xtrpow.toString());
+
+                // test the XTR double power r=Tr(x^e)
+                var fp16xtrpow2 = readFP16(vector.FP16xtrpow2, ctx);
+                var fp482 = readFP16(vector.FP482, ctx);
+                var fp483 = readFP16(vector.FP483, ctx);
+                var fp484 = readFP16(vector.FP484, ctx);
+                var BIGsc2 = readBIG(vector.BIGsc2, ctx);
+                a1 = fp481.xtr_pow2(fp482,fp483,fp484,BIGsc2,BIGsc1);
+                expect(a1.toString()).to.equal(fp16xtrpow2.toString());
+            });
+            done();
+        });
+    });
+});
diff --git a/test/test_FP24_js b/test/test_FP24_js
new file mode 100644
index 0000000..da76b0f
--- /dev/null
+++ b/test/test_FP24_js
@@ -0,0 +1,235 @@
+/*
+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.
+*/
+
+
+/* Test FP24 ARITHMETICS - test driver and function exerciser for FP4 API Functions */
+
+var chai = require('chai');
+
+var CTX = require("../index");
+
+var expect = chai.expect;
+
+var pf_curves = ['BLS24'];
+
+var readBIG = function(string, ctx) {
+    while (string.length != ctx.BIG.MODBYTES*2){string = "00"+string;}
+    return ctx.BIG.fromBytes(Buffer.from(string, "hex"));
+}
+
+var readFP2 = function(string, ctx) {
+    string = string.split(",");
+    var cox = string[0].slice(1);
+    var coy = string[1].slice(0,-1);
+
+    var x = readBIG(cox,ctx);
+    var y = readBIG(coy,ctx);
+
+    return new ctx.FP2(x,y);;
+}
+
+var readFP4 = function(string, ctx) {
+    var X, Y;
+
+    string = string.split("],[");
+    var cox = string[0].slice(1) + "]";
+    var coy = "[" + string[1].slice(0,-1);
+
+    X = readFP2(cox,ctx);
+    Y = readFP2(coy,ctx);
+
+    return new ctx.FP4(X,Y);
+}
+
+var readFP8 = function(string, ctx) {
+    var X, Y;
... 1392 lines suppressed ...