diff --git a/libff/algebra/scalar_multiplication/multiexp.hpp b/libff/algebra/scalar_multiplication/multiexp.hpp
index bbbdb040..0e503ed6 100755
--- a/libff/algebra/scalar_multiplication/multiexp.hpp
+++ b/libff/algebra/scalar_multiplication/multiexp.hpp
@@ -116,6 +116,13 @@ std::vector<T> batch_exp(const size_t scalar_size,
                          const window_table<T> &table,
                          const std::vector<FieldT> &v);
 
+template<typename T, typename FieldT>
+std::vector<T> batch_exp(const size_t scalar_size,
+                         const size_t window,
+                         const window_table<T> &table,
+                         const std::vector<FieldT> &v,
+                         size_t num_entries);
+
 template<typename T, typename FieldT>
 std::vector<T> batch_exp_with_coeff(const size_t scalar_size,
                                     const size_t window,
diff --git a/libff/algebra/scalar_multiplication/multiexp.tcc b/libff/algebra/scalar_multiplication/multiexp.tcc
index 0c85e2bc..b7782119 100755
--- a/libff/algebra/scalar_multiplication/multiexp.tcc
+++ b/libff/algebra/scalar_multiplication/multiexp.tcc
@@ -620,17 +620,27 @@ std::vector<T> batch_exp(const size_t scalar_size,
                          const size_t window,
                          const window_table<T> &table,
                          const std::vector<FieldT> &v)
+{
+    return batch_exp(scalar_size, window, table, v, v.size());
+}
+
+template<typename T, typename FieldT>
+std::vector<T> batch_exp(const size_t scalar_size,
+                         const size_t window,
+                         const window_table<T> &table,
+                         const std::vector<FieldT> &v,
+                         size_t num_entries)
 {
     if (!inhibit_profiling_info)
     {
         print_indent();
     }
-    std::vector<T> res(v.size(), table[0][0]);
+    std::vector<T> res(num_entries, table[0][0]);
 
 #ifdef MULTICORE
 #pragma omp parallel for
 #endif
-    for (size_t i = 0; i < v.size(); ++i)
+    for (size_t i = 0; i < num_entries; ++i)
     {
         res[i] = windowed_exp(scalar_size, window, table, v[i]);
 
diff --git a/libff/algebra/scalar_multiplication/wnaf.hpp b/libff/algebra/scalar_multiplication/wnaf.hpp
index 6c65cde2..c6320b62 100755
--- a/libff/algebra/scalar_multiplication/wnaf.hpp
+++ b/libff/algebra/scalar_multiplication/wnaf.hpp
@@ -18,12 +18,32 @@
 
 namespace libff {
 
+/**
+ * Find the wNAF representation of the given scalar relative to the given
+ * window size, reusing the given vector to store it.
+ */
+template<mp_size_t n>
+void update_wnaf(std::vector<long> &naf, const size_t window_size, const bigint<n> &scalar);
+
 /**
  * Find the wNAF representation of the given scalar relative to the given window size.
  */
 template<mp_size_t n>
 std::vector<long> find_wnaf(const size_t window_size, const bigint<n> &scalar);
 
+/**
+ * Compute optimal window size.
+ */
+template<typename T>
+size_t wnaf_opt_window_size(const size_t scalar_bits);
+
+/**
+ * In additive notation, use wNAF exponentiation (with the given window size)
+ * to compute scalar * base, for a scalar in naf form.
+ */
+template<typename T>
+T fixed_window_wnaf_exp(const size_t window_size, const T &base, const std::vector<long> &naf);
+
 /**
  * In additive notation, use wNAF exponentiation (with the given window size) to compute scalar * base.
  */
diff --git a/libff/algebra/scalar_multiplication/wnaf.tcc b/libff/algebra/scalar_multiplication/wnaf.tcc
index 5a8205e7..65b2b880 100755
--- a/libff/algebra/scalar_multiplication/wnaf.tcc
+++ b/libff/algebra/scalar_multiplication/wnaf.tcc
@@ -19,10 +19,10 @@
 namespace libff {
 
 template<mp_size_t n>
-std::vector<long> find_wnaf(const size_t window_size, const bigint<n> &scalar)
+void update_wnaf(std::vector<long> &wnaf, const size_t window_size, const bigint<n> &scalar)
 {
     const size_t length = scalar.max_bits(); // upper bound
-    std::vector<long> res(length+1);
+    wnaf.resize(length+1);
     bigint<n> c = scalar;
     long j = 0;
     while (!c.is_zero())
@@ -49,19 +49,40 @@ std::vector<long> find_wnaf(const size_t window_size, const bigint<n> &scalar)
         {
             u = 0;
         }
-        res[j] = u;
+        wnaf[j] = u;
         ++j;
 
         mpn_rshift(c.data, c.data, n, 1); // c = c/2
     }
 
+    wnaf.resize(j);
+}
+
+template<mp_size_t n>
+std::vector<long> find_wnaf(const size_t window_size, const bigint<n> &scalar)
+{
+    std::vector<long> res;
+    update_wnaf(res, window_size, scalar);
     return res;
 }
 
-template<typename T, mp_size_t n>
-T fixed_window_wnaf_exp(const size_t window_size, const T &base, const bigint<n> &scalar)
+template<typename T>
+size_t wnaf_opt_window_size(const size_t scalar_bits)
+{
+    for (long i = T::wnaf_window_table.size() - 1; i >= 0; --i)
+    {
+        if (scalar_bits >= T::wnaf_window_table[i])
+        {
+            return i+1;
+        }
+    }
+
+    return 0;
+}
+
+template<typename T>
+T fixed_window_wnaf_exp(const size_t window_size, const T &base, const std::vector<long> &naf)
 {
-    std::vector<long> naf = find_wnaf(window_size, scalar);
     std::vector<T> table(1ul<<(window_size-1));
     T tmp = base;
     T dbl = base.dbl();
@@ -98,18 +119,16 @@ T fixed_window_wnaf_exp(const size_t window_size, const T &base, const bigint<n>
 }
 
 template<typename T, mp_size_t n>
-T opt_window_wnaf_exp(const T &base, const bigint<n> &scalar, const size_t scalar_bits)
+T fixed_window_wnaf_exp(const size_t window_size, const T &base, const bigint<n> &scalar)
 {
-    size_t best = 0;
-    for (long i = T::wnaf_window_table.size() - 1; i >= 0; --i)
-    {
-        if (scalar_bits >= T::wnaf_window_table[i])
-        {
-            best = i+1;
-            break;
-        }
-    }
+    std::vector<long> naf = find_wnaf(window_size, scalar);
+    return fixed_window_wnaf_exp<T>(window_size, base, naf);
+}
 
+template<typename T, mp_size_t n>
+T opt_window_wnaf_exp(const T &base, const bigint<n> &scalar, const size_t scalar_bits)
+{
+    const size_t best = wnaf_opt_window_size<T>(scalar_bits);
     if (best > 0)
     {
         return fixed_window_wnaf_exp(best, base, scalar);