diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,12 @@
    - SPDX-License-Identifier: MPL-2.0
    -->
 
+## v0.0.3
+
+* Minor tweaks for GHC 9.8 compatibility.
+* Types `Point` and `Affine` now have `PointKind` parameter be role `nominal`, as coercing those between point types will break invariants.
+* Bundled blst version bumped to v0.3.11.
+
 ## v0.0.2
 
 * Prevent inlining of foreign calls. This fixes a potential efficiency issue,
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
 
 HsBLST is low-level Haskell bindings and a high-level interface to [BLST](https://github.com/supranational/blst) -- a multilingual BLS12-381 signature library.
 
-This package includes sources from v0.3.10 version of BLST, licensed under
+This package includes sources from v0.3.11 version of BLST, licensed under
 [Apache License 2.0](https://github.com/supranational/blst/blob/master/LICENSE)
 
 ## Build Instructions [↑](#hsblst)
diff --git a/c-source/README.md b/c-source/README.md
--- a/c-source/README.md
+++ b/c-source/README.md
@@ -1,4 +1,4 @@
-[![Build Status](https://travis-ci.com/supranational/blst.svg?branch=master)](https://travis-ci.com/github/supranational/blst) [![Actions status](https://github.com/supranational/blst/workflows/build/badge.svg)](https://github.com/supranational/blst/actions) [![Total alerts](https://img.shields.io/lgtm/alerts/g/supranational/blst.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/supranational/blst/alerts/)
+[![Build Status](https://travis-ci.com/supranational/blst.svg?branch=master)](https://travis-ci.com/github/supranational/blst) [![Actions status](https://github.com/supranational/blst/workflows/build/badge.svg)](https://github.com/supranational/blst/actions)
 <div align="left">
   <img src=blst_logo_small.png>
 </div>
@@ -56,6 +56,8 @@
 - [Python](bindings/python)
 - [Java](bindings/java)
 - [Node.js](bindings/node.js)
+- [Emscripten](bindings/emscripten)
+- [C#](bindings/c%23)
 
 ## API
 
@@ -134,7 +136,7 @@
 * The third-most significant bit is set if (and only if) this point is in compressed form _and_ it is not the point at infinity _and_ its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate.
 
 ## Build
-The build process is very simple and only requires a C complier. It's integrated into the Go and Rust ecosystems, so that respective users would go about as they would with any other external module. Otherwise, a binary library would have to be compiled.
+The build process is very simple and only requires a C compiler. It's integrated into the Go and Rust ecosystems, so that respective users would go about as they would with any other external module. Otherwise, a binary library would have to be compiled.
 
 ### C static library
 A static library called libblst.a can be built in the current working directory of the user's choice:
diff --git a/c-source/bindings/blst.h b/c-source/bindings/blst.h
--- a/c-source/bindings/blst.h
+++ b/c-source/bindings/blst.h
@@ -83,7 +83,7 @@
 
 #ifndef SWIG
 /*
- * BLS12-381-specifc Fr operations.
+ * BLS12-381-specific Fr operations.
  */
 void blst_fr_add(blst_fr *ret, const blst_fr *a, const blst_fr *b);
 void blst_fr_sub(blst_fr *ret, const blst_fr *a, const blst_fr *b);
@@ -102,7 +102,7 @@
 void blst_scalar_from_fr(blst_scalar *ret, const blst_fr *a);
 
 /*
- * BLS12-381-specifc Fp operations.
+ * BLS12-381-specific Fp operations.
  */
 void blst_fp_add(blst_fp *ret, const blst_fp *a, const blst_fp *b);
 void blst_fp_sub(blst_fp *ret, const blst_fp *a, const blst_fp *b);
@@ -126,7 +126,7 @@
 void blst_lendian_from_fp(byte ret[48], const blst_fp *a);
 
 /*
- * BLS12-381-specifc Fp2 operations.
+ * BLS12-381-specific Fp2 operations.
  */
 void blst_fp2_add(blst_fp2 *ret, const blst_fp2 *a, const blst_fp2 *b);
 void blst_fp2_sub(blst_fp2 *ret, const blst_fp2 *a, const blst_fp2 *b);
@@ -141,7 +141,7 @@
 bool blst_fp2_sqrt(blst_fp2 *ret, const blst_fp2 *a);
 
 /*
- * BLS12-381-specifc Fp12 operations.
+ * BLS12-381-specific Fp12 operations.
  */
 void blst_fp12_sqr(blst_fp12 *ret, const blst_fp12 *a);
 void blst_fp12_cyclotomic_sqr(blst_fp12 *ret, const blst_fp12 *a);
@@ -155,11 +155,11 @@
 bool blst_fp12_is_equal(const blst_fp12 *a, const blst_fp12 *b);
 bool blst_fp12_is_one(const blst_fp12 *a);
 bool blst_fp12_in_group(const blst_fp12 *a);
-const blst_fp12 *blst_fp12_one();
+const blst_fp12 *blst_fp12_one(void);
 #endif  // SWIG
 
 /*
- * BLS12-381-specifc point operations.
+ * BLS12-381-specific point operations.
  */
 typedef struct { blst_fp x, y, z; } blst_p1;
 typedef struct { blst_fp x, y; } blst_p1_affine;
@@ -180,13 +180,13 @@
 bool blst_p1_in_g1(const blst_p1 *p);
 bool blst_p1_is_equal(const blst_p1 *a, const blst_p1 *b);
 bool blst_p1_is_inf(const blst_p1 *a);
-const blst_p1 *blst_p1_generator();
+const blst_p1 *blst_p1_generator(void);
 
 bool blst_p1_affine_on_curve(const blst_p1_affine *p);
 bool blst_p1_affine_in_g1(const blst_p1_affine *p);
 bool blst_p1_affine_is_equal(const blst_p1_affine *a, const blst_p1_affine *b);
 bool blst_p1_affine_is_inf(const blst_p1_affine *a);
-const blst_p1_affine *blst_p1_affine_generator();
+const blst_p1_affine *blst_p1_affine_generator(void);
 
 typedef struct { blst_fp2 x, y, z; } blst_p2;
 typedef struct { blst_fp2 x, y; } blst_p2_affine;
@@ -207,13 +207,13 @@
 bool blst_p2_in_g2(const blst_p2 *p);
 bool blst_p2_is_equal(const blst_p2 *a, const blst_p2 *b);
 bool blst_p2_is_inf(const blst_p2 *a);
-const blst_p2 *blst_p2_generator();
+const blst_p2 *blst_p2_generator(void);
 
 bool blst_p2_affine_on_curve(const blst_p2_affine *p);
 bool blst_p2_affine_in_g2(const blst_p2_affine *p);
 bool blst_p2_affine_is_equal(const blst_p2_affine *a, const blst_p2_affine *b);
 bool blst_p2_affine_is_inf(const blst_p2_affine *a);
-const blst_p2_affine *blst_p2_affine_generator();
+const blst_p2_affine *blst_p2_affine_generator(void);
 
 /*
  * Multi-scalar multiplications and other multi-point operations.
@@ -337,6 +337,9 @@
 #ifndef SWIG
 void blst_miller_loop(blst_fp12 *ret, const blst_p2_affine *Q,
                                       const blst_p1_affine *P);
+void blst_miller_loop_n(blst_fp12 *ret, const blst_p2_affine *const Qs[],
+                                        const blst_p1_affine *const Ps[],
+                                        size_t n);
 void blst_final_exp(blst_fp12 *ret, const blst_fp12 *f);
 void blst_precompute_lines(blst_fp6 Qlines[68], const blst_p2_affine *Q);
 void blst_miller_loop_lines(blst_fp12 *ret, const blst_fp6 Qlines[68],
@@ -352,7 +355,7 @@
 typedef struct blst_opaque blst_pairing;
 #endif
 
-size_t blst_pairing_sizeof();
+size_t blst_pairing_sizeof(void);
 void blst_pairing_init(blst_pairing *new_ctx, bool hash_or_encode,
                        const byte *DST DEFNULL, size_t DST_len DEFNULL);
 const byte *blst_pairing_get_dst(const blst_pairing *ctx);
diff --git a/c-source/bindings/blst_aux.h b/c-source/bindings/blst_aux.h
--- a/c-source/bindings/blst_aux.h
+++ b/c-source/bindings/blst_aux.h
@@ -10,8 +10,14 @@
  * depending on their proven/unproven worthiness.
  */
 
+void blst_fr_ct_bfly(blst_fr *x0, blst_fr *x1, const blst_fr *twiddle);
+void blst_fr_gs_bfly(blst_fr *x0, blst_fr *x1, const blst_fr *twiddle);
 void blst_fr_to(blst_fr *ret, const blst_fr *a);
 void blst_fr_from(blst_fr *ret, const blst_fr *a);
+#ifdef BLST_FR_PENTAROOT
+void blst_fr_pentaroot(blst_fr *ret, const blst_fr *a);
+void blst_fr_pentapow(blst_fr *ret, const blst_fr *a);
+#endif
 
 void blst_fp_to(blst_fp *ret, const blst_fp *a);
 void blst_fp_from(blst_fp *ret, const blst_fp *a);
@@ -50,7 +56,11 @@
 void blst_sign_pk2_in_g2(byte out[96], blst_p1_affine *out_sig,
                          const blst_p1 *hash, const blst_scalar *SK);
 
+#ifdef __BLST_RUST_BINDGEN__
 typedef struct {} blst_uniq;
+#else
+typedef struct blst_opaque blst_uniq;
+#endif
 
 size_t blst_uniq_sizeof(size_t n_nodes);
 void blst_uniq_init(blst_uniq *tree);
@@ -94,9 +104,14 @@
 void blst_fr_from_hexascii(blst_fr *ret, const byte *hex);
 void blst_fp_from_hexascii(blst_fp *ret, const byte *hex);
 
-size_t blst_p1_sizeof();
-size_t blst_p1_affine_sizeof();
-size_t blst_p2_sizeof();
-size_t blst_p2_affine_sizeof();
-size_t blst_fp12_sizeof();
+size_t blst_p1_sizeof(void);
+size_t blst_p1_affine_sizeof(void);
+size_t blst_p2_sizeof(void);
+size_t blst_p2_affine_sizeof(void);
+size_t blst_fp12_sizeof(void);
+
+/*
+ * Single-shot SHA-256 hash function.
+ */
+void blst_sha256(byte out[32], const byte *msg, size_t msg_len);
 #endif
diff --git a/c-source/build/assembly.S b/c-source/build/assembly.S
--- a/c-source/build/assembly.S
+++ b/c-source/build/assembly.S
@@ -2,23 +2,22 @@
 # if defined(__ELF__)
 #  if defined(__BLST_PORTABLE__)
 #   include "elf/sha256-portable-x86_64.s"
-#  else
-#   include "elf/sha256-x86_64.s"
+#   define blst_sha256_block_data_order blst_sha256_block_ssse3
 #  endif
-#  if defined(__ADX__) && !defined(__BLST_PORTABLE__)
+#  include "elf/sha256-x86_64.s"
+#  if defined(__ADX__) || defined(__BLST_PORTABLE__)
 #   include "elf/ctx_inverse_mod_384-x86_64.s"
-#  else
+#  endif
+#  if !defined(__ADX__) || defined(__BLST_PORTABLE__)
 #   include "elf/ctq_inverse_mod_384-x86_64.s"
 #  endif
 #  include "elf/add_mod_384-x86_64.s"
 #  include "elf/add_mod_384x384-x86_64.s"
-#  define __add_mod_384     __add_mont_384
-#  define __sub_mod_384     __sub_mont_384
-#  define __sub_mod_384x384 __sub_mont_384x384
-#  if defined(__ADX__) && !defined(__BLST_PORTABLE__)
+#  if defined(__ADX__) || defined(__BLST_PORTABLE__)
 #   include "elf/mulx_mont_384-x86_64.s"
 #   include "elf/mulx_mont_256-x86_64.s"
-#  else
+#  endif
+#  if !defined(__ADX__) || defined(__BLST_PORTABLE__)
 #   include "elf/mulq_mont_384-x86_64.s"
 #   include "elf/mulq_mont_256-x86_64.s"
 #  endif
@@ -27,25 +26,20 @@
 #  include "elf/div3w-x86_64.s"
 #  include "elf/ct_is_square_mod_384-x86_64.s"
 # elif defined(_WIN64) || defined(__CYGWIN__)
-#  if defined(__BLST_PORTABLE__)
-#   include "coff/sha256-portable-x86_64.s"
-#  else
-#   include "coff/sha256-x86_64.s"
-#  endif
-#  if defined(__ADX__) && !defined(__BLST_PORTABLE__)
+#  include "coff/sha256-x86_64.s"
+#  if defined(__ADX__) || defined(__BLST_PORTABLE__)
 #   include "coff/ctx_inverse_mod_384-x86_64.s"
-#  else
+#  endif
+#  if !defined(__ADX__) || defined(__BLST_PORTABLE__)
 #   include "coff/ctq_inverse_mod_384-x86_64.s"
 #  endif
 #  include "coff/add_mod_384-x86_64.s"
 #  include "coff/add_mod_384x384-x86_64.s"
-#  define __add_mod_384     __add_mont_384
-#  define __sub_mod_384     __sub_mont_384
-#  define __sub_mod_384x384 __sub_mont_384x384
-#  if defined(__ADX__) && !defined(__BLST_PORTABLE__)
+#  if defined(__ADX__) || defined(__BLST_PORTABLE__)
 #   include "coff/mulx_mont_384-x86_64.s"
 #   include "coff/mulx_mont_256-x86_64.s"
-#  else
+#  endif
+#  if !defined(__ADX__) || defined(__BLST_PORTABLE__)
 #   include "coff/mulq_mont_384-x86_64.s"
 #   include "coff/mulq_mont_256-x86_64.s"
 #  endif
@@ -55,20 +49,19 @@
 #  include "coff/ct_is_square_mod_384-x86_64.s"
 # elif defined(__APPLE__)
 #  include "mach-o/sha256-x86_64.s"
-#  if defined(__ADX__) && !defined(__BLST_PORTABLE__)
+#  if defined(__ADX__) || defined(__BLST_PORTABLE__)
 #   include "mach-o/ctx_inverse_mod_384-x86_64.s"
-#  else
+#  endif
+#  if !defined(__ADX__) || defined(__BLST_PORTABLE__)
 #   include "mach-o/ctq_inverse_mod_384-x86_64.s"
 #  endif
 #  include "mach-o/add_mod_384-x86_64.s"
 #  include "mach-o/add_mod_384x384-x86_64.s"
-#  define __add_mod_384     __add_mont_384
-#  define __sub_mod_384     __sub_mont_384
-#  define __sub_mod_384x384 __sub_mont_384x384
-#  if defined(__ADX__) && !defined(__BLST_PORTABLE__)
+#  if defined(__ADX__) || defined(__BLST_PORTABLE__)
 #   include "mach-o/mulx_mont_384-x86_64.s"
 #   include "mach-o/mulx_mont_256-x86_64.s"
-#  else
+#  endif
+#  if !defined(__ADX__) || defined(__BLST_PORTABLE__)
 #   include "mach-o/mulq_mont_384-x86_64.s"
 #   include "mach-o/mulq_mont_256-x86_64.s"
 #  endif
diff --git a/c-source/build/coff/add_mod_256-x86_64.s b/c-source/build/coff/add_mod_256-x86_64.s
--- a/c-source/build/coff/add_mod_256-x86_64.s
+++ b/c-source/build/coff/add_mod_256-x86_64.s
@@ -10,14 +10,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_add_mod_256:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	subq	$8,%rsp
@@ -81,13 +81,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_mul_by_3_mod_256:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
 	pushq	%rbx
 
 	pushq	%r12
@@ -161,14 +161,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_lshift_mod_256:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	pushq	%r12
@@ -218,14 +218,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_rshift_mod_256:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	subq	$8,%rsp
@@ -307,14 +307,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_cneg_mod_256:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	pushq	%r12
@@ -385,14 +385,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sub_mod_256:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	subq	$8,%rsp
@@ -454,10 +454,10 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_check_mod_256:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
 
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
 	movq	0(%rdi),%rax
 	movq	8(%rdi),%r9
 	movq	16(%rdi),%r10
@@ -497,14 +497,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_add_n_check_mod_256:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	subq	$8,%rsp
@@ -573,14 +573,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sub_n_check_mod_256:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	subq	$8,%rsp
@@ -744,8 +744,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_add_mod_256_body:
 .byte	1,0,9,0
 .byte	0x00,0x34,0x01,0x00
@@ -753,7 +754,8 @@
 .byte	0x00,0x74,0x04,0x00
 .byte	0x00,0x64,0x05,0x00
 .byte	0x00,0x22
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_add_mod_256_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -764,8 +766,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_mul_by_3_mod_256_body:
 .byte	1,0,11,0
 .byte	0x00,0xc4,0x00,0x00
@@ -785,8 +788,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_lshift_mod_256_body:
 .byte	1,0,11,0
 .byte	0x00,0xc4,0x00,0x00
@@ -806,8 +810,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_rshift_mod_256_body:
 .byte	1,0,9,0
 .byte	0x00,0x34,0x01,0x00
@@ -815,7 +820,8 @@
 .byte	0x00,0x74,0x04,0x00
 .byte	0x00,0x64,0x05,0x00
 .byte	0x00,0x22
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_rshift_mod_256_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -826,8 +832,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_cneg_mod_256_body:
 .byte	1,0,11,0
 .byte	0x00,0xc4,0x00,0x00
@@ -847,8 +854,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sub_mod_256_body:
 .byte	1,0,9,0
 .byte	0x00,0x34,0x01,0x00
@@ -856,7 +864,8 @@
 .byte	0x00,0x74,0x04,0x00
 .byte	0x00,0x64,0x05,0x00
 .byte	0x00,0x22
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sub_mod_256_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -873,8 +882,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_add_n_check_mod_256_body:
 .byte	1,0,9,0
 .byte	0x00,0x34,0x01,0x00
@@ -882,7 +892,8 @@
 .byte	0x00,0x74,0x04,0x00
 .byte	0x00,0x64,0x05,0x00
 .byte	0x00,0x22
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_add_n_check_mod_256_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -893,8 +904,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sub_n_check_mod_256_body:
 .byte	1,0,9,0
 .byte	0x00,0x34,0x01,0x00
@@ -902,7 +914,8 @@
 .byte	0x00,0x74,0x04,0x00
 .byte	0x00,0x64,0x05,0x00
 .byte	0x00,0x22
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sub_n_check_mod_256_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
diff --git a/c-source/build/coff/add_mod_384-armv8.S b/c-source/build/coff/add_mod_384-armv8.S
--- a/c-source/build/coff/add_mod_384-armv8.S
+++ b/c-source/build/coff/add_mod_384-armv8.S
@@ -786,6 +786,23 @@
 
 	ret
 
+.globl	vec_select_32
+
+.def	vec_select_32;
+.type	32;
+.endef
+.p2align	5
+vec_select_32:
+	dup	v6.2d, x3
+	ld1	{v0.2d, v1.2d, v2.2d}, [x1],#48
+	cmeq	v6.2d, v6.2d, #0
+	ld1	{v3.2d, v4.2d, v5.2d}, [x2],#48
+	bit	v0.16b, v3.16b, v6.16b
+	bit	v1.16b, v4.16b, v6.16b
+	bit	v2.16b, v5.16b, v6.16b
+	st1	{v0.2d, v1.2d, v2.2d}, [x0]
+	ret
+
 .globl	vec_select_48
 
 .def	vec_select_48;
@@ -977,5 +994,63 @@
 	cmp	x0, x1
 	csel	x0, x1, x0, hi
 	prfm	pldl1keep, [x0]
+	ret
+
+.globl	vec_is_zero_16x
+
+.def	vec_is_zero_16x;
+.type	32;
+.endef
+.p2align	5
+vec_is_zero_16x:
+	ld1	{v0.2d}, [x0], #16
+	lsr	x1, x1, #4
+	sub	x1, x1, #1
+	cbz	x1, .Loop_is_zero_done
+
+.Loop_is_zero:
+	ld1	{v1.2d}, [x0], #16
+	orr	v0.16b, v0.16b, v1.16b
+	sub	x1, x1, #1
+	cbnz	x1, .Loop_is_zero
+
+.Loop_is_zero_done:
+	dup	v1.2d, v0.d[1]
+	orr	v0.16b, v0.16b, v1.16b
+	mov	x1, v0.d[0]
+	mov	x0, #1
+	cmp	x1, #0
+	csel	x0, x0, xzr, eq
+	ret
+
+.globl	vec_is_equal_16x
+
+.def	vec_is_equal_16x;
+.type	32;
+.endef
+.p2align	5
+vec_is_equal_16x:
+	ld1	{v0.2d}, [x0], #16
+	ld1	{v1.2d}, [x1], #16
+	lsr	x2, x2, #4
+	eor	v0.16b, v0.16b, v1.16b
+
+.Loop_is_equal:
+	sub	x2, x2, #1
+	cbz	x2, .Loop_is_equal_done
+	ld1	{v1.2d}, [x0], #16
+	ld1	{v2.2d}, [x1], #16
+	eor	v1.16b, v1.16b, v2.16b
+	orr	v0.16b, v0.16b, v1.16b
+	b	.Loop_is_equal
+	nop
+
+.Loop_is_equal_done:
+	dup	v1.2d, v0.d[1]
+	orr	v0.16b, v0.16b, v1.16b
+	mov	x1, v0.d[0]
+	mov	x0, #1
+	cmp	x1, #0
+	csel	x0, x0, xzr, eq
 	ret
 
diff --git a/c-source/build/coff/add_mod_384-x86_64.s b/c-source/build/coff/add_mod_384-x86_64.s
--- a/c-source/build/coff/add_mod_384-x86_64.s
+++ b/c-source/build/coff/add_mod_384-x86_64.s
@@ -10,14 +10,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_add_mod_384:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	pushq	%r12
@@ -118,14 +118,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_add_mod_384x:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	pushq	%r12
@@ -186,14 +186,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_rshift_mod_384:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	pushq	%r12
@@ -315,13 +315,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_div_by_2_mod_384:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
 	pushq	%rbx
 
 	pushq	%r12
@@ -387,14 +387,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_lshift_mod_384:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	pushq	%r12
@@ -528,13 +528,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_mul_by_3_mod_384:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
 	pushq	%rbx
 
 	pushq	%r12
@@ -595,13 +595,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_mul_by_8_mod_384:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
 	pushq	%rbx
 
 	pushq	%r12
@@ -669,13 +669,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_mul_by_3_mod_384x:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
 	pushq	%rbx
 
 	pushq	%r12
@@ -752,13 +752,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_mul_by_8_mod_384x:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
 	pushq	%rbx
 
 	pushq	%r12
@@ -845,14 +845,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_cneg_mod_384:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	pushq	%r12
@@ -952,14 +952,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sub_mod_384:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	pushq	%r12
@@ -1058,14 +1058,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sub_mod_384x:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	pushq	%r12
@@ -1124,13 +1124,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_mul_by_1_plus_i_mod_384x:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
 	pushq	%rbx
 
 	pushq	%r12
@@ -1274,10 +1274,10 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sgn0_pty_mod_384:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
 
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
 .LSEH_body_sgn0_pty_mod_384:
 
 	movq	0(%rdi),%r8
@@ -1328,12 +1328,12 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sgn0_pty_mod_384x:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
 	pushq	%rbx
 
 	subq	$8,%rsp
@@ -1439,6 +1439,35 @@
 	.byte	0xf3,0xc3
 
 .LSEH_end_sgn0_pty_mod_384x:
+.globl	vec_select_32
+
+.def	vec_select_32;	.scl 2;	.type 32;	.endef
+.p2align	5
+vec_select_32:
+	.byte	0xf3,0x0f,0x1e,0xfa
+
+	movd	%r9d,%xmm5
+	pxor	%xmm4,%xmm4
+	pshufd	$0,%xmm5,%xmm5
+	movdqu	(%rdx),%xmm0
+	leaq	16(%rdx),%rdx
+	pcmpeqd	%xmm4,%xmm5
+	movdqu	(%r8),%xmm1
+	leaq	16(%r8),%r8
+	pcmpeqd	%xmm5,%xmm4
+	leaq	16(%rcx),%rcx
+	pand	%xmm4,%xmm0
+	movdqu	0+16-16(%rdx),%xmm2
+	pand	%xmm5,%xmm1
+	movdqu	0+16-16(%r8),%xmm3
+	por	%xmm1,%xmm0
+	movdqu	%xmm0,0-16(%rcx)
+	pand	%xmm4,%xmm2
+	pand	%xmm5,%xmm3
+	por	%xmm3,%xmm2
+	movdqu	%xmm2,16-16(%rcx)
+	.byte	0xf3,0xc3
+
 .globl	vec_select_48
 
 .def	vec_select_48;	.scl 2;	.type 32;	.endef
@@ -1854,6 +1883,69 @@
 	prefetchnta	(%rcx)
 	.byte	0xf3,0xc3
 
+.globl	vec_is_zero_16x
+
+.def	vec_is_zero_16x;	.scl 2;	.type 32;	.endef
+.p2align	5
+vec_is_zero_16x:
+	.byte	0xf3,0x0f,0x1e,0xfa
+
+	shrl	$4,%edx
+	movdqu	(%rcx),%xmm0
+	leaq	16(%rcx),%rcx
+
+.Loop_is_zero:
+	decl	%edx
+	jz	.Loop_is_zero_done
+	movdqu	(%rcx),%xmm1
+	leaq	16(%rcx),%rcx
+	por	%xmm1,%xmm0
+	jmp	.Loop_is_zero
+
+.Loop_is_zero_done:
+	pshufd	$0x4e,%xmm0,%xmm1
+	por	%xmm1,%xmm0
+.byte	102,72,15,126,192
+	incl	%edx
+	testq	%rax,%rax
+	cmovnzl	%edx,%eax
+	xorl	$1,%eax
+	.byte	0xf3,0xc3
+
+.globl	vec_is_equal_16x
+
+.def	vec_is_equal_16x;	.scl 2;	.type 32;	.endef
+.p2align	5
+vec_is_equal_16x:
+	.byte	0xf3,0x0f,0x1e,0xfa
+
+	shrl	$4,%r8d
+	movdqu	(%rcx),%xmm0
+	movdqu	(%rdx),%xmm1
+	subq	%rcx,%rdx
+	leaq	16(%rcx),%rcx
+	pxor	%xmm1,%xmm0
+
+.Loop_is_equal:
+	decl	%r8d
+	jz	.Loop_is_equal_done
+	movdqu	(%rcx),%xmm1
+	movdqu	(%rcx,%rdx,1),%xmm2
+	leaq	16(%rcx),%rcx
+	pxor	%xmm2,%xmm1
+	por	%xmm1,%xmm0
+	jmp	.Loop_is_equal
+
+.Loop_is_equal_done:
+	pshufd	$0x4e,%xmm0,%xmm1
+	por	%xmm1,%xmm0
+.byte	102,72,15,126,192
+	incl	%r8d
+	testq	%rax,%rax
+	cmovnzl	%r8d,%eax
+	xorl	$1,%eax
+	.byte	0xf3,0xc3
+
 .section	.pdata
 .p2align	2
 .rva	.LSEH_begin_add_mod_384
@@ -2042,8 +2134,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_add_mod_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -2055,7 +2148,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_add_mod_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -2066,8 +2160,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_add_mod_384x_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x03,0x00
@@ -2079,7 +2174,8 @@
 .byte	0x00,0x74,0x0a,0x00
 .byte	0x00,0x64,0x0b,0x00
 .byte	0x00,0x82
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_add_mod_384x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -2090,8 +2186,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_rshift_mod_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -2103,7 +2200,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_rshift_mod_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -2114,8 +2212,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_div_by_2_mod_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -2127,7 +2226,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_div_by_2_mod_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -2138,8 +2238,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_lshift_mod_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -2151,7 +2252,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_lshift_mod_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -2162,8 +2264,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_mul_by_3_mod_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -2175,7 +2278,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_mul_by_3_mod_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -2186,8 +2290,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_mul_by_8_mod_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -2199,7 +2304,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_mul_by_8_mod_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -2210,8 +2316,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_mul_by_3_mod_384x_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -2223,7 +2330,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_mul_by_3_mod_384x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -2234,8 +2342,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_mul_by_8_mod_384x_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -2247,7 +2356,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_mul_by_8_mod_384x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -2258,8 +2368,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_cneg_mod_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -2271,7 +2382,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_cneg_mod_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -2282,8 +2394,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sub_mod_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -2295,7 +2408,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sub_mod_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -2306,8 +2420,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sub_mod_384x_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x03,0x00
@@ -2319,7 +2434,8 @@
 .byte	0x00,0x74,0x0a,0x00
 .byte	0x00,0x64,0x0b,0x00
 .byte	0x00,0x82
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sub_mod_384x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -2330,8 +2446,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_mul_by_1_plus_i_mod_384x_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x07,0x00
@@ -2343,7 +2460,8 @@
 .byte	0x00,0x74,0x0e,0x00
 .byte	0x00,0x64,0x0f,0x00
 .byte	0x00,0xc2
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_mul_by_1_plus_i_mod_384x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -2354,8 +2472,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sgn0_pty_mod_384_body:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -2371,8 +2490,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sgn0_pty_mod_384x_body:
 .byte	1,0,9,0
 .byte	0x00,0x34,0x01,0x00
@@ -2380,7 +2500,8 @@
 .byte	0x00,0x74,0x04,0x00
 .byte	0x00,0x64,0x05,0x00
 .byte	0x00,0x22
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sgn0_pty_mod_384x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
diff --git a/c-source/build/coff/add_mod_384x384-x86_64.s b/c-source/build/coff/add_mod_384x384-x86_64.s
--- a/c-source/build/coff/add_mod_384x384-x86_64.s
+++ b/c-source/build/coff/add_mod_384x384-x86_64.s
@@ -145,14 +145,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_add_mod_384x384:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	pushq	%r12
@@ -202,14 +202,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sub_mod_384x384:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	pushq	%r12
@@ -280,8 +280,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_add_mod_384x384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -293,7 +294,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_add_mod_384x384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -304,8 +306,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sub_mod_384x384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -317,7 +320,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sub_mod_384x384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
diff --git a/c-source/build/coff/ct_inverse_mod_256-armv8.S b/c-source/build/coff/ct_inverse_mod_256-armv8.S
--- a/c-source/build/coff/ct_inverse_mod_256-armv8.S
+++ b/c-source/build/coff/ct_inverse_mod_256-armv8.S
@@ -1,6 +1,7 @@
 .text
 
 .globl	ct_inverse_mod_256
+
 .def	ct_inverse_mod_256;
 .type	32;
 .endef
@@ -62,14 +63,14 @@
 	madd	x4, x16, x8, xzr	// |u|*|f0|
 	madd	x4, x17, x9, x4	// |v|*|g0|
 	str	x4, [x0,#8*4]
-	asr	x5, x4, #63		// sign extenstion
+	asr	x5, x4, #63		// sign extension
 	stp	x5, x5, [x0,#8*5]
 	stp	x5, x5, [x0,#8*7]
 
 	madd	x4, x12, x8, xzr	// |u|*|f1|
 	madd	x4, x13, x9, x4	// |v|*|g1|
 	str	x4, [x0,#8*9]
-	asr	x5, x4, #63		// sign extenstion
+	asr	x5, x4, #63		// sign extension
 	stp	x5, x5, [x0,#8*10]
 	stp	x5, x5, [x0,#8*12]
 	eor	x1, x1, #256		// flip-flop src |a|b|u|v|
diff --git a/c-source/build/coff/ct_inverse_mod_256-x86_64.s b/c-source/build/coff/ct_inverse_mod_256-x86_64.s
--- a/c-source/build/coff/ct_inverse_mod_256-x86_64.s
+++ b/c-source/build/coff/ct_inverse_mod_256-x86_64.s
@@ -1,6 +1,7 @@
 .text	
 
 .globl	ct_inverse_mod_256
+
 .def	ct_inverse_mod_256;	.scl 2;	.type 32;	.endef
 .p2align	5
 ct_inverse_mod_256:
@@ -9,14 +10,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_ct_inverse_mod_256:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
-	movq	%r9,%rcx
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	movq	%r9,%rcx
 	pushq	%rbx
 
 	pushq	%r12
@@ -1188,8 +1189,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_ct_inverse_mod_256_body:
 .byte	1,0,18,0
 .byte	0x00,0xf4,0x86,0x00
@@ -1201,6 +1203,8 @@
 .byte	0x00,0x74,0x8d,0x00
 .byte	0x00,0x64,0x8e,0x00
 .byte	0x00,0x01,0x8c,0x00
+.byte	0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_ct_inverse_mod_256_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
diff --git a/c-source/build/coff/ct_inverse_mod_384-armv8.S b/c-source/build/coff/ct_inverse_mod_384-armv8.S
--- a/c-source/build/coff/ct_inverse_mod_384-armv8.S
+++ b/c-source/build/coff/ct_inverse_mod_384-armv8.S
@@ -1,6 +1,7 @@
 .text
 
 .globl	ct_inverse_mod_383
+
 .def	ct_inverse_mod_383;
 .type	32;
 .endef
@@ -73,7 +74,7 @@
 	adds	x3, x3, x5
 	adc	x4, x4, x6
 	stp	x3, x4, [x0,#8*6]
-	asr	x5, x4, #63		// sign extenstion
+	asr	x5, x4, #63		// sign extension
 	stp	x5, x5, [x0,#8*8]
 	stp	x5, x5, [x0,#8*10]
 
@@ -84,7 +85,7 @@
 	adds	x3, x3, x5
 	adc	x4, x4, x6
 	stp	x3, x4, [x0,#8*12]
-	asr	x5, x4, #63		// sign extenstion
+	asr	x5, x4, #63		// sign extension
 	stp	x5, x5, [x0,#8*14]
 	stp	x5, x5, [x0,#8*16]
 	eor	x1, x1, #256		// flip-flop src |a|b|u|v|
diff --git a/c-source/build/coff/ct_is_square_mod_384-armv8.S b/c-source/build/coff/ct_is_square_mod_384-armv8.S
--- a/c-source/build/coff/ct_is_square_mod_384-armv8.S
+++ b/c-source/build/coff/ct_is_square_mod_384-armv8.S
@@ -1,6 +1,7 @@
 .text
 
 .globl	ct_is_square_mod_384
+
 .def	ct_is_square_mod_384;
 .type	32;
 .endef
diff --git a/c-source/build/coff/ct_is_square_mod_384-x86_64.s b/c-source/build/coff/ct_is_square_mod_384-x86_64.s
--- a/c-source/build/coff/ct_is_square_mod_384-x86_64.s
+++ b/c-source/build/coff/ct_is_square_mod_384-x86_64.s
@@ -1,6 +1,7 @@
 .text	
 
 .globl	ct_is_square_mod_384
+
 .def	ct_is_square_mod_384;	.scl 2;	.type 32;	.endef
 .p2align	5
 ct_is_square_mod_384:
@@ -9,12 +10,12 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_ct_is_square_mod_384:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
 
 
 	pushq	%rbp
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
 	pushq	%rbx
 
 	pushq	%r12
@@ -484,8 +485,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_ct_is_square_mod_384_body:
 .byte	1,0,18,0
 .byte	0x00,0xf4,0x43,0x00
@@ -497,6 +499,8 @@
 .byte	0x00,0x74,0x4a,0x00
 .byte	0x00,0x64,0x4b,0x00
 .byte	0x00,0x01,0x49,0x00
+.byte	0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_ct_is_square_mod_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
diff --git a/c-source/build/coff/ctq_inverse_mod_384-x86_64.s b/c-source/build/coff/ctq_inverse_mod_384-x86_64.s
--- a/c-source/build/coff/ctq_inverse_mod_384-x86_64.s
+++ b/c-source/build/coff/ctq_inverse_mod_384-x86_64.s
@@ -1,6 +1,8 @@
+.comm	__blst_platform_cap,4
 .text	
 
 .globl	ct_inverse_mod_383
+
 .def	ct_inverse_mod_383;	.scl 2;	.type 32;	.endef
 .p2align	5
 ct_inverse_mod_383:
@@ -9,12 +11,16 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_ct_inverse_mod_383:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	ct_inverse_mod_383$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -1200,8 +1206,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_ct_inverse_mod_383_body:
 .byte	1,0,18,0
 .byte	0x00,0xf4,0x8b,0x00
@@ -1213,6 +1220,8 @@
 .byte	0x00,0x74,0x92,0x00
 .byte	0x00,0x64,0x93,0x00
 .byte	0x00,0x01,0x91,0x00
+.byte	0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_ct_inverse_mod_383_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
diff --git a/c-source/build/coff/ctx_inverse_mod_384-x86_64.s b/c-source/build/coff/ctx_inverse_mod_384-x86_64.s
--- a/c-source/build/coff/ctx_inverse_mod_384-x86_64.s
+++ b/c-source/build/coff/ctx_inverse_mod_384-x86_64.s
@@ -1,6 +1,7 @@
 .text	
 
 .globl	ctx_inverse_mod_383
+
 .def	ctx_inverse_mod_383;	.scl 2;	.type 32;	.endef
 .p2align	5
 ctx_inverse_mod_383:
@@ -9,12 +10,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_ctx_inverse_mod_383:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+ct_inverse_mod_383$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -812,7 +814,7 @@
 
 	movq	48(%rsi),%r10
 
-	call	__inner_loop_62
+	call	__tail_loop_53
 
 
 
@@ -1514,9 +1516,9 @@
 	.byte	0xf3,0xc3
 
 
-.def	__inner_loop_62;	.scl 3;	.type 32;	.endef
+.def	__tail_loop_53;	.scl 3;	.type 32;	.endef
 .p2align	5
-__inner_loop_62:
+__tail_loop_53:
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 	movq	$1,%rdx
@@ -1524,7 +1526,7 @@
 	xorq	%r12,%r12
 	movq	$1,%r13
 
-.Loop_62:
+.Loop_53:
 	xorq	%rax,%rax
 	testq	$1,%r8
 	movq	%r10,%rbx
@@ -1551,7 +1553,7 @@
 	subq	%rax,%rdx
 	subq	%rbx,%rcx
 	subl	$1,%edi
-	jnz	.Loop_62
+	jnz	.Loop_53
 
 	.byte	0xf3,0xc3
 
@@ -1575,8 +1577,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_ctx_inverse_mod_383_body:
 .byte	1,0,18,0
 .byte	0x00,0xf4,0x8b,0x00
@@ -1588,6 +1591,8 @@
 .byte	0x00,0x74,0x92,0x00
 .byte	0x00,0x64,0x93,0x00
 .byte	0x00,0x01,0x91,0x00
+.byte	0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_ctx_inverse_mod_383_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
diff --git a/c-source/build/coff/div3w-armv8.S b/c-source/build/coff/div3w-armv8.S
--- a/c-source/build/coff/div3w-armv8.S
+++ b/c-source/build/coff/div3w-armv8.S
@@ -27,7 +27,7 @@
 	asr	x3,x0,#63	// top bit -> mask
 	add	x0,x0,x0	// Q <<= 1
 	subs	x6,x4,x1	// R - D
-	add	x0,x0,#1	// Q + specilative bit
+	add	x0,x0,#1	// Q + speculative bit
 	sbcs	x7,x5,x2
 	sbc	x0,x0,xzr	// subtract speculative bit
 
diff --git a/c-source/build/coff/div3w-x86_64.s b/c-source/build/coff/div3w-x86_64.s
--- a/c-source/build/coff/div3w-x86_64.s
+++ b/c-source/build/coff/div3w-x86_64.s
@@ -8,11 +8,14 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 	movq	%rdi,8(%rsp)
 	movq	%rsi,16(%rsp)
-	movq	%rsp,%rax
+	movq	%rsp,%r11
 .LSEH_begin_div_3_limbs:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
+.LSEH_body_div_3_limbs:
 
 	movq	(%rdi),%r8
 	movq	8(%rdi),%r9
@@ -45,9 +48,12 @@
 
 	orq	%rcx,%rax
 
-	movq	8(%rsp),%rdi
-	movq	16(%rsp),%rsi
+.LSEH_epilogue_div_3_limbs:
+	mov	8(%rsp),%rdi
+	mov	16(%rsp),%rsi
+
 	.byte	0xf3,0xc3
+
 .LSEH_end_div_3_limbs:
 .globl	quot_rem_128
 
@@ -57,11 +63,14 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 	movq	%rdi,8(%rsp)
 	movq	%rsi,16(%rsp)
-	movq	%rsp,%rax
+	movq	%rsp,%r11
 .LSEH_begin_quot_rem_128:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
+.LSEH_body_quot_rem_128:
 
 	movq	%rdx,%rax
 	movq	%rdx,%rcx
@@ -97,9 +106,12 @@
 
 	movq	%rcx,%rax
 
-	movq	8(%rsp),%rdi
-	movq	16(%rsp),%rsi
+.LSEH_epilogue_quot_rem_128:
+	mov	8(%rsp),%rdi
+	mov	16(%rsp),%rsi
+
 	.byte	0xf3,0xc3
+
 .LSEH_end_quot_rem_128:
 
 
@@ -114,11 +126,14 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 	movq	%rdi,8(%rsp)
 	movq	%rsi,16(%rsp)
-	movq	%rsp,%rax
+	movq	%rsp,%r11
 .LSEH_begin_quot_rem_64:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
+.LSEH_body_quot_rem_64:
 
 	movq	%rdx,%rax
 	imulq	0(%rsi),%rdx
@@ -130,11 +145,104 @@
 	movq	%r10,0(%rdi)
 	movq	%rax,8(%rdi)
 
-	movq	8(%rsp),%rdi
-	movq	16(%rsp),%rsi
+.LSEH_epilogue_quot_rem_64:
+	mov	8(%rsp),%rdi
+	mov	16(%rsp),%rsi
+
 	.byte	0xf3,0xc3
+
 .LSEH_end_quot_rem_64:
 .section	.pdata
 .p2align	2
+.rva	.LSEH_begin_div_3_limbs
+.rva	.LSEH_body_div_3_limbs
+.rva	.LSEH_info_div_3_limbs_prologue
+
+.rva	.LSEH_body_div_3_limbs
+.rva	.LSEH_epilogue_div_3_limbs
+.rva	.LSEH_info_div_3_limbs_body
+
+.rva	.LSEH_epilogue_div_3_limbs
+.rva	.LSEH_end_div_3_limbs
+.rva	.LSEH_info_div_3_limbs_epilogue
+
+.rva	.LSEH_begin_quot_rem_128
+.rva	.LSEH_body_quot_rem_128
+.rva	.LSEH_info_quot_rem_128_prologue
+
+.rva	.LSEH_body_quot_rem_128
+.rva	.LSEH_epilogue_quot_rem_128
+.rva	.LSEH_info_quot_rem_128_body
+
+.rva	.LSEH_epilogue_quot_rem_128
+.rva	.LSEH_end_quot_rem_128
+.rva	.LSEH_info_quot_rem_128_epilogue
+
+.rva	.LSEH_begin_quot_rem_64
+.rva	.LSEH_body_quot_rem_64
+.rva	.LSEH_info_quot_rem_64_prologue
+
+.rva	.LSEH_body_quot_rem_64
+.rva	.LSEH_epilogue_quot_rem_64
+.rva	.LSEH_info_quot_rem_64_body
+
+.rva	.LSEH_epilogue_quot_rem_64
+.rva	.LSEH_end_quot_rem_64
+.rva	.LSEH_info_quot_rem_64_epilogue
+
 .section	.xdata
 .p2align	3
+.LSEH_info_div_3_limbs_prologue:
+.byte	1,0,5,0x0b
+.byte	0,0x74,1,0
+.byte	0,0x64,2,0
+.byte	0,0xb3
+.byte	0,0
+.long	0,0
+.LSEH_info_div_3_limbs_body:
+.byte	1,0,4,0
+.byte	0x00,0x74,0x01,0x00
+.byte	0x00,0x64,0x02,0x00
+.byte	0x00,0x00,0x00,0x00
+.LSEH_info_div_3_limbs_epilogue:
+.byte	1,0,4,0
+.byte	0x00,0x74,0x01,0x00
+.byte	0x00,0x64,0x02,0x00
+.byte	0x00,0x00,0x00,0x00
+
+.LSEH_info_quot_rem_128_prologue:
+.byte	1,0,5,0x0b
+.byte	0,0x74,1,0
+.byte	0,0x64,2,0
+.byte	0,0xb3
+.byte	0,0
+.long	0,0
+.LSEH_info_quot_rem_128_body:
+.byte	1,0,4,0
+.byte	0x00,0x74,0x01,0x00
+.byte	0x00,0x64,0x02,0x00
+.byte	0x00,0x00,0x00,0x00
+.LSEH_info_quot_rem_128_epilogue:
+.byte	1,0,4,0
+.byte	0x00,0x74,0x01,0x00
+.byte	0x00,0x64,0x02,0x00
+.byte	0x00,0x00,0x00,0x00
+
+.LSEH_info_quot_rem_64_prologue:
+.byte	1,0,5,0x0b
+.byte	0,0x74,1,0
+.byte	0,0x64,2,0
+.byte	0,0xb3
+.byte	0,0
+.long	0,0
+.LSEH_info_quot_rem_64_body:
+.byte	1,0,4,0
+.byte	0x00,0x74,0x01,0x00
+.byte	0x00,0x64,0x02,0x00
+.byte	0x00,0x00,0x00,0x00
+.LSEH_info_quot_rem_64_epilogue:
+.byte	1,0,4,0
+.byte	0x00,0x74,0x01,0x00
+.byte	0x00,0x64,0x02,0x00
+.byte	0x00,0x00,0x00,0x00
+
diff --git a/c-source/build/coff/mulq_mont_256-x86_64.s b/c-source/build/coff/mulq_mont_256-x86_64.s
--- a/c-source/build/coff/mulq_mont_256-x86_64.s
+++ b/c-source/build/coff/mulq_mont_256-x86_64.s
@@ -1,3 +1,4 @@
+.comm	__blst_platform_cap,4
 .text	
 
 .globl	mul_mont_sparse_256
@@ -10,13 +11,17 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_mul_mont_sparse_256:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
 	movq	40(%rsp),%r8
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	mul_mont_sparse_256$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -80,12 +85,16 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sqr_mont_sparse_256:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sqr_mont_sparse_256$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -430,12 +439,16 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_from_mont_256:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	from_mont_256$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -510,12 +523,16 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_redc_mont_256:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	redc_mont_256$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -778,8 +795,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_mul_mont_sparse_256_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -791,7 +809,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_mul_mont_sparse_256_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -802,8 +821,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sqr_mont_sparse_256_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -815,7 +835,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sqr_mont_sparse_256_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -826,8 +847,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_from_mont_256_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -839,7 +861,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_from_mont_256_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -850,8 +873,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_redc_mont_256_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -863,7 +887,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_redc_mont_256_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
diff --git a/c-source/build/coff/mulq_mont_384-x86_64.s b/c-source/build/coff/mulq_mont_384-x86_64.s
--- a/c-source/build/coff/mulq_mont_384-x86_64.s
+++ b/c-source/build/coff/mulq_mont_384-x86_64.s
@@ -1,3 +1,4 @@
+.comm	__blst_platform_cap,4
 .text	
 
 
@@ -6,9 +7,9 @@
 
 
 
-.def	__sub_mod_384x384;	.scl 3;	.type 32;	.endef
+.def	__subq_mod_384x384;	.scl 3;	.type 32;	.endef
 .p2align	5
-__sub_mod_384x384:
+__subq_mod_384x384:
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 	movq	0(%rsi),%r8
@@ -73,9 +74,9 @@
 	.byte	0xf3,0xc3
 
 
-.def	__add_mod_384;	.scl 3;	.type 32;	.endef
+.def	__addq_mod_384;	.scl 3;	.type 32;	.endef
 .p2align	5
-__add_mod_384:
+__addq_mod_384:
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 	movq	0(%rsi),%r8
@@ -123,9 +124,9 @@
 	.byte	0xf3,0xc3
 
 
-.def	__sub_mod_384;	.scl 3;	.type 32;	.endef
+.def	__subq_mod_384;	.scl 3;	.type 32;	.endef
 .p2align	5
-__sub_mod_384:
+__subq_mod_384:
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 	movq	0(%rsi),%r8
@@ -135,7 +136,7 @@
 	movq	32(%rsi),%r12
 	movq	40(%rsi),%r13
 
-__sub_mod_384_a_is_loaded:
+__subq_mod_384_a_is_loaded:
 	subq	0(%rdx),%r8
 	movq	0(%rcx),%r14
 	sbbq	8(%rdx),%r9
@@ -182,13 +183,17 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_mul_mont_384x:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
 	movq	40(%rsp),%r8
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	mul_mont_384x$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -229,12 +234,12 @@
 	movq	8(%rsp),%rcx
 	leaq	-48(%rsi),%rdx
 	leaq	40+192+48(%rsp),%rdi
-	call	__add_mod_384
+	call	__addq_mod_384
 
 	movq	16(%rsp),%rsi
 	leaq	48(%rsi),%rdx
 	leaq	-48(%rdi),%rdi
-	call	__add_mod_384
+	call	__addq_mod_384
 
 	leaq	(%rdi),%rbx
 	leaq	48(%rdi),%rsi
@@ -244,17 +249,17 @@
 	leaq	(%rdi),%rsi
 	leaq	40(%rsp),%rdx
 	movq	8(%rsp),%rcx
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 	leaq	(%rdi),%rsi
 	leaq	-96(%rdi),%rdx
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 
 	leaq	40(%rsp),%rsi
 	leaq	40+96(%rsp),%rdx
 	leaq	40(%rsp),%rdi
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 	movq	%rcx,%rbx
 
@@ -263,14 +268,14 @@
 	movq	0(%rsp),%rcx
 	movq	32(%rsp),%rdi
 	call	__mulq_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redq_tail_mont_384
 
 
 	leaq	40+192(%rsp),%rsi
 	movq	0(%rsp),%rcx
 	leaq	48(%rdi),%rdi
 	call	__mulq_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redq_tail_mont_384
 
 	leaq	328(%rsp),%r8
 	movq	0(%r8),%r15
@@ -304,12 +309,16 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sqr_mont_384x:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sqr_mont_384x$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -335,13 +344,13 @@
 
 	leaq	48(%rsi),%rdx
 	leaq	32(%rsp),%rdi
-	call	__add_mod_384
+	call	__addq_mod_384
 
 
 	movq	16(%rsp),%rsi
 	leaq	48(%rsi),%rdx
 	leaq	32+48(%rsp),%rdi
-	call	__sub_mod_384
+	call	__subq_mod_384
 
 
 	movq	16(%rsp),%rsi
@@ -433,12 +442,16 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_mul_382x:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	mul_382x$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -528,18 +541,18 @@
 	leaq	32(%rsp),%rdx
 	movq	24(%rsp),%rcx
 	movq	%rsi,%rdi
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 
 	leaq	0(%rdi),%rsi
 	leaq	-96(%rdi),%rdx
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 
 	leaq	-96(%rdi),%rsi
 	leaq	32(%rsp),%rdx
 	leaq	-96(%rdi),%rdi
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 	leaq	136(%rsp),%r8
 	movq	0(%r8),%r15
@@ -573,11 +586,15 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sqr_382x:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sqr_382x$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -628,7 +645,7 @@
 
 	leaq	48(%rsi),%rdx
 	leaq	48(%rdi),%rdi
-	call	__sub_mod_384_a_is_loaded
+	call	__subq_mod_384_a_is_loaded
 
 
 	leaq	(%rdi),%rsi
@@ -710,11 +727,15 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_mul_384:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	mul_384$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -1039,10 +1060,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sqr_384:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
 
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sqr_384$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -1286,12 +1311,16 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sqr_mont_384:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sqr_mont_384$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -1321,7 +1350,7 @@
 	movq	104(%rsp),%rbx
 	movq	112(%rsp),%rdi
 	call	__mulq_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redq_tail_mont_384
 
 	leaq	120(%rsp),%r8
 	movq	120(%rsp),%r15
@@ -1358,12 +1387,16 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_redc_mont_384:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	redc_mont_384$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -1383,7 +1416,7 @@
 
 	movq	%rdx,%rbx
 	call	__mulq_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redq_tail_mont_384
 
 	movq	8(%rsp),%r15
 
@@ -1420,12 +1453,16 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_from_mont_384:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	from_mont_384$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -1795,9 +1832,9 @@
 	.byte	0xf3,0xc3
 
 
-.def	__redc_tail_mont_384;	.scl 3;	.type 32;	.endef
+.def	__redq_tail_mont_384;	.scl 3;	.type 32;	.endef
 .p2align	5
-__redc_tail_mont_384:
+__redq_tail_mont_384:
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 	addq	48(%rsi),%r14
@@ -1852,11 +1889,15 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sgn0_pty_mont_384:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sgn0_pty_mont_384$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -1934,11 +1975,15 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sgn0_pty_mont_384x:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sgn0_pty_mont_384x$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -2065,13 +2110,17 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_mul_mont_384:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
 	movq	40(%rsp),%r8
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	mul_mont_384$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -2733,14 +2782,18 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sqr_n_mul_mont_384:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
 	movq	40(%rsp),%r8
 	movq	48(%rsp),%r9
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sqr_n_mul_mont_384$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -2774,7 +2827,7 @@
 	movq	0(%rsp),%rcx
 	movq	16(%rsp),%rbx
 	call	__mulq_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redq_tail_mont_384
 
 	movd	%xmm1,%edx
 	leaq	0(%rdi),%rsi
@@ -2828,14 +2881,18 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sqr_n_mul_mont_383:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
 	movq	40(%rsp),%r8
 	movq	48(%rsp),%r9
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sqr_n_mul_mont_383$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -3494,12 +3551,16 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sqr_mont_382x:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sqr_mont_382x$1
+#endif
 	pushq	%rbp
 
 	pushq	%rbx
@@ -3858,8 +3919,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_mul_mont_384x_body:
 .byte	1,0,18,0
 .byte	0x00,0xf4,0x29,0x00
@@ -3871,6 +3933,8 @@
 .byte	0x00,0x74,0x30,0x00
 .byte	0x00,0x64,0x31,0x00
 .byte	0x00,0x01,0x2f,0x00
+.byte	0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_mul_mont_384x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3881,8 +3945,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sqr_mont_384x_body:
 .byte	1,0,18,0
 .byte	0x00,0xf4,0x11,0x00
@@ -3894,6 +3959,8 @@
 .byte	0x00,0x74,0x18,0x00
 .byte	0x00,0x64,0x19,0x00
 .byte	0x00,0x01,0x17,0x00
+.byte	0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sqr_mont_384x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3904,8 +3971,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_mul_382x_body:
 .byte	1,0,18,0
 .byte	0x00,0xf4,0x11,0x00
@@ -3917,6 +3985,8 @@
 .byte	0x00,0x74,0x18,0x00
 .byte	0x00,0x64,0x19,0x00
 .byte	0x00,0x01,0x17,0x00
+.byte	0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_mul_382x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3927,8 +3997,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sqr_382x_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -3940,7 +4011,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sqr_382x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3951,8 +4023,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_mul_384_body:
 .byte	1,0,11,0
 .byte	0x00,0xc4,0x00,0x00
@@ -3972,8 +4045,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sqr_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -3985,7 +4059,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sqr_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3996,8 +4071,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sqr_mont_384_body:
 .byte	1,0,18,0
 .byte	0x00,0xf4,0x0f,0x00
@@ -4009,6 +4085,8 @@
 .byte	0x00,0x74,0x16,0x00
 .byte	0x00,0x64,0x17,0x00
 .byte	0x00,0x01,0x15,0x00
+.byte	0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sqr_mont_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -4019,8 +4097,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_redc_mont_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -4032,7 +4111,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_redc_mont_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -4043,8 +4123,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_from_mont_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -4056,7 +4137,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_from_mont_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -4067,8 +4149,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sgn0_pty_mont_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -4080,7 +4163,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sgn0_pty_mont_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -4091,8 +4175,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sgn0_pty_mont_384x_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -4104,7 +4189,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sgn0_pty_mont_384x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -4115,8 +4201,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_mul_mont_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x03,0x00
@@ -4128,7 +4215,8 @@
 .byte	0x00,0x74,0x0a,0x00
 .byte	0x00,0x64,0x0b,0x00
 .byte	0x00,0x82
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_mul_mont_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -4139,8 +4227,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sqr_n_mul_mont_384_body:
 .byte	1,0,18,0
 .byte	0x00,0xf4,0x11,0x00
@@ -4152,6 +4241,8 @@
 .byte	0x00,0x74,0x18,0x00
 .byte	0x00,0x64,0x19,0x00
 .byte	0x00,0x01,0x17,0x00
+.byte	0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sqr_n_mul_mont_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -4162,8 +4253,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sqr_n_mul_mont_383_body:
 .byte	1,0,18,0
 .byte	0x00,0xf4,0x11,0x00
@@ -4175,6 +4267,8 @@
 .byte	0x00,0x74,0x18,0x00
 .byte	0x00,0x64,0x19,0x00
 .byte	0x00,0x01,0x17,0x00
+.byte	0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sqr_n_mul_mont_383_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -4185,8 +4279,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sqr_mont_382x_body:
 .byte	1,0,18,0
 .byte	0x00,0xf4,0x11,0x00
@@ -4198,6 +4293,8 @@
 .byte	0x00,0x74,0x18,0x00
 .byte	0x00,0x64,0x19,0x00
 .byte	0x00,0x01,0x17,0x00
+.byte	0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sqr_mont_382x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
diff --git a/c-source/build/coff/mulx_mont_256-x86_64.s b/c-source/build/coff/mulx_mont_256-x86_64.s
--- a/c-source/build/coff/mulx_mont_256-x86_64.s
+++ b/c-source/build/coff/mulx_mont_256-x86_64.s
@@ -10,13 +10,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_mulx_mont_sparse_256:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
 	movq	40(%rsp),%r8
-
-
+mul_mont_sparse_256$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -78,12 +79,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sqrx_mont_sparse_256:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+sqr_mont_sparse_256$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -342,12 +344,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_fromx_mont_256:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+from_mont_256$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -422,12 +425,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_redcx_mont_256:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+redc_mont_256$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -690,8 +694,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_mulx_mont_sparse_256_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -703,7 +708,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_mulx_mont_sparse_256_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -714,8 +720,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sqrx_mont_sparse_256_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -727,7 +734,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sqrx_mont_sparse_256_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -738,8 +746,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_fromx_mont_256_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -751,7 +760,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_fromx_mont_256_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -762,8 +772,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_redcx_mont_256_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -775,7 +786,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_redcx_mont_256_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
diff --git a/c-source/build/coff/mulx_mont_384-x86_64.s b/c-source/build/coff/mulx_mont_384-x86_64.s
--- a/c-source/build/coff/mulx_mont_384-x86_64.s
+++ b/c-source/build/coff/mulx_mont_384-x86_64.s
@@ -6,9 +6,9 @@
 
 
 
-.def	__sub_mod_384x384;	.scl 3;	.type 32;	.endef
+.def	__subx_mod_384x384;	.scl 3;	.type 32;	.endef
 .p2align	5
-__sub_mod_384x384:
+__subx_mod_384x384:
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 	movq	0(%rsi),%r8
@@ -73,9 +73,9 @@
 	.byte	0xf3,0xc3
 
 
-.def	__add_mod_384;	.scl 3;	.type 32;	.endef
+.def	__addx_mod_384;	.scl 3;	.type 32;	.endef
 .p2align	5
-__add_mod_384:
+__addx_mod_384:
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 	movq	0(%rsi),%r8
@@ -123,9 +123,9 @@
 	.byte	0xf3,0xc3
 
 
-.def	__sub_mod_384;	.scl 3;	.type 32;	.endef
+.def	__subx_mod_384;	.scl 3;	.type 32;	.endef
 .p2align	5
-__sub_mod_384:
+__subx_mod_384:
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 	movq	0(%rsi),%r8
@@ -135,7 +135,7 @@
 	movq	32(%rsi),%r12
 	movq	40(%rsi),%r13
 
-__sub_mod_384_a_is_loaded:
+__subx_mod_384_a_is_loaded:
 	subq	0(%rdx),%r8
 	movq	0(%rcx),%r14
 	sbbq	8(%rdx),%r9
@@ -182,13 +182,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_mulx_mont_384x:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
 	movq	40(%rsp),%r8
-
-
+mul_mont_384x$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -230,12 +231,12 @@
 	leaq	(%rbx),%rsi
 	leaq	-48(%rbx),%rdx
 	leaq	40+192+48(%rsp),%rdi
-	call	__add_mod_384
+	call	__addx_mod_384
 
 	movq	24(%rsp),%rsi
 	leaq	48(%rsi),%rdx
 	leaq	-48(%rdi),%rdi
-	call	__add_mod_384
+	call	__addx_mod_384
 
 	leaq	(%rdi),%rbx
 	leaq	48(%rdi),%rsi
@@ -245,17 +246,17 @@
 	leaq	(%rdi),%rsi
 	leaq	40(%rsp),%rdx
 	movq	8(%rsp),%rcx
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 	leaq	(%rdi),%rsi
 	leaq	-96(%rdi),%rdx
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 
 	leaq	40(%rsp),%rsi
 	leaq	40+96(%rsp),%rdx
 	leaq	40(%rsp),%rdi
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 	leaq	(%rcx),%rbx
 
@@ -264,14 +265,14 @@
 	movq	0(%rsp),%rcx
 	movq	32(%rsp),%rdi
 	call	__mulx_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redx_tail_mont_384
 
 
 	leaq	40+192(%rsp),%rsi
 	movq	0(%rsp),%rcx
 	leaq	48(%rdi),%rdi
 	call	__mulx_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redx_tail_mont_384
 
 	leaq	328(%rsp),%r8
 	movq	0(%r8),%r15
@@ -305,12 +306,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sqrx_mont_384x:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+sqr_mont_384x$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -337,13 +339,13 @@
 
 	leaq	48(%rsi),%rdx
 	leaq	32(%rsp),%rdi
-	call	__add_mod_384
+	call	__addx_mod_384
 
 
 	movq	24(%rsp),%rsi
 	leaq	48(%rsi),%rdx
 	leaq	32+48(%rsp),%rdi
-	call	__sub_mod_384
+	call	__subx_mod_384
 
 
 	movq	24(%rsp),%rsi
@@ -445,12 +447,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_mulx_382x:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+mul_382x$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -540,18 +543,18 @@
 	leaq	32(%rsp),%rdx
 	movq	24(%rsp),%rcx
 	movq	%rsi,%rdi
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 
 	leaq	0(%rdi),%rsi
 	leaq	-96(%rdi),%rdx
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 
 	leaq	-96(%rdi),%rsi
 	leaq	32(%rsp),%rdx
 	leaq	-96(%rdi),%rdi
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 	leaq	136(%rsp),%r8
 	movq	0(%r8),%r15
@@ -585,11 +588,12 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sqrx_382x:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
-
-
+sqr_382x$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -640,7 +644,7 @@
 
 	leaq	48(%rsi),%rdx
 	leaq	48(%rdi),%rdi
-	call	__sub_mod_384_a_is_loaded
+	call	__subx_mod_384_a_is_loaded
 
 
 	leaq	(%rdi),%rsi
@@ -722,11 +726,12 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_mulx_384:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
-
-
+mul_384$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -950,10 +955,11 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sqrx_384:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
 
 
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+sqr_384$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -1145,12 +1151,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_redcx_mont_384:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+redc_mont_384$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -1170,7 +1177,7 @@
 
 	movq	%rdx,%rbx
 	call	__mulx_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redx_tail_mont_384
 
 	movq	8(%rsp),%r15
 
@@ -1207,12 +1214,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_fromx_mont_384:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+from_mont_384$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -1473,9 +1481,9 @@
 	.byte	0xf3,0xc3
 
 
-.def	__redc_tail_mont_384;	.scl 3;	.type 32;	.endef
+.def	__redx_tail_mont_384;	.scl 3;	.type 32;	.endef
 .p2align	5
-__redc_tail_mont_384:
+__redx_tail_mont_384:
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 	addq	48(%rsi),%r14
@@ -1530,11 +1538,12 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sgn0x_pty_mont_384:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
-
-
+sgn0_pty_mont_384$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -1612,11 +1621,12 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sgn0x_pty_mont_384x:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
-
-
+sgn0_pty_mont_384x$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -1743,13 +1753,14 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_mulx_mont_384:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
 	movq	40(%rsp),%r8
-
-
+mul_mont_384$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -2215,12 +2226,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sqrx_mont_384:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+sqr_mont_384$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -2287,14 +2299,15 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sqrx_n_mul_mont_384:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
 	movq	40(%rsp),%r8
 	movq	48(%rsp),%r9
-
-
+sqr_n_mul_mont_384$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -2379,14 +2392,15 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sqrx_n_mul_mont_383:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
 	movq	40(%rsp),%r8
 	movq	48(%rsp),%r9
-
-
+sqr_n_mul_mont_383$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -2831,12 +2845,13 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_sqrx_mont_382x:
+
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
 	movq	%r9,%rcx
-
-
+sqr_mont_382x$1:
 	pushq	%rbp
 
 	pushq	%rbx
@@ -3205,8 +3220,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_mulx_mont_384x_body:
 .byte	1,0,18,0
 .byte	0x00,0xf4,0x29,0x00
@@ -3218,6 +3234,8 @@
 .byte	0x00,0x74,0x30,0x00
 .byte	0x00,0x64,0x31,0x00
 .byte	0x00,0x01,0x2f,0x00
+.byte	0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_mulx_mont_384x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3228,8 +3246,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sqrx_mont_384x_body:
 .byte	1,0,18,0
 .byte	0x00,0xf4,0x11,0x00
@@ -3241,6 +3260,8 @@
 .byte	0x00,0x74,0x18,0x00
 .byte	0x00,0x64,0x19,0x00
 .byte	0x00,0x01,0x17,0x00
+.byte	0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sqrx_mont_384x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3251,8 +3272,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_mulx_382x_body:
 .byte	1,0,18,0
 .byte	0x00,0xf4,0x11,0x00
@@ -3264,6 +3286,8 @@
 .byte	0x00,0x74,0x18,0x00
 .byte	0x00,0x64,0x19,0x00
 .byte	0x00,0x01,0x17,0x00
+.byte	0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_mulx_382x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3274,8 +3298,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sqrx_382x_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -3287,7 +3312,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sqrx_382x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3298,8 +3324,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_mulx_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x00,0x00
@@ -3311,7 +3338,8 @@
 .byte	0x00,0x74,0x07,0x00
 .byte	0x00,0x64,0x08,0x00
 .byte	0x00,0x52
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_mulx_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3322,8 +3350,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sqrx_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -3335,7 +3364,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sqrx_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3346,8 +3376,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_redcx_mont_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -3359,7 +3390,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_redcx_mont_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3370,8 +3402,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_fromx_mont_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -3383,7 +3416,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_fromx_mont_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3394,8 +3428,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sgn0x_pty_mont_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -3407,7 +3442,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sgn0x_pty_mont_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3418,8 +3454,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sgn0x_pty_mont_384x_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x01,0x00
@@ -3431,7 +3468,8 @@
 .byte	0x00,0x74,0x08,0x00
 .byte	0x00,0x64,0x09,0x00
 .byte	0x00,0x62
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sgn0x_pty_mont_384x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3442,8 +3480,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_mulx_mont_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x03,0x00
@@ -3455,7 +3494,8 @@
 .byte	0x00,0x74,0x0a,0x00
 .byte	0x00,0x64,0x0b,0x00
 .byte	0x00,0x82
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_mulx_mont_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3466,8 +3506,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sqrx_mont_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x03,0x00
@@ -3479,7 +3520,8 @@
 .byte	0x00,0x74,0x0a,0x00
 .byte	0x00,0x64,0x0b,0x00
 .byte	0x00,0x82
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sqrx_mont_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3490,8 +3532,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sqrx_n_mul_mont_384_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x05,0x00
@@ -3503,7 +3546,8 @@
 .byte	0x00,0x74,0x0c,0x00
 .byte	0x00,0x64,0x0d,0x00
 .byte	0x00,0xa2
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sqrx_n_mul_mont_384_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3514,8 +3558,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sqrx_n_mul_mont_383_body:
 .byte	1,0,17,0
 .byte	0x00,0xf4,0x05,0x00
@@ -3527,7 +3572,8 @@
 .byte	0x00,0x74,0x0c,0x00
 .byte	0x00,0x64,0x0d,0x00
 .byte	0x00,0xa2
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sqrx_n_mul_mont_383_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
@@ -3538,8 +3584,9 @@
 .byte	1,0,5,0x0b
 .byte	0,0x74,1,0
 .byte	0,0x64,2,0
-.byte	0,0x03
+.byte	0,0xb3
 .byte	0,0
+.long	0,0
 .LSEH_info_sqrx_mont_382x_body:
 .byte	1,0,18,0
 .byte	0x00,0xf4,0x11,0x00
@@ -3551,6 +3598,8 @@
 .byte	0x00,0x74,0x18,0x00
 .byte	0x00,0x64,0x19,0x00
 .byte	0x00,0x01,0x17,0x00
+.byte	0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_sqrx_mont_382x_epilogue:
 .byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
diff --git a/c-source/build/coff/sha256-armv8.S b/c-source/build/coff/sha256-armv8.S
--- a/c-source/build/coff/sha256-armv8.S
+++ b/c-source/build/coff/sha256-armv8.S
@@ -10,11 +10,12 @@
 //
 // sha256_block procedure for ARMv8.
 //
-// This module is stripped of scalar code paths, with raionale that all
+// This module is stripped of scalar code paths, with rationale that all
 // known processors are NEON-capable.
 //
 // See original module at CRYPTOGAMS for further details.
 
+.comm	__blst_platform_cap,4
 .text
 
 .p2align	6
@@ -188,6 +189,11 @@
 .endef
 .p2align	4
 blst_sha256_block_data_order:
+	adrp	x16,__blst_platform_cap
+	ldr	w16,[x16,#:lo12:__blst_platform_cap]
+	tst	w16,#1
+	b.ne	.Lv8_entry
+
 	stp	x29, x30, [sp, #-16]!
 	mov	x29, sp
 	sub	sp,sp,#16*4
diff --git a/c-source/build/coff/sha256-portable-x86_64.s b/c-source/build/coff/sha256-portable-x86_64.s
--- a/c-source/build/coff/sha256-portable-x86_64.s
+++ b/c-source/build/coff/sha256-portable-x86_64.s
@@ -1,3 +1,4 @@
+.comm	__blst_platform_cap,4
 .text	
 
 .globl	blst_sha256_block_data_order
@@ -9,15 +10,21 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_blst_sha256_block_data_order:
+
+
+	pushq	%rbp
+
+	movq	%rsp,%rbp
+
 	movq	%rcx,%rdi
 	movq	%rdx,%rsi
 	movq	%r8,%rdx
-
-
+#ifdef __BLST_PORTABLE__
+	testl	$2,__blst_platform_cap(%rip)
+	jnz	.Lblst_sha256_block_data_order$2
+#endif
 	pushq	%rbx
 
-	pushq	%rbp
-
 	pushq	%r12
 
 	pushq	%r13
@@ -29,13 +36,14 @@
 	shlq	$4,%rdx
 	subq	$64+24,%rsp
 
+
+.LSEH_body_blst_sha256_block_data_order:
+
 	leaq	(%rsi,%rdx,4),%rdx
 	movq	%rdi,64+0(%rsp)
 	movq	%rsi,64+8(%rsp)
 	movq	%rdx,64+16(%rsp)
-.LSEH_body_blst_sha256_block_data_order:
 
-
 	movl	0(%rdi),%eax
 	movl	4(%rdi),%ebx
 	movl	8(%rdi),%ecx
@@ -1637,17 +1645,11 @@
 	leaq	64+24+48(%rsp),%r11
 
 	movq	64+24(%rsp),%r15
-
 	movq	-40(%r11),%r14
-
 	movq	-32(%r11),%r13
-
 	movq	-24(%r11),%r12
-
-	movq	-16(%r11),%rbp
-
-	movq	-8(%r11),%rbx
-
+	movq	-16(%r11),%rbx
+	movq	-8(%r11),%rbp
 .LSEH_epilogue_blst_sha256_block_data_order:
 	mov	8(%r11),%rdi
 	mov	16(%r11),%rsi
@@ -1657,6 +1659,7 @@
 
 .LSEH_end_blst_sha256_block_data_order:
 
+#ifndef __BLST_PORTABLE__
 .p2align	6
 
 K256:
@@ -1742,6 +1745,7 @@
 	movq	%r11,24(%rcx)
 	.byte	0xf3,0xc3
 
+#endif
 .section	.pdata
 .p2align	2
 .rva	.LSEH_begin_blst_sha256_block_data_order
@@ -1759,26 +1763,30 @@
 .section	.xdata
 .p2align	3
 .LSEH_info_blst_sha256_block_data_order_prologue:
-.byte	1,0,5,0x0b
-.byte	0,0x74,1,0
-.byte	0,0x64,2,0
-.byte	0,0x03
-.byte	0,0
+.byte	1,4,6,0x05
+.byte	4,0x74,2,0
+.byte	4,0x64,3,0
+.byte	4,0x53
+.byte	1,0x50
+.long	0,0
 .LSEH_info_blst_sha256_block_data_order_body:
 .byte	1,0,18,0
 .byte	0x00,0xf4,0x0b,0x00
 .byte	0x00,0xe4,0x0c,0x00
 .byte	0x00,0xd4,0x0d,0x00
 .byte	0x00,0xc4,0x0e,0x00
-.byte	0x00,0x54,0x0f,0x00
-.byte	0x00,0x34,0x10,0x00
+.byte	0x00,0x34,0x0f,0x00
+.byte	0x00,0x54,0x10,0x00
 .byte	0x00,0x74,0x12,0x00
 .byte	0x00,0x64,0x13,0x00
 .byte	0x00,0x01,0x11,0x00
+.byte	0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_blst_sha256_block_data_order_epilogue:
 .byte	1,0,5,11
 .byte	0x00,0x74,0x01,0x00
 .byte	0x00,0x64,0x02,0x00
-.byte	0x00,0x03
-.byte	0x00,0x00
+.byte	0x00,0xb3
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 
diff --git a/c-source/build/coff/sha256-x86_64.s b/c-source/build/coff/sha256-x86_64.s
--- a/c-source/build/coff/sha256-x86_64.s
+++ b/c-source/build/coff/sha256-x86_64.s
@@ -1,3 +1,4 @@
+.comm	__blst_platform_cap,4
 .text	
 
 .p2align	6
@@ -34,22 +35,23 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_blst_sha256_block_data_order_shaext:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
 
 
-	subq	$0x58,%rsp
-
-	movaps	%xmm6,-88(%r11)
-
-	movaps	%xmm7,-72(%r11)
+	pushq	%rbp
 
-	movaps	%xmm8,-56(%r11)
+	movq	%rsp,%rbp
 
-	movaps	%xmm9,-40(%r11)
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+.Lblst_sha256_block_data_order$2:
+	subq	$0x50,%rsp
 
-	movaps	%xmm10,-24(%r11)
+	movaps	%xmm6,-80(%rbp)
+	movaps	%xmm7,-64(%rbp)
+	movaps	%xmm8,-48(%rbp)
+	movaps	%xmm9,-32(%rbp)
+	movaps	%xmm10,-16(%rbp)
 
 .LSEH_body_blst_sha256_block_data_order_shaext:
 
@@ -254,16 +256,18 @@
 
 	movdqu	%xmm1,(%rdi)
 	movdqu	%xmm2,16(%rdi)
-	movaps	-88(%r11),%xmm6
-	movaps	-72(%r11),%xmm7
-	movaps	-56(%r11),%xmm8
-	movaps	-40(%r11),%xmm9
-	movaps	-24(%r11),%xmm10
-	movq	%r11,%rsp
+	movaps	-80(%rbp),%xmm6
+	movaps	-64(%rbp),%xmm7
+	movaps	-48(%rbp),%xmm8
+	movaps	-32(%rbp),%xmm9
+	movaps	-16(%rbp),%xmm10
+	movq	%rbp,%rsp
 
+	popq	%rbp
+
 .LSEH_epilogue_blst_sha256_block_data_order_shaext:
-	mov	8(%r11),%rdi
-	mov	16(%r11),%rsi
+	mov	8(%rsp),%rdi
+	mov	16(%rsp),%rsi
 
 	.byte	0xf3,0xc3
 
@@ -278,13 +282,17 @@
 	movq	%rsi,16(%rsp)
 	movq	%rsp,%r11
 .LSEH_begin_blst_sha256_block_data_order:
-	movq	%rcx,%rdi
-	movq	%rdx,%rsi
-	movq	%r8,%rdx
 
 
 	pushq	%rbp
 
+	movq	%rsp,%rbp
+
+	movq	%rcx,%rdi
+	movq	%rdx,%rsi
+	movq	%r8,%rdx
+	testl	$2,__blst_platform_cap(%rip)
+	jnz	.Lblst_sha256_block_data_order$2
 	pushq	%rbx
 
 	pushq	%r12
@@ -296,21 +304,16 @@
 	pushq	%r15
 
 	shlq	$4,%rdx
-	subq	$104,%rsp
+	subq	$88,%rsp
 
 	leaq	(%rsi,%rdx,4),%rdx
-	movq	%rdi,0(%rsp)
-
-	movq	%rdx,16(%rsp)
-	movaps	%xmm6,32(%rsp)
-
-	movaps	%xmm7,48(%rsp)
-
-	movaps	%xmm8,64(%rsp)
-
-	movaps	%xmm9,80(%rsp)
+	movq	%rdi,-64(%rbp)
 
-	movq	%rsp,%rbp
+	movq	%rdx,-48(%rbp)
+	movaps	%xmm6,-128(%rbp)
+	movaps	%xmm7,-112(%rbp)
+	movaps	%xmm8,-96(%rbp)
+	movaps	%xmm9,-80(%rbp)
 
 .LSEH_body_blst_sha256_block_data_order:
 
@@ -331,7 +334,7 @@
 .p2align	4
 .Lloop_ssse3:
 	movdqa	K256+256(%rip),%xmm7
-	movq	%rsi,8(%rbp)
+	movq	%rsi,-56(%rbp)
 	movdqu	0(%rsi),%xmm0
 	movdqu	16(%rsi),%xmm1
 	movdqu	32(%rsi),%xmm2
@@ -1356,9 +1359,9 @@
 	addl	%r15d,%eax
 	movl	%r8d,%r13d
 	addl	%eax,%r14d
-	movq	0(%rbp),%rdi
+	movq	-64(%rbp),%rdi
 	movl	%r14d,%eax
-	movq	8(%rbp),%rsi
+	movq	-56(%rbp),%rsi
 
 	addl	0(%rdi),%eax
 	addl	4(%rdi),%ebx
@@ -1370,7 +1373,7 @@
 	addl	28(%rdi),%r11d
 
 	leaq	64(%rsi),%rsi
-	cmpq	16(%rbp),%rsi
+	cmpq	-48(%rbp),%rsi
 
 	movl	%eax,0(%rdi)
 	movl	%ebx,4(%rdi)
@@ -1383,33 +1386,27 @@
 	jb	.Lloop_ssse3
 
 	xorps	%xmm0,%xmm0
-	leaq	104+48(%rbp),%r11
-
 	movaps	%xmm0,0(%rsp)
 	movaps	%xmm0,16(%rsp)
 	movaps	%xmm0,32(%rsp)
 	movaps	%xmm0,48(%rsp)
-	movaps	32(%rbp),%xmm6
-	movaps	48(%rbp),%xmm7
-	movaps	64(%rbp),%xmm8
-	movaps	80(%rbp),%xmm9
-	movq	104(%rbp),%r15
-
-	movq	-40(%r11),%r14
-
-	movq	-32(%r11),%r13
-
-	movq	-24(%r11),%r12
-
-	movq	-16(%r11),%rbx
+	movaps	-128(%rbp),%xmm6
+	movaps	-112(%rbp),%xmm7
+	movaps	-96(%rbp),%xmm8
+	movaps	-80(%rbp),%xmm9
+	movq	-40(%rbp),%r15
+	movq	-32(%rbp),%r14
+	movq	-24(%rbp),%r13
+	movq	-16(%rbp),%r12
+	movq	-8(%rbp),%rbx
+	movq	%rbp,%rsp
 
-	movq	-8(%r11),%rbp
+	popq	%rbp
 
 .LSEH_epilogue_blst_sha256_block_data_order:
-	mov	8(%r11),%rdi
-	mov	16(%r11),%rsi
+	mov	8(%rsp),%rdi
+	mov	16(%rsp),%rsi
 
-	leaq	(%r11),%rsp
 	.byte	0xf3,0xc3
 
 .LSEH_end_blst_sha256_block_data_order:
@@ -1506,13 +1503,14 @@
 .section	.xdata
 .p2align	3
 .LSEH_info_blst_sha256_block_data_order_shaext_prologue:
-.byte	1,0,5,0x0b
-.byte	0,0x74,1,0
-.byte	0,0x64,2,0
-.byte	0,0x03
-.byte	0,0
+.byte	1,4,6,0x05
+.byte	4,0x74,2,0
+.byte	4,0x64,3,0
+.byte	4,0x53
+.byte	1,0x50
+.long	0,0
 .LSEH_info_blst_sha256_block_data_order_shaext_body:
-.byte	1,0,15,0
+.byte	1,0,17,85
 .byte	0x00,0x68,0x00,0x00
 .byte	0x00,0x78,0x01,0x00
 .byte	0x00,0x88,0x02,0x00
@@ -1520,41 +1518,45 @@
 .byte	0x00,0xa8,0x04,0x00
 .byte	0x00,0x74,0x0c,0x00
 .byte	0x00,0x64,0x0d,0x00
-.byte	0x00,0xa2
+.byte	0x00,0x53
+.byte	0x00,0x92
+.byte	0x00,0x50
 .byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_blst_sha256_block_data_order_shaext_epilogue:
-.byte	1,0,5,11
+.byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
 .byte	0x00,0x64,0x02,0x00
-.byte	0x00,0x03
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 
 .LSEH_info_blst_sha256_block_data_order_prologue:
-.byte	1,0,5,0x0b
-.byte	0,0x74,1,0
-.byte	0,0x64,2,0
-.byte	0,0x03
-.byte	0,0
+.byte	1,4,6,0x05
+.byte	4,0x74,2,0
+.byte	4,0x64,3,0
+.byte	4,0x53
+.byte	1,0x50
+.long	0,0
 .LSEH_info_blst_sha256_block_data_order_body:
-.byte	1,0,26,5
-.byte	0x00,0x68,0x02,0x00
-.byte	0x00,0x78,0x03,0x00
-.byte	0x00,0x88,0x04,0x00
-.byte	0x00,0x98,0x05,0x00
-.byte	0x00,0xf4,0x0d,0x00
-.byte	0x00,0xe4,0x0e,0x00
-.byte	0x00,0xd4,0x0f,0x00
-.byte	0x00,0xc4,0x10,0x00
-.byte	0x00,0x34,0x11,0x00
-.byte	0x00,0x74,0x14,0x00
-.byte	0x00,0x64,0x15,0x00
-.byte	0x00,0x03
-.byte	0x00,0x01,0x12,0x00
+.byte	1,0,25,133
+.byte	0x00,0x68,0x00,0x00
+.byte	0x00,0x78,0x01,0x00
+.byte	0x00,0x88,0x02,0x00
+.byte	0x00,0x98,0x03,0x00
+.byte	0x00,0xf4,0x0b,0x00
+.byte	0x00,0xe4,0x0c,0x00
+.byte	0x00,0xd4,0x0d,0x00
+.byte	0x00,0xc4,0x0e,0x00
+.byte	0x00,0x34,0x0f,0x00
+.byte	0x00,0x74,0x12,0x00
+.byte	0x00,0x64,0x13,0x00
+.byte	0x00,0x53
+.byte	0x00,0xf2
 .byte	0x00,0x50
+.byte	0x00,0x00,0x00,0x00,0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 .LSEH_info_blst_sha256_block_data_order_epilogue:
-.byte	1,0,5,11
+.byte	1,0,4,0
 .byte	0x00,0x74,0x01,0x00
 .byte	0x00,0x64,0x02,0x00
-.byte	0x00,0x03
-.byte	0x00,0x00
+.byte	0x00,0x00,0x00,0x00
 
diff --git a/c-source/build/elf/add_mod_384-armv8.S b/c-source/build/elf/add_mod_384-armv8.S
--- a/c-source/build/elf/add_mod_384-armv8.S
+++ b/c-source/build/elf/add_mod_384-armv8.S
@@ -748,6 +748,21 @@
 
 	ret
 .size	sgn0_pty_mod_384x,.-sgn0_pty_mod_384x
+.globl	vec_select_32
+.hidden	vec_select_32
+.type	vec_select_32,%function
+.align	5
+vec_select_32:
+	dup	v6.2d, x3
+	ld1	{v0.2d, v1.2d, v2.2d}, [x1],#48
+	cmeq	v6.2d, v6.2d, #0
+	ld1	{v3.2d, v4.2d, v5.2d}, [x2],#48
+	bit	v0.16b, v3.16b, v6.16b
+	bit	v1.16b, v4.16b, v6.16b
+	bit	v2.16b, v5.16b, v6.16b
+	st1	{v0.2d, v1.2d, v2.2d}, [x0]
+	ret
+.size	vec_select_32,.-vec_select_32
 .globl	vec_select_48
 .hidden	vec_select_48
 .type	vec_select_48,%function
@@ -929,3 +944,57 @@
 	prfm	pldl1keep, [x0]
 	ret
 .size	vec_prefetch,.-vec_prefetch
+.globl	vec_is_zero_16x
+.hidden	vec_is_zero_16x
+.type	vec_is_zero_16x,%function
+.align	5
+vec_is_zero_16x:
+	ld1	{v0.2d}, [x0], #16
+	lsr	x1, x1, #4
+	sub	x1, x1, #1
+	cbz	x1, .Loop_is_zero_done
+
+.Loop_is_zero:
+	ld1	{v1.2d}, [x0], #16
+	orr	v0.16b, v0.16b, v1.16b
+	sub	x1, x1, #1
+	cbnz	x1, .Loop_is_zero
+
+.Loop_is_zero_done:
+	dup	v1.2d, v0.d[1]
+	orr	v0.16b, v0.16b, v1.16b
+	mov	x1, v0.d[0]
+	mov	x0, #1
+	cmp	x1, #0
+	csel	x0, x0, xzr, eq
+	ret
+.size	vec_is_zero_16x,.-vec_is_zero_16x
+.globl	vec_is_equal_16x
+.hidden	vec_is_equal_16x
+.type	vec_is_equal_16x,%function
+.align	5
+vec_is_equal_16x:
+	ld1	{v0.2d}, [x0], #16
+	ld1	{v1.2d}, [x1], #16
+	lsr	x2, x2, #4
+	eor	v0.16b, v0.16b, v1.16b
+
+.Loop_is_equal:
+	sub	x2, x2, #1
+	cbz	x2, .Loop_is_equal_done
+	ld1	{v1.2d}, [x0], #16
+	ld1	{v2.2d}, [x1], #16
+	eor	v1.16b, v1.16b, v2.16b
+	orr	v0.16b, v0.16b, v1.16b
+	b	.Loop_is_equal
+	nop
+
+.Loop_is_equal_done:
+	dup	v1.2d, v0.d[1]
+	orr	v0.16b, v0.16b, v1.16b
+	mov	x1, v0.d[0]
+	mov	x0, #1
+	cmp	x1, #0
+	csel	x0, x0, xzr, eq
+	ret
+.size	vec_is_equal_16x,.-vec_is_equal_16x
diff --git a/c-source/build/elf/add_mod_384-x86_64.s b/c-source/build/elf/add_mod_384-x86_64.s
--- a/c-source/build/elf/add_mod_384-x86_64.s
+++ b/c-source/build/elf/add_mod_384-x86_64.s
@@ -1372,6 +1372,37 @@
 	.byte	0xf3,0xc3
 .cfi_endproc	
 .size	sgn0_pty_mod_384x,.-sgn0_pty_mod_384x
+.globl	vec_select_32
+.hidden	vec_select_32
+.type	vec_select_32,@function
+.align	32
+vec_select_32:
+.cfi_startproc
+	.byte	0xf3,0x0f,0x1e,0xfa
+
+	movd	%ecx,%xmm5
+	pxor	%xmm4,%xmm4
+	pshufd	$0,%xmm5,%xmm5
+	movdqu	(%rsi),%xmm0
+	leaq	16(%rsi),%rsi
+	pcmpeqd	%xmm4,%xmm5
+	movdqu	(%rdx),%xmm1
+	leaq	16(%rdx),%rdx
+	pcmpeqd	%xmm5,%xmm4
+	leaq	16(%rdi),%rdi
+	pand	%xmm4,%xmm0
+	movdqu	0+16-16(%rsi),%xmm2
+	pand	%xmm5,%xmm1
+	movdqu	0+16-16(%rdx),%xmm3
+	por	%xmm1,%xmm0
+	movdqu	%xmm0,0-16(%rdi)
+	pand	%xmm4,%xmm2
+	pand	%xmm5,%xmm3
+	por	%xmm3,%xmm2
+	movdqu	%xmm2,16-16(%rdi)
+	.byte	0xf3,0xc3
+.cfi_endproc
+.size	vec_select_32,.-vec_select_32
 .globl	vec_select_48
 .hidden	vec_select_48
 .type	vec_select_48,@function
@@ -1799,6 +1830,73 @@
 	.byte	0xf3,0xc3
 .cfi_endproc
 .size	vec_prefetch,.-vec_prefetch
+.globl	vec_is_zero_16x
+.hidden	vec_is_zero_16x
+.type	vec_is_zero_16x,@function
+.align	32
+vec_is_zero_16x:
+.cfi_startproc
+	.byte	0xf3,0x0f,0x1e,0xfa
+
+	shrl	$4,%esi
+	movdqu	(%rdi),%xmm0
+	leaq	16(%rdi),%rdi
+
+.Loop_is_zero:
+	decl	%esi
+	jz	.Loop_is_zero_done
+	movdqu	(%rdi),%xmm1
+	leaq	16(%rdi),%rdi
+	por	%xmm1,%xmm0
+	jmp	.Loop_is_zero
+
+.Loop_is_zero_done:
+	pshufd	$0x4e,%xmm0,%xmm1
+	por	%xmm1,%xmm0
+.byte	102,72,15,126,192
+	incl	%esi
+	testq	%rax,%rax
+	cmovnzl	%esi,%eax
+	xorl	$1,%eax
+	.byte	0xf3,0xc3
+.cfi_endproc
+.size	vec_is_zero_16x,.-vec_is_zero_16x
+.globl	vec_is_equal_16x
+.hidden	vec_is_equal_16x
+.type	vec_is_equal_16x,@function
+.align	32
+vec_is_equal_16x:
+.cfi_startproc
+	.byte	0xf3,0x0f,0x1e,0xfa
+
+	shrl	$4,%edx
+	movdqu	(%rdi),%xmm0
+	movdqu	(%rsi),%xmm1
+	subq	%rdi,%rsi
+	leaq	16(%rdi),%rdi
+	pxor	%xmm1,%xmm0
+
+.Loop_is_equal:
+	decl	%edx
+	jz	.Loop_is_equal_done
+	movdqu	(%rdi),%xmm1
+	movdqu	(%rdi,%rsi,1),%xmm2
+	leaq	16(%rdi),%rdi
+	pxor	%xmm2,%xmm1
+	por	%xmm1,%xmm0
+	jmp	.Loop_is_equal
+
+.Loop_is_equal_done:
+	pshufd	$0x4e,%xmm0,%xmm1
+	por	%xmm1,%xmm0
+.byte	102,72,15,126,192
+	incl	%edx
+	testq	%rax,%rax
+	cmovnzl	%edx,%eax
+	xorl	$1,%eax
+	.byte	0xf3,0xc3
+.cfi_endproc
+.size	vec_is_equal_16x,.-vec_is_equal_16x
 
 .section	.note.GNU-stack,"",@progbits
 .section	.note.gnu.property,"a",@note
diff --git a/c-source/build/elf/ct_inverse_mod_256-armv8.S b/c-source/build/elf/ct_inverse_mod_256-armv8.S
--- a/c-source/build/elf/ct_inverse_mod_256-armv8.S
+++ b/c-source/build/elf/ct_inverse_mod_256-armv8.S
@@ -1,6 +1,7 @@
 .text
 
 .globl	ct_inverse_mod_256
+.hidden	ct_inverse_mod_256
 .type	ct_inverse_mod_256, %function
 .align	5
 ct_inverse_mod_256:
@@ -60,14 +61,14 @@
 	madd	x4, x16, x8, xzr	// |u|*|f0|
 	madd	x4, x17, x9, x4	// |v|*|g0|
 	str	x4, [x0,#8*4]
-	asr	x5, x4, #63		// sign extenstion
+	asr	x5, x4, #63		// sign extension
 	stp	x5, x5, [x0,#8*5]
 	stp	x5, x5, [x0,#8*7]
 
 	madd	x4, x12, x8, xzr	// |u|*|f1|
 	madd	x4, x13, x9, x4	// |v|*|g1|
 	str	x4, [x0,#8*9]
-	asr	x5, x4, #63		// sign extenstion
+	asr	x5, x4, #63		// sign extension
 	stp	x5, x5, [x0,#8*10]
 	stp	x5, x5, [x0,#8*12]
 	eor	x1, x1, #256		// flip-flop src |a|b|u|v|
diff --git a/c-source/build/elf/ct_inverse_mod_256-x86_64.s b/c-source/build/elf/ct_inverse_mod_256-x86_64.s
--- a/c-source/build/elf/ct_inverse_mod_256-x86_64.s
+++ b/c-source/build/elf/ct_inverse_mod_256-x86_64.s
@@ -1,6 +1,7 @@
 .text	
 
 .globl	ct_inverse_mod_256
+.hidden	ct_inverse_mod_256
 .type	ct_inverse_mod_256,@function
 .align	32
 ct_inverse_mod_256:
diff --git a/c-source/build/elf/ct_inverse_mod_384-armv8.S b/c-source/build/elf/ct_inverse_mod_384-armv8.S
--- a/c-source/build/elf/ct_inverse_mod_384-armv8.S
+++ b/c-source/build/elf/ct_inverse_mod_384-armv8.S
@@ -1,6 +1,7 @@
 .text
 
 .globl	ct_inverse_mod_383
+.hidden	ct_inverse_mod_383
 .type	ct_inverse_mod_383, %function
 .align	5
 ct_inverse_mod_383:
@@ -71,7 +72,7 @@
 	adds	x3, x3, x5
 	adc	x4, x4, x6
 	stp	x3, x4, [x0,#8*6]
-	asr	x5, x4, #63		// sign extenstion
+	asr	x5, x4, #63		// sign extension
 	stp	x5, x5, [x0,#8*8]
 	stp	x5, x5, [x0,#8*10]
 
@@ -82,7 +83,7 @@
 	adds	x3, x3, x5
 	adc	x4, x4, x6
 	stp	x3, x4, [x0,#8*12]
-	asr	x5, x4, #63		// sign extenstion
+	asr	x5, x4, #63		// sign extension
 	stp	x5, x5, [x0,#8*14]
 	stp	x5, x5, [x0,#8*16]
 	eor	x1, x1, #256		// flip-flop src |a|b|u|v|
diff --git a/c-source/build/elf/ct_is_square_mod_384-armv8.S b/c-source/build/elf/ct_is_square_mod_384-armv8.S
--- a/c-source/build/elf/ct_is_square_mod_384-armv8.S
+++ b/c-source/build/elf/ct_is_square_mod_384-armv8.S
@@ -1,6 +1,7 @@
 .text
 
 .globl	ct_is_square_mod_384
+.hidden	ct_is_square_mod_384
 .type	ct_is_square_mod_384, %function
 .align	5
 ct_is_square_mod_384:
diff --git a/c-source/build/elf/ct_is_square_mod_384-x86_64.s b/c-source/build/elf/ct_is_square_mod_384-x86_64.s
--- a/c-source/build/elf/ct_is_square_mod_384-x86_64.s
+++ b/c-source/build/elf/ct_is_square_mod_384-x86_64.s
@@ -1,6 +1,7 @@
 .text	
 
 .globl	ct_is_square_mod_384
+.hidden	ct_is_square_mod_384
 .type	ct_is_square_mod_384,@function
 .align	32
 ct_is_square_mod_384:
diff --git a/c-source/build/elf/ctq_inverse_mod_384-x86_64.s b/c-source/build/elf/ctq_inverse_mod_384-x86_64.s
--- a/c-source/build/elf/ctq_inverse_mod_384-x86_64.s
+++ b/c-source/build/elf/ctq_inverse_mod_384-x86_64.s
@@ -1,6 +1,8 @@
+.comm	__blst_platform_cap,4
 .text	
 
 .globl	ct_inverse_mod_383
+.hidden	ct_inverse_mod_383
 .type	ct_inverse_mod_383,@function
 .align	32
 ct_inverse_mod_383:
@@ -8,6 +10,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	ct_inverse_mod_383$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
diff --git a/c-source/build/elf/ctx_inverse_mod_384-x86_64.s b/c-source/build/elf/ctx_inverse_mod_384-x86_64.s
--- a/c-source/build/elf/ctx_inverse_mod_384-x86_64.s
+++ b/c-source/build/elf/ctx_inverse_mod_384-x86_64.s
@@ -1,6 +1,7 @@
 .text	
 
 .globl	ctx_inverse_mod_383
+.hidden	ctx_inverse_mod_383
 .type	ctx_inverse_mod_383,@function
 .align	32
 ctx_inverse_mod_383:
@@ -8,6 +9,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+ct_inverse_mod_383$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -810,7 +812,7 @@
 
 	movq	48(%rsi),%r10
 
-	call	__inner_loop_62
+	call	__tail_loop_53
 
 
 
@@ -1521,9 +1523,9 @@
 .cfi_endproc
 .size	__inner_loop_31,.-__inner_loop_31
 
-.type	__inner_loop_62,@function
+.type	__tail_loop_53,@function
 .align	32
-__inner_loop_62:
+__tail_loop_53:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -1532,7 +1534,7 @@
 	xorq	%r12,%r12
 	movq	$1,%r13
 
-.Loop_62:
+.Loop_53:
 	xorq	%rax,%rax
 	testq	$1,%r8
 	movq	%r10,%rbx
@@ -1559,11 +1561,11 @@
 	subq	%rax,%rdx
 	subq	%rbx,%rcx
 	subl	$1,%edi
-	jnz	.Loop_62
+	jnz	.Loop_53
 
 	.byte	0xf3,0xc3
 .cfi_endproc
-.size	__inner_loop_62,.-__inner_loop_62
+.size	__tail_loop_53,.-__tail_loop_53
 
 .section	.note.GNU-stack,"",@progbits
 .section	.note.gnu.property,"a",@note
diff --git a/c-source/build/elf/div3w-armv8.S b/c-source/build/elf/div3w-armv8.S
--- a/c-source/build/elf/div3w-armv8.S
+++ b/c-source/build/elf/div3w-armv8.S
@@ -25,7 +25,7 @@
 	asr	x3,x0,#63	// top bit -> mask
 	add	x0,x0,x0	// Q <<= 1
 	subs	x6,x4,x1	// R - D
-	add	x0,x0,#1	// Q + specilative bit
+	add	x0,x0,#1	// Q + speculative bit
 	sbcs	x7,x5,x2
 	sbc	x0,x0,xzr	// subtract speculative bit
 
diff --git a/c-source/build/elf/div3w-x86_64.s b/c-source/build/elf/div3w-x86_64.s
--- a/c-source/build/elf/div3w-x86_64.s
+++ b/c-source/build/elf/div3w-x86_64.s
@@ -8,6 +8,8 @@
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
+
+
 	movq	(%rdi),%r8
 	movq	8(%rdi),%r9
 	xorq	%rax,%rax
@@ -39,8 +41,9 @@
 
 	orq	%rcx,%rax
 
+
 	.byte	0xf3,0xc3
-.cfi_endproc
+.cfi_endproc	
 .size	div_3_limbs,.-div_3_limbs
 .globl	quot_rem_128
 .hidden	quot_rem_128
@@ -50,6 +53,8 @@
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
+
+
 	movq	%rdx,%rax
 	movq	%rdx,%rcx
 
@@ -84,8 +89,9 @@
 
 	movq	%rcx,%rax
 
+
 	.byte	0xf3,0xc3
-.cfi_endproc
+.cfi_endproc	
 .size	quot_rem_128,.-quot_rem_128
 
 
@@ -100,6 +106,8 @@
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
+
+
 	movq	%rdx,%rax
 	imulq	0(%rsi),%rdx
 
@@ -110,8 +118,9 @@
 	movq	%r10,0(%rdi)
 	movq	%rax,8(%rdi)
 
+
 	.byte	0xf3,0xc3
-.cfi_endproc
+.cfi_endproc	
 .size	quot_rem_64,.-quot_rem_64
 
 .section	.note.GNU-stack,"",@progbits
diff --git a/c-source/build/elf/mulq_mont_256-x86_64.s b/c-source/build/elf/mulq_mont_256-x86_64.s
--- a/c-source/build/elf/mulq_mont_256-x86_64.s
+++ b/c-source/build/elf/mulq_mont_256-x86_64.s
@@ -1,3 +1,4 @@
+.comm	__blst_platform_cap,4
 .text	
 
 .globl	mul_mont_sparse_256
@@ -9,6 +10,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	mul_mont_sparse_256$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -73,6 +78,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sqr_mont_sparse_256$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -419,6 +428,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	from_mont_256$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -494,6 +507,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	redc_mont_256$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
diff --git a/c-source/build/elf/mulq_mont_384-x86_64.s b/c-source/build/elf/mulq_mont_384-x86_64.s
--- a/c-source/build/elf/mulq_mont_384-x86_64.s
+++ b/c-source/build/elf/mulq_mont_384-x86_64.s
@@ -1,3 +1,4 @@
+.comm	__blst_platform_cap,4
 .text	
 
 
@@ -6,9 +7,9 @@
 
 
 
-.type	__sub_mod_384x384,@function
+.type	__subq_mod_384x384,@function
 .align	32
-__sub_mod_384x384:
+__subq_mod_384x384:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -73,11 +74,11 @@
 
 	.byte	0xf3,0xc3
 .cfi_endproc
-.size	__sub_mod_384x384,.-__sub_mod_384x384
+.size	__subq_mod_384x384,.-__subq_mod_384x384
 
-.type	__add_mod_384,@function
+.type	__addq_mod_384,@function
 .align	32
-__add_mod_384:
+__addq_mod_384:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -125,11 +126,11 @@
 
 	.byte	0xf3,0xc3
 .cfi_endproc
-.size	__add_mod_384,.-__add_mod_384
+.size	__addq_mod_384,.-__addq_mod_384
 
-.type	__sub_mod_384,@function
+.type	__subq_mod_384,@function
 .align	32
-__sub_mod_384:
+__subq_mod_384:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -140,7 +141,7 @@
 	movq	32(%rsi),%r12
 	movq	40(%rsi),%r13
 
-__sub_mod_384_a_is_loaded:
+__subq_mod_384_a_is_loaded:
 	subq	0(%rdx),%r8
 	movq	0(%rcx),%r14
 	sbbq	8(%rdx),%r9
@@ -177,7 +178,7 @@
 
 	.byte	0xf3,0xc3
 .cfi_endproc
-.size	__sub_mod_384,.-__sub_mod_384
+.size	__subq_mod_384,.-__subq_mod_384
 .globl	mul_mont_384x
 .hidden	mul_mont_384x
 .type	mul_mont_384x,@function
@@ -187,6 +188,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	mul_mont_384x$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -232,12 +237,12 @@
 	movq	8(%rsp),%rcx
 	leaq	-48(%rsi),%rdx
 	leaq	40+192+48(%rsp),%rdi
-	call	__add_mod_384
+	call	__addq_mod_384
 
 	movq	16(%rsp),%rsi
 	leaq	48(%rsi),%rdx
 	leaq	-48(%rdi),%rdi
-	call	__add_mod_384
+	call	__addq_mod_384
 
 	leaq	(%rdi),%rbx
 	leaq	48(%rdi),%rsi
@@ -247,17 +252,17 @@
 	leaq	(%rdi),%rsi
 	leaq	40(%rsp),%rdx
 	movq	8(%rsp),%rcx
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 	leaq	(%rdi),%rsi
 	leaq	-96(%rdi),%rdx
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 
 	leaq	40(%rsp),%rsi
 	leaq	40+96(%rsp),%rdx
 	leaq	40(%rsp),%rdi
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 	movq	%rcx,%rbx
 
@@ -266,14 +271,14 @@
 	movq	0(%rsp),%rcx
 	movq	32(%rsp),%rdi
 	call	__mulq_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redq_tail_mont_384
 
 
 	leaq	40+192(%rsp),%rsi
 	movq	0(%rsp),%rcx
 	leaq	48(%rdi),%rdi
 	call	__mulq_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redq_tail_mont_384
 
 	leaq	328(%rsp),%r8
 	movq	0(%r8),%r15
@@ -303,6 +308,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sqr_mont_384x$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -333,13 +342,13 @@
 
 	leaq	48(%rsi),%rdx
 	leaq	32(%rsp),%rdi
-	call	__add_mod_384
+	call	__addq_mod_384
 
 
 	movq	16(%rsp),%rsi
 	leaq	48(%rsi),%rdx
 	leaq	32+48(%rsp),%rdi
-	call	__sub_mod_384
+	call	__subq_mod_384
 
 
 	movq	16(%rsp),%rsi
@@ -427,6 +436,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	mul_382x$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -521,18 +534,18 @@
 	leaq	32(%rsp),%rdx
 	movq	24(%rsp),%rcx
 	movq	%rsi,%rdi
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 
 	leaq	0(%rdi),%rsi
 	leaq	-96(%rdi),%rdx
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 
 	leaq	-96(%rdi),%rsi
 	leaq	32(%rsp),%rdx
 	leaq	-96(%rdi),%rdi
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 	leaq	136(%rsp),%r8
 	movq	0(%r8),%r15
@@ -562,6 +575,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sqr_382x$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -617,7 +634,7 @@
 
 	leaq	48(%rsi),%rdx
 	leaq	48(%rdi),%rdi
-	call	__sub_mod_384_a_is_loaded
+	call	__subq_mod_384_a_is_loaded
 
 
 	leaq	(%rdi),%rsi
@@ -695,6 +712,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	mul_384$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1019,6 +1040,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sqr_384$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1265,6 +1290,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sqr_mont_384$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1299,7 +1328,7 @@
 	movq	104(%rsp),%rbx
 	movq	112(%rsp),%rdi
 	call	__mulq_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redq_tail_mont_384
 
 	leaq	120(%rsp),%r8
 	movq	120(%rsp),%r15
@@ -1332,6 +1361,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	redc_mont_384$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1356,7 +1389,7 @@
 
 	movq	%rdx,%rbx
 	call	__mulq_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redq_tail_mont_384
 
 	movq	8(%rsp),%r15
 .cfi_restore	%r15
@@ -1389,6 +1422,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	from_mont_384$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1762,9 +1799,9 @@
 .cfi_endproc
 .size	__mulq_by_1_mont_384,.-__mulq_by_1_mont_384
 
-.type	__redc_tail_mont_384,@function
+.type	__redq_tail_mont_384,@function
 .align	32
-__redc_tail_mont_384:
+__redq_tail_mont_384:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -1809,7 +1846,7 @@
 
 	.byte	0xf3,0xc3
 .cfi_endproc
-.size	__redc_tail_mont_384,.-__redc_tail_mont_384
+.size	__redq_tail_mont_384,.-__redq_tail_mont_384
 
 .globl	sgn0_pty_mont_384
 .hidden	sgn0_pty_mont_384
@@ -1820,6 +1857,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sgn0_pty_mont_384$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1898,6 +1939,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sgn0_pty_mont_384x$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -2025,6 +2070,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	mul_mont_384$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -2689,6 +2738,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sqr_n_mul_mont_384$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -2727,7 +2780,7 @@
 	movq	0(%rsp),%rcx
 	movq	16(%rsp),%rbx
 	call	__mulq_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redq_tail_mont_384
 
 	movd	%xmm1,%edx
 	leaq	0(%rdi),%rsi
@@ -2777,6 +2830,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sqr_n_mul_mont_383$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -3438,6 +3495,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,__blst_platform_cap(%rip)
+	jnz	sqr_mont_382x$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
diff --git a/c-source/build/elf/mulx_mont_256-x86_64.s b/c-source/build/elf/mulx_mont_256-x86_64.s
--- a/c-source/build/elf/mulx_mont_256-x86_64.s
+++ b/c-source/build/elf/mulx_mont_256-x86_64.s
@@ -9,6 +9,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+mul_mont_sparse_256$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -71,6 +72,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sqr_mont_sparse_256$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -332,6 +334,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+from_mont_256$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -407,6 +410,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+redc_mont_256$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
diff --git a/c-source/build/elf/mulx_mont_384-x86_64.s b/c-source/build/elf/mulx_mont_384-x86_64.s
--- a/c-source/build/elf/mulx_mont_384-x86_64.s
+++ b/c-source/build/elf/mulx_mont_384-x86_64.s
@@ -6,9 +6,9 @@
 
 
 
-.type	__sub_mod_384x384,@function
+.type	__subx_mod_384x384,@function
 .align	32
-__sub_mod_384x384:
+__subx_mod_384x384:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -73,11 +73,11 @@
 
 	.byte	0xf3,0xc3
 .cfi_endproc
-.size	__sub_mod_384x384,.-__sub_mod_384x384
+.size	__subx_mod_384x384,.-__subx_mod_384x384
 
-.type	__add_mod_384,@function
+.type	__addx_mod_384,@function
 .align	32
-__add_mod_384:
+__addx_mod_384:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -125,11 +125,11 @@
 
 	.byte	0xf3,0xc3
 .cfi_endproc
-.size	__add_mod_384,.-__add_mod_384
+.size	__addx_mod_384,.-__addx_mod_384
 
-.type	__sub_mod_384,@function
+.type	__subx_mod_384,@function
 .align	32
-__sub_mod_384:
+__subx_mod_384:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -140,7 +140,7 @@
 	movq	32(%rsi),%r12
 	movq	40(%rsi),%r13
 
-__sub_mod_384_a_is_loaded:
+__subx_mod_384_a_is_loaded:
 	subq	0(%rdx),%r8
 	movq	0(%rcx),%r14
 	sbbq	8(%rdx),%r9
@@ -177,7 +177,7 @@
 
 	.byte	0xf3,0xc3
 .cfi_endproc
-.size	__sub_mod_384,.-__sub_mod_384
+.size	__subx_mod_384,.-__subx_mod_384
 .globl	mulx_mont_384x
 .hidden	mulx_mont_384x
 .type	mulx_mont_384x,@function
@@ -187,6 +187,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+mul_mont_384x$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -233,12 +234,12 @@
 	leaq	(%rbx),%rsi
 	leaq	-48(%rbx),%rdx
 	leaq	40+192+48(%rsp),%rdi
-	call	__add_mod_384
+	call	__addx_mod_384
 
 	movq	24(%rsp),%rsi
 	leaq	48(%rsi),%rdx
 	leaq	-48(%rdi),%rdi
-	call	__add_mod_384
+	call	__addx_mod_384
 
 	leaq	(%rdi),%rbx
 	leaq	48(%rdi),%rsi
@@ -248,17 +249,17 @@
 	leaq	(%rdi),%rsi
 	leaq	40(%rsp),%rdx
 	movq	8(%rsp),%rcx
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 	leaq	(%rdi),%rsi
 	leaq	-96(%rdi),%rdx
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 
 	leaq	40(%rsp),%rsi
 	leaq	40+96(%rsp),%rdx
 	leaq	40(%rsp),%rdi
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 	leaq	(%rcx),%rbx
 
@@ -267,14 +268,14 @@
 	movq	0(%rsp),%rcx
 	movq	32(%rsp),%rdi
 	call	__mulx_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redx_tail_mont_384
 
 
 	leaq	40+192(%rsp),%rsi
 	movq	0(%rsp),%rcx
 	leaq	48(%rdi),%rdi
 	call	__mulx_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redx_tail_mont_384
 
 	leaq	328(%rsp),%r8
 	movq	0(%r8),%r15
@@ -304,6 +305,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sqr_mont_384x$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -335,13 +337,13 @@
 
 	leaq	48(%rsi),%rdx
 	leaq	32(%rsp),%rdi
-	call	__add_mod_384
+	call	__addx_mod_384
 
 
 	movq	24(%rsp),%rsi
 	leaq	48(%rsi),%rdx
 	leaq	32+48(%rsp),%rdi
-	call	__sub_mod_384
+	call	__subx_mod_384
 
 
 	movq	24(%rsp),%rsi
@@ -439,6 +441,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+mul_382x$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -533,18 +536,18 @@
 	leaq	32(%rsp),%rdx
 	movq	24(%rsp),%rcx
 	movq	%rsi,%rdi
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 
 	leaq	0(%rdi),%rsi
 	leaq	-96(%rdi),%rdx
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 
 	leaq	-96(%rdi),%rsi
 	leaq	32(%rsp),%rdx
 	leaq	-96(%rdi),%rdi
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 	leaq	136(%rsp),%r8
 	movq	0(%r8),%r15
@@ -574,6 +577,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sqr_382x$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -629,7 +633,7 @@
 
 	leaq	48(%rsi),%rdx
 	leaq	48(%rdi),%rdi
-	call	__sub_mod_384_a_is_loaded
+	call	__subx_mod_384_a_is_loaded
 
 
 	leaq	(%rdi),%rsi
@@ -707,6 +711,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+mul_384$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -933,6 +938,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sqr_384$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1127,6 +1133,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+redc_mont_384$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1151,7 +1158,7 @@
 
 	movq	%rdx,%rbx
 	call	__mulx_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redx_tail_mont_384
 
 	movq	8(%rsp),%r15
 .cfi_restore	%r15
@@ -1184,6 +1191,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+from_mont_384$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1448,9 +1456,9 @@
 .cfi_endproc
 .size	__mulx_by_1_mont_384,.-__mulx_by_1_mont_384
 
-.type	__redc_tail_mont_384,@function
+.type	__redx_tail_mont_384,@function
 .align	32
-__redc_tail_mont_384:
+__redx_tail_mont_384:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -1495,7 +1503,7 @@
 
 	.byte	0xf3,0xc3
 .cfi_endproc
-.size	__redc_tail_mont_384,.-__redc_tail_mont_384
+.size	__redx_tail_mont_384,.-__redx_tail_mont_384
 
 .globl	sgn0x_pty_mont_384
 .hidden	sgn0x_pty_mont_384
@@ -1506,6 +1514,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sgn0_pty_mont_384$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1584,6 +1593,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sgn0_pty_mont_384x$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1711,6 +1721,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+mul_mont_384$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -2178,6 +2189,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sqr_mont_384$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -2245,6 +2257,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sqr_n_mul_mont_384$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -2330,6 +2343,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sqr_n_mul_mont_383$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -2776,6 +2790,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sqr_mont_382x$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
diff --git a/c-source/build/elf/sha256-armv8.S b/c-source/build/elf/sha256-armv8.S
--- a/c-source/build/elf/sha256-armv8.S
+++ b/c-source/build/elf/sha256-armv8.S
@@ -10,11 +10,12 @@
 //
 // sha256_block procedure for ARMv8.
 //
-// This module is stripped of scalar code paths, with raionale that all
+// This module is stripped of scalar code paths, with rationale that all
 // known processors are NEON-capable.
 //
 // See original module at CRYPTOGAMS for further details.
 
+.comm	__blst_platform_cap,4
 .text
 
 .align	6
@@ -184,6 +185,11 @@
 .type	blst_sha256_block_data_order,%function
 .align	4
 blst_sha256_block_data_order:
+	adrp	x16,__blst_platform_cap
+	ldr	w16,[x16,#:lo12:__blst_platform_cap]
+	tst	w16,#1
+	b.ne	.Lv8_entry
+
 	stp	x29, x30, [sp, #-16]!
 	mov	x29, sp
 	sub	sp,sp,#16*4
diff --git a/c-source/build/elf/sha256-portable-x86_64.s b/c-source/build/elf/sha256-portable-x86_64.s
--- a/c-source/build/elf/sha256-portable-x86_64.s
+++ b/c-source/build/elf/sha256-portable-x86_64.s
@@ -1,3 +1,4 @@
+.comm	__blst_platform_cap,4
 .text	
 
 .globl	blst_sha256_block_data_order
@@ -8,33 +9,35 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
-	pushq	%rbx
-.cfi_adjust_cfa_offset	8
-.cfi_offset	%rbx,-16
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
-.cfi_offset	%rbp,-24
+.cfi_offset	%rbp,-16
+	movq	%rsp,%rbp
+.cfi_def_cfa_register	%rbp
+#ifdef __BLST_PORTABLE__
+	testl	$2,__blst_platform_cap(%rip)
+	jnz	.Lblst_sha256_block_data_order$2
+#endif
+	pushq	%rbx
+.cfi_offset	%rbx,-24
 	pushq	%r12
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%r12,-32
 	pushq	%r13
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%r13,-40
 	pushq	%r14
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%r14,-48
 	pushq	%r15
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%r15,-56
 	shlq	$4,%rdx
 	subq	$64+24,%rsp
-.cfi_adjust_cfa_offset	16*4+3*8
+
+.cfi_def_cfa	%rsp,144
+
 	leaq	(%rsi,%rdx,4),%rdx
 	movq	%rdi,64+0(%rsp)
 	movq	%rsi,64+8(%rsp)
 	movq	%rdx,64+16(%rsp)
 
-
 	movl	0(%rdi),%eax
 	movl	4(%rdi),%ebx
 	movl	8(%rdi),%ecx
@@ -1636,23 +1639,23 @@
 	leaq	64+24+48(%rsp),%r11
 .cfi_def_cfa	%r11,8
 	movq	64+24(%rsp),%r15
-.cfi_restore	%r15
 	movq	-40(%r11),%r14
-.cfi_restore	%r14
 	movq	-32(%r11),%r13
-.cfi_restore	%r13
 	movq	-24(%r11),%r12
+	movq	-16(%r11),%rbx
+	movq	-8(%r11),%rbp
 .cfi_restore	%r12
-	movq	-16(%r11),%rbp
+.cfi_restore	%r13
+.cfi_restore	%r14
+.cfi_restore	%r15
 .cfi_restore	%rbp
-	movq	-8(%r11),%rbx
 .cfi_restore	%rbx
-
 	leaq	(%r11),%rsp
 	.byte	0xf3,0xc3
 .cfi_endproc	
 .size	blst_sha256_block_data_order,.-blst_sha256_block_data_order
 
+#ifndef __BLST_PORTABLE__
 .align	64
 .type	K256,@object
 K256:
@@ -1744,6 +1747,7 @@
 	.byte	0xf3,0xc3
 .cfi_endproc
 .size	blst_sha256_hcopy,.-blst_sha256_hcopy
+#endif
 
 .section	.note.GNU-stack,"",@progbits
 .section	.note.gnu.property,"a",@note
diff --git a/c-source/build/elf/sha256-x86_64.s b/c-source/build/elf/sha256-x86_64.s
--- a/c-source/build/elf/sha256-x86_64.s
+++ b/c-source/build/elf/sha256-x86_64.s
@@ -1,3 +1,4 @@
+.comm	__blst_platform_cap,4
 .text	
 
 .align	64
@@ -33,6 +34,13 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+	pushq	%rbp
+.cfi_adjust_cfa_offset	8
+.cfi_offset	%rbp,-16
+	movq	%rsp,%rbp
+.cfi_def_cfa_register	%rbp
+.Lblst_sha256_block_data_order$2:
+
 	leaq	K256+128(%rip),%rcx
 	movdqu	(%rdi),%xmm1
 	movdqu	16(%rdi),%xmm2
@@ -234,6 +242,11 @@
 
 	movdqu	%xmm1,(%rdi)
 	movdqu	%xmm2,16(%rdi)
+.cfi_def_cfa_register	%rsp
+	popq	%rbp
+.cfi_adjust_cfa_offset	-8
+.cfi_restore	%rbp
+
 	.byte	0xf3,0xc3
 .cfi_endproc	
 .size	blst_sha256_block_data_order_shaext,.-blst_sha256_block_data_order_shaext
@@ -249,30 +262,27 @@
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
+	movq	%rsp,%rbp
+.cfi_def_cfa_register	%rbp
+	testl	$2,__blst_platform_cap(%rip)
+	jnz	.Lblst_sha256_block_data_order$2
 	pushq	%rbx
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%rbx,-24
 	pushq	%r12
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%r12,-32
 	pushq	%r13
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%r13,-40
 	pushq	%r14
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%r14,-48
 	pushq	%r15
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%r15,-56
 	shlq	$4,%rdx
-	subq	$40,%rsp
-.cfi_adjust_cfa_offset	40
+	subq	$24,%rsp
+
 	leaq	(%rsi,%rdx,4),%rdx
-	movq	%rdi,0(%rsp)
+	movq	%rdi,-64(%rbp)
 
-	movq	%rdx,16(%rsp)
-	movq	%rsp,%rbp
-.cfi_def_cfa_register	%rbp
+	movq	%rdx,-48(%rbp)
 
 
 	leaq	-64(%rsp),%rsp
@@ -291,7 +301,7 @@
 .align	16
 .Lloop_ssse3:
 	movdqa	K256+256(%rip),%xmm7
-	movq	%rsi,8(%rbp)
+	movq	%rsi,-56(%rbp)
 	movdqu	0(%rsi),%xmm0
 	movdqu	16(%rsi),%xmm1
 	movdqu	32(%rsi),%xmm2
@@ -1316,9 +1326,9 @@
 	addl	%r15d,%eax
 	movl	%r8d,%r13d
 	addl	%eax,%r14d
-	movq	0(%rbp),%rdi
+	movq	-64(%rbp),%rdi
 	movl	%r14d,%eax
-	movq	8(%rbp),%rsi
+	movq	-56(%rbp),%rsi
 
 	addl	0(%rdi),%eax
 	addl	4(%rdi),%ebx
@@ -1330,7 +1340,7 @@
 	addl	28(%rdi),%r11d
 
 	leaq	64(%rsi),%rsi
-	cmpq	16(%rbp),%rsi
+	cmpq	-48(%rbp),%rsi
 
 	movl	%eax,0(%rdi)
 	movl	%ebx,4(%rdi)
@@ -1343,26 +1353,25 @@
 	jb	.Lloop_ssse3
 
 	xorps	%xmm0,%xmm0
-	leaq	40+48(%rbp),%r11
-.cfi_def_cfa	%r11,8
 	movaps	%xmm0,0(%rsp)
 	movaps	%xmm0,16(%rsp)
 	movaps	%xmm0,32(%rsp)
 	movaps	%xmm0,48(%rsp)
-	movq	40(%rbp),%r15
-.cfi_restore	%r15
-	movq	-40(%r11),%r14
-.cfi_restore	%r14
-	movq	-32(%r11),%r13
-.cfi_restore	%r13
-	movq	-24(%r11),%r12
+	movq	-40(%rbp),%r15
+	movq	-32(%rbp),%r14
+	movq	-24(%rbp),%r13
+	movq	-16(%rbp),%r12
+	movq	-8(%rbp),%rbx
+	movq	%rbp,%rsp
+.cfi_def_cfa_register	%rsp
+	popq	%rbp
+.cfi_adjust_cfa_offset	-8
+.cfi_restore	%rbp
 .cfi_restore	%r12
-	movq	-16(%r11),%rbx
+.cfi_restore	%r13
+.cfi_restore	%r14
+.cfi_restore	%r15
 .cfi_restore	%rbx
-	movq	-8(%r11),%rbp
-.cfi_restore	%rbp
-
-	leaq	(%r11),%rsp
 	.byte	0xf3,0xc3
 .cfi_endproc	
 .size	blst_sha256_block_data_order,.-blst_sha256_block_data_order
diff --git a/c-source/build/mach-o/add_mod_384-armv8.S b/c-source/build/mach-o/add_mod_384-armv8.S
--- a/c-source/build/mach-o/add_mod_384-armv8.S
+++ b/c-source/build/mach-o/add_mod_384-armv8.S
@@ -748,6 +748,21 @@
 
 	ret
 
+.globl	_vec_select_32
+.private_extern	_vec_select_32
+
+.align	5
+_vec_select_32:
+	dup	v6.2d, x3
+	ld1	{v0.2d, v1.2d, v2.2d}, [x1],#48
+	cmeq	v6.2d, v6.2d, #0
+	ld1	{v3.2d, v4.2d, v5.2d}, [x2],#48
+	bit	v0.16b, v3.16b, v6.16b
+	bit	v1.16b, v4.16b, v6.16b
+	bit	v2.16b, v5.16b, v6.16b
+	st1	{v0.2d, v1.2d, v2.2d}, [x0]
+	ret
+
 .globl	_vec_select_48
 .private_extern	_vec_select_48
 
@@ -927,5 +942,59 @@
 	cmp	x0, x1
 	csel	x0, x1, x0, hi
 	prfm	pldl1keep, [x0]
+	ret
+
+.globl	_vec_is_zero_16x
+.private_extern	_vec_is_zero_16x
+
+.align	5
+_vec_is_zero_16x:
+	ld1	{v0.2d}, [x0], #16
+	lsr	x1, x1, #4
+	sub	x1, x1, #1
+	cbz	x1, Loop_is_zero_done
+
+Loop_is_zero:
+	ld1	{v1.2d}, [x0], #16
+	orr	v0.16b, v0.16b, v1.16b
+	sub	x1, x1, #1
+	cbnz	x1, Loop_is_zero
+
+Loop_is_zero_done:
+	dup	v1.2d, v0.d[1]
+	orr	v0.16b, v0.16b, v1.16b
+	mov	x1, v0.d[0]
+	mov	x0, #1
+	cmp	x1, #0
+	csel	x0, x0, xzr, eq
+	ret
+
+.globl	_vec_is_equal_16x
+.private_extern	_vec_is_equal_16x
+
+.align	5
+_vec_is_equal_16x:
+	ld1	{v0.2d}, [x0], #16
+	ld1	{v1.2d}, [x1], #16
+	lsr	x2, x2, #4
+	eor	v0.16b, v0.16b, v1.16b
+
+Loop_is_equal:
+	sub	x2, x2, #1
+	cbz	x2, Loop_is_equal_done
+	ld1	{v1.2d}, [x0], #16
+	ld1	{v2.2d}, [x1], #16
+	eor	v1.16b, v1.16b, v2.16b
+	orr	v0.16b, v0.16b, v1.16b
+	b	Loop_is_equal
+	nop
+
+Loop_is_equal_done:
+	dup	v1.2d, v0.d[1]
+	orr	v0.16b, v0.16b, v1.16b
+	mov	x1, v0.d[0]
+	mov	x0, #1
+	cmp	x1, #0
+	csel	x0, x0, xzr, eq
 	ret
 
diff --git a/c-source/build/mach-o/add_mod_384-x86_64.s b/c-source/build/mach-o/add_mod_384-x86_64.s
--- a/c-source/build/mach-o/add_mod_384-x86_64.s
+++ b/c-source/build/mach-o/add_mod_384-x86_64.s
@@ -1372,6 +1372,37 @@
 	.byte	0xf3,0xc3
 .cfi_endproc	
 
+.globl	_vec_select_32
+.private_extern	_vec_select_32
+
+.p2align	5
+_vec_select_32:
+.cfi_startproc
+	.byte	0xf3,0x0f,0x1e,0xfa
+
+	movd	%ecx,%xmm5
+	pxor	%xmm4,%xmm4
+	pshufd	$0,%xmm5,%xmm5
+	movdqu	(%rsi),%xmm0
+	leaq	16(%rsi),%rsi
+	pcmpeqd	%xmm4,%xmm5
+	movdqu	(%rdx),%xmm1
+	leaq	16(%rdx),%rdx
+	pcmpeqd	%xmm5,%xmm4
+	leaq	16(%rdi),%rdi
+	pand	%xmm4,%xmm0
+	movdqu	0+16-16(%rsi),%xmm2
+	pand	%xmm5,%xmm1
+	movdqu	0+16-16(%rdx),%xmm3
+	por	%xmm1,%xmm0
+	movdqu	%xmm0,0-16(%rdi)
+	pand	%xmm4,%xmm2
+	pand	%xmm5,%xmm3
+	por	%xmm3,%xmm2
+	movdqu	%xmm2,16-16(%rdi)
+	.byte	0xf3,0xc3
+.cfi_endproc
+
 .globl	_vec_select_48
 .private_extern	_vec_select_48
 
@@ -1796,6 +1827,73 @@
 	cmpq	%rsi,%rdi
 	cmovaq	%rsi,%rdi
 	prefetchnta	(%rdi)
+	.byte	0xf3,0xc3
+.cfi_endproc
+
+.globl	_vec_is_zero_16x
+.private_extern	_vec_is_zero_16x
+
+.p2align	5
+_vec_is_zero_16x:
+.cfi_startproc
+	.byte	0xf3,0x0f,0x1e,0xfa
+
+	shrl	$4,%esi
+	movdqu	(%rdi),%xmm0
+	leaq	16(%rdi),%rdi
+
+L$oop_is_zero:
+	decl	%esi
+	jz	L$oop_is_zero_done
+	movdqu	(%rdi),%xmm1
+	leaq	16(%rdi),%rdi
+	por	%xmm1,%xmm0
+	jmp	L$oop_is_zero
+
+L$oop_is_zero_done:
+	pshufd	$0x4e,%xmm0,%xmm1
+	por	%xmm1,%xmm0
+.byte	102,72,15,126,192
+	incl	%esi
+	testq	%rax,%rax
+	cmovnzl	%esi,%eax
+	xorl	$1,%eax
+	.byte	0xf3,0xc3
+.cfi_endproc
+
+.globl	_vec_is_equal_16x
+.private_extern	_vec_is_equal_16x
+
+.p2align	5
+_vec_is_equal_16x:
+.cfi_startproc
+	.byte	0xf3,0x0f,0x1e,0xfa
+
+	shrl	$4,%edx
+	movdqu	(%rdi),%xmm0
+	movdqu	(%rsi),%xmm1
+	subq	%rdi,%rsi
+	leaq	16(%rdi),%rdi
+	pxor	%xmm1,%xmm0
+
+L$oop_is_equal:
+	decl	%edx
+	jz	L$oop_is_equal_done
+	movdqu	(%rdi),%xmm1
+	movdqu	(%rdi,%rsi,1),%xmm2
+	leaq	16(%rdi),%rdi
+	pxor	%xmm2,%xmm1
+	por	%xmm1,%xmm0
+	jmp	L$oop_is_equal
+
+L$oop_is_equal_done:
+	pshufd	$0x4e,%xmm0,%xmm1
+	por	%xmm1,%xmm0
+.byte	102,72,15,126,192
+	incl	%edx
+	testq	%rax,%rax
+	cmovnzl	%edx,%eax
+	xorl	$1,%eax
 	.byte	0xf3,0xc3
 .cfi_endproc
 
diff --git a/c-source/build/mach-o/ct_inverse_mod_256-armv8.S b/c-source/build/mach-o/ct_inverse_mod_256-armv8.S
--- a/c-source/build/mach-o/ct_inverse_mod_256-armv8.S
+++ b/c-source/build/mach-o/ct_inverse_mod_256-armv8.S
@@ -1,6 +1,7 @@
 .text
 
 .globl	_ct_inverse_mod_256
+.private_extern	_ct_inverse_mod_256
 
 .align	5
 _ct_inverse_mod_256:
@@ -60,14 +61,14 @@
 	madd	x4, x16, x8, xzr	// |u|*|f0|
 	madd	x4, x17, x9, x4	// |v|*|g0|
 	str	x4, [x0,#8*4]
-	asr	x5, x4, #63		// sign extenstion
+	asr	x5, x4, #63		// sign extension
 	stp	x5, x5, [x0,#8*5]
 	stp	x5, x5, [x0,#8*7]
 
 	madd	x4, x12, x8, xzr	// |u|*|f1|
 	madd	x4, x13, x9, x4	// |v|*|g1|
 	str	x4, [x0,#8*9]
-	asr	x5, x4, #63		// sign extenstion
+	asr	x5, x4, #63		// sign extension
 	stp	x5, x5, [x0,#8*10]
 	stp	x5, x5, [x0,#8*12]
 	eor	x1, x1, #256		// flip-flop src |a|b|u|v|
diff --git a/c-source/build/mach-o/ct_inverse_mod_256-x86_64.s b/c-source/build/mach-o/ct_inverse_mod_256-x86_64.s
--- a/c-source/build/mach-o/ct_inverse_mod_256-x86_64.s
+++ b/c-source/build/mach-o/ct_inverse_mod_256-x86_64.s
@@ -1,6 +1,7 @@
 .text	
 
 .globl	_ct_inverse_mod_256
+.private_extern	_ct_inverse_mod_256
 
 .p2align	5
 _ct_inverse_mod_256:
diff --git a/c-source/build/mach-o/ct_inverse_mod_384-armv8.S b/c-source/build/mach-o/ct_inverse_mod_384-armv8.S
--- a/c-source/build/mach-o/ct_inverse_mod_384-armv8.S
+++ b/c-source/build/mach-o/ct_inverse_mod_384-armv8.S
@@ -1,6 +1,7 @@
 .text
 
 .globl	_ct_inverse_mod_383
+.private_extern	_ct_inverse_mod_383
 
 .align	5
 _ct_inverse_mod_383:
@@ -71,7 +72,7 @@
 	adds	x3, x3, x5
 	adc	x4, x4, x6
 	stp	x3, x4, [x0,#8*6]
-	asr	x5, x4, #63		// sign extenstion
+	asr	x5, x4, #63		// sign extension
 	stp	x5, x5, [x0,#8*8]
 	stp	x5, x5, [x0,#8*10]
 
@@ -82,7 +83,7 @@
 	adds	x3, x3, x5
 	adc	x4, x4, x6
 	stp	x3, x4, [x0,#8*12]
-	asr	x5, x4, #63		// sign extenstion
+	asr	x5, x4, #63		// sign extension
 	stp	x5, x5, [x0,#8*14]
 	stp	x5, x5, [x0,#8*16]
 	eor	x1, x1, #256		// flip-flop src |a|b|u|v|
diff --git a/c-source/build/mach-o/ct_is_square_mod_384-armv8.S b/c-source/build/mach-o/ct_is_square_mod_384-armv8.S
--- a/c-source/build/mach-o/ct_is_square_mod_384-armv8.S
+++ b/c-source/build/mach-o/ct_is_square_mod_384-armv8.S
@@ -1,6 +1,7 @@
 .text
 
 .globl	_ct_is_square_mod_384
+.private_extern	_ct_is_square_mod_384
 
 .align	5
 _ct_is_square_mod_384:
diff --git a/c-source/build/mach-o/ct_is_square_mod_384-x86_64.s b/c-source/build/mach-o/ct_is_square_mod_384-x86_64.s
--- a/c-source/build/mach-o/ct_is_square_mod_384-x86_64.s
+++ b/c-source/build/mach-o/ct_is_square_mod_384-x86_64.s
@@ -1,6 +1,7 @@
 .text	
 
 .globl	_ct_is_square_mod_384
+.private_extern	_ct_is_square_mod_384
 
 .p2align	5
 _ct_is_square_mod_384:
diff --git a/c-source/build/mach-o/ctq_inverse_mod_384-x86_64.s b/c-source/build/mach-o/ctq_inverse_mod_384-x86_64.s
--- a/c-source/build/mach-o/ctq_inverse_mod_384-x86_64.s
+++ b/c-source/build/mach-o/ctq_inverse_mod_384-x86_64.s
@@ -1,6 +1,8 @@
+.comm	___blst_platform_cap,4
 .text	
 
 .globl	_ct_inverse_mod_383
+.private_extern	_ct_inverse_mod_383
 
 .p2align	5
 _ct_inverse_mod_383:
@@ -8,6 +10,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	ct_inverse_mod_383$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
diff --git a/c-source/build/mach-o/ctx_inverse_mod_384-x86_64.s b/c-source/build/mach-o/ctx_inverse_mod_384-x86_64.s
--- a/c-source/build/mach-o/ctx_inverse_mod_384-x86_64.s
+++ b/c-source/build/mach-o/ctx_inverse_mod_384-x86_64.s
@@ -1,6 +1,7 @@
 .text	
 
 .globl	_ctx_inverse_mod_383
+.private_extern	_ctx_inverse_mod_383
 
 .p2align	5
 _ctx_inverse_mod_383:
@@ -8,6 +9,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+ct_inverse_mod_383$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -810,7 +812,7 @@
 
 	movq	48(%rsi),%r10
 
-	call	__inner_loop_62
+	call	__tail_loop_53
 
 
 
@@ -1523,7 +1525,7 @@
 
 
 .p2align	5
-__inner_loop_62:
+__tail_loop_53:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -1532,7 +1534,7 @@
 	xorq	%r12,%r12
 	movq	$1,%r13
 
-L$oop_62:
+L$oop_53:
 	xorq	%rax,%rax
 	testq	$1,%r8
 	movq	%r10,%rbx
@@ -1559,7 +1561,7 @@
 	subq	%rax,%rdx
 	subq	%rbx,%rcx
 	subl	$1,%edi
-	jnz	L$oop_62
+	jnz	L$oop_53
 
 	.byte	0xf3,0xc3
 .cfi_endproc
diff --git a/c-source/build/mach-o/div3w-armv8.S b/c-source/build/mach-o/div3w-armv8.S
--- a/c-source/build/mach-o/div3w-armv8.S
+++ b/c-source/build/mach-o/div3w-armv8.S
@@ -25,7 +25,7 @@
 	asr	x3,x0,#63	// top bit -> mask
 	add	x0,x0,x0	// Q <<= 1
 	subs	x6,x4,x1	// R - D
-	add	x0,x0,#1	// Q + specilative bit
+	add	x0,x0,#1	// Q + speculative bit
 	sbcs	x7,x5,x2
 	sbc	x0,x0,xzr	// subtract speculative bit
 
diff --git a/c-source/build/mach-o/div3w-x86_64.s b/c-source/build/mach-o/div3w-x86_64.s
--- a/c-source/build/mach-o/div3w-x86_64.s
+++ b/c-source/build/mach-o/div3w-x86_64.s
@@ -8,6 +8,8 @@
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
+
+
 	movq	(%rdi),%r8
 	movq	8(%rdi),%r9
 	xorq	%rax,%rax
@@ -39,8 +41,9 @@
 
 	orq	%rcx,%rax
 
+
 	.byte	0xf3,0xc3
-.cfi_endproc
+.cfi_endproc	
 
 .globl	_quot_rem_128
 .private_extern	_quot_rem_128
@@ -50,6 +53,8 @@
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
+
+
 	movq	%rdx,%rax
 	movq	%rdx,%rcx
 
@@ -84,8 +89,9 @@
 
 	movq	%rcx,%rax
 
+
 	.byte	0xf3,0xc3
-.cfi_endproc
+.cfi_endproc	
 
 
 
@@ -100,6 +106,8 @@
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
+
+
 	movq	%rdx,%rax
 	imulq	0(%rsi),%rdx
 
@@ -110,6 +118,7 @@
 	movq	%r10,0(%rdi)
 	movq	%rax,8(%rdi)
 
+
 	.byte	0xf3,0xc3
-.cfi_endproc
+.cfi_endproc	
 
diff --git a/c-source/build/mach-o/mulq_mont_256-x86_64.s b/c-source/build/mach-o/mulq_mont_256-x86_64.s
--- a/c-source/build/mach-o/mulq_mont_256-x86_64.s
+++ b/c-source/build/mach-o/mulq_mont_256-x86_64.s
@@ -1,3 +1,4 @@
+.comm	___blst_platform_cap,4
 .text	
 
 .globl	_mul_mont_sparse_256
@@ -9,6 +10,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	mul_mont_sparse_256$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -73,6 +78,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	sqr_mont_sparse_256$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -419,6 +428,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	from_mont_256$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -494,6 +507,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	redc_mont_256$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
diff --git a/c-source/build/mach-o/mulq_mont_384-x86_64.s b/c-source/build/mach-o/mulq_mont_384-x86_64.s
--- a/c-source/build/mach-o/mulq_mont_384-x86_64.s
+++ b/c-source/build/mach-o/mulq_mont_384-x86_64.s
@@ -1,3 +1,4 @@
+.comm	___blst_platform_cap,4
 .text	
 
 
@@ -8,7 +9,7 @@
 
 
 .p2align	5
-__sub_mod_384x384:
+__subq_mod_384x384:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -77,7 +78,7 @@
 
 
 .p2align	5
-__add_mod_384:
+__addq_mod_384:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -129,7 +130,7 @@
 
 
 .p2align	5
-__sub_mod_384:
+__subq_mod_384:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -140,7 +141,7 @@
 	movq	32(%rsi),%r12
 	movq	40(%rsi),%r13
 
-__sub_mod_384_a_is_loaded:
+__subq_mod_384_a_is_loaded:
 	subq	0(%rdx),%r8
 	movq	0(%rcx),%r14
 	sbbq	8(%rdx),%r9
@@ -187,6 +188,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	mul_mont_384x$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -232,12 +237,12 @@
 	movq	8(%rsp),%rcx
 	leaq	-48(%rsi),%rdx
 	leaq	40+192+48(%rsp),%rdi
-	call	__add_mod_384
+	call	__addq_mod_384
 
 	movq	16(%rsp),%rsi
 	leaq	48(%rsi),%rdx
 	leaq	-48(%rdi),%rdi
-	call	__add_mod_384
+	call	__addq_mod_384
 
 	leaq	(%rdi),%rbx
 	leaq	48(%rdi),%rsi
@@ -247,17 +252,17 @@
 	leaq	(%rdi),%rsi
 	leaq	40(%rsp),%rdx
 	movq	8(%rsp),%rcx
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 	leaq	(%rdi),%rsi
 	leaq	-96(%rdi),%rdx
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 
 	leaq	40(%rsp),%rsi
 	leaq	40+96(%rsp),%rdx
 	leaq	40(%rsp),%rdi
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 	movq	%rcx,%rbx
 
@@ -266,14 +271,14 @@
 	movq	0(%rsp),%rcx
 	movq	32(%rsp),%rdi
 	call	__mulq_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redq_tail_mont_384
 
 
 	leaq	40+192(%rsp),%rsi
 	movq	0(%rsp),%rcx
 	leaq	48(%rdi),%rdi
 	call	__mulq_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redq_tail_mont_384
 
 	leaq	328(%rsp),%r8
 	movq	0(%r8),%r15
@@ -303,6 +308,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	sqr_mont_384x$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -333,13 +342,13 @@
 
 	leaq	48(%rsi),%rdx
 	leaq	32(%rsp),%rdi
-	call	__add_mod_384
+	call	__addq_mod_384
 
 
 	movq	16(%rsp),%rsi
 	leaq	48(%rsi),%rdx
 	leaq	32+48(%rsp),%rdi
-	call	__sub_mod_384
+	call	__subq_mod_384
 
 
 	movq	16(%rsp),%rsi
@@ -427,6 +436,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	mul_382x$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -521,18 +534,18 @@
 	leaq	32(%rsp),%rdx
 	movq	24(%rsp),%rcx
 	movq	%rsi,%rdi
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 
 	leaq	0(%rdi),%rsi
 	leaq	-96(%rdi),%rdx
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 
 	leaq	-96(%rdi),%rsi
 	leaq	32(%rsp),%rdx
 	leaq	-96(%rdi),%rdi
-	call	__sub_mod_384x384
+	call	__subq_mod_384x384
 
 	leaq	136(%rsp),%r8
 	movq	0(%r8),%r15
@@ -562,6 +575,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	sqr_382x$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -617,7 +634,7 @@
 
 	leaq	48(%rsi),%rdx
 	leaq	48(%rdi),%rdi
-	call	__sub_mod_384_a_is_loaded
+	call	__subq_mod_384_a_is_loaded
 
 
 	leaq	(%rdi),%rsi
@@ -695,6 +712,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	mul_384$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1019,6 +1040,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	sqr_384$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1265,6 +1290,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	sqr_mont_384$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1299,7 +1328,7 @@
 	movq	104(%rsp),%rbx
 	movq	112(%rsp),%rdi
 	call	__mulq_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redq_tail_mont_384
 
 	leaq	120(%rsp),%r8
 	movq	120(%rsp),%r15
@@ -1332,6 +1361,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	redc_mont_384$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1356,7 +1389,7 @@
 
 	movq	%rdx,%rbx
 	call	__mulq_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redq_tail_mont_384
 
 	movq	8(%rsp),%r15
 .cfi_restore	%r15
@@ -1389,6 +1422,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	from_mont_384$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1764,7 +1801,7 @@
 
 
 .p2align	5
-__redc_tail_mont_384:
+__redq_tail_mont_384:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -1820,6 +1857,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	sgn0_pty_mont_384$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1898,6 +1939,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	sgn0_pty_mont_384x$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -2025,6 +2070,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	mul_mont_384$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -2689,6 +2738,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	sqr_n_mul_mont_384$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -2727,7 +2780,7 @@
 	movq	0(%rsp),%rcx
 	movq	16(%rsp),%rbx
 	call	__mulq_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redq_tail_mont_384
 
 	movd	%xmm1,%edx
 	leaq	0(%rdi),%rsi
@@ -2777,6 +2830,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	sqr_n_mul_mont_383$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -3438,6 +3495,10 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+#ifdef __BLST_PORTABLE__
+	testl	$1,___blst_platform_cap(%rip)
+	jnz	sqr_mont_382x$1
+#endif
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
diff --git a/c-source/build/mach-o/mulx_mont_256-x86_64.s b/c-source/build/mach-o/mulx_mont_256-x86_64.s
--- a/c-source/build/mach-o/mulx_mont_256-x86_64.s
+++ b/c-source/build/mach-o/mulx_mont_256-x86_64.s
@@ -9,6 +9,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+mul_mont_sparse_256$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -71,6 +72,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sqr_mont_sparse_256$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -332,6 +334,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+from_mont_256$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -407,6 +410,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+redc_mont_256$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
diff --git a/c-source/build/mach-o/mulx_mont_384-x86_64.s b/c-source/build/mach-o/mulx_mont_384-x86_64.s
--- a/c-source/build/mach-o/mulx_mont_384-x86_64.s
+++ b/c-source/build/mach-o/mulx_mont_384-x86_64.s
@@ -8,7 +8,7 @@
 
 
 .p2align	5
-__sub_mod_384x384:
+__subx_mod_384x384:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -77,7 +77,7 @@
 
 
 .p2align	5
-__add_mod_384:
+__addx_mod_384:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -129,7 +129,7 @@
 
 
 .p2align	5
-__sub_mod_384:
+__subx_mod_384:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -140,7 +140,7 @@
 	movq	32(%rsi),%r12
 	movq	40(%rsi),%r13
 
-__sub_mod_384_a_is_loaded:
+__subx_mod_384_a_is_loaded:
 	subq	0(%rdx),%r8
 	movq	0(%rcx),%r14
 	sbbq	8(%rdx),%r9
@@ -187,6 +187,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+mul_mont_384x$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -233,12 +234,12 @@
 	leaq	(%rbx),%rsi
 	leaq	-48(%rbx),%rdx
 	leaq	40+192+48(%rsp),%rdi
-	call	__add_mod_384
+	call	__addx_mod_384
 
 	movq	24(%rsp),%rsi
 	leaq	48(%rsi),%rdx
 	leaq	-48(%rdi),%rdi
-	call	__add_mod_384
+	call	__addx_mod_384
 
 	leaq	(%rdi),%rbx
 	leaq	48(%rdi),%rsi
@@ -248,17 +249,17 @@
 	leaq	(%rdi),%rsi
 	leaq	40(%rsp),%rdx
 	movq	8(%rsp),%rcx
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 	leaq	(%rdi),%rsi
 	leaq	-96(%rdi),%rdx
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 
 	leaq	40(%rsp),%rsi
 	leaq	40+96(%rsp),%rdx
 	leaq	40(%rsp),%rdi
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 	leaq	(%rcx),%rbx
 
@@ -267,14 +268,14 @@
 	movq	0(%rsp),%rcx
 	movq	32(%rsp),%rdi
 	call	__mulx_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redx_tail_mont_384
 
 
 	leaq	40+192(%rsp),%rsi
 	movq	0(%rsp),%rcx
 	leaq	48(%rdi),%rdi
 	call	__mulx_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redx_tail_mont_384
 
 	leaq	328(%rsp),%r8
 	movq	0(%r8),%r15
@@ -304,6 +305,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sqr_mont_384x$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -335,13 +337,13 @@
 
 	leaq	48(%rsi),%rdx
 	leaq	32(%rsp),%rdi
-	call	__add_mod_384
+	call	__addx_mod_384
 
 
 	movq	24(%rsp),%rsi
 	leaq	48(%rsi),%rdx
 	leaq	32+48(%rsp),%rdi
-	call	__sub_mod_384
+	call	__subx_mod_384
 
 
 	movq	24(%rsp),%rsi
@@ -439,6 +441,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+mul_382x$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -533,18 +536,18 @@
 	leaq	32(%rsp),%rdx
 	movq	24(%rsp),%rcx
 	movq	%rsi,%rdi
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 
 	leaq	0(%rdi),%rsi
 	leaq	-96(%rdi),%rdx
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 
 	leaq	-96(%rdi),%rsi
 	leaq	32(%rsp),%rdx
 	leaq	-96(%rdi),%rdi
-	call	__sub_mod_384x384
+	call	__subx_mod_384x384
 
 	leaq	136(%rsp),%r8
 	movq	0(%r8),%r15
@@ -574,6 +577,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sqr_382x$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -629,7 +633,7 @@
 
 	leaq	48(%rsi),%rdx
 	leaq	48(%rdi),%rdi
-	call	__sub_mod_384_a_is_loaded
+	call	__subx_mod_384_a_is_loaded
 
 
 	leaq	(%rdi),%rsi
@@ -707,6 +711,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+mul_384$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -933,6 +938,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sqr_384$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1127,6 +1133,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+redc_mont_384$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1151,7 +1158,7 @@
 
 	movq	%rdx,%rbx
 	call	__mulx_by_1_mont_384
-	call	__redc_tail_mont_384
+	call	__redx_tail_mont_384
 
 	movq	8(%rsp),%r15
 .cfi_restore	%r15
@@ -1184,6 +1191,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+from_mont_384$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1450,7 +1458,7 @@
 
 
 .p2align	5
-__redc_tail_mont_384:
+__redx_tail_mont_384:
 .cfi_startproc
 	.byte	0xf3,0x0f,0x1e,0xfa
 
@@ -1506,6 +1514,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sgn0_pty_mont_384$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1584,6 +1593,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sgn0_pty_mont_384x$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -1711,6 +1721,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+mul_mont_384$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -2178,6 +2189,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sqr_mont_384$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -2245,6 +2257,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sqr_n_mul_mont_384$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -2330,6 +2343,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sqr_n_mul_mont_383$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
@@ -2776,6 +2790,7 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+sqr_mont_382x$1:
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
diff --git a/c-source/build/mach-o/sha256-armv8.S b/c-source/build/mach-o/sha256-armv8.S
--- a/c-source/build/mach-o/sha256-armv8.S
+++ b/c-source/build/mach-o/sha256-armv8.S
@@ -10,11 +10,12 @@
 //
 // sha256_block procedure for ARMv8.
 //
-// This module is stripped of scalar code paths, with raionale that all
+// This module is stripped of scalar code paths, with rationale that all
 // known processors are NEON-capable.
 //
 // See original module at CRYPTOGAMS for further details.
 
+.comm	___blst_platform_cap,4
 .text
 
 .align	6
@@ -184,6 +185,11 @@
 
 .align	4
 _blst_sha256_block_data_order:
+	adrp	x16,___blst_platform_cap@PAGE
+	ldr	w16,[x16,___blst_platform_cap@PAGEOFF]
+	tst	w16,#1
+	b.ne	Lv8_entry
+
 	stp	x29, x30, [sp, #-16]!
 	mov	x29, sp
 	sub	sp,sp,#16*4
diff --git a/c-source/build/mach-o/sha256-portable-x86_64.s b/c-source/build/mach-o/sha256-portable-x86_64.s
--- a/c-source/build/mach-o/sha256-portable-x86_64.s
+++ b/c-source/build/mach-o/sha256-portable-x86_64.s
@@ -1,3 +1,4 @@
+.comm	___blst_platform_cap,4
 .text	
 
 .globl	_blst_sha256_block_data_order
@@ -8,33 +9,35 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
-	pushq	%rbx
-.cfi_adjust_cfa_offset	8
-.cfi_offset	%rbx,-16
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
-.cfi_offset	%rbp,-24
+.cfi_offset	%rbp,-16
+	movq	%rsp,%rbp
+.cfi_def_cfa_register	%rbp
+#ifdef __BLST_PORTABLE__
+	testl	$2,___blst_platform_cap(%rip)
+	jnz	L$blst_sha256_block_data_order$2
+#endif
+	pushq	%rbx
+.cfi_offset	%rbx,-24
 	pushq	%r12
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%r12,-32
 	pushq	%r13
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%r13,-40
 	pushq	%r14
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%r14,-48
 	pushq	%r15
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%r15,-56
 	shlq	$4,%rdx
 	subq	$64+24,%rsp
-.cfi_adjust_cfa_offset	16*4+3*8
+
+.cfi_def_cfa	%rsp,144
+
 	leaq	(%rsi,%rdx,4),%rdx
 	movq	%rdi,64+0(%rsp)
 	movq	%rsi,64+8(%rsp)
 	movq	%rdx,64+16(%rsp)
 
-
 	movl	0(%rdi),%eax
 	movl	4(%rdi),%ebx
 	movl	8(%rdi),%ecx
@@ -1636,23 +1639,23 @@
 	leaq	64+24+48(%rsp),%r11
 .cfi_def_cfa	%r11,8
 	movq	64+24(%rsp),%r15
-.cfi_restore	%r15
 	movq	-40(%r11),%r14
-.cfi_restore	%r14
 	movq	-32(%r11),%r13
-.cfi_restore	%r13
 	movq	-24(%r11),%r12
+	movq	-16(%r11),%rbx
+	movq	-8(%r11),%rbp
 .cfi_restore	%r12
-	movq	-16(%r11),%rbp
+.cfi_restore	%r13
+.cfi_restore	%r14
+.cfi_restore	%r15
 .cfi_restore	%rbp
-	movq	-8(%r11),%rbx
 .cfi_restore	%rbx
-
 	leaq	(%r11),%rsp
 	.byte	0xf3,0xc3
 .cfi_endproc	
 
 
+#ifndef __BLST_PORTABLE__
 .p2align	6
 
 K256:
@@ -1744,3 +1747,4 @@
 	.byte	0xf3,0xc3
 .cfi_endproc
 
+#endif
diff --git a/c-source/build/mach-o/sha256-x86_64.s b/c-source/build/mach-o/sha256-x86_64.s
--- a/c-source/build/mach-o/sha256-x86_64.s
+++ b/c-source/build/mach-o/sha256-x86_64.s
@@ -1,3 +1,4 @@
+.comm	___blst_platform_cap,4
 .text	
 
 .p2align	6
@@ -33,6 +34,13 @@
 	.byte	0xf3,0x0f,0x1e,0xfa
 
 
+	pushq	%rbp
+.cfi_adjust_cfa_offset	8
+.cfi_offset	%rbp,-16
+	movq	%rsp,%rbp
+.cfi_def_cfa_register	%rbp
+L$blst_sha256_block_data_order$2:
+
 	leaq	K256+128(%rip),%rcx
 	movdqu	(%rdi),%xmm1
 	movdqu	16(%rdi),%xmm2
@@ -234,6 +242,11 @@
 
 	movdqu	%xmm1,(%rdi)
 	movdqu	%xmm2,16(%rdi)
+.cfi_def_cfa_register	%rsp
+	popq	%rbp
+.cfi_adjust_cfa_offset	-8
+.cfi_restore	%rbp
+
 	.byte	0xf3,0xc3
 .cfi_endproc	
 
@@ -249,30 +262,27 @@
 	pushq	%rbp
 .cfi_adjust_cfa_offset	8
 .cfi_offset	%rbp,-16
+	movq	%rsp,%rbp
+.cfi_def_cfa_register	%rbp
+	testl	$2,___blst_platform_cap(%rip)
+	jnz	L$blst_sha256_block_data_order$2
 	pushq	%rbx
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%rbx,-24
 	pushq	%r12
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%r12,-32
 	pushq	%r13
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%r13,-40
 	pushq	%r14
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%r14,-48
 	pushq	%r15
-.cfi_adjust_cfa_offset	8
 .cfi_offset	%r15,-56
 	shlq	$4,%rdx
-	subq	$40,%rsp
-.cfi_adjust_cfa_offset	40
+	subq	$24,%rsp
+
 	leaq	(%rsi,%rdx,4),%rdx
-	movq	%rdi,0(%rsp)
+	movq	%rdi,-64(%rbp)
 
-	movq	%rdx,16(%rsp)
-	movq	%rsp,%rbp
-.cfi_def_cfa_register	%rbp
+	movq	%rdx,-48(%rbp)
 
 
 	leaq	-64(%rsp),%rsp
@@ -291,7 +301,7 @@
 .p2align	4
 L$loop_ssse3:
 	movdqa	K256+256(%rip),%xmm7
-	movq	%rsi,8(%rbp)
+	movq	%rsi,-56(%rbp)
 	movdqu	0(%rsi),%xmm0
 	movdqu	16(%rsi),%xmm1
 	movdqu	32(%rsi),%xmm2
@@ -1316,9 +1326,9 @@
 	addl	%r15d,%eax
 	movl	%r8d,%r13d
 	addl	%eax,%r14d
-	movq	0(%rbp),%rdi
+	movq	-64(%rbp),%rdi
 	movl	%r14d,%eax
-	movq	8(%rbp),%rsi
+	movq	-56(%rbp),%rsi
 
 	addl	0(%rdi),%eax
 	addl	4(%rdi),%ebx
@@ -1330,7 +1340,7 @@
 	addl	28(%rdi),%r11d
 
 	leaq	64(%rsi),%rsi
-	cmpq	16(%rbp),%rsi
+	cmpq	-48(%rbp),%rsi
 
 	movl	%eax,0(%rdi)
 	movl	%ebx,4(%rdi)
@@ -1343,26 +1353,25 @@
 	jb	L$loop_ssse3
 
 	xorps	%xmm0,%xmm0
-	leaq	40+48(%rbp),%r11
-.cfi_def_cfa	%r11,8
 	movaps	%xmm0,0(%rsp)
 	movaps	%xmm0,16(%rsp)
 	movaps	%xmm0,32(%rsp)
 	movaps	%xmm0,48(%rsp)
-	movq	40(%rbp),%r15
-.cfi_restore	%r15
-	movq	-40(%r11),%r14
-.cfi_restore	%r14
-	movq	-32(%r11),%r13
-.cfi_restore	%r13
-	movq	-24(%r11),%r12
+	movq	-40(%rbp),%r15
+	movq	-32(%rbp),%r14
+	movq	-24(%rbp),%r13
+	movq	-16(%rbp),%r12
+	movq	-8(%rbp),%rbx
+	movq	%rbp,%rsp
+.cfi_def_cfa_register	%rsp
+	popq	%rbp
+.cfi_adjust_cfa_offset	-8
+.cfi_restore	%rbp
 .cfi_restore	%r12
-	movq	-16(%r11),%rbx
+.cfi_restore	%r13
+.cfi_restore	%r14
+.cfi_restore	%r15
 .cfi_restore	%rbx
-	movq	-8(%r11),%rbp
-.cfi_restore	%rbp
-
-	leaq	(%r11),%rsp
 	.byte	0xf3,0xc3
 .cfi_endproc	
 
diff --git a/c-source/src/aggregate.c b/c-source/src/aggregate.c
--- a/c-source/src/aggregate.c
+++ b/c-source/src/aggregate.c
@@ -90,7 +90,7 @@
 
 /*
  * Optional |nbits|-wide |scalar| is used to facilitate multiple aggregated
- * signature vetification as discussed at
+ * signature verification as discussed at
  * https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407.
  * Usage pattern is not finalized yet, because (sig != NULL) is better and
  * will be handled separately...
diff --git a/c-source/src/bulk_addition.c b/c-source/src/bulk_addition.c
--- a/c-source/src/bulk_addition.c
+++ b/c-source/src/bulk_addition.c
@@ -145,8 +145,7 @@
 void prefix##s_add(ptype *sum, const ptype##_affine *const points[], \
                                size_t npoints) \
 { \
-    /* Performance with 288K scratch is within 1-2-3% from optimal */ \
-    const size_t stride = sizeof(ptype)==sizeof(POINTonE1) ? 2048 : 1024; \
+    const size_t stride = SCRATCH_LIMIT / sizeof(ptype); \
     ptype *scratch = alloca((npoints > stride ? stride : npoints) * \
                             sizeof(ptype)); \
     const ptype##_affine *point = NULL; \
@@ -162,6 +161,15 @@
         npoints -= j; \
     } \
 }
+
+#ifndef SCRATCH_LIMIT
+# ifdef __wasm__
+#  define SCRATCH_LIMIT (45 * 1024)
+# else
+   /* Performance with 144K scratch is within 1-2-3% from optimal */
+#  define SCRATCH_LIMIT (144 * 1024)
+# endif
+#endif
 
 ADDITION_BTREE(blst_p1, POINTonE1, 384, fp, BLS12_381_Rx.p2)
 
diff --git a/c-source/src/bytes.h b/c-source/src/bytes.h
--- a/c-source/src/bytes.h
+++ b/c-source/src/bytes.h
@@ -26,7 +26,7 @@
          * 'if (n % sizeof(limb_t) == 0)' is omitted because it's cheaper
          * to perform redundant stores than to pay penalty for
          * mispredicted branch. Besides, some compilers unroll the
-         * loop and remove redundant stores to 'restict'-ed storage...
+         * loop and remove redundant stores to 'restrict'-ed storage...
          */
         ret[n / sizeof(limb_t)] = limb;
     }
@@ -55,7 +55,7 @@
          * 'if (n % sizeof(limb_t) == 0)' is omitted because it's cheaper
          * to perform redundant stores than to pay penalty for
          * mispredicted branch. Besides, some compilers unroll the
-         * loop and remove redundant stores to 'restict'-ed storage...
+         * loop and remove redundant stores to 'restrict'-ed storage...
          */
         ret[n / sizeof(limb_t)] = limb;
     }
diff --git a/c-source/src/cpuid.c b/c-source/src/cpuid.c
new file mode 100644
--- /dev/null
+++ b/c-source/src/cpuid.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright Supranational LLC
+ * Licensed under the Apache License, Version 2.0, see LICENSE for details.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#if (defined(__GNUC__) || defined(__clang__) || defined(__SUNPRO_C)) && !defined(_WIN32)
+__attribute__((visibility("hidden")))
+#endif
+int __blst_platform_cap = 0;
+
+#if defined(__x86_64__) || defined(__x86_64) || defined(_M_X64)
+
+# if defined(__GNUC__) || defined(__clang__) || defined(__SUNPRO_C)
+static void __cpuidex(int info[4], int func, int sub)
+{
+    int eax, ebx, ecx, edx;
+
+    __asm__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
+                    : "a"(func), "c"(sub));
+
+    info[0] = eax;
+    info[1] = ebx;
+    info[2] = ecx;
+    info[3] = edx;
+}
+# else
+#  include <intrin.h>
+# endif
+
+# if defined(__GNUC__) || defined(__clang__)
+__attribute__((constructor))
+# endif
+static int __blst_cpuid(void)
+{
+    int info[4], cap = 0;
+
+    __cpuidex(info, 0, 0);
+    if (info[0] > 6) {
+        __cpuidex(info, 7, 0);
+        cap |= (info[1]>>19) & 1; /* ADX */
+        cap |= (info[1]>>28) & 2; /* SHA */
+    }
+
+    __blst_platform_cap = cap;
+
+    return 0;
+}
+
+# if defined(_MSC_VER) && !defined(__clang__)
+#  pragma section(".CRT$XCU",read)
+__declspec(allocate(".CRT$XCU")) static int (*p)(void) = __blst_cpuid;
+# elif defined(__SUNPRO_C)
+#  pragma init(__blst_cpuid)
+# endif
+
+#elif defined(__aarch64__) || defined(__aarch64)
+
+# if defined(__linux__) && (defined(__GNUC__) || defined(__clang__))
+extern unsigned long getauxval(unsigned long type) __attribute__ ((weak));
+
+__attribute__((constructor))
+static int __blst_cpuid(void)
+{
+    int cap = 0;
+
+    if (getauxval) {
+        unsigned long hwcap_ce = getauxval(16);
+        cap = (hwcap_ce>>6) & 1; /* SHA256 */
+    }
+
+    __blst_platform_cap = cap;
+
+    return 0;
+}
+# elif defined(__APPLE__) && (defined(__GNUC__) || defined(__clang__))
+__attribute__((constructor))
+static int __blst_cpuid()
+{
+    __blst_platform_cap = 1; /* SHA256 */
+    return 0;
+}
+# endif
+
+#endif
diff --git a/c-source/src/e1.c b/c-source/src/e1.c
--- a/c-source/src/e1.c
+++ b/c-source/src/e1.c
@@ -155,7 +155,7 @@
 {
     if (vec_is_zero(in->X, 2*sizeof(in->X))) {
         bytes_zero(out, 96);
-        out[0] = 0x40;    /* infinitiy bit */
+        out[0] = 0x40;    /* infinity bit */
     } else {
         (void)POINTonE1_affine_Serialize_BE(out, in);
     }
@@ -178,7 +178,7 @@
 {
     if (vec_is_zero(in->Z, sizeof(in->Z))) {
         bytes_zero(out, 96);
-        out[0] = 0x40;    /* infinitiy bit */
+        out[0] = 0x40;    /* infinity bit */
     } else {
         (void)POINTonE1_Serialize_BE(out, in);
     }
@@ -202,7 +202,7 @@
 {
     if (vec_is_zero(in->X, 2*sizeof(in->X))) {
         bytes_zero(out, 48);
-        out[0] = 0xc0;    /* compressed and infinitiy bits */
+        out[0] = 0xc0;    /* compressed and infinity bits */
     } else {
         limb_t sign = POINTonE1_affine_Compress_BE(out, in);
         out[0] |= (unsigned char)(0x80 | ((sign & 2) << 4));
@@ -226,7 +226,7 @@
 {
     if (vec_is_zero(in->Z, sizeof(in->Z))) {
         bytes_zero(out, 48);
-        out[0] = 0xc0;    /* compressed and infinitiy bits */
+        out[0] = 0xc0;    /* compressed and infinity bits */
     } else {
         limb_t sign = POINTonE1_Compress_BE(out, in);
         out[0] |= (unsigned char)(0x80 | ((sign & 2) << 4));
diff --git a/c-source/src/e2.c b/c-source/src/e2.c
--- a/c-source/src/e2.c
+++ b/c-source/src/e2.c
@@ -196,7 +196,7 @@
 {
     if (vec_is_zero(in->X, 2*sizeof(in->X))) {
         bytes_zero(out, 192);
-        out[0] = 0x40;    /* infinitiy bit */
+        out[0] = 0x40;    /* infinity bit */
     } else {
         (void)POINTonE2_affine_Serialize_BE(out, in);
     }
@@ -219,7 +219,7 @@
 {
     if (vec_is_zero(in->Z, sizeof(in->Z))) {
         bytes_zero(out, 192);
-        out[0] = 0x40;    /* infinitiy bit */
+        out[0] = 0x40;    /* infinity bit */
     } else {
         (void)POINTonE2_Serialize_BE(out, in);
     }
@@ -245,7 +245,7 @@
 {
     if (vec_is_zero(in->X, 2*sizeof(in->X))) {
         bytes_zero(out, 96);
-        out[0] = 0xc0;    /* compressed and infinitiy bits */
+        out[0] = 0xc0;    /* compressed and infinity bits */
     } else {
         limb_t sign = POINTonE2_affine_Compress_BE(out, in);
         out[0] |= (unsigned char)(0x80 | ((sign & 2) << 4));
@@ -269,7 +269,7 @@
 {
     if (vec_is_zero(in->Z, sizeof(in->Z))) {
         bytes_zero(out, 96);
-        out[0] = 0xc0;    /* compressed and infinitiy bits */
+        out[0] = 0xc0;    /* compressed and infinity bits */
     } else {
         limb_t sign = POINTonE2_Compress_BE(out, in);
         out[0] |= (unsigned char)(0x80 | ((sign & 2) << 4));
diff --git a/c-source/src/ec_mult.h b/c-source/src/ec_mult.h
--- a/c-source/src/ec_mult.h
+++ b/c-source/src/ec_mult.h
@@ -46,9 +46,10 @@
 static limb_t booth_encode(limb_t wval, size_t sz)
 {
     limb_t mask = 0 - (wval >> sz);     /* "sign" bit -> mask */
+    launder(mask);
 
     wval = (wval + 1) >> 1;
-    wval = (wval & ~mask) | ((0-wval) & mask);
+    wval = (wval ^ mask) - mask;
 
     /* &0x1f, but <=0x10, is index in table, rest is extended "sign" bit */
     return wval;
@@ -61,7 +62,7 @@
  * pass order's bit-length, which is customarily publicly known, instead
  * of the factual scalars' bit-lengths. This is facilitated by point
  * addition subroutines implemented to handle points at infinity, which
- * are encoded as Z==0. [Doubling agorithms handle such points at
+ * are encoded as Z==0. [Doubling algorithms handle such points at
  * infinity "naturally," since resulting Z is product of original Z.]
  */
 #define POINT_MULT_SCALAR_WX_IMPL(ptype, SZ) \
diff --git a/c-source/src/exports.c b/c-source/src/exports.c
--- a/c-source/src/exports.c
+++ b/c-source/src/exports.c
@@ -19,7 +19,7 @@
 #include "bytes.h"
 
 /*
- * BLS12-381-specifc Fr shortcuts to assembly.
+ * BLS12-381-specific Fr shortcuts to assembly.
  */
 void blst_fr_add(vec256 ret, const vec256 a, const vec256 b)
 {   add_mod_256(ret, a, b, BLS12_381_r);   }
@@ -39,6 +39,24 @@
 void blst_fr_mul(vec256 ret, const vec256 a, const vec256 b)
 {   mul_mont_sparse_256(ret, a, b, BLS12_381_r, r0);   }
 
+void blst_fr_ct_bfly(vec256 x0, vec256 x1, const vec256 twiddle)
+{
+    vec256 x2;
+
+    mul_mont_sparse_256(x2, x1, twiddle, BLS12_381_r, r0);
+    sub_mod_256(x1, x0, x2, BLS12_381_r);
+    add_mod_256(x0, x0, x2, BLS12_381_r);
+}
+
+void blst_fr_gs_bfly(vec256 x0, vec256 x1, const vec256 twiddle)
+{
+    vec256 x2;
+
+    sub_mod_256(x2, x0, x1, BLS12_381_r);
+    add_mod_256(x0, x0, x1, BLS12_381_r);
+    mul_mont_sparse_256(x1, x2, twiddle, BLS12_381_r, r0);
+}
+
 void blst_fr_sqr(vec256 ret, const vec256 a)
 {   sqr_mont_sparse_256(ret, a, BLS12_381_r, r0);   }
 
@@ -102,27 +120,26 @@
 
 int blst_sk_mul_n_check(pow256 ret, const pow256 a, const pow256 b)
 {
-    vec256 a_fr, b_fr;
+    vec256 t[2];
     const union {
         long one;
         char little;
     } is_endian = { 1 };
+    bool_t is_zero;
 
     if (((size_t)a|(size_t)b)%sizeof(limb_t) != 0 || !is_endian.little) {
-        limbs_from_le_bytes(a_fr, a, sizeof(a_fr));
-        limbs_from_le_bytes(b_fr, b, sizeof(a_fr));
-        a = (const byte *)a_fr;
-        b = (const byte *)b_fr;
+        limbs_from_le_bytes(t[0], a, sizeof(pow256));
+        limbs_from_le_bytes(t[1], b, sizeof(pow256));
+        a = (const byte *)t[0];
+        b = (const byte *)t[1];
     }
-    mul_mont_sparse_256(a_fr, (const limb_t *)a, BLS12_381_rRR,
-                                                 BLS12_381_r, r0);
-    mul_mont_sparse_256(b_fr, (const limb_t *)b, BLS12_381_rRR,
-                                                 BLS12_381_r, r0);
-    mul_mont_sparse_256(a_fr, a_fr, b_fr, BLS12_381_r, r0);
-    from_mont_256(a_fr, a_fr, BLS12_381_r, r0);
-    le_bytes_from_limbs(ret, a_fr, sizeof(a_fr));
+    mul_mont_sparse_256(t[0], BLS12_381_rRR, (const limb_t *)a, BLS12_381_r, r0);
+    mul_mont_sparse_256(t[0], t[0], (const limb_t *)b, BLS12_381_r, r0);
+    le_bytes_from_limbs(ret, t[0], sizeof(pow256));
+    is_zero = vec_is_zero(t[0], sizeof(vec256));
+    vec_zero(t, sizeof(t));
 
-    return (int)(vec_is_zero(a_fr, sizeof(a_fr)) ^ 1);
+    return (int)(is_zero^1);
 }
 
 void blst_sk_inverse(pow256 ret, const pow256 a)
@@ -150,7 +167,7 @@
 }
 
 /*
- * BLS12-381-specifc Fp shortcuts to assembly.
+ * BLS12-381-specific Fp shortcuts to assembly.
  */
 void blst_fp_add(vec384 ret, const vec384 a, const vec384 b)
 {   add_fp(ret, a, b);   }
@@ -284,7 +301,7 @@
 }
 
 /*
- * BLS12-381-specifc Fp2 shortcuts to assembly.
+ * BLS12-381-specific Fp2 shortcuts to assembly.
  */
 void blst_fp2_add(vec384x ret, const vec384x a, const vec384x b)
 {   add_fp2(ret, a, b);   }
@@ -311,7 +328,7 @@
 {   cneg_fp2(ret, a, is_zero(flag) ^ 1);   }
 
 /*
- * Scalar serialization/deseriazation
+ * Scalar serialization/deserialization.
  */
 void blst_scalar_from_uint32(pow256 ret, const unsigned int a[8])
 {
@@ -480,68 +497,75 @@
 
 int blst_scalar_from_le_bytes(pow256 out, const unsigned char *bytes, size_t n)
 {
-    struct { vec256 out, digit, radix; } t;
+    size_t rem = (n - 1) % 32 + 1;
+    struct { vec256 out, digit; } t;
     limb_t ret;
 
     vec_zero(t.out, sizeof(t.out));
-    vec_copy(t.radix, BLS12_381_rRR, sizeof(t.radix));
 
-    while (n > 32) {
-        limbs_from_le_bytes(t.digit, bytes, 32);
-        from_mont_256(t.digit, t.digit, BLS12_381_r, r0);
-        mul_mont_sparse_256(t.digit, t.digit, t.radix, BLS12_381_r, r0);
+    n -= rem;
+    limbs_from_le_bytes(t.out, bytes += n, rem);
+    mul_mont_sparse_256(t.out, BLS12_381_rRR, t.out, BLS12_381_r, r0);
+
+    while (n) {
+        limbs_from_le_bytes(t.digit, bytes -= 32, 32);
         add_mod_256(t.out, t.out, t.digit, BLS12_381_r);
-        mul_mont_sparse_256(t.radix, t.radix, BLS12_381_rRR, BLS12_381_r, r0);
-        bytes += 32;
+        mul_mont_sparse_256(t.out, BLS12_381_rRR, t.out, BLS12_381_r, r0);
         n -= 32;
     }
 
-    vec_zero(t.digit, sizeof(t.digit));
-    limbs_from_le_bytes(t.digit, bytes, n);
-    from_mont_256(t.digit, t.digit, BLS12_381_r, r0);
-    mul_mont_sparse_256(t.digit, t.digit, t.radix, BLS12_381_r, r0);
-    add_mod_256(t.out, t.out, t.digit, BLS12_381_r);
+    from_mont_256(t.out, t.out, BLS12_381_r, r0);
 
     ret = vec_is_zero(t.out, sizeof(t.out));
     le_bytes_from_limbs(out, t.out, 32);
-    vec_zero(t.out, 2*sizeof(t.out));
+    vec_zero(&t, sizeof(t));
 
     return (int)(ret^1);
 }
 
 int blst_scalar_from_be_bytes(pow256 out, const unsigned char *bytes, size_t n)
 {
-    struct { vec256 out, digit, radix; } t;
+    size_t rem = (n - 1) % 32 + 1;
+    struct { vec256 out, digit; } t;
     limb_t ret;
 
     vec_zero(t.out, sizeof(t.out));
-    vec_copy(t.radix, BLS12_381_rRR, sizeof(t.radix));
 
-    bytes += n;
-    while (n > 32) {
-        limbs_from_be_bytes(t.digit, bytes -= 32, 32);
-        from_mont_256(t.digit, t.digit, BLS12_381_r, r0);
-        mul_mont_sparse_256(t.digit, t.digit, t.radix, BLS12_381_r, r0);
+    limbs_from_be_bytes(t.out, bytes, rem);
+    mul_mont_sparse_256(t.out, BLS12_381_rRR, t.out, BLS12_381_r, r0);
+
+    while (n -= rem) {
+        limbs_from_be_bytes(t.digit, bytes += rem, 32);
         add_mod_256(t.out, t.out, t.digit, BLS12_381_r);
-        mul_mont_sparse_256(t.radix, t.radix, BLS12_381_rRR, BLS12_381_r, r0);
-        n -= 32;
+        mul_mont_sparse_256(t.out, BLS12_381_rRR, t.out, BLS12_381_r, r0);
+        rem = 32;
     }
 
-    vec_zero(t.digit, sizeof(t.digit));
-    limbs_from_be_bytes(t.digit, bytes -= n, n);
-    from_mont_256(t.digit, t.digit, BLS12_381_r, r0);
-    mul_mont_sparse_256(t.digit, t.digit, t.radix, BLS12_381_r, r0);
-    add_mod_256(t.out, t.out, t.digit, BLS12_381_r);
+    from_mont_256(t.out, t.out, BLS12_381_r, r0);
 
     ret = vec_is_zero(t.out, sizeof(t.out));
     le_bytes_from_limbs(out, t.out, 32);
-    vec_zero(t.out, 2*sizeof(t.out));
+    vec_zero(&t, sizeof(t));
 
     return (int)(ret^1);
 }
 
 /*
- * Test facilitator
+ * Single-short SHA-256 hash function.
+ */
+#include "sha256.h"
+
+void blst_sha256(unsigned char md[32], const void *msg, size_t len)
+{
+    SHA256_CTX ctx;
+
+    sha256_init(&ctx);
+    sha256_update(&ctx, msg, len);
+    sha256_final(md, &ctx);
+}
+
+/*
+ * Test facilitator.
  */
 void blst_scalar_from_hexascii(pow256 ret, const char *hex)
 {   bytes_from_hexascii(ret, sizeof(pow256), hex);   }
diff --git a/c-source/src/fields.h b/c-source/src/fields.h
--- a/c-source/src/fields.h
+++ b/c-source/src/fields.h
@@ -10,7 +10,7 @@
 #include "consts.h"
 
 /*
- * BLS12-381-specifc Fp shortcuts to assembly.
+ * BLS12-381-specific Fp shortcuts to assembly.
  */
 static inline void add_fp(vec384 ret, const vec384 a, const vec384 b)
 {   add_mod_384(ret, a, b, BLS12_381_P);   }
@@ -49,7 +49,7 @@
 {   redc_mont_384(ret, a, BLS12_381_P, p0);   }
 
 /*
- * BLS12-381-specifc Fp2 shortcuts to assembly.
+ * BLS12-381-specific Fp2 shortcuts to assembly.
  */
 static inline void add_fp2(vec384x ret, const vec384x a, const vec384x b)
 {   add_mod_384x(ret, a, b, BLS12_381_P);   }
diff --git a/c-source/src/fp12_tower.c b/c-source/src/fp12_tower.c
--- a/c-source/src/fp12_tower.c
+++ b/c-source/src/fp12_tower.c
@@ -545,7 +545,7 @@
     mul_by_u_plus_1_fp2(c1, c1);
     mul_fp2(t0, a[0], a[1]);
     sub_fp2(c1, c1, t0);
- 
+
     /* c2 = a1^2 - a0*a2 */
     sqr_fp2(c2, a[1]);
     mul_fp2(t0, a[0], a[2]);
@@ -733,7 +733,7 @@
 
 
 /*
- * BLS12-381-specifc Fp12 shortcuts.
+ * BLS12-381-specific Fp12 shortcuts.
  */
 void blst_fp12_sqr(vec384fp12 ret, const vec384fp12 a)
 {   sqr_fp12(ret, a);   }
diff --git a/c-source/src/multi_scalar.c b/c-source/src/multi_scalar.c
--- a/c-source/src/multi_scalar.c
+++ b/c-source/src/multi_scalar.c
@@ -399,7 +399,20 @@
                               size_t npoints, \
                               const byte *const scalars[], size_t nbits, \
                               ptype##xyzz scratch[]) \
-{ ptype##s_mult_pippenger(ret, points, npoints, scalars, nbits, scratch, 0); }
+{ \
+    if (npoints == 1) { \
+        prefix##_from_affine(ret, points[0]); \
+        prefix##_mult(ret, ret, scalars[0], nbits); \
+        return; \
+    } \
+    if ((npoints * sizeof(ptype##_affine) * 8 * 3) <= SCRATCH_LIMIT) { \
+        ptype##_affine *table = alloca(npoints * sizeof(ptype##_affine) * 8); \
+        ptype##s_precompute_wbits(table, 4, points, npoints); \
+        ptype##s_mult_wbits(ret, table, 4, npoints, scalars, nbits, NULL); \
+        return; \
+    } \
+    ptype##s_mult_pippenger(ret, points, npoints, scalars, nbits, scratch, 0); \
+}
 
 DECLARE_PRIVATE_POINTXYZZ(POINTonE1, 384)
 POINTXYZZ_TO_JACOBIAN_IMPL(POINTonE1, 384, fp)
diff --git a/c-source/src/no_asm.h b/c-source/src/no_asm.h
--- a/c-source/src/no_asm.h
+++ b/c-source/src/no_asm.h
@@ -16,9 +16,20 @@
 # pragma GCC diagnostic ignored "-Wstatic-in-inline"
 #endif
 
+#if !defined(__clang__) && !defined(__builtin_assume)
+# if defined(__GNUC__) && __GNUC__>=5
+#  define __builtin_assume(condition) if (!(condition)) __builtin_unreachable()
+# elif defined(_MSC_VER)
+#  define __builtin_assume(condition) __assume(condition)
+# else
+#  define __builtin_assume(condition) (void)(condition)
+# endif
+#endif
+
 static void mul_mont_n(limb_t ret[], const limb_t a[], const limb_t b[],
                        const limb_t p[], limb_t n0, size_t n)
 {
+    __builtin_assume(n != 0 && n%2 == 0);
     llimb_t limbx;
     limb_t mask, borrow, mx, hi, tmp[n+1], carry;
     size_t i, j;
@@ -64,6 +75,7 @@
     }
 
     mask = carry - borrow;
+    launder(mask);
 
     for(i=0; i<n; i++)
         ret[i] = (ret[i] & ~mask) | (tmp[i] & mask);
@@ -92,6 +104,7 @@
 static void add_mod_n(limb_t ret[], const limb_t a[], const limb_t b[],
                       const limb_t p[], size_t n)
 {
+    __builtin_assume(n != 0);
     llimb_t limbx;
     limb_t mask, carry, borrow, tmp[n];
     size_t i;
@@ -109,6 +122,7 @@
     }
 
     mask = carry - borrow;
+    launder(mask);
 
     for(i=0; i<n; i++)
         ret[i] = (ret[i] & ~mask) | (tmp[i] & mask);
@@ -125,6 +139,7 @@
 static void sub_mod_n(limb_t ret[], const limb_t a[], const limb_t b[],
                       const limb_t p[], size_t n)
 {
+    __builtin_assume(n != 0);
     llimb_t limbx;
     limb_t mask, carry, borrow;
     size_t i;
@@ -136,6 +151,7 @@
     }
 
     mask = 0 - borrow;
+    launder(mask);
 
     for (carry=0, i=0; i<n; i++) {
         limbx = ret[i] + ((p[i] & mask) + (llimb_t)carry);
@@ -155,6 +171,7 @@
 static void mul_by_3_mod_n(limb_t ret[], const limb_t a[], const limb_t p[],
                            size_t n)
 {
+    __builtin_assume(n != 0);
     llimb_t limbx;
     limb_t mask, carry, borrow, tmp[n], two_a[n];
     size_t i;
@@ -172,6 +189,7 @@
     }
 
     mask = carry - borrow;
+    launder(mask);
 
     for(i=0; i<n; i++)
         two_a[i] = (two_a[i] & ~mask) | (tmp[i] & mask);
@@ -189,6 +207,7 @@
     }
 
     mask = carry - borrow;
+    launder(mask);
 
     for(i=0; i<n; i++)
         ret[i] = (ret[i] & ~mask) | (tmp[i] & mask);
@@ -205,6 +224,8 @@
 static void lshift_mod_n(limb_t ret[], const limb_t a[], size_t count,
                          const limb_t p[], size_t n)
 {
+    __builtin_assume(count != 0);
+    __builtin_assume(n != 0);
     llimb_t limbx;
     limb_t mask, carry, borrow, tmp[n];
     size_t i;
@@ -223,6 +244,7 @@
         }
 
         mask = carry - borrow;
+        launder(mask);
 
         for(i=0; i<n; i++)
             ret[i] = (ret[i] & ~mask) | (tmp[i] & mask);
@@ -242,6 +264,7 @@
 static void cneg_mod_n(limb_t ret[], const limb_t a[], bool_t flag,
                        const limb_t p[], size_t n)
 {
+    __builtin_assume(n != 0);
     llimb_t limbx;
     limb_t borrow, mask, tmp[n];
     size_t i;
@@ -269,6 +292,7 @@
 
 static limb_t check_mod_n(const byte a[], const limb_t p[], size_t n)
 {
+    __builtin_assume(n != 0);
     llimb_t limbx;
     limb_t borrow, ai, acc;
     size_t i, j;
@@ -293,6 +317,7 @@
 static limb_t add_n_check_mod_n(byte ret[], const byte a[], const byte b[],
                                             const limb_t p[], size_t n)
 {
+    __builtin_assume(n != 0);
     limb_t ret_[n], a_[n], b_[n], zero;
 
     limbs_from_le_bytes(a_, a, sizeof(a_));
@@ -316,6 +341,7 @@
 static limb_t sub_n_check_mod_n(byte ret[], const byte a[], const byte b[],
                                             const limb_t p[], size_t n)
 {
+    __builtin_assume(n != 0);
     limb_t ret_[n], a_[n], b_[n], zero;
 
     limbs_from_le_bytes(a_, a, sizeof(a_));
@@ -339,6 +365,7 @@
 static void from_mont_n(limb_t ret[], const limb_t a[],
                         const limb_t p[], limb_t n0, size_t n)
 {
+    __builtin_assume(n != 0 && n%2 == 0);
     llimb_t limbx;
     limb_t mask, borrow, mx, hi, tmp[n];
     size_t i, j;
@@ -364,6 +391,7 @@
     }
 
     mask = 0 - borrow;
+    launder(mask);
 
     for(i=0; i<n; i++)
         ret[i] = (ret[i] & ~mask) | (tmp[i] & mask);
@@ -380,6 +408,7 @@
 static void redc_mont_n(limb_t ret[], const limb_t a[],
                         const limb_t p[], limb_t n0, size_t n)
 {
+    __builtin_assume(n != 0 && n%2 == 0);
     llimb_t limbx;
     limb_t mask, carry, borrow, mx, hi, tmp[n];
     const limb_t *b = a;
@@ -411,6 +440,7 @@
     }
 
     mask = carry - borrow;
+    launder(mask);
 
     for(i=0; i<n; i++)
         ret[i] = (ret[i] & ~mask) | (tmp[i] & mask);
@@ -427,12 +457,15 @@
 static void rshift_mod_n(limb_t ret[], const limb_t a[], size_t count,
                          const limb_t p[], size_t n)
 {
+    __builtin_assume(count != 0);
+    __builtin_assume(n != 0 && n%2 == 0);
     llimb_t limbx;
     limb_t mask, carry, limb, next;
     size_t i;
 
     while (count--) {
         mask = 0 - (a[0] & 1);
+        launder(mask);
         for (carry=0, i=0; i<n; i++) {
             limbx = a[i] + ((p[i]&mask) + (llimb_t)carry);
             ret[i] = (limb_t)limbx;
@@ -467,6 +500,7 @@
 
 static limb_t sgn0_pty_mod_n(const limb_t a[], const limb_t p[], size_t n)
 {
+    __builtin_assume(n != 0);
     llimb_t limbx;
     limb_t carry, borrow, ret, tmp[n];
     size_t i;
@@ -552,6 +586,7 @@
 static void mul_mont_nonred_n(limb_t ret[], const limb_t a[], const limb_t b[],
                               const limb_t p[], limb_t n0, size_t n)
 {
+    __builtin_assume(n != 0 && n%2 == 0);
     llimb_t limbx;
     limb_t mx, hi, tmp[n+1];
     size_t i, j;
@@ -592,6 +627,7 @@
 void sqr_n_mul_mont_383(vec384 ret, const vec384 a, size_t count,
                         const vec384 p, limb_t n0, const vec384 b)
 {
+    __builtin_assume(count != 0);
     while(count--) {
         mul_mont_nonred_n(ret, a, a, p, n0, NLIMBS(384));
         a = ret;
@@ -621,6 +657,7 @@
         borrow = (limb_t)(limbx >> LIMB_T_BITS) & 1;
     }
     mask = 0 - borrow;
+    launder(mask);
 
     /* "mul_mont_n(ret[1], a[0], a[1], p, n0, NLIMBS(384));" */
     mul_mont_nonred_n(ret[1], a[0], a[1], p, n0, NLIMBS(384));
@@ -642,6 +679,7 @@
         borrow = (limb_t)(limbx >> LIMB_T_BITS) & 1;
     }
     mask = 0 - borrow;
+    launder(mask);
     for (carry=0, i=0; i<NLIMBS(384); i++) {
         limbx = ret[0][i] + ((p[i] & mask) + (llimb_t)carry);
         ret[0][i] = (limb_t)limbx;
@@ -649,7 +687,11 @@
     }
 }
 
-#define MSB(x) ((x) >> (LIMB_T_BITS-1))
+#if defined(__GNUC__) || defined(__clang__)
+# define MSB(x) ({ limb_t ret = (x) >> (LIMB_T_BITS-1); launder(ret); ret; })
+#else
+# define MSB(x) ((x) >> (LIMB_T_BITS-1))
+#endif
 
 static size_t num_bits(limb_t l)
 {
@@ -704,6 +746,7 @@
 static void ab_approximation_n(limb_t a_[2], const limb_t a[],
                                limb_t b_[2], const limb_t b[], size_t n)
 {
+    __builtin_assume(n != 0 && n%2 == 0);
     limb_t a_hi, a_lo, b_hi, b_lo, mask;
     size_t i;
 
@@ -729,6 +772,7 @@
 static void inner_loop_n(factors *fg, const limb_t a_[2], const limb_t b_[2],
                          size_t n)
 {
+    __builtin_assume(n != 0);
     llimb_t limbx;
     limb_t f0 = 1, g0 = 0, f1 = 0, g1 = 1;
     limb_t a_lo, a_hi, b_lo, b_hi, t_lo, t_hi, odd, borrow, xorm;
@@ -784,6 +828,7 @@
 
 static limb_t cneg_n(limb_t ret[], const limb_t a[], limb_t neg, size_t n)
 {
+    __builtin_assume(n != 0);
     llimb_t limbx = 0;
     limb_t carry;
     size_t i;
@@ -799,6 +844,7 @@
 
 static limb_t add_n(limb_t ret[], const limb_t a[], limb_t b[], size_t n)
 {
+    __builtin_assume(n != 0);
     llimb_t limbx;
     limb_t carry;
     size_t i;
@@ -814,6 +860,7 @@
 
 static limb_t umul_n(limb_t ret[], const limb_t a[], limb_t b, size_t n)
 {
+    __builtin_assume(n != 0);
     llimb_t limbx;
     limb_t hi;
     size_t i;
@@ -831,6 +878,7 @@
                                            const limb_t b[], limb_t *g_,
                                            size_t n)
 {
+    __builtin_assume(n != 0);
     limb_t a_[n+1], b_[n+1], f, g, neg, carry, hi;
     size_t i;
 
@@ -872,6 +920,7 @@
 static limb_t smul_2n(limb_t ret[], const limb_t u[], limb_t f,
                                     const limb_t v[], limb_t g, size_t n)
 {
+    __builtin_assume(n != 0);
     limb_t u_[n], v_[n], neg, hi;
 
     /* |u|*|f_| */
@@ -895,6 +944,7 @@
 static void ct_inverse_mod_n(limb_t ret[], const limb_t inp[],
                              const limb_t mod[], const limb_t modx[], size_t n)
 {
+    __builtin_assume(n != 0 && n%2 == 0);
     llimb_t limbx;
     limb_t a[n], b[n], u[2*n], v[2*n], t[2*n];
     limb_t a_[2], b_[2], sign, carry, top;
@@ -935,13 +985,13 @@
     add_n(ret+n, ret+n, a, n);
 }
 
-#define CT_INVERSE_MOD_IMPL(bits) \
-inline void ct_inverse_mod_##bits(vec##bits ret, const vec##bits inp, \
+#define CT_INVERSE_MOD_IMPL(bits, bits2) \
+inline void ct_inverse_mod_##bits(vec##bits2 ret, const vec##bits inp, \
                                   const vec##bits mod, const vec##bits modx) \
 {   ct_inverse_mod_n(ret, inp, mod, modx, NLIMBS(bits));   }
 
-CT_INVERSE_MOD_IMPL(256)
-CT_INVERSE_MOD_IMPL(384)
+CT_INVERSE_MOD_IMPL(256, 512)
+CT_INVERSE_MOD_IMPL(384, 768)
 
 /*
  * Copy of inner_loop_n above, but with |L| updates.
@@ -949,6 +999,7 @@
 static limb_t legendre_loop_n(limb_t L, factors *fg, const limb_t a_[2],
                               const limb_t b_[2], size_t n)
 {
+    __builtin_assume(n != 0);
     llimb_t limbx;
     limb_t f0 = 1, g0 = 0, f1 = 0, g1 = 1;
     limb_t a_lo, a_hi, b_lo, b_hi, t_lo, t_hi, odd, borrow, xorm;
@@ -1010,6 +1061,7 @@
 
 static bool_t ct_is_sqr_mod_n(const limb_t inp[], const limb_t mod[], size_t n)
 {
+    __builtin_assume(n != 0 && n%2 == 0);
     limb_t a[n], b[n], t[n];
     limb_t a_[2], b_[2], neg, L = 0;
     factors fg;
@@ -1103,6 +1155,7 @@
 static limb_t quot_rem_n(limb_t *div_rem, const limb_t *divisor,
                                           limb_t quotient, size_t n)
 {
+    __builtin_assume(n != 0 && n%2 == 0);
     llimb_t limbx;
     limb_t tmp[n+1], carry, mask, borrow;
     size_t i;
@@ -1123,6 +1176,7 @@
     }
 
     mask = 0 - borrow;
+    launder(mask);
 
     /* if quotient was off by one, add divisor to the remainder */
     for (carry=0, i=0; i<n; i++) {
diff --git a/c-source/src/pairing.c b/c-source/src/pairing.c
--- a/c-source/src/pairing.c
+++ b/c-source/src/pairing.c
@@ -409,6 +409,55 @@
                        P ? P : (const POINTonE1_affine *)&BLS12_381_G1, 1);
 }
 
+#ifndef MILLER_LOOP_N_MAX
+# define MILLER_LOOP_N_MAX 16
+#endif
+
+void blst_miller_loop_n(vec384fp12 out, const POINTonE2_affine *const Qs[],
+                                        const POINTonE1_affine *const Ps[],
+                                        size_t n)
+{   /* ~10KB of stack storage */
+    POINTonE2 T[MILLER_LOOP_N_MAX];
+    POINTonE2_affine Q[MILLER_LOOP_N_MAX];
+    POINTonE1_affine Px2[MILLER_LOOP_N_MAX];
+    const POINTonE2_affine *Qptr = NULL;
+    const POINTonE1_affine *Pptr = NULL;
+    size_t i, j;
+
+    for (i = 0, j = 0; j < n; j++) {
+        Qptr = *Qs ? *Qs++ : Qptr+1;
+        Pptr = *Ps ? *Ps++ : Pptr+1;
+
+        /* Move common expression from line evaluation to line_by_Px2.  */
+        add_fp(Px2[i].X, Pptr->X, Pptr->X);
+        neg_fp(Px2[i].X, Px2[i].X);
+        add_fp(Px2[i].Y, Pptr->Y, Pptr->Y);
+
+        vec_copy(Q[i].X, Qptr->X, 2*sizeof(Q[i].X));
+        vec_copy(T[i].X, Qptr->X, 2*sizeof(T[i].X));
+        vec_copy(T[i].Z, BLS12_381_Rx.p2, sizeof(T[i].Z));
+
+        if (++i == MILLER_LOOP_N_MAX || j == n-1) {
+            vec384fp12 tmp;
+            vec384fp6 *ret = j < MILLER_LOOP_N_MAX ? out : tmp;
+
+            /* first step is ret = 1^2*line, which is just ret = line       */
+            start_dbl_n(ret, T, Px2, i);            /* 0x2                  */
+            add_n_dbl_n(ret, T, Q, Px2, i, 2);      /* ..0xc                */
+            add_n_dbl_n(ret, T, Q, Px2, i, 3);      /* ..0x68               */
+            add_n_dbl_n(ret, T, Q, Px2, i, 9);      /* ..0xd200             */
+            add_n_dbl_n(ret, T, Q, Px2, i, 32);     /* ..0xd20100000000     */
+            add_n_dbl_n(ret, T, Q, Px2, i, 16);     /* ..0xd201000000010000 */
+            conjugate_fp12(ret);            /* account for z being negative */
+
+            if (j >= MILLER_LOOP_N_MAX)
+                mul_fp12(out, out, ret);
+
+            i = 0;
+        }
+    }
+}
+
 void blst_final_exp(vec384fp12 ret, const vec384fp12 f)
 {   final_exp(ret, f);   }
 
diff --git a/c-source/src/pentaroot-addchain.h b/c-source/src/pentaroot-addchain.h
new file mode 100644
--- /dev/null
+++ b/c-source/src/pentaroot-addchain.h
@@ -0,0 +1,333 @@
+/*
+ * Copyright Supranational LLC
+ * Licensed under the Apache License, Version 2.0, see LICENSE for details.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/*
+ * The "magic" number is 1/5 modulo BLS12_381_r-1. Exponentiation to which
+ * yields 5th root of the base.
+ *
+ * Generated with 'addchain 20974350070050476191779096203274386335076221000211055129041463479975432473805'
+ * https://github.com/kwantam/addchain
+ * # Bos-Coster (win=4)           :  307 (15)
+ * # Bos-Coster (win=10)          :  307 (18)
+ * # Yacobi                       :  319 (16)
+ * # Bos-Coster (win=2)           :  319 ( 5)
+ * # Bos-Coster (win=5)           :  306 (19) <<<
+ * # Bos-Coster (win=7)           :  311 (22)
+ * # Bos-Coster (win=9)           :  313 (20)
+ * # Bos-Coster (win=3)           :  314 ( 9)
+ * # Bos-Coster (win=6)           :  309 (21)
+ * # Bos-Coster (win=8)           :  309 (23)
+ * # Bergeron-Berstel-Brlek-Duboc :  334 ( 5)
+ */
+
+#define PENTAROOT_MOD_BLS12_381_r(out, inp, ptype) do { \
+ptype t[19]; \
+vec_copy(t[1], inp, sizeof(ptype)); /*    0: 1 */\
+sqr(t[7], t[1]);                    /*    1: 2 */\
+sqr(t[0], t[7]);                    /*    2: 4 */\
+sqr(t[2], t[0]);                    /*    3: 8 */\
+mul(t[10], t[2], t[1]);             /*    4: 9 */\
+mul(t[3], t[10], t[7]);             /*    5: b */\
+mul(t[1], t[10], t[0]);             /*    6: d */\
+mul(t[5], t[3], t[0]);              /*    7: f */\
+mul(t[9], t[10], t[2]);             /*    8: 11 */\
+mul(t[4], t[3], t[2]);              /*    9: 13 */\
+mul(t[15], t[5], t[2]);             /*   10: 17 */\
+mul(t[8], t[15], t[2]);             /*   11: 1f */\
+mul(t[13], t[8], t[7]);             /*   12: 21 */\
+mul(t[14], t[8], t[0]);             /*   13: 23 */\
+mul(t[12], t[13], t[0]);            /*   14: 25 */\
+mul(t[6], t[8], t[2]);              /*   15: 27 */\
+mul(t[11], t[14], t[2]);            /*   16: 2b */\
+sqr(t[0], t[15]);                   /*   17: 2e */\
+mul(t[18], t[6], t[2]);             /*   18: 2f */\
+mul(t[2], t[11], t[2]);             /*   19: 33 */\
+mul(t[16], t[2], t[7]);             /*   20: 35 */\
+mul(t[7], t[0], t[3]);              /*   21: 39 */\
+mul(t[17], t[0], t[5]);             /*   22: 3d */\
+/* sqr(t[0], t[0]); */              /*   23: 5c */\
+/* sqr(t[0], t[0]); */              /*   24: b8 */\
+/* sqr(t[0], t[0]); */              /*   25: 170 */\
+/* sqr(t[0], t[0]); */              /*   26: 2e0 */\
+/* sqr(t[0], t[0]); */              /*   27: 5c0 */\
+/* sqr(t[0], t[0]); */              /*   28: b80 */\
+/* sqr(t[0], t[0]); */              /*   29: 1700 */\
+sqr_n_mul(t[0], t[0], 7, t[18]);    /*   30: 172f */\
+/* sqr(t[0], t[0]); */              /*   31: 2e5e */\
+/* sqr(t[0], t[0]); */              /*   32: 5cbc */\
+/* sqr(t[0], t[0]); */              /*   33: b978 */\
+/* sqr(t[0], t[0]); */              /*   34: 172f0 */\
+/* sqr(t[0], t[0]); */              /*   35: 2e5e0 */\
+/* sqr(t[0], t[0]); */              /*   36: 5cbc0 */\
+sqr_n_mul(t[0], t[0], 6, t[13]);    /*   37: 5cbe1 */\
+/* sqr(t[0], t[0]); */              /*   38: b97c2 */\
+/* sqr(t[0], t[0]); */              /*   39: 172f84 */\
+/* sqr(t[0], t[0]); */              /*   40: 2e5f08 */\
+/* sqr(t[0], t[0]); */              /*   41: 5cbe10 */\
+/* sqr(t[0], t[0]); */              /*   42: b97c20 */\
+/* sqr(t[0], t[0]); */              /*   43: 172f840 */\
+sqr_n_mul(t[0], t[0], 6, t[17]);    /*   44: 172f87d */\
+/* sqr(t[0], t[0]); */              /*   45: 2e5f0fa */\
+/* sqr(t[0], t[0]); */              /*   46: 5cbe1f4 */\
+/* sqr(t[0], t[0]); */              /*   47: b97c3e8 */\
+/* sqr(t[0], t[0]); */              /*   48: 172f87d0 */\
+/* sqr(t[0], t[0]); */              /*   49: 2e5f0fa0 */\
+/* sqr(t[0], t[0]); */              /*   50: 5cbe1f40 */\
+sqr_n_mul(t[0], t[0], 6, t[16]);    /*   51: 5cbe1f75 */\
+/* sqr(t[0], t[0]); */              /*   52: b97c3eea */\
+/* sqr(t[0], t[0]); */              /*   53: 172f87dd4 */\
+/* sqr(t[0], t[0]); */              /*   54: 2e5f0fba8 */\
+/* sqr(t[0], t[0]); */              /*   55: 5cbe1f750 */\
+/* sqr(t[0], t[0]); */              /*   56: b97c3eea0 */\
+sqr_n_mul(t[0], t[0], 5, t[15]);    /*   57: b97c3eeb7 */\
+/* sqr(t[0], t[0]); */              /*   58: 172f87dd6e */\
+/* sqr(t[0], t[0]); */              /*   59: 2e5f0fbadc */\
+/* sqr(t[0], t[0]); */              /*   60: 5cbe1f75b8 */\
+/* sqr(t[0], t[0]); */              /*   61: b97c3eeb70 */\
+/* sqr(t[0], t[0]); */              /*   62: 172f87dd6e0 */\
+/* sqr(t[0], t[0]); */              /*   63: 2e5f0fbadc0 */\
+sqr_n_mul(t[0], t[0], 6, t[15]);    /*   64: 2e5f0fbadd7 */\
+/* sqr(t[0], t[0]); */              /*   65: 5cbe1f75bae */\
+/* sqr(t[0], t[0]); */              /*   66: b97c3eeb75c */\
+/* sqr(t[0], t[0]); */              /*   67: 172f87dd6eb8 */\
+/* sqr(t[0], t[0]); */              /*   68: 2e5f0fbadd70 */\
+/* sqr(t[0], t[0]); */              /*   69: 5cbe1f75bae0 */\
+/* sqr(t[0], t[0]); */              /*   70: b97c3eeb75c0 */\
+/* sqr(t[0], t[0]); */              /*   71: 172f87dd6eb80 */\
+/* sqr(t[0], t[0]); */              /*   72: 2e5f0fbadd700 */\
+sqr_n_mul(t[0], t[0], 8, t[14]);    /*   73: 2e5f0fbadd723 */\
+/* sqr(t[0], t[0]); */              /*   74: 5cbe1f75bae46 */\
+/* sqr(t[0], t[0]); */              /*   75: b97c3eeb75c8c */\
+/* sqr(t[0], t[0]); */              /*   76: 172f87dd6eb918 */\
+/* sqr(t[0], t[0]); */              /*   77: 2e5f0fbadd7230 */\
+/* sqr(t[0], t[0]); */              /*   78: 5cbe1f75bae460 */\
+/* sqr(t[0], t[0]); */              /*   79: b97c3eeb75c8c0 */\
+/* sqr(t[0], t[0]); */              /*   80: 172f87dd6eb9180 */\
+/* sqr(t[0], t[0]); */              /*   81: 2e5f0fbadd72300 */\
+sqr_n_mul(t[0], t[0], 8, t[13]);    /*   82: 2e5f0fbadd72321 */\
+/* sqr(t[0], t[0]); */              /*   83: 5cbe1f75bae4642 */\
+/* sqr(t[0], t[0]); */              /*   84: b97c3eeb75c8c84 */\
+/* sqr(t[0], t[0]); */              /*   85: 172f87dd6eb91908 */\
+/* sqr(t[0], t[0]); */              /*   86: 2e5f0fbadd723210 */\
+/* sqr(t[0], t[0]); */              /*   87: 5cbe1f75bae46420 */\
+/* sqr(t[0], t[0]); */              /*   88: b97c3eeb75c8c840 */\
+sqr_n_mul(t[0], t[0], 6, t[2]);     /*   89: b97c3eeb75c8c873 */\
+/* sqr(t[0], t[0]); */              /*   90: 172f87dd6eb9190e6 */\
+/* sqr(t[0], t[0]); */              /*   91: 2e5f0fbadd72321cc */\
+/* sqr(t[0], t[0]); */              /*   92: 5cbe1f75bae464398 */\
+/* sqr(t[0], t[0]); */              /*   93: b97c3eeb75c8c8730 */\
+/* sqr(t[0], t[0]); */              /*   94: 172f87dd6eb9190e60 */\
+/* sqr(t[0], t[0]); */              /*   95: 2e5f0fbadd72321cc0 */\
+sqr_n_mul(t[0], t[0], 6, t[13]);    /*   96: 2e5f0fbadd72321ce1 */\
+/* sqr(t[0], t[0]); */              /*   97: 5cbe1f75bae46439c2 */\
+/* sqr(t[0], t[0]); */              /*   98: b97c3eeb75c8c87384 */\
+/* sqr(t[0], t[0]); */              /*   99: 172f87dd6eb9190e708 */\
+/* sqr(t[0], t[0]); */              /*  100: 2e5f0fbadd72321ce10 */\
+/* sqr(t[0], t[0]); */              /*  101: 5cbe1f75bae46439c20 */\
+/* sqr(t[0], t[0]); */              /*  102: b97c3eeb75c8c873840 */\
+/* sqr(t[0], t[0]); */              /*  103: 172f87dd6eb9190e7080 */\
+sqr_n_mul(t[0], t[0], 7, t[12]);    /*  104: 172f87dd6eb9190e70a5 */\
+/* sqr(t[0], t[0]); */              /*  105: 2e5f0fbadd72321ce14a */\
+/* sqr(t[0], t[0]); */              /*  106: 5cbe1f75bae46439c294 */\
+/* sqr(t[0], t[0]); */              /*  107: b97c3eeb75c8c8738528 */\
+/* sqr(t[0], t[0]); */              /*  108: 172f87dd6eb9190e70a50 */\
+/* sqr(t[0], t[0]); */              /*  109: 2e5f0fbadd72321ce14a0 */\
+/* sqr(t[0], t[0]); */              /*  110: 5cbe1f75bae46439c2940 */\
+/* sqr(t[0], t[0]); */              /*  111: b97c3eeb75c8c87385280 */\
+/* sqr(t[0], t[0]); */              /*  112: 172f87dd6eb9190e70a500 */\
+sqr_n_mul(t[0], t[0], 8, t[11]);    /*  113: 172f87dd6eb9190e70a52b */\
+/* sqr(t[0], t[0]); */              /*  114: 2e5f0fbadd72321ce14a56 */\
+/* sqr(t[0], t[0]); */              /*  115: 5cbe1f75bae46439c294ac */\
+/* sqr(t[0], t[0]); */              /*  116: b97c3eeb75c8c873852958 */\
+/* sqr(t[0], t[0]); */              /*  117: 172f87dd6eb9190e70a52b0 */\
+/* sqr(t[0], t[0]); */              /*  118: 2e5f0fbadd72321ce14a560 */\
+/* sqr(t[0], t[0]); */              /*  119: 5cbe1f75bae46439c294ac0 */\
+sqr_n_mul(t[0], t[0], 6, t[1]);     /*  120: 5cbe1f75bae46439c294acd */\
+/* sqr(t[0], t[0]); */              /*  121: b97c3eeb75c8c873852959a */\
+/* sqr(t[0], t[0]); */              /*  122: 172f87dd6eb9190e70a52b34 */\
+/* sqr(t[0], t[0]); */              /*  123: 2e5f0fbadd72321ce14a5668 */\
+/* sqr(t[0], t[0]); */              /*  124: 5cbe1f75bae46439c294acd0 */\
+/* sqr(t[0], t[0]); */              /*  125: b97c3eeb75c8c873852959a0 */\
+/* sqr(t[0], t[0]); */              /*  126: 172f87dd6eb9190e70a52b340 */\
+/* sqr(t[0], t[0]); */              /*  127: 2e5f0fbadd72321ce14a56680 */\
+/* sqr(t[0], t[0]); */              /*  128: 5cbe1f75bae46439c294acd00 */\
+sqr_n_mul(t[0], t[0], 8, t[2]);     /*  129: 5cbe1f75bae46439c294acd33 */\
+/* sqr(t[0], t[0]); */              /*  130: b97c3eeb75c8c873852959a66 */\
+/* sqr(t[0], t[0]); */              /*  131: 172f87dd6eb9190e70a52b34cc */\
+/* sqr(t[0], t[0]); */              /*  132: 2e5f0fbadd72321ce14a566998 */\
+/* sqr(t[0], t[0]); */              /*  133: 5cbe1f75bae46439c294acd330 */\
+/* sqr(t[0], t[0]); */              /*  134: b97c3eeb75c8c873852959a660 */\
+/* sqr(t[0], t[0]); */              /*  135: 172f87dd6eb9190e70a52b34cc0 */\
+sqr_n_mul(t[0], t[0], 6, t[11]);    /*  136: 172f87dd6eb9190e70a52b34ceb */\
+/* sqr(t[0], t[0]); */              /*  137: 2e5f0fbadd72321ce14a56699d6 */\
+/* sqr(t[0], t[0]); */              /*  138: 5cbe1f75bae46439c294acd33ac */\
+/* sqr(t[0], t[0]); */              /*  139: b97c3eeb75c8c873852959a6758 */\
+/* sqr(t[0], t[0]); */              /*  140: 172f87dd6eb9190e70a52b34ceb0 */\
+sqr_n_mul(t[0], t[0], 4, t[10]);    /*  141: 172f87dd6eb9190e70a52b34ceb9 */\
+/* sqr(t[0], t[0]); */              /*  142: 2e5f0fbadd72321ce14a56699d72 */\
+/* sqr(t[0], t[0]); */              /*  143: 5cbe1f75bae46439c294acd33ae4 */\
+/* sqr(t[0], t[0]); */              /*  144: b97c3eeb75c8c873852959a675c8 */\
+/* sqr(t[0], t[0]); */              /*  145: 172f87dd6eb9190e70a52b34ceb90 */\
+/* sqr(t[0], t[0]); */              /*  146: 2e5f0fbadd72321ce14a56699d720 */\
+sqr_n_mul(t[0], t[0], 5, t[8]);     /*  147: 2e5f0fbadd72321ce14a56699d73f */\
+/* sqr(t[0], t[0]); */              /*  148: 5cbe1f75bae46439c294acd33ae7e */\
+/* sqr(t[0], t[0]); */              /*  149: b97c3eeb75c8c873852959a675cfc */\
+/* sqr(t[0], t[0]); */              /*  150: 172f87dd6eb9190e70a52b34ceb9f8 */\
+/* sqr(t[0], t[0]); */              /*  151: 2e5f0fbadd72321ce14a56699d73f0 */\
+/* sqr(t[0], t[0]); */              /*  152: 5cbe1f75bae46439c294acd33ae7e0 */\
+/* sqr(t[0], t[0]); */              /*  153: b97c3eeb75c8c873852959a675cfc0 */\
+/* sqr(t[0], t[0]); */              /*  154: 172f87dd6eb9190e70a52b34ceb9f80 */\
+/* sqr(t[0], t[0]); */              /*  155: 2e5f0fbadd72321ce14a56699d73f00 */\
+/* sqr(t[0], t[0]); */              /*  156: 5cbe1f75bae46439c294acd33ae7e00 */\
+/* sqr(t[0], t[0]); */              /*  157: b97c3eeb75c8c873852959a675cfc00 */\
+/* sqr(t[0], t[0]); */              /*  158: 172f87dd6eb9190e70a52b34ceb9f800 */\
+/* sqr(t[0], t[0]); */              /*  159: 2e5f0fbadd72321ce14a56699d73f000 */\
+/* sqr(t[0], t[0]); */              /*  160: 5cbe1f75bae46439c294acd33ae7e000 */\
+/* sqr(t[0], t[0]); */              /*  161: b97c3eeb75c8c873852959a675cfc000 */\
+/* sqr(t[0], t[0]); */              /*  162: 172f87dd6eb9190e70a52b34ceb9f8000 */\
+sqr_n_mul(t[0], t[0], 15, t[9]);    /*  163: 172f87dd6eb9190e70a52b34ceb9f8011 */\
+/* sqr(t[0], t[0]); */              /*  164: 2e5f0fbadd72321ce14a56699d73f0022 */\
+/* sqr(t[0], t[0]); */              /*  165: 5cbe1f75bae46439c294acd33ae7e0044 */\
+/* sqr(t[0], t[0]); */              /*  166: b97c3eeb75c8c873852959a675cfc0088 */\
+/* sqr(t[0], t[0]); */              /*  167: 172f87dd6eb9190e70a52b34ceb9f80110 */\
+/* sqr(t[0], t[0]); */              /*  168: 2e5f0fbadd72321ce14a56699d73f00220 */\
+/* sqr(t[0], t[0]); */              /*  169: 5cbe1f75bae46439c294acd33ae7e00440 */\
+/* sqr(t[0], t[0]); */              /*  170: b97c3eeb75c8c873852959a675cfc00880 */\
+/* sqr(t[0], t[0]); */              /*  171: 172f87dd6eb9190e70a52b34ceb9f801100 */\
+sqr_n_mul(t[0], t[0], 8, t[3]);     /*  172: 172f87dd6eb9190e70a52b34ceb9f80110b */\
+/* sqr(t[0], t[0]); */              /*  173: 2e5f0fbadd72321ce14a56699d73f002216 */\
+/* sqr(t[0], t[0]); */              /*  174: 5cbe1f75bae46439c294acd33ae7e00442c */\
+/* sqr(t[0], t[0]); */              /*  175: b97c3eeb75c8c873852959a675cfc008858 */\
+/* sqr(t[0], t[0]); */              /*  176: 172f87dd6eb9190e70a52b34ceb9f80110b0 */\
+/* sqr(t[0], t[0]); */              /*  177: 2e5f0fbadd72321ce14a56699d73f0022160 */\
+sqr_n_mul(t[0], t[0], 5, t[8]);     /*  178: 2e5f0fbadd72321ce14a56699d73f002217f */\
+/* sqr(t[0], t[0]); */              /*  179: 5cbe1f75bae46439c294acd33ae7e00442fe */\
+/* sqr(t[0], t[0]); */              /*  180: b97c3eeb75c8c873852959a675cfc00885fc */\
+/* sqr(t[0], t[0]); */              /*  181: 172f87dd6eb9190e70a52b34ceb9f80110bf8 */\
+/* sqr(t[0], t[0]); */              /*  182: 2e5f0fbadd72321ce14a56699d73f002217f0 */\
+/* sqr(t[0], t[0]); */              /*  183: 5cbe1f75bae46439c294acd33ae7e00442fe0 */\
+/* sqr(t[0], t[0]); */              /*  184: b97c3eeb75c8c873852959a675cfc00885fc0 */\
+/* sqr(t[0], t[0]); */              /*  185: 172f87dd6eb9190e70a52b34ceb9f80110bf80 */\
+/* sqr(t[0], t[0]); */              /*  186: 2e5f0fbadd72321ce14a56699d73f002217f00 */\
+/* sqr(t[0], t[0]); */              /*  187: 5cbe1f75bae46439c294acd33ae7e00442fe00 */\
+/* sqr(t[0], t[0]); */              /*  188: b97c3eeb75c8c873852959a675cfc00885fc00 */\
+sqr_n_mul(t[0], t[0], 10, t[7]);    /*  189: b97c3eeb75c8c873852959a675cfc00885fc39 */\
+/* sqr(t[0], t[0]); */              /*  190: 172f87dd6eb9190e70a52b34ceb9f80110bf872 */\
+/* sqr(t[0], t[0]); */              /*  191: 2e5f0fbadd72321ce14a56699d73f002217f0e4 */\
+/* sqr(t[0], t[0]); */              /*  192: 5cbe1f75bae46439c294acd33ae7e00442fe1c8 */\
+/* sqr(t[0], t[0]); */              /*  193: b97c3eeb75c8c873852959a675cfc00885fc390 */\
+/* sqr(t[0], t[0]); */              /*  194: 172f87dd6eb9190e70a52b34ceb9f80110bf8720 */\
+/* sqr(t[0], t[0]); */              /*  195: 2e5f0fbadd72321ce14a56699d73f002217f0e40 */\
+sqr_n_mul(t[0], t[0], 6, t[6]);     /*  196: 2e5f0fbadd72321ce14a56699d73f002217f0e67 */\
+/* sqr(t[0], t[0]); */              /*  197: 5cbe1f75bae46439c294acd33ae7e00442fe1cce */\
+/* sqr(t[0], t[0]); */              /*  198: b97c3eeb75c8c873852959a675cfc00885fc399c */\
+/* sqr(t[0], t[0]); */              /*  199: 172f87dd6eb9190e70a52b34ceb9f80110bf87338 */\
+/* sqr(t[0], t[0]); */              /*  200: 2e5f0fbadd72321ce14a56699d73f002217f0e670 */\
+/* sqr(t[0], t[0]); */              /*  201: 5cbe1f75bae46439c294acd33ae7e00442fe1cce0 */\
+sqr_n_mul(t[0], t[0], 5, t[4]);     /*  202: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3 */\
+/* sqr(t[0], t[0]); */              /*  203: b97c3eeb75c8c873852959a675cfc00885fc399e6 */\
+/* sqr(t[0], t[0]); */              /*  204: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cc */\
+/* sqr(t[0], t[0]); */              /*  205: 2e5f0fbadd72321ce14a56699d73f002217f0e6798 */\
+/* sqr(t[0], t[0]); */              /*  206: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf30 */\
+/* sqr(t[0], t[0]); */              /*  207: b97c3eeb75c8c873852959a675cfc00885fc399e60 */\
+/* sqr(t[0], t[0]); */              /*  208: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cc0 */\
+/* sqr(t[0], t[0]); */              /*  209: 2e5f0fbadd72321ce14a56699d73f002217f0e67980 */\
+/* sqr(t[0], t[0]); */              /*  210: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf300 */\
+sqr_n_mul(t[0], t[0], 8, t[2]);     /*  211: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf333 */\
+/* sqr(t[0], t[0]); */              /*  212: b97c3eeb75c8c873852959a675cfc00885fc399e666 */\
+/* sqr(t[0], t[0]); */              /*  213: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc */\
+/* sqr(t[0], t[0]); */              /*  214: 2e5f0fbadd72321ce14a56699d73f002217f0e679998 */\
+/* sqr(t[0], t[0]); */              /*  215: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3330 */\
+/* sqr(t[0], t[0]); */              /*  216: b97c3eeb75c8c873852959a675cfc00885fc399e6660 */\
+/* sqr(t[0], t[0]); */              /*  217: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc0 */\
+/* sqr(t[0], t[0]); */              /*  218: 2e5f0fbadd72321ce14a56699d73f002217f0e6799980 */\
+sqr_n_mul(t[0], t[0], 7, t[5]);     /*  219: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f */\
+/* sqr(t[0], t[0]); */              /*  220: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e */\
+/* sqr(t[0], t[0]); */              /*  221: b97c3eeb75c8c873852959a675cfc00885fc399e6663c */\
+/* sqr(t[0], t[0]); */              /*  222: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78 */\
+/* sqr(t[0], t[0]); */              /*  223: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f0 */\
+/* sqr(t[0], t[0]); */              /*  224: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e0 */\
+/* sqr(t[0], t[0]); */              /*  225: b97c3eeb75c8c873852959a675cfc00885fc399e6663c0 */\
+/* sqr(t[0], t[0]); */              /*  226: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc780 */\
+/* sqr(t[0], t[0]); */              /*  227: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f00 */\
+/* sqr(t[0], t[0]); */              /*  228: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e00 */\
+sqr_n_mul(t[0], t[0], 9, t[2]);     /*  229: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e33 */\
+/* sqr(t[0], t[0]); */              /*  230: b97c3eeb75c8c873852959a675cfc00885fc399e6663c66 */\
+/* sqr(t[0], t[0]); */              /*  231: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc */\
+/* sqr(t[0], t[0]); */              /*  232: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f198 */\
+/* sqr(t[0], t[0]); */              /*  233: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e330 */\
+/* sqr(t[0], t[0]); */              /*  234: b97c3eeb75c8c873852959a675cfc00885fc399e6663c660 */\
+/* sqr(t[0], t[0]); */              /*  235: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc0 */\
+/* sqr(t[0], t[0]); */              /*  236: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f1980 */\
+sqr_n_mul(t[0], t[0], 7, t[4]);     /*  237: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f1993 */\
+/* sqr(t[0], t[0]); */              /*  238: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e3326 */\
+/* sqr(t[0], t[0]); */              /*  239: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664c */\
+/* sqr(t[0], t[0]); */              /*  240: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc98 */\
+/* sqr(t[0], t[0]); */              /*  241: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f19930 */\
+/* sqr(t[0], t[0]); */              /*  242: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e33260 */\
+/* sqr(t[0], t[0]); */              /*  243: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664c0 */\
+/* sqr(t[0], t[0]); */              /*  244: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc980 */\
+/* sqr(t[0], t[0]); */              /*  245: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f199300 */\
+sqr_n_mul(t[0], t[0], 8, t[2]);     /*  246: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f199333 */\
+/* sqr(t[0], t[0]); */              /*  247: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e332666 */\
+/* sqr(t[0], t[0]); */              /*  248: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664ccc */\
+/* sqr(t[0], t[0]); */              /*  249: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc9998 */\
+/* sqr(t[0], t[0]); */              /*  250: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f1993330 */\
+/* sqr(t[0], t[0]); */              /*  251: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e3326660 */\
+/* sqr(t[0], t[0]); */              /*  252: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664ccc0 */\
+/* sqr(t[0], t[0]); */              /*  253: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc99980 */\
+/* sqr(t[0], t[0]); */              /*  254: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f19933300 */\
+sqr_n_mul(t[0], t[0], 8, t[2]);     /*  255: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f19933333 */\
+/* sqr(t[0], t[0]); */              /*  256: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e33266666 */\
+/* sqr(t[0], t[0]); */              /*  257: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664ccccc */\
+/* sqr(t[0], t[0]); */              /*  258: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc999998 */\
+/* sqr(t[0], t[0]); */              /*  259: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f199333330 */\
+/* sqr(t[0], t[0]); */              /*  260: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e332666660 */\
+/* sqr(t[0], t[0]); */              /*  261: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664ccccc0 */\
+/* sqr(t[0], t[0]); */              /*  262: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc9999980 */\
+/* sqr(t[0], t[0]); */              /*  263: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f1993333300 */\
+sqr_n_mul(t[0], t[0], 8, t[2]);     /*  264: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f1993333333 */\
+/* sqr(t[0], t[0]); */              /*  265: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e3326666666 */\
+/* sqr(t[0], t[0]); */              /*  266: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664ccccccc */\
+/* sqr(t[0], t[0]); */              /*  267: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc99999998 */\
+/* sqr(t[0], t[0]); */              /*  268: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f19933333330 */\
+/* sqr(t[0], t[0]); */              /*  269: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e33266666660 */\
+/* sqr(t[0], t[0]); */              /*  270: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664ccccccc0 */\
+sqr_n_mul(t[0], t[0], 6, t[3]);     /*  271: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664cccccccb */\
+/* sqr(t[0], t[0]); */              /*  272: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc999999996 */\
+/* sqr(t[0], t[0]); */              /*  273: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f19933333332c */\
+/* sqr(t[0], t[0]); */              /*  274: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e332666666658 */\
+/* sqr(t[0], t[0]); */              /*  275: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664cccccccb0 */\
+/* sqr(t[0], t[0]); */              /*  276: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc9999999960 */\
+/* sqr(t[0], t[0]); */              /*  277: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f19933333332c0 */\
+/* sqr(t[0], t[0]); */              /*  278: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e3326666666580 */\
+/* sqr(t[0], t[0]); */              /*  279: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664cccccccb00 */\
+sqr_n_mul(t[0], t[0], 8, t[2]);     /*  280: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664cccccccb33 */\
+/* sqr(t[0], t[0]); */              /*  281: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc99999999666 */\
+/* sqr(t[0], t[0]); */              /*  282: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f19933333332ccc */\
+/* sqr(t[0], t[0]); */              /*  283: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e33266666665998 */\
+/* sqr(t[0], t[0]); */              /*  284: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664cccccccb330 */\
+/* sqr(t[0], t[0]); */              /*  285: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc999999996660 */\
+/* sqr(t[0], t[0]); */              /*  286: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f19933333332ccc0 */\
+/* sqr(t[0], t[0]); */              /*  287: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e332666666659980 */\
+/* sqr(t[0], t[0]); */              /*  288: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664cccccccb3300 */\
+sqr_n_mul(t[0], t[0], 8, t[2]);     /*  289: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664cccccccb3333 */\
+/* sqr(t[0], t[0]); */              /*  290: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc9999999966666 */\
+/* sqr(t[0], t[0]); */              /*  291: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f19933333332ccccc */\
+/* sqr(t[0], t[0]); */              /*  292: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e3326666666599998 */\
+/* sqr(t[0], t[0]); */              /*  293: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664cccccccb33330 */\
+/* sqr(t[0], t[0]); */              /*  294: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc99999999666660 */\
+/* sqr(t[0], t[0]); */              /*  295: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f19933333332ccccc0 */\
+/* sqr(t[0], t[0]); */              /*  296: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e33266666665999980 */\
+/* sqr(t[0], t[0]); */              /*  297: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664cccccccb333300 */\
+sqr_n_mul(t[0], t[0], 8, t[2]);     /*  298: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664cccccccb333333 */\
+/* sqr(t[0], t[0]); */              /*  299: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc999999996666666 */\
+/* sqr(t[0], t[0]); */              /*  300: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f19933333332ccccccc */\
+/* sqr(t[0], t[0]); */              /*  301: 5cbe1f75bae46439c294acd33ae7e00442fe1ccf3331e332666666659999998 */\
+/* sqr(t[0], t[0]); */              /*  302: b97c3eeb75c8c873852959a675cfc00885fc399e6663c664cccccccb3333330 */\
+/* sqr(t[0], t[0]); */              /*  303: 172f87dd6eb9190e70a52b34ceb9f80110bf8733cccc78cc9999999966666660 */\
+/* sqr(t[0], t[0]); */              /*  304: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f19933333332ccccccc0 */\
+sqr_n_mul(out, t[0], 6, t[1]);      /*  305: 2e5f0fbadd72321ce14a56699d73f002217f0e679998f19933333332cccccccd */\
+} while(0)
diff --git a/c-source/src/pentaroot.c b/c-source/src/pentaroot.c
new file mode 100644
--- /dev/null
+++ b/c-source/src/pentaroot.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright Supranational LLC
+ * Licensed under the Apache License, Version 2.0, see LICENSE for details.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "fields.h"
+
+static inline void mul_fr(vec256 ret, const vec256 a, const vec256 b)
+{   mul_mont_sparse_256(ret, a, b, BLS12_381_r, r0);   }
+
+static inline void sqr_fr(vec256 ret, const vec256 a)
+{   sqr_mont_sparse_256(ret, a, BLS12_381_r, r0);   }
+
+#ifdef __OPTIMIZE_SIZE__
+void blst_fr_pentaroot(vec256 out, const vec256 inp)
+{
+    static const byte pow[] = {
+        TO_BYTES(0x33333332cccccccd), TO_BYTES(0x217f0e679998f199),
+        TO_BYTES(0xe14a56699d73f002), TO_BYTES(0x2e5f0fbadd72321c)
+    };
+    size_t pow_bits = 254;
+    vec256 ret;
+
+    vec_copy(ret, inp, sizeof(ret));  /* ret = inp^1 */
+    --pow_bits; /* most significant bit is set, skip over */
+    while (pow_bits--) {
+        sqr_fr(ret, ret);
+        if (is_bit_set(pow, pow_bits))
+            mul_fr(ret, ret, inp);
+    }
+    vec_copy(out, ret, sizeof(ret));  /* out = ret */
+}
+#else
+# if 0
+/*
+ * "255"-bit variant omits full reductions at the ends of squarings,
+ * not implemented yet[?].
+ */
+static inline void sqr_n_mul_fr(vec256 out, const vec256 a, size_t count,
+                                const vec256 b)
+{   sqr_n_mul_mont_255(out, a, count, BLS12_381_r, r0, b);   }
+# else
+static void sqr_n_mul_fr(vec256 out, const vec256 a, size_t count,
+                         const vec256 b)
+{
+    do {
+        sqr_fr(out, a);
+        a = out;
+    } while (--count);
+    mul_fr(out, out, b);
+}
+# endif
+
+# define sqr(ret,a)		sqr_fr(ret,a)
+# define mul(ret,a,b)		mul_fr(ret,a,b)
+# define sqr_n_mul(ret,a,n,b)	sqr_n_mul_fr(ret,a,n,b)
+
+# include "pentaroot-addchain.h"
+void blst_fr_pentaroot(vec256 out, const vec256 inp)
+{   PENTAROOT_MOD_BLS12_381_r(out, inp, vec256);   }
+# undef PENTAROOT_MOD_BLS12_381_r
+
+# undef sqr_n_mul
+# undef sqr
+# undef mul
+#endif
+
+void blst_fr_pentapow(vec256 out, const vec256 inp)
+{
+    vec256 tmp;
+
+    sqr_fr(tmp, inp);
+    sqr_fr(tmp, tmp);
+    mul_fr(out, tmp, inp);
+}
diff --git a/c-source/src/server.c b/c-source/src/server.c
--- a/c-source/src/server.c
+++ b/c-source/src/server.c
@@ -21,4 +21,10 @@
 #include "consts.c"
 #include "vect.c"
 #include "exports.c"
-#include "rb_tree.c"
+#ifndef __BLST_CGO__
+# include "rb_tree.c"
+#endif
+#ifdef BLST_FR_PENTAROOT
+# include "pentaroot.c"
+#endif
+#include "cpuid.c"
diff --git a/c-source/src/vect.h b/c-source/src/vect.h
--- a/c-source/src/vect.h
+++ b/c-source/src/vect.h
@@ -61,7 +61,7 @@
 typedef byte pow256[256/8];
 
 /*
- * Internal Boolean type, Bolean by value, hence safe to cast to or
+ * Internal Boolean type, Boolean by value, hence safe to cast to or
  * reinterpret as 'bool'.
  */
 typedef limb_t bool_t;
@@ -147,7 +147,6 @@
 # define mul_mont_384x mulx_mont_384x
 # define sqr_mont_384x sqrx_mont_384x
 # define sqr_mont_382x sqrx_mont_382x
-# define sqr_n_mul_mont_384x sqrx_n_mul_mont_384x
 # define mul_382x mulx_382x
 # define sqr_382x sqrx_382x
 #endif
@@ -156,8 +155,6 @@
                    const vec384 p, limb_t n0);
 void sqr_mont_384x(vec384x ret, const vec384x a, const vec384 p, limb_t n0);
 void sqr_mont_382x(vec384x ret, const vec384x a, const vec384 p, limb_t n0);
-void sqr_n_mul_mont_384x(vec384x ret, const vec384x a, size_t count,
-                         const vec384 p, limb_t n0, const vec384x b);
 void mul_382x(vec768 ret[2], const vec384x a, const vec384x b, const vec384 p);
 void sqr_382x(vec768 ret[2], const vec384x a, const vec384 p);
 
@@ -213,11 +210,25 @@
 # endif
 #endif
 
+#if defined(__GNUC__) || defined(__clang__)
+# define launder(var) __asm__ __volatile__("" : "+r"(var))
+#else
+# define launder(var)
+#endif
+
 static inline bool_t is_bit_set(const byte *v, size_t i)
-{   return (v[i/8] >> (i%8)) & 1;   }
+{
+    bool_t ret = (v[i/8] >> (i%8)) & 1;
+    launder(ret);
+    return ret;
+}
 
 static inline bool_t byte_is_zero(unsigned char c)
-{   return ((limb_t)(c) - 1) >> (LIMB_T_BITS - 1);   }
+{
+    limb_t ret = ((limb_t)(c) - 1) >> (LIMB_T_BITS - 1);
+    launder(ret);
+    return ret;
+}
 
 static inline bool_t bytes_are_zero(const unsigned char *a, size_t num)
 {
@@ -235,9 +246,12 @@
 {
     limb_t ai, *ap = (limb_t *)a;
     limb_t bi, *bp = (limb_t *)b;
-    limb_t xorm, mask = (limb_t)0 - cbit;
+    limb_t xorm, mask;
     size_t i;
 
+    launder(cbit);
+    mask = (limb_t)0 - cbit;
+
     num /= sizeof(limb_t);
 
     for (i = 0; i < num; i++) {
@@ -248,6 +262,7 @@
 }
 
 /* ret = bit ? a : b */
+void vec_select_32(void *ret, const void *a, const void *b, bool_t sel_a);
 void vec_select_48(void *ret, const void *a, const void *b, bool_t sel_a);
 void vec_select_96(void *ret, const void *a, const void *b, bool_t sel_a);
 void vec_select_144(void *ret, const void *a, const void *b, bool_t sel_a);
@@ -256,8 +271,10 @@
 static inline void vec_select(void *ret, const void *a, const void *b,
                               size_t num, bool_t sel_a)
 {
+    launder(sel_a);
 #ifndef __BLST_NO_ASM__
-    if (num == 48)          vec_select_48(ret, a, b, sel_a);
+    if (num == 32)          vec_select_32(ret, a, b, sel_a);
+    else if (num == 48)     vec_select_48(ret, a, b, sel_a);
     else if (num == 96)     vec_select_96(ret, a, b, sel_a);
     else if (num == 144)    vec_select_144(ret, a, b, sel_a);
     else if (num == 192)    vec_select_192(ret, a, b, sel_a);
@@ -266,7 +283,8 @@
     if (0) ;
 #endif
     else {
-        limb_t bi, *rp = (limb_t *)ret;
+        limb_t bi;
+        volatile limb_t *rp = (limb_t *)ret;
         const limb_t *ap = (const limb_t *)a;
         const limb_t *bp = (const limb_t *)b;
         limb_t xorm, mask = (limb_t)0 - sel_a;
@@ -282,7 +300,11 @@
 }
 
 static inline bool_t is_zero(limb_t l)
-{   return (~l & (l - 1)) >> (LIMB_T_BITS - 1);   }
+{
+    limb_t ret = (~l & (l - 1)) >> (LIMB_T_BITS - 1);
+    launder(ret);
+    return ret;
+}
 
 static inline bool_t vec_is_zero(const void *a, size_t num)
 {
@@ -290,6 +312,12 @@
     limb_t acc;
     size_t i;
 
+#ifndef __BLST_NO_ASM__
+    bool_t vec_is_zero_16x(const void *a, size_t num);
+    if ((num & 15) == 0)
+        return vec_is_zero_16x(a, num);
+#endif
+
     num /= sizeof(limb_t);
 
     for (acc = 0, i = 0; i < num; i++)
@@ -305,6 +333,12 @@
     limb_t acc;
     size_t i;
 
+#ifndef __BLST_NO_ASM__
+    bool_t vec_is_equal_16x(const void *a, const void *b, size_t num);
+    if ((num & 15) == 0)
+        return vec_is_equal_16x(a, b, num);
+#endif
+
     num /= sizeof(limb_t);
 
     for (acc = 0, i = 0; i < num; i++)
@@ -342,8 +376,8 @@
     for (i = 0; i < num; i++)
         rp[i] = 0;
 
-#if defined(__GNUC__) && !defined(__NVCC__)
-    asm volatile("" : : "r"(ret) : "memory");
+#if defined(__GNUC__) || defined(__clang__)
+    __asm__ __volatile__("" : : "r"(ret) : "memory");
 #endif
 }
 
@@ -364,7 +398,7 @@
 # pragma warning(disable: 4127 4189)
 #endif
 
-#if !defined(__wasm__)
+#if !defined(__wasm__) && __STDC_HOSTED__-0 != 0
 # include <stdlib.h>
 #endif
 
diff --git a/hsblst.cabal b/hsblst.cabal
--- a/hsblst.cabal
+++ b/hsblst.cabal
@@ -1,11 +1,11 @@
-cabal-version: 1.12
+cabal-version: 3.0
 
 -- This file has been generated from package.yaml by hpack version 0.34.4.
 --
 -- see: https://github.com/sol/hpack
 
 name:           hsblst
-version:        0.0.2
+version:        0.0.3
 synopsis:       Haskell bindings to BLST
 description:    HsBLST is low-level Haskell bindings and a high-level interface to [BLST](https://github.com/supranational/blst) -- a multilingual BLS12-381 signature library.
 category:       Cryptography
@@ -18,12 +18,10 @@
 license-file:   LICENSE
 build-type:     Simple
 tested-with:
-    GHC == 9.0.2
-  , GHC == 9.2.8
-  , GHC == 9.4.5
+    GHC == 9.4.8
+  , GHC == 9.6.3
+  , GHC == 9.8.1
 extra-source-files:
-    README.md
-    CHANGELOG.md
     c-source/build/coff/add_mod_256-x86_64.s
     c-source/build/coff/add_mod_384-x86_64.s
     c-source/build/coff/add_mod_384x384-x86_64.s
@@ -99,6 +97,7 @@
     c-source/src/client_min_pk.c
     c-source/src/client_min_sig.c
     c-source/src/consts.c
+    c-source/src/cpuid.c
     c-source/src/e1.c
     c-source/src/e2.c
     c-source/src/exp.c
@@ -110,6 +109,7 @@
     c-source/src/map_to_g2.c
     c-source/src/multi_scalar.c
     c-source/src/pairing.c
+    c-source/src/pentaroot.c
     c-source/src/rb_tree.c
     c-source/src/recip.c
     c-source/src/server.c
@@ -122,6 +122,7 @@
     c-source/src/errors.h
     c-source/src/fields.h
     c-source/src/no_asm.h
+    c-source/src/pentaroot-addchain.h
     c-source/src/point.h
     c-source/src/recip-addchain.h
     c-source/src/sha256.h
@@ -129,6 +130,9 @@
     c-source/src/vect.h
     c-source/bindings/blst.h
     c-source/bindings/blst_aux.h
+extra-doc-files:
+    README.md
+    CHANGELOG.md
     c-source/LICENSE
     c-source/README.md
 
@@ -146,6 +150,8 @@
       Crypto.BLST.Internal.Types
   other-modules:
       Paths_hsblst
+  autogen-modules:
+      Paths_hsblst
   hs-source-dirs:
       src
   default-extensions:
@@ -201,16 +207,15 @@
       c-source/bindings
   c-sources:
       c-source/src/server.c
-      c-source/build/assembly.S
-  build-tools:
-      c2hs
   build-depends:
-      base >=4.15.1.0 && <4.18
-    , deepseq >=1.4.5.0 && <1.5
+      base >=4.17 && <4.20
+    , deepseq >=1.4.5.0 && <1.5.1
     , memory >=0.16.0 && <0.19
   if impl(ghc >= 9.2)
     ghc-options: -Wno-missing-kind-signatures
   default-language: Haskell2010
+  asm-sources: c-source/build/assembly.S
+  build-tool-depends: c2hs:c2hs
 
 test-suite hsblst-test
   type: exitcode-stdio-1.0
@@ -222,6 +227,8 @@
       Test.BLST.Tezos
       Test.BLST.Util
       Paths_hsblst
+  autogen-modules:
+      Paths_hsblst
   hs-source-dirs:
       test
   default-extensions:
@@ -276,14 +283,14 @@
   build-tool-depends:
       tasty-discover:tasty-discover
   build-depends:
-      base >=4.15.1.0 && <4.18
-    , bytestring >=0.10.12.1 && <0.12
-    , hex-text >=0.1.0.6 && <0.2
+      base >=4.17 && <4.20
+    , base16-bytestring ==1.0.*
+    , bytestring >=0.10.12.1 && <0.13
     , hsblst
     , memory >=0.16.0 && <0.19
-    , tasty >=1.4.2.1 && <1.5
+    , tasty >=1.4.2.1 && <1.6
     , tasty-hunit >=0.10.0.3 && <0.11
-    , text >=1.2.5.0 && <1.3 || >=2.0.1 && <2.1
+    , text >=1.2.5.0 && <1.3 || >=2.0.1 && <2.1 || >=2.1 && <2.2
   if impl(ghc >= 9.2)
     ghc-options: -Wno-missing-kind-signatures
   if impl(ghc < 9.4)
diff --git a/src/Crypto/BLST/Internal/Bindings.chs b/src/Crypto/BLST/Internal/Bindings.chs
--- a/src/Crypto/BLST/Internal/Bindings.chs
+++ b/src/Crypto/BLST/Internal/Bindings.chs
@@ -4,6 +4,7 @@
 #include <blst.h>
 
 {-# OPTIONS_HADDOCK not-home #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
 
 -- | Lower-level bindings. Functions starting with @blst_@ are raw c2hs
 -- bindings. Others are slightly higher level wrappers around those bindings.
diff --git a/src/Crypto/BLST/Internal/Bindings/Types.hs b/src/Crypto/BLST/Internal/Bindings/Types.hs
--- a/src/Crypto/BLST/Internal/Bindings/Types.hs
+++ b/src/Crypto/BLST/Internal/Bindings/Types.hs
@@ -2,6 +2,7 @@
 -- SPDX-License-Identifier: MPL-2.0
 
 {-# OPTIONS_HADDOCK not-home #-}
+{-# LANGUAGE RoleAnnotations #-}
 
 -- | Types for lower-level bindings
 module Crypto.BLST.Internal.Bindings.Types
@@ -29,6 +30,7 @@
 type SizeOf :: Type -> Nat
 type family SizeOf t
 
+type role Point nominal
 -- | Point representation.
 newtype Point (a :: PointKind) = Point ( SizedByteArray (SizeOf (Point a)) Bytes )
   deriving stock (Show, Eq)
@@ -36,6 +38,7 @@
 instance NFData (Point a) where
   rnf = rnf @Bytes . unSizedByteArray . coerce
 
+type role Affine nominal
 -- | Affine point representation.
 newtype Affine (a :: PointKind) = Affine { unAffine :: SizedByteArray (SizeOf (Affine a)) Bytes }
   deriving stock (Show, Eq)
diff --git a/src/Crypto/BLST/Internal/Types.hs b/src/Crypto/BLST/Internal/Types.hs
--- a/src/Crypto/BLST/Internal/Types.hs
+++ b/src/Crypto/BLST/Internal/Types.hs
@@ -2,6 +2,7 @@
 -- SPDX-License-Identifier: MPL-2.0
 
 {-# OPTIONS_HADDOCK not-home #-}
+{-# LANGUAGE RoleAnnotations #-}
 
 -- | Types used for the high-level interface.
 module Crypto.BLST.Internal.Types
@@ -35,6 +36,7 @@
 
 type instance ByteSize 'Serialize SecretKey = SkSerializeSize
 
+type role PublicKey nominal
 -- | Public key representation.
 type PublicKey :: Curve -> Type
 newtype PublicKey c = PublicKey (Affine (CurveToPkPoint c))
@@ -44,6 +46,7 @@
 type instance ByteSize 'Serialize (PublicKey c) = SerializedSize (CurveToPkPoint c)
 type instance ByteSize 'Compress (PublicKey c) = CompressedSize (CurveToPkPoint c)
 
+type role Signature nominal phantom
 -- | Signature representation.
 type Signature :: Curve -> EncodeMethod -> Type
 newtype Signature c m = Signature (Affine (CurveToMsgPoint c))
diff --git a/test/Test/BLST/Util.hs b/test/Test/BLST/Util.hs
--- a/test/Test/BLST/Util.hs
+++ b/test/Test/BLST/Util.hs
@@ -16,12 +16,13 @@
 import Data.ByteArray qualified as BA
 import Data.ByteArray.Sized (SizedByteArray)
 import Data.ByteArray.Sized qualified as AS
-import Data.Maybe (fromJust, fromMaybe)
+import Data.ByteString.Base16 qualified as B16
+import Data.Maybe (fromMaybe)
 import Data.Proxy (Proxy(..))
 import Data.Text (Text, unpack)
+import Data.Text.Encoding (decodeUtf8, encodeUtf8)
 import GHC.TypeNats (KnownNat, natVal)
 import System.IO.Unsafe (unsafePerformIO)
-import Text.Hex (decodeHex, encodeHex)
 
 import Crypto.BLST.Internal.Bindings qualified as B
 import Crypto.BLST.Internal.Classy qualified as C
@@ -29,14 +30,14 @@
 fromHex :: forall n. (KnownNat n) => Text -> SizedByteArray n Bytes
 fromHex arg = AS.convert
   . fromMaybe (error $ "Expected " <> show (natVal @n Proxy) <> " bytes got " <> unpack arg)
-  . AS.sizedByteArray . fromJust . decodeHex
+  . AS.sizedByteArray . B16.decodeLenient . encodeUtf8
   $ arg
 
 fromHex' :: BA.ByteArray a => Text -> a
-fromHex' = BA.convert . fromJust . decodeHex
+fromHex' = BA.convert . B16.decodeLenient . encodeUtf8
 
 toHex :: BA.ByteArray a => SizedByteArray n a -> Text
-toHex = encodeHex . BA.convert . AS.unSizedByteArray
+toHex = decodeUtf8 . B16.encode . BA.convert . AS.unSizedByteArray
 
 deserializePoint :: C.IsPoint p => Text -> B.Point p
 deserializePoint = unsafePerformIO . C.fromAffine . deserializeAffine
