Trim Z coordinates from the OPENSSL_SMALL P-256 tables.

The small P-256 tables currently store 2 * 16 points in Jacobian
coordinates, but all the Z values are one, except for the two entries
which store infinity. Instead, store only affine coordinates and omit
the infinity entries. (We can recover infinity with constant-time
selects.)

This trims 1152 bytes from the table. Comparing the sizes of the bssl
tool (stripped, otherwise debug symbols undo the size gain), the binary
is 4096 bytes smaller, but I suspect this is just an artifact of
something rounding to page sizes.

Along the way, I've scripted the table generation and merged it into a
much generalized version of make_p256-x86_64-table.go.

As a bonus, by cutting the size of the table we scan, it's faster!
(ECDSA verify was already not scanning a table, so that one staying the
same is expected.)

Before:
Did 22302 ECDH P-256 operations in 4009795us (5561.9 ops/sec)
Did 62000 ECDSA P-256 signing operations in 4020075us (15422.6 ops/sec)
Did 26544 ECDSA P-256 verify operations in 4056526us (6543.5 ops/sec)

After:
Did 23001 ECDH P-256 operations in 4016544us (5726.6 ops/sec) [+3.0%]
Did 66000 ECDSA P-256 signing operations in 4043083us (16324.2 ops/sec) [+5.8%]
Did 26544 ECDSA P-256 verify operations in 4051220us (6552.1 ops/sec) [+0.1%]

Change-Id: Ie88898fd56e57505e3a325c50bbaf0dc5d42eeb3
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/41164
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/fipsmodule/ec/make_p256-x86_64-table.go b/crypto/fipsmodule/ec/make_p256-x86_64-table.go
deleted file mode 100644
index 604fb85..0000000
--- a/crypto/fipsmodule/ec/make_p256-x86_64-table.go
+++ /dev/null
@@ -1,126 +0,0 @@
-/* Copyright (c) 2018, Google Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
-
-package main
-
-import (
-	"crypto/elliptic"
-	"fmt"
-	"math/big"
-	"os"
-)
-
-const fileHeader = `/*
- * Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
- * Copyright (c) 2015, Intel Inc.
- *
- * Licensed under the OpenSSL license (the "License").  You may not use
- * this file except in compliance with the License.  You can obtain a copy
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-// This is the precomputed constant time access table for the code in
-// p256-x86_64.c, for the default generator. The table consists of 37
-// subtables, each subtable contains 64 affine points. The affine points are
-// encoded as eight uint64's, four for the x coordinate and four for the y.
-// Both values are in little-endian order. There are 37 tables because a
-// signed, 6-bit wNAF form of the scalar is used and ceil(256/(6 + 1)) = 37.
-// Within each table there are 64 values because the 6-bit wNAF value can take
-// 64 values, ignoring the sign bit, which is implemented by performing a
-// negation of the affine point when required. We would like to align it to 2MB
-// in order to increase the chances of using a large page but that appears to
-// lead to invalid ELF files being produced.
-
-// This file is generated by make_p256-x86_64-table.go.
-
-static const alignas(4096) PRECOMP256_ROW ecp_nistz256_precomputed[37] = {
-`
-
-func main() {
-	os.Stdout.WriteString(fileHeader)
-
-	scalar, tmp := new(big.Int), new(big.Int)
-	p256 := elliptic.P256()
-	p := p256.Params().P
-
-	// The wNAF windows are 7 bits wide, so advance across the 256-bit scalar
-	// space in 7-bit increments.
-	for shift := uint(0); shift < 256; shift += 7 {
-		// For each window, encode 64 multiples of the base point.
-		for multiple := 1; multiple <= 64; multiple++ {
-			scalar.SetInt64(int64(multiple))
-			scalar.Lsh(scalar, shift)
-
-			x, y := p256.ScalarBaseMult(scalar.Bytes())
-
-			toMontgomery(x, p)
-			toMontgomery(y, p)
-
-			if multiple == 1 {
-				os.Stdout.WriteString("        {{")
-			} else {
-				os.Stdout.WriteString("         {")
-			}
-			printNum(x, tmp)
-
-			os.Stdout.WriteString(",\n          ")
-			printNum(y, tmp)
-
-			if multiple == 64 {
-				os.Stdout.WriteString("}}")
-			} else {
-				os.Stdout.WriteString("},\n")
-			}
-		}
-
-		if shift+7 < 256 {
-			os.Stdout.WriteString(",\n")
-		} else {
-			os.Stdout.WriteString("};\n")
-		}
-	}
-}
-
-var mask, R *big.Int
-
-func init() {
-	mask = new(big.Int).SetUint64(0xffffffffffffffff)
-	R = new(big.Int).SetInt64(1)
-	R.Lsh(R, 256)
-}
-
-func printNum(n, tmp *big.Int) {
-	fmt.Printf("{")
-	for i := 0; i < 4; i++ {
-		tmp.And(n, mask)
-		limb := tmp.Uint64()
-		fmt.Printf("TOBN(0x%08x, 0x%08x)", uint32(limb>>32), uint32(limb))
-		n.Rsh(n, 64)
-
-		switch i {
-		case 0, 2:
-			os.Stdout.WriteString(", ")
-		case 1:
-			os.Stdout.WriteString(",\n           ")
-		}
-	}
-	fmt.Printf("}")
-}
-
-// toMontgomery sets n to be n×R mod p
-func toMontgomery(n, p *big.Int) {
-	n.Mul(n, R)
-	n.Mod(n, p)
-}
diff --git a/crypto/fipsmodule/ec/make_tables.go b/crypto/fipsmodule/ec/make_tables.go
new file mode 100644
index 0000000..8abefad
--- /dev/null
+++ b/crypto/fipsmodule/ec/make_tables.go
@@ -0,0 +1,408 @@
+/* Copyright (c) 2020, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+package main
+
+import (
+	"crypto/elliptic"
+	"fmt"
+	"io"
+	"math/big"
+	"os"
+)
+
+func main() {
+	if err := writeP256X86_64Table("p256-x86_64-table.h"); err != nil {
+		fmt.Fprintf(os.Stderr, "Error writing p256-x86_64-table.h: %s\n", err)
+		os.Exit(1)
+	}
+
+	if err := writeP256Table("p256_table.h"); err != nil {
+		fmt.Fprintf(os.Stderr, "Error writing p256_table.h: %s\n", err)
+		os.Exit(1)
+	}
+}
+
+func writeP256X86_64Table(path string) error {
+	curve := elliptic.P256()
+	tables := make([][][2]*big.Int, 0, 37)
+	for shift := 0; shift < 256; shift += 7 {
+		row := makeMultiples(curve, 64, shift)
+		tables = append(tables, row)
+	}
+
+	f, err := os.Create(path)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	const fileHeader = `/*
+ * Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright (c) 2015, Intel Inc.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+// This is the precomputed constant time access table for the code in
+// p256-x86_64.c, for the default generator. The table consists of 37
+// subtables, each subtable contains 64 affine points. The affine points are
+// encoded as eight uint64's, four for the x coordinate and four for the y.
+// Both values are in little-endian order. There are 37 tables because a
+// signed, 6-bit wNAF form of the scalar is used and ceil(256/(6 + 1)) = 37.
+// Within each table there are 64 values because the 6-bit wNAF value can take
+// 64 values, ignoring the sign bit, which is implemented by performing a
+// negation of the affine point when required. We would like to align it to 2MB
+// in order to increase the chances of using a large page but that appears to
+// lead to invalid ELF files being produced.
+
+// This file is generated by make_tables.go.
+
+static const alignas(4096) PRECOMP256_ROW ecp_nistz256_precomputed[37] = `
+	if _, err := f.WriteString(fileHeader); err != nil {
+		return err
+	}
+	// TODO(davidben): An indent of 4 would match our style better. For now the
+	// indent is 8 so it generates the same table as before.
+	if err := writeTables(f, curve, tables, true, 8, writeBNMont); err != nil {
+		return err
+	}
+	if _, err := f.WriteString(";\n"); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func writeP256Table(path string) error {
+	curve := elliptic.P256()
+	tables := [][][2]*big.Int{
+		makeComb(curve, 64, 4, 0),
+		makeComb(curve, 64, 4, 32),
+	}
+
+	f, err := os.Create(path)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	const fileHeader = `/* Copyright (c) 2020, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+// This file is generated by make_tables.go.
+
+// Base point pre computation
+// --------------------------
+//
+// Two different sorts of precomputed tables are used in the following code.
+// Each contain various points on the curve, where each point is three field
+// elements (x, y, z).
+//
+// For the base point table, z is usually 1 (0 for the point at infinity).
+// This table has 2 * 16 elements, starting with the following:
+// index | bits    | point
+// ------+---------+------------------------------
+//     0 | 0 0 0 0 | 0G
+//     1 | 0 0 0 1 | 1G
+//     2 | 0 0 1 0 | 2^64G
+//     3 | 0 0 1 1 | (2^64 + 1)G
+//     4 | 0 1 0 0 | 2^128G
+//     5 | 0 1 0 1 | (2^128 + 1)G
+//     6 | 0 1 1 0 | (2^128 + 2^64)G
+//     7 | 0 1 1 1 | (2^128 + 2^64 + 1)G
+//     8 | 1 0 0 0 | 2^192G
+//     9 | 1 0 0 1 | (2^192 + 1)G
+//    10 | 1 0 1 0 | (2^192 + 2^64)G
+//    11 | 1 0 1 1 | (2^192 + 2^64 + 1)G
+//    12 | 1 1 0 0 | (2^192 + 2^128)G
+//    13 | 1 1 0 1 | (2^192 + 2^128 + 1)G
+//    14 | 1 1 1 0 | (2^192 + 2^128 + 2^64)G
+//    15 | 1 1 1 1 | (2^192 + 2^128 + 2^64 + 1)G
+// followed by a copy of this with each element multiplied by 2^32.
+//
+// The reason for this is so that we can clock bits into four different
+// locations when doing simple scalar multiplies against the base point,
+// and then another four locations using the second 16 elements.
+//
+// Tables for other points have table[i] = iG for i in 0 .. 16.
+
+// fiat_p256_g_pre_comp is the table of precomputed base points
+#if defined(BORINGSSL_NISTP256_64BIT)
+static const fiat_p256_felem fiat_p256_g_pre_comp[2][15][2] = `
+	if _, err := f.WriteString(fileHeader); err != nil {
+		return err
+	}
+	if err := writeTables(f, curve, tables, true, 4, writeU64Mont); err != nil {
+		return err
+	}
+	if _, err := f.WriteString(";\n#else\nstatic const fiat_p256_felem fiat_p256_g_pre_comp[2][15][2] = "); err != nil {
+		return err
+	}
+	if err := writeTables(f, curve, tables, true, 4, writeU32Mont); err != nil {
+		return err
+	}
+	if _, err := f.WriteString(";\n#endif\n"); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// makeMultiples returns a table of the first n multiples of 2^shift * G,
+// starting from 1 * 2^shift * G.
+func makeMultiples(curve elliptic.Curve, n, shift int) [][2]*big.Int {
+	ret := make([][2]*big.Int, n)
+	x, y := curve.Params().Gx, curve.Params().Gy
+	for j := 0; j < shift; j++ {
+		x, y = curve.Double(x, y)
+	}
+	ret[1-1] = [2]*big.Int{x, y}
+	for i := 2; i <= n; i++ {
+		if i&1 == 0 {
+			x, y := curve.Double(ret[i/2-1][0], ret[i/2-1][1])
+			ret[i-1] = [2]*big.Int{x, y}
+		} else {
+			x, y := curve.Add(ret[i-1-1][0], ret[i-1-1][1], ret[1-1][0], ret[1-1][1])
+			ret[i-1] = [2]*big.Int{x, y}
+		}
+	}
+	return ret
+}
+
+// makeComb returns a table of 2^size - 1 points. The i-1th entry is k*G.
+// If i is represented in binary by b0*2^0 + b1*2^1 + ... bn*2^n, k is
+// b0*2^(shift + 0*stride) + b1*2^(shift + 1*stride) + ... + bn*2^(shift + n*stride).
+// The entry for i = 0 is omitted because it is always the point at infinity.
+func makeComb(curve elliptic.Curve, stride, size, shift int) [][2]*big.Int {
+	ret := make([][2]*big.Int, 1<<size-1)
+	x, y := curve.Params().Gx, curve.Params().Gy
+	for j := 0; j < shift; j++ {
+		x, y = curve.Double(x, y)
+	}
+	ret[1<<0-1] = [2]*big.Int{x, y}
+	for i := 1; i < size; i++ {
+		// Entry 2^i is entry 2^(i-1) doubled stride times.
+		x, y = ret[1<<(i-1)-1][0], ret[1<<(i-1)-1][1]
+		for j := 0; j < stride; j++ {
+			x, y = curve.Double(x, y)
+		}
+		ret[1<<i-1] = [2]*big.Int{x, y}
+		// The remaining entries with MSB 2^i are computed by adding entry 2^i
+		// to the corresponding previous entry.
+		for j := 1; j < 1<<i; j++ {
+			x, y = curve.Add(ret[1<<i-1][0], ret[1<<i-1][1], ret[j-1][0], ret[j-1][1])
+			ret[1<<i+j-1] = [2]*big.Int{x, y}
+		}
+	}
+	return ret
+}
+
+// toMontgomery sets n to be n×R mod p, where R is the Montgomery factor.
+func toMontgomery(curve elliptic.Curve, n *big.Int) *big.Int {
+	params := curve.Params()
+	// R is the bit width of p, rounded up to word size.
+	rounded64 := 64 * ((params.BitSize + 63) / 64)
+	rounded32 := 32 * ((params.BitSize + 31) / 32)
+	if rounded64 != rounded32 {
+		panic(fmt.Sprintf("Montgomery form for %s is inconsistent between 32-bit and 64-bit", params.Name))
+	}
+	R := new(big.Int).SetInt64(1)
+	R.Lsh(R, uint(rounded64))
+
+	ret := new(big.Int).Mul(n, R)
+	ret.Mod(ret, params.P)
+	return ret
+}
+
+func bigIntToU64s(curve elliptic.Curve, n *big.Int) []uint64 {
+	words := (curve.Params().BitSize + 63) / 64
+	ret := make([]uint64, words)
+	bytes := n.Bytes()
+	for i, b := range bytes {
+		i = len(bytes) - i - 1
+		ret[i/8] |= uint64(b) << (8 * (i % 8))
+	}
+	return ret
+}
+
+func bigIntToU32s(curve elliptic.Curve, n *big.Int) []uint64 {
+	words := (curve.Params().BitSize + 31) / 32
+	ret := make([]uint64, words)
+	bytes := n.Bytes()
+	for i, b := range bytes {
+		i = len(bytes) - i - 1
+		ret[i/4] |= uint64(b) << (8 * (i % 4))
+	}
+	return ret
+}
+
+func writeIndent(w io.Writer, indent int) error {
+	for i := 0; i < indent; i++ {
+		if _, err := io.WriteString(w, " "); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func writeWords(w io.Writer, words []uint64, wrap, indent int, format func(uint64) string) error {
+	if _, err := io.WriteString(w, "{"); err != nil {
+		return err
+	}
+	for i, word := range words {
+		if i > 0 {
+			if i%wrap == 0 {
+				if _, err := io.WriteString(w, ",\n"); err != nil {
+					return err
+				}
+				if err := writeIndent(w, indent+1); err != nil {
+					return err
+				}
+			} else {
+				if _, err := io.WriteString(w, ", "); err != nil {
+					return err
+				}
+			}
+		}
+		if _, err := io.WriteString(w, format(word)); err != nil {
+			return err
+		}
+	}
+	if _, err := io.WriteString(w, "}"); err != nil {
+		return err
+	}
+	return nil
+}
+
+func writeBNMont(w io.Writer, curve elliptic.Curve, n *big.Int, indent int) error {
+	n = toMontgomery(curve, n)
+	return writeWords(w, bigIntToU64s(curve, n), 2, indent, func(word uint64) string {
+		return fmt.Sprintf("TOBN(0x%08x, 0x%08x)", uint32(word>>32), uint32(word))
+	})
+}
+
+func writeU64Mont(w io.Writer, curve elliptic.Curve, n *big.Int, indent int) error {
+	n = toMontgomery(curve, n)
+	return writeWords(w, bigIntToU64s(curve, n), 3, indent, func(word uint64) string {
+		return fmt.Sprintf("0x%016x", word)
+	})
+}
+
+func writeU32Mont(w io.Writer, curve elliptic.Curve, n *big.Int, indent int) error {
+	n = toMontgomery(curve, n)
+	return writeWords(w, bigIntToU32s(curve, n), 6, indent, func(word uint64) string {
+		if word >= 1<<32 {
+			panic(fmt.Sprintf("word too large: 0x%x", word))
+		}
+		return fmt.Sprintf("0x%08x", word)
+	})
+}
+
+type writeBigIntFunc func(w io.Writer, curve elliptic.Curve, n *big.Int, indent int) error
+
+func writeTable(w io.Writer, curve elliptic.Curve, table [][2]*big.Int, isRoot bool, indent int, writeBigInt writeBigIntFunc) error {
+	if _, err := io.WriteString(w, "{"); err != nil {
+		return err
+	}
+	if isRoot {
+		if _, err := io.WriteString(w, "\n"); err != nil {
+			return err
+		}
+		if err := writeIndent(w, indent); err != nil {
+			return err
+		}
+	} else {
+		indent++
+	}
+	for i, point := range table {
+		if i != 0 {
+			if _, err := io.WriteString(w, ",\n"); err != nil {
+				return err
+			}
+			if err := writeIndent(w, indent); err != nil {
+				return err
+			}
+		}
+		if _, err := io.WriteString(w, "{"); err != nil {
+			return err
+		}
+		if err := writeBigInt(w, curve, point[0], indent+1); err != nil {
+			return err
+		}
+		if _, err := io.WriteString(w, ",\n"); err != nil {
+			return err
+		}
+		if err := writeIndent(w, indent+1); err != nil {
+			return err
+		}
+		if err := writeBigInt(w, curve, point[1], indent+1); err != nil {
+			return err
+		}
+		if _, err := io.WriteString(w, "}"); err != nil {
+			return err
+		}
+	}
+	if _, err := io.WriteString(w, "}"); err != nil {
+		return err
+	}
+	return nil
+}
+
+func writeTables(w io.Writer, curve elliptic.Curve, tables [][][2]*big.Int, isRoot bool, indent int, writeBigInt writeBigIntFunc) error {
+	if _, err := io.WriteString(w, "{"); err != nil {
+		return err
+	}
+	if isRoot {
+		if _, err := io.WriteString(w, "\n"); err != nil {
+			return err
+		}
+		if err := writeIndent(w, indent); err != nil {
+			return err
+		}
+	} else {
+		indent++
+	}
+	for i, table := range tables {
+		if i != 0 {
+			if _, err := io.WriteString(w, ",\n"); err != nil {
+				return err
+			}
+			if err := writeIndent(w, indent); err != nil {
+				return err
+			}
+		}
+		if err := writeTable(w, curve, table, false, indent, writeBigInt); err != nil {
+			return err
+		}
+	}
+	if _, err := io.WriteString(w, "}"); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/crypto/fipsmodule/ec/p256-x86_64-table.h b/crypto/fipsmodule/ec/p256-x86_64-table.h
index ac0d657..357045f 100644
--- a/crypto/fipsmodule/ec/p256-x86_64-table.h
+++ b/crypto/fipsmodule/ec/p256-x86_64-table.h
@@ -20,7 +20,7 @@
 // in order to increase the chances of using a large page but that appears to
 // lead to invalid ELF files being produced.
 
-// This file is generated by make_p256-x86_64-table.go.
+// This file is generated by make_tables.go.
 
 static const alignas(4096) PRECOMP256_ROW ecp_nistz256_precomputed[37] = {
         {{{TOBN(0x79e730d4, 0x18a9143c), TOBN(0x75ba95fc, 0x5fedb601),
diff --git a/crypto/fipsmodule/ec/p256.c b/crypto/fipsmodule/ec/p256.c
index 542550f..9355ac1 100644
--- a/crypto/fipsmodule/ec/p256.c
+++ b/crypto/fipsmodule/ec/p256.c
@@ -44,16 +44,17 @@
 // utility functions, handwritten
 
 #if defined(BORINGSSL_NISTP256_64BIT)
-
 #define FIAT_P256_NLIMBS 4
 typedef uint64_t fiat_p256_limb_t;
 typedef uint64_t fiat_p256_felem[FIAT_P256_NLIMBS];
+static const fiat_p256_felem fiat_p256_one = {0x1, 0xffffffff00000000,
+                                              0xffffffffffffffff, 0xfffffffe};
 #else  // 64BIT; else 32BIT
-
 #define FIAT_P256_NLIMBS 8
 typedef uint32_t fiat_p256_limb_t;
 typedef uint32_t fiat_p256_felem[FIAT_P256_NLIMBS];
-
+static const fiat_p256_felem fiat_p256_one = {
+    0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0};
 #endif  // 64BIT
 
 
@@ -360,355 +361,22 @@
   fiat_p256_cmovznz(z3, z2nz, z1, z_out);
 }
 
-// Base point pre computation
-// --------------------------
-//
-// Two different sorts of precomputed tables are used in the following code.
-// Each contain various points on the curve, where each point is three field
-// elements (x, y, z).
-//
-// For the base point table, z is usually 1 (0 for the point at infinity).
-// This table has 2 * 16 elements, starting with the following:
-// index | bits    | point
-// ------+---------+------------------------------
-//     0 | 0 0 0 0 | 0G
-//     1 | 0 0 0 1 | 1G
-//     2 | 0 0 1 0 | 2^64G
-//     3 | 0 0 1 1 | (2^64 + 1)G
-//     4 | 0 1 0 0 | 2^128G
-//     5 | 0 1 0 1 | (2^128 + 1)G
-//     6 | 0 1 1 0 | (2^128 + 2^64)G
-//     7 | 0 1 1 1 | (2^128 + 2^64 + 1)G
-//     8 | 1 0 0 0 | 2^192G
-//     9 | 1 0 0 1 | (2^192 + 1)G
-//    10 | 1 0 1 0 | (2^192 + 2^64)G
-//    11 | 1 0 1 1 | (2^192 + 2^64 + 1)G
-//    12 | 1 1 0 0 | (2^192 + 2^128)G
-//    13 | 1 1 0 1 | (2^192 + 2^128 + 1)G
-//    14 | 1 1 1 0 | (2^192 + 2^128 + 2^64)G
-//    15 | 1 1 1 1 | (2^192 + 2^128 + 2^64 + 1)G
-// followed by a copy of this with each element multiplied by 2^32.
-//
-// The reason for this is so that we can clock bits into four different
-// locations when doing simple scalar multiplies against the base point,
-// and then another four locations using the second 16 elements.
-//
-// Tables for other points have table[i] = iG for i in 0 .. 16.
+#include "./p256_table.h"
 
-// fiat_p256_g_pre_comp is the table of precomputed base points
-#if defined(BORINGSSL_NISTP256_64BIT)
-static const fiat_p256_felem fiat_p256_g_pre_comp[2][16][3] = {
-    {{{0x0, 0x0, 0x0, 0x0}, {0x0, 0x0, 0x0, 0x0}, {0x0, 0x0, 0x0, 0x0}},
-     {{0x79e730d418a9143c, 0x75ba95fc5fedb601, 0x79fb732b77622510,
-       0x18905f76a53755c6},
-      {0xddf25357ce95560a, 0x8b4ab8e4ba19e45c, 0xd2e88688dd21f325,
-       0x8571ff1825885d85},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0x4f922fc516a0d2bb, 0xd5cc16c1a623499, 0x9241cf3a57c62c8b,
-       0x2f5e6961fd1b667f},
-      {0x5c15c70bf5a01797, 0x3d20b44d60956192, 0x4911b37071fdb52,
-       0xf648f9168d6f0f7b},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0x9e566847e137bbbc, 0xe434469e8a6a0bec, 0xb1c4276179d73463,
-       0x5abe0285133d0015},
-      {0x92aa837cc04c7dab, 0x573d9f4c43260c07, 0xc93156278e6cc37,
-       0x94bb725b6b6f7383},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0x62a8c244bfe20925, 0x91c19ac38fdce867, 0x5a96a5d5dd387063,
-       0x61d587d421d324f6},
-      {0xe87673a2a37173ea, 0x2384800853778b65, 0x10f8441e05bab43e,
-       0xfa11fe124621efbe},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0x1c891f2b2cb19ffd, 0x1ba8d5bb1923c23, 0xb6d03d678ac5ca8e,
-       0x586eb04c1f13bedc},
-      {0xc35c6e527e8ed09, 0x1e81a33c1819ede2, 0x278fd6c056c652fa,
-       0x19d5ac0870864f11},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0x62577734d2b533d5, 0x673b8af6a1bdddc0, 0x577e7c9aa79ec293,
-       0xbb6de651c3b266b1},
-      {0xe7e9303ab65259b3, 0xd6a0afd3d03a7480, 0xc5ac83d19b3cfc27,
-       0x60b4619a5d18b99b},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0xbd6a38e11ae5aa1c, 0xb8b7652b49e73658, 0xb130014ee5f87ed,
-       0x9d0f27b2aeebffcd},
-      {0xca9246317a730a55, 0x9c955b2fddbbc83a, 0x7c1dfe0ac019a71,
-       0x244a566d356ec48d},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0x56f8410ef4f8b16a, 0x97241afec47b266a, 0xa406b8e6d9c87c1,
-       0x803f3e02cd42ab1b},
-      {0x7f0309a804dbec69, 0xa83b85f73bbad05f, 0xc6097273ad8e197f,
-       0xc097440e5067adc1},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0x846a56f2c379ab34, 0xa8ee068b841df8d1, 0x20314459176c68ef,
-       0xf1af32d5915f1f30},
-      {0x99c375315d75bd50, 0x837cffbaf72f67bc, 0x613a41848d7723f,
-       0x23d0f130e2d41c8b},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0xed93e225d5be5a2b, 0x6fe799835934f3c6, 0x4314092622626ffc,
-       0x50bbb4d97990216a},
-      {0x378191c6e57ec63e, 0x65422c40181dcdb2, 0x41a8099b0236e0f6,
-       0x2b10011801fe49c3},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0xfc68b5c59b391593, 0xc385f5a2598270fc, 0x7144f3aad19adcbb,
-       0xdd55899983fbae0c},
-      {0x93b88b8e74b82ff4, 0xd2e03c4071e734c9, 0x9a7a9eaf43c0322a,
-       0xe6e4c551149d6041},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0x5fe14bfe80ec21fe, 0xf6ce116ac255be82, 0x98bc5a072f4a5d67,
-       0xfad27148db7e63af},
-      {0x90c0b6ac29ab05b3, 0x37a9a83c4e251ae6, 0xa7dc875c2aade7d,
-       0x77387de39f0e1a84},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0x1e9ecc49a56c0dd7, 0xa5cffcd846086c74, 0x8f7a1408f505aece,
-       0xb37b85c0bef0c47e},
-      {0x3596b6e4cc0e6a8f, 0xfd6d4bbf6b388f23, 0xaba453fac39cef4e,
-       0x9c135ac8f9f628d5},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0xa1c729495c8f8be, 0x2961c4803bf362bf, 0x9e418403df63d4ac,
-       0xc109f9cb91ece900},
-      {0xc2d095d058945705, 0xb9083d96ddeb85c0, 0x84692b8d7a40449b,
-       0x9bc3344f2eee1ee1},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0xd5ae35642913074, 0x55491b2748a542b1, 0x469ca665b310732a,
-       0x29591d525f1a4cc1},
-      {0xe76f5b6bb84f983f, 0xbe7eef419f5f84e1, 0x1200d49680baa189,
-       0x6376551f18ef332c},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}}},
-    {{{0x0, 0x0, 0x0, 0x0}, {0x0, 0x0, 0x0, 0x0}, {0x0, 0x0, 0x0, 0x0}},
-     {{0x202886024147519a, 0xd0981eac26b372f0, 0xa9d4a7caa785ebc8,
-       0xd953c50ddbdf58e9},
-      {0x9d6361ccfd590f8f, 0x72e9626b44e6c917, 0x7fd9611022eb64cf,
-       0x863ebb7e9eb288f3},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0x4fe7ee31b0e63d34, 0xf4600572a9e54fab, 0xc0493334d5e7b5a4,
-       0x8589fb9206d54831},
-      {0xaa70f5cc6583553a, 0x879094ae25649e5, 0xcc90450710044652,
-       0xebb0696d02541c4f},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0xabbaa0c03b89da99, 0xa6f2d79eb8284022, 0x27847862b81c05e8,
-       0x337a4b5905e54d63},
-      {0x3c67500d21f7794a, 0x207005b77d6d7f61, 0xa5a378104cfd6e8,
-       0xd65e0d5f4c2fbd6},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0xd433e50f6d3549cf, 0x6f33696ffacd665e, 0x695bfdacce11fcb4,
-       0x810ee252af7c9860},
-      {0x65450fe17159bb2c, 0xf7dfbebe758b357b, 0x2b057e74d69fea72,
-       0xd485717a92731745},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0xce1f69bbe83f7669, 0x9f8ae8272877d6b, 0x9548ae543244278d,
-       0x207755dee3c2c19c},
-      {0x87bd61d96fef1945, 0x18813cefb12d28c3, 0x9fbcd1d672df64aa,
-       0x48dc5ee57154b00d},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0xef0f469ef49a3154, 0x3e85a5956e2b2e9a, 0x45aaec1eaa924a9c,
-       0xaa12dfc8a09e4719},
-      {0x26f272274df69f1d, 0xe0e4c82ca2ff5e73, 0xb9d8ce73b7a9dd44,
-       0x6c036e73e48ca901},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0xe1e421e1a47153f0, 0xb86c3b79920418c9, 0x93bdce87705d7672,
-       0xf25ae793cab79a77},
-      {0x1f3194a36d869d0c, 0x9d55c8824986c264, 0x49fb5ea3096e945e,
-       0x39b8e65313db0a3e},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0xe3417bc035d0b34a, 0x440b386b8327c0a7, 0x8fb7262dac0362d1,
-       0x2c41114ce0cdf943},
-      {0x2ba5cef1ad95a0b1, 0xc09b37a867d54362, 0x26d6cdd201e486c9,
-       0x20477abf42ff9297},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0xf121b41bc0a67d2, 0x62d4760a444d248a, 0xe044f1d659b4737,
-       0x8fde365250bb4a8},
-      {0xaceec3da848bf287, 0xc2a62182d3369d6e, 0x3582dfdc92449482,
-       0x2f7e2fd2565d6cd7},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0xa0122b5178a876b, 0x51ff96ff085104b4, 0x50b31ab14f29f76,
-       0x84abb28b5f87d4e6},
-      {0xd5ed439f8270790a, 0x2d6cb59d85e3f46b, 0x75f55c1b6c1e2212,
-       0xe5436f6717655640},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0xc2965ecc9aeb596d, 0x1ea03e7023c92b4, 0x4704b4b62e013961,
-       0xca8fd3f905ea367},
-      {0x92523a42551b2b61, 0x1eb7a89c390fcd06, 0xe7f1d2be0392a63e,
-       0x96dca2644ddb0c33},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0x231c210e15339848, 0xe87a28e870778c8d, 0x9d1de6616956e170,
-       0x4ac3c9382bb09c0b},
-      {0x19be05516998987d, 0x8b2376c4ae09f4d6, 0x1de0b7651a3f933d,
-       0x380d94c7e39705f4},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0x3685954b8c31c31d, 0x68533d005bf21a0c, 0xbd7626e75c79ec9,
-       0xca17754742c69d54},
-      {0xcc6edafff6d2dbb2, 0xfd0d8cbd174a9d18, 0x875e8793aa4578e8,
-       0xa976a7139cab2ce6},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0xce37ab11b43ea1db, 0xa7ff1a95259d292, 0x851b02218f84f186,
-       0xa7222beadefaad13},
-      {0xa2ac78ec2b0a9144, 0x5a024051f2fa59c5, 0x91d1eca56147ce38,
-       0xbe94d523bc2ac690},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}},
-     {{0x2d8daefd79ec1a0f, 0x3bbcd6fdceb39c97, 0xf5575ffc58f61a95,
-       0xdbd986c4adf7b420},
-      {0x81aa881415f39eb7, 0x6ee2fcf5b98d976c, 0x5465475dcf2f717d,
-       0x8e24d3c46860bbd0},
-      {0x1, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffe}}}};
-#else
-static const fiat_p256_felem fiat_p256_g_pre_comp[2][16][3] = {
-    {{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
-      {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
-      {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
-     {{0x18a9143c, 0x79e730d4, 0x5fedb601, 0x75ba95fc, 0x77622510, 0x79fb732b,
-       0xa53755c6, 0x18905f76},
-      {0xce95560a, 0xddf25357, 0xba19e45c, 0x8b4ab8e4, 0xdd21f325, 0xd2e88688,
-       0x25885d85, 0x8571ff18},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0x16a0d2bb, 0x4f922fc5, 0x1a623499, 0xd5cc16c, 0x57c62c8b, 0x9241cf3a,
-       0xfd1b667f, 0x2f5e6961},
-      {0xf5a01797, 0x5c15c70b, 0x60956192, 0x3d20b44d, 0x71fdb52, 0x4911b37,
-       0x8d6f0f7b, 0xf648f916},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0xe137bbbc, 0x9e566847, 0x8a6a0bec, 0xe434469e, 0x79d73463, 0xb1c42761,
-       0x133d0015, 0x5abe0285},
-      {0xc04c7dab, 0x92aa837c, 0x43260c07, 0x573d9f4c, 0x78e6cc37, 0xc931562,
-       0x6b6f7383, 0x94bb725b},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0xbfe20925, 0x62a8c244, 0x8fdce867, 0x91c19ac3, 0xdd387063, 0x5a96a5d5,
-       0x21d324f6, 0x61d587d4},
-      {0xa37173ea, 0xe87673a2, 0x53778b65, 0x23848008, 0x5bab43e, 0x10f8441e,
-       0x4621efbe, 0xfa11fe12},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0x2cb19ffd, 0x1c891f2b, 0xb1923c23, 0x1ba8d5b, 0x8ac5ca8e, 0xb6d03d67,
-       0x1f13bedc, 0x586eb04c},
-      {0x27e8ed09, 0xc35c6e5, 0x1819ede2, 0x1e81a33c, 0x56c652fa, 0x278fd6c0,
-       0x70864f11, 0x19d5ac08},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0xd2b533d5, 0x62577734, 0xa1bdddc0, 0x673b8af6, 0xa79ec293, 0x577e7c9a,
-       0xc3b266b1, 0xbb6de651},
-      {0xb65259b3, 0xe7e9303a, 0xd03a7480, 0xd6a0afd3, 0x9b3cfc27, 0xc5ac83d1,
-       0x5d18b99b, 0x60b4619a},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0x1ae5aa1c, 0xbd6a38e1, 0x49e73658, 0xb8b7652b, 0xee5f87ed, 0xb130014,
-       0xaeebffcd, 0x9d0f27b2},
-      {0x7a730a55, 0xca924631, 0xddbbc83a, 0x9c955b2f, 0xac019a71, 0x7c1dfe0,
-       0x356ec48d, 0x244a566d},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0xf4f8b16a, 0x56f8410e, 0xc47b266a, 0x97241afe, 0x6d9c87c1, 0xa406b8e,
-       0xcd42ab1b, 0x803f3e02},
-      {0x4dbec69, 0x7f0309a8, 0x3bbad05f, 0xa83b85f7, 0xad8e197f, 0xc6097273,
-       0x5067adc1, 0xc097440e},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0xc379ab34, 0x846a56f2, 0x841df8d1, 0xa8ee068b, 0x176c68ef, 0x20314459,
-       0x915f1f30, 0xf1af32d5},
-      {0x5d75bd50, 0x99c37531, 0xf72f67bc, 0x837cffba, 0x48d7723f, 0x613a418,
-       0xe2d41c8b, 0x23d0f130},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0xd5be5a2b, 0xed93e225, 0x5934f3c6, 0x6fe79983, 0x22626ffc, 0x43140926,
-       0x7990216a, 0x50bbb4d9},
-      {0xe57ec63e, 0x378191c6, 0x181dcdb2, 0x65422c40, 0x236e0f6, 0x41a8099b,
-       0x1fe49c3, 0x2b100118},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0x9b391593, 0xfc68b5c5, 0x598270fc, 0xc385f5a2, 0xd19adcbb, 0x7144f3aa,
-       0x83fbae0c, 0xdd558999},
-      {0x74b82ff4, 0x93b88b8e, 0x71e734c9, 0xd2e03c40, 0x43c0322a, 0x9a7a9eaf,
-       0x149d6041, 0xe6e4c551},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0x80ec21fe, 0x5fe14bfe, 0xc255be82, 0xf6ce116a, 0x2f4a5d67, 0x98bc5a07,
-       0xdb7e63af, 0xfad27148},
-      {0x29ab05b3, 0x90c0b6ac, 0x4e251ae6, 0x37a9a83c, 0xc2aade7d, 0xa7dc875,
-       0x9f0e1a84, 0x77387de3},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0xa56c0dd7, 0x1e9ecc49, 0x46086c74, 0xa5cffcd8, 0xf505aece, 0x8f7a1408,
-       0xbef0c47e, 0xb37b85c0},
-      {0xcc0e6a8f, 0x3596b6e4, 0x6b388f23, 0xfd6d4bbf, 0xc39cef4e, 0xaba453fa,
-       0xf9f628d5, 0x9c135ac8},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0x95c8f8be, 0xa1c7294, 0x3bf362bf, 0x2961c480, 0xdf63d4ac, 0x9e418403,
-       0x91ece900, 0xc109f9cb},
-      {0x58945705, 0xc2d095d0, 0xddeb85c0, 0xb9083d96, 0x7a40449b, 0x84692b8d,
-       0x2eee1ee1, 0x9bc3344f},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0x42913074, 0xd5ae356, 0x48a542b1, 0x55491b27, 0xb310732a, 0x469ca665,
-       0x5f1a4cc1, 0x29591d52},
-      {0xb84f983f, 0xe76f5b6b, 0x9f5f84e1, 0xbe7eef41, 0x80baa189, 0x1200d496,
-       0x18ef332c, 0x6376551f},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}}},
-    {{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
-      {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
-      {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
-     {{0x4147519a, 0x20288602, 0x26b372f0, 0xd0981eac, 0xa785ebc8, 0xa9d4a7ca,
-       0xdbdf58e9, 0xd953c50d},
-      {0xfd590f8f, 0x9d6361cc, 0x44e6c917, 0x72e9626b, 0x22eb64cf, 0x7fd96110,
-       0x9eb288f3, 0x863ebb7e},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0xb0e63d34, 0x4fe7ee31, 0xa9e54fab, 0xf4600572, 0xd5e7b5a4, 0xc0493334,
-       0x6d54831, 0x8589fb92},
-      {0x6583553a, 0xaa70f5cc, 0xe25649e5, 0x879094a, 0x10044652, 0xcc904507,
-       0x2541c4f, 0xebb0696d},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0x3b89da99, 0xabbaa0c0, 0xb8284022, 0xa6f2d79e, 0xb81c05e8, 0x27847862,
-       0x5e54d63, 0x337a4b59},
-      {0x21f7794a, 0x3c67500d, 0x7d6d7f61, 0x207005b7, 0x4cfd6e8, 0xa5a3781,
-       0xf4c2fbd6, 0xd65e0d5},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0x6d3549cf, 0xd433e50f, 0xfacd665e, 0x6f33696f, 0xce11fcb4, 0x695bfdac,
-       0xaf7c9860, 0x810ee252},
-      {0x7159bb2c, 0x65450fe1, 0x758b357b, 0xf7dfbebe, 0xd69fea72, 0x2b057e74,
-       0x92731745, 0xd485717a},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0xe83f7669, 0xce1f69bb, 0x72877d6b, 0x9f8ae82, 0x3244278d, 0x9548ae54,
-       0xe3c2c19c, 0x207755de},
-      {0x6fef1945, 0x87bd61d9, 0xb12d28c3, 0x18813cef, 0x72df64aa, 0x9fbcd1d6,
-       0x7154b00d, 0x48dc5ee5},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0xf49a3154, 0xef0f469e, 0x6e2b2e9a, 0x3e85a595, 0xaa924a9c, 0x45aaec1e,
-       0xa09e4719, 0xaa12dfc8},
-      {0x4df69f1d, 0x26f27227, 0xa2ff5e73, 0xe0e4c82c, 0xb7a9dd44, 0xb9d8ce73,
-       0xe48ca901, 0x6c036e73},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0xa47153f0, 0xe1e421e1, 0x920418c9, 0xb86c3b79, 0x705d7672, 0x93bdce87,
-       0xcab79a77, 0xf25ae793},
-      {0x6d869d0c, 0x1f3194a3, 0x4986c264, 0x9d55c882, 0x96e945e, 0x49fb5ea3,
-       0x13db0a3e, 0x39b8e653},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0x35d0b34a, 0xe3417bc0, 0x8327c0a7, 0x440b386b, 0xac0362d1, 0x8fb7262d,
-       0xe0cdf943, 0x2c41114c},
-      {0xad95a0b1, 0x2ba5cef1, 0x67d54362, 0xc09b37a8, 0x1e486c9, 0x26d6cdd2,
-       0x42ff9297, 0x20477abf},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0xbc0a67d2, 0xf121b41, 0x444d248a, 0x62d4760a, 0x659b4737, 0xe044f1d,
-       0x250bb4a8, 0x8fde365},
-      {0x848bf287, 0xaceec3da, 0xd3369d6e, 0xc2a62182, 0x92449482, 0x3582dfdc,
-       0x565d6cd7, 0x2f7e2fd2},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0x178a876b, 0xa0122b5, 0x85104b4, 0x51ff96ff, 0x14f29f76, 0x50b31ab,
-       0x5f87d4e6, 0x84abb28b},
-      {0x8270790a, 0xd5ed439f, 0x85e3f46b, 0x2d6cb59d, 0x6c1e2212, 0x75f55c1b,
-       0x17655640, 0xe5436f67},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0x9aeb596d, 0xc2965ecc, 0x23c92b4, 0x1ea03e7, 0x2e013961, 0x4704b4b6,
-       0x905ea367, 0xca8fd3f},
-      {0x551b2b61, 0x92523a42, 0x390fcd06, 0x1eb7a89c, 0x392a63e, 0xe7f1d2be,
-       0x4ddb0c33, 0x96dca264},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0x15339848, 0x231c210e, 0x70778c8d, 0xe87a28e8, 0x6956e170, 0x9d1de661,
-       0x2bb09c0b, 0x4ac3c938},
-      {0x6998987d, 0x19be0551, 0xae09f4d6, 0x8b2376c4, 0x1a3f933d, 0x1de0b765,
-       0xe39705f4, 0x380d94c7},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0x8c31c31d, 0x3685954b, 0x5bf21a0c, 0x68533d00, 0x75c79ec9, 0xbd7626e,
-       0x42c69d54, 0xca177547},
-      {0xf6d2dbb2, 0xcc6edaff, 0x174a9d18, 0xfd0d8cbd, 0xaa4578e8, 0x875e8793,
-       0x9cab2ce6, 0xa976a713},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0xb43ea1db, 0xce37ab11, 0x5259d292, 0xa7ff1a9, 0x8f84f186, 0x851b0221,
-       0xdefaad13, 0xa7222bea},
-      {0x2b0a9144, 0xa2ac78ec, 0xf2fa59c5, 0x5a024051, 0x6147ce38, 0x91d1eca5,
-       0xbc2ac690, 0xbe94d523},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}},
-     {{0x79ec1a0f, 0x2d8daefd, 0xceb39c97, 0x3bbcd6fd, 0x58f61a95, 0xf5575ffc,
-       0xadf7b420, 0xdbd986c4},
-      {0x15f39eb7, 0x81aa8814, 0xb98d976c, 0x6ee2fcf5, 0xcf2f717d, 0x5465475d,
-       0x6860bbd0, 0x8e24d3c4},
-      {0x1, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0x0}}}};
-#endif
+// fiat_p256_select_point_affine selects the |idx-1|th point from a
+// precomputation table and copies it to out. If |idx| is zero, the output is
+// the point at infinity.
+static void fiat_p256_select_point_affine(
+    const fiat_p256_limb_t idx, size_t size,
+    const fiat_p256_felem pre_comp[/*size*/][2], fiat_p256_felem out[3]) {
+  OPENSSL_memset(out, 0, sizeof(fiat_p256_felem) * 3);
+  for (size_t i = 0; i < size; i++) {
+    fiat_p256_limb_t mismatch = i ^ (idx - 1);
+    fiat_p256_cmovznz(out[0], mismatch, pre_comp[i][0], out[0]);
+    fiat_p256_cmovznz(out[1], mismatch, pre_comp[i][1], out[1]);
+  }
+  fiat_p256_cmovznz(out[2], idx, out[2], fiat_p256_one);
+}
 
 // fiat_p256_select_point selects the |idx|th point from a precomputation table
 // and copies it to out.
@@ -880,7 +548,7 @@
     bits |= fiat_p256_get_bit(scalar->bytes, i + 96) << 1;
     bits |= fiat_p256_get_bit(scalar->bytes, i + 32);
     // Select the point to add, in constant time.
-    fiat_p256_select_point(bits, 16, fiat_p256_g_pre_comp[1], tmp);
+    fiat_p256_select_point_affine(bits, 15, fiat_p256_g_pre_comp[1], tmp);
 
     if (!skip) {
       fiat_p256_point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2],
@@ -898,7 +566,7 @@
     bits |= fiat_p256_get_bit(scalar->bytes, i + 64) << 1;
     bits |= fiat_p256_get_bit(scalar->bytes, i);
     // Select the point to add, in constant time.
-    fiat_p256_select_point(bits, 16, fiat_p256_g_pre_comp[0], tmp);
+    fiat_p256_select_point_affine(bits, 15, fiat_p256_g_pre_comp[0], tmp);
     fiat_p256_point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 1 /* mixed */,
                         tmp[0], tmp[1], tmp[2]);
   }
@@ -949,21 +617,26 @@
       bits |= fiat_p256_get_bit(g_scalar->bytes, i + 160) << 2;
       bits |= fiat_p256_get_bit(g_scalar->bytes, i + 96) << 1;
       bits |= fiat_p256_get_bit(g_scalar->bytes, i + 32);
-      fiat_p256_point_add(ret[0], ret[1], ret[2], ret[0], ret[1], ret[2],
-                          1 /* mixed */, fiat_p256_g_pre_comp[1][bits][0],
-                          fiat_p256_g_pre_comp[1][bits][1],
-                          fiat_p256_g_pre_comp[1][bits][2]);
-      skip = 0;
+      if (bits != 0) {
+        fiat_p256_point_add(ret[0], ret[1], ret[2], ret[0], ret[1], ret[2],
+                            1 /* mixed */, fiat_p256_g_pre_comp[1][bits - 1][0],
+                            fiat_p256_g_pre_comp[1][bits - 1][1],
+                            fiat_p256_one);
+        skip = 0;
+      }
 
       // Second, look at the current position.
       bits = fiat_p256_get_bit(g_scalar->bytes, i + 192) << 3;
       bits |= fiat_p256_get_bit(g_scalar->bytes, i + 128) << 2;
       bits |= fiat_p256_get_bit(g_scalar->bytes, i + 64) << 1;
       bits |= fiat_p256_get_bit(g_scalar->bytes, i);
-      fiat_p256_point_add(ret[0], ret[1], ret[2], ret[0], ret[1], ret[2],
-                          1 /* mixed */, fiat_p256_g_pre_comp[0][bits][0],
-                          fiat_p256_g_pre_comp[0][bits][1],
-                          fiat_p256_g_pre_comp[0][bits][2]);
+      if (bits != 0) {
+        fiat_p256_point_add(ret[0], ret[1], ret[2], ret[0], ret[1], ret[2],
+                            1 /* mixed */, fiat_p256_g_pre_comp[0][bits - 1][0],
+                            fiat_p256_g_pre_comp[0][bits - 1][1],
+                            fiat_p256_one);
+        skip = 0;
+      }
     }
 
     int digit = p_wNAF[i];
diff --git a/crypto/fipsmodule/ec/p256_table.h b/crypto/fipsmodule/ec/p256_table.h
new file mode 100644
index 0000000..14129a3
--- /dev/null
+++ b/crypto/fipsmodule/ec/p256_table.h
@@ -0,0 +1,297 @@
+/* Copyright (c) 2020, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+// This file is generated by make_tables.go.
+
+// Base point pre computation
+// --------------------------
+//
+// Two different sorts of precomputed tables are used in the following code.
+// Each contain various points on the curve, where each point is three field
+// elements (x, y, z).
+//
+// For the base point table, z is usually 1 (0 for the point at infinity).
+// This table has 2 * 16 elements, starting with the following:
+// index | bits    | point
+// ------+---------+------------------------------
+//     0 | 0 0 0 0 | 0G
+//     1 | 0 0 0 1 | 1G
+//     2 | 0 0 1 0 | 2^64G
+//     3 | 0 0 1 1 | (2^64 + 1)G
+//     4 | 0 1 0 0 | 2^128G
+//     5 | 0 1 0 1 | (2^128 + 1)G
+//     6 | 0 1 1 0 | (2^128 + 2^64)G
+//     7 | 0 1 1 1 | (2^128 + 2^64 + 1)G
+//     8 | 1 0 0 0 | 2^192G
+//     9 | 1 0 0 1 | (2^192 + 1)G
+//    10 | 1 0 1 0 | (2^192 + 2^64)G
+//    11 | 1 0 1 1 | (2^192 + 2^64 + 1)G
+//    12 | 1 1 0 0 | (2^192 + 2^128)G
+//    13 | 1 1 0 1 | (2^192 + 2^128 + 1)G
+//    14 | 1 1 1 0 | (2^192 + 2^128 + 2^64)G
+//    15 | 1 1 1 1 | (2^192 + 2^128 + 2^64 + 1)G
+// followed by a copy of this with each element multiplied by 2^32.
+//
+// The reason for this is so that we can clock bits into four different
+// locations when doing simple scalar multiplies against the base point,
+// and then another four locations using the second 16 elements.
+//
+// Tables for other points have table[i] = iG for i in 0 .. 16.
+
+// fiat_p256_g_pre_comp is the table of precomputed base points
+#if defined(BORINGSSL_NISTP256_64BIT)
+static const fiat_p256_felem fiat_p256_g_pre_comp[2][15][2] = {
+    {{{0x79e730d418a9143c, 0x75ba95fc5fedb601, 0x79fb732b77622510,
+       0x18905f76a53755c6},
+      {0xddf25357ce95560a, 0x8b4ab8e4ba19e45c, 0xd2e88688dd21f325,
+       0x8571ff1825885d85}},
+     {{0x4f922fc516a0d2bb, 0x0d5cc16c1a623499, 0x9241cf3a57c62c8b,
+       0x2f5e6961fd1b667f},
+      {0x5c15c70bf5a01797, 0x3d20b44d60956192, 0x04911b37071fdb52,
+       0xf648f9168d6f0f7b}},
+     {{0x9e566847e137bbbc, 0xe434469e8a6a0bec, 0xb1c4276179d73463,
+       0x5abe0285133d0015},
+      {0x92aa837cc04c7dab, 0x573d9f4c43260c07, 0x0c93156278e6cc37,
+       0x94bb725b6b6f7383}},
+     {{0x62a8c244bfe20925, 0x91c19ac38fdce867, 0x5a96a5d5dd387063,
+       0x61d587d421d324f6},
+      {0xe87673a2a37173ea, 0x2384800853778b65, 0x10f8441e05bab43e,
+       0xfa11fe124621efbe}},
+     {{0x1c891f2b2cb19ffd, 0x01ba8d5bb1923c23, 0xb6d03d678ac5ca8e,
+       0x586eb04c1f13bedc},
+      {0x0c35c6e527e8ed09, 0x1e81a33c1819ede2, 0x278fd6c056c652fa,
+       0x19d5ac0870864f11}},
+     {{0x62577734d2b533d5, 0x673b8af6a1bdddc0, 0x577e7c9aa79ec293,
+       0xbb6de651c3b266b1},
+      {0xe7e9303ab65259b3, 0xd6a0afd3d03a7480, 0xc5ac83d19b3cfc27,
+       0x60b4619a5d18b99b}},
+     {{0xbd6a38e11ae5aa1c, 0xb8b7652b49e73658, 0x0b130014ee5f87ed,
+       0x9d0f27b2aeebffcd},
+      {0xca9246317a730a55, 0x9c955b2fddbbc83a, 0x07c1dfe0ac019a71,
+       0x244a566d356ec48d}},
+     {{0x56f8410ef4f8b16a, 0x97241afec47b266a, 0x0a406b8e6d9c87c1,
+       0x803f3e02cd42ab1b},
+      {0x7f0309a804dbec69, 0xa83b85f73bbad05f, 0xc6097273ad8e197f,
+       0xc097440e5067adc1}},
+     {{0x846a56f2c379ab34, 0xa8ee068b841df8d1, 0x20314459176c68ef,
+       0xf1af32d5915f1f30},
+      {0x99c375315d75bd50, 0x837cffbaf72f67bc, 0x0613a41848d7723f,
+       0x23d0f130e2d41c8b}},
+     {{0xed93e225d5be5a2b, 0x6fe799835934f3c6, 0x4314092622626ffc,
+       0x50bbb4d97990216a},
+      {0x378191c6e57ec63e, 0x65422c40181dcdb2, 0x41a8099b0236e0f6,
+       0x2b10011801fe49c3}},
+     {{0xfc68b5c59b391593, 0xc385f5a2598270fc, 0x7144f3aad19adcbb,
+       0xdd55899983fbae0c},
+      {0x93b88b8e74b82ff4, 0xd2e03c4071e734c9, 0x9a7a9eaf43c0322a,
+       0xe6e4c551149d6041}},
+     {{0x5fe14bfe80ec21fe, 0xf6ce116ac255be82, 0x98bc5a072f4a5d67,
+       0xfad27148db7e63af},
+      {0x90c0b6ac29ab05b3, 0x37a9a83c4e251ae6, 0x0a7dc875c2aade7d,
+       0x77387de39f0e1a84}},
+     {{0x1e9ecc49a56c0dd7, 0xa5cffcd846086c74, 0x8f7a1408f505aece,
+       0xb37b85c0bef0c47e},
+      {0x3596b6e4cc0e6a8f, 0xfd6d4bbf6b388f23, 0xaba453fac39cef4e,
+       0x9c135ac8f9f628d5}},
+     {{0x0a1c729495c8f8be, 0x2961c4803bf362bf, 0x9e418403df63d4ac,
+       0xc109f9cb91ece900},
+      {0xc2d095d058945705, 0xb9083d96ddeb85c0, 0x84692b8d7a40449b,
+       0x9bc3344f2eee1ee1}},
+     {{0x0d5ae35642913074, 0x55491b2748a542b1, 0x469ca665b310732a,
+       0x29591d525f1a4cc1},
+      {0xe76f5b6bb84f983f, 0xbe7eef419f5f84e1, 0x1200d49680baa189,
+       0x6376551f18ef332c}}},
+    {{{0x202886024147519a, 0xd0981eac26b372f0, 0xa9d4a7caa785ebc8,
+       0xd953c50ddbdf58e9},
+      {0x9d6361ccfd590f8f, 0x72e9626b44e6c917, 0x7fd9611022eb64cf,
+       0x863ebb7e9eb288f3}},
+     {{0x4fe7ee31b0e63d34, 0xf4600572a9e54fab, 0xc0493334d5e7b5a4,
+       0x8589fb9206d54831},
+      {0xaa70f5cc6583553a, 0x0879094ae25649e5, 0xcc90450710044652,
+       0xebb0696d02541c4f}},
+     {{0xabbaa0c03b89da99, 0xa6f2d79eb8284022, 0x27847862b81c05e8,
+       0x337a4b5905e54d63},
+      {0x3c67500d21f7794a, 0x207005b77d6d7f61, 0x0a5a378104cfd6e8,
+       0x0d65e0d5f4c2fbd6}},
+     {{0xd433e50f6d3549cf, 0x6f33696ffacd665e, 0x695bfdacce11fcb4,
+       0x810ee252af7c9860},
+      {0x65450fe17159bb2c, 0xf7dfbebe758b357b, 0x2b057e74d69fea72,
+       0xd485717a92731745}},
+     {{0xce1f69bbe83f7669, 0x09f8ae8272877d6b, 0x9548ae543244278d,
+       0x207755dee3c2c19c},
+      {0x87bd61d96fef1945, 0x18813cefb12d28c3, 0x9fbcd1d672df64aa,
+       0x48dc5ee57154b00d}},
+     {{0xef0f469ef49a3154, 0x3e85a5956e2b2e9a, 0x45aaec1eaa924a9c,
+       0xaa12dfc8a09e4719},
+      {0x26f272274df69f1d, 0xe0e4c82ca2ff5e73, 0xb9d8ce73b7a9dd44,
+       0x6c036e73e48ca901}},
+     {{0xe1e421e1a47153f0, 0xb86c3b79920418c9, 0x93bdce87705d7672,
+       0xf25ae793cab79a77},
+      {0x1f3194a36d869d0c, 0x9d55c8824986c264, 0x49fb5ea3096e945e,
+       0x39b8e65313db0a3e}},
+     {{0xe3417bc035d0b34a, 0x440b386b8327c0a7, 0x8fb7262dac0362d1,
+       0x2c41114ce0cdf943},
+      {0x2ba5cef1ad95a0b1, 0xc09b37a867d54362, 0x26d6cdd201e486c9,
+       0x20477abf42ff9297}},
+     {{0x0f121b41bc0a67d2, 0x62d4760a444d248a, 0x0e044f1d659b4737,
+       0x08fde365250bb4a8},
+      {0xaceec3da848bf287, 0xc2a62182d3369d6e, 0x3582dfdc92449482,
+       0x2f7e2fd2565d6cd7}},
+     {{0x0a0122b5178a876b, 0x51ff96ff085104b4, 0x050b31ab14f29f76,
+       0x84abb28b5f87d4e6},
+      {0xd5ed439f8270790a, 0x2d6cb59d85e3f46b, 0x75f55c1b6c1e2212,
+       0xe5436f6717655640}},
+     {{0xc2965ecc9aeb596d, 0x01ea03e7023c92b4, 0x4704b4b62e013961,
+       0x0ca8fd3f905ea367},
+      {0x92523a42551b2b61, 0x1eb7a89c390fcd06, 0xe7f1d2be0392a63e,
+       0x96dca2644ddb0c33}},
+     {{0x231c210e15339848, 0xe87a28e870778c8d, 0x9d1de6616956e170,
+       0x4ac3c9382bb09c0b},
+      {0x19be05516998987d, 0x8b2376c4ae09f4d6, 0x1de0b7651a3f933d,
+       0x380d94c7e39705f4}},
+     {{0x3685954b8c31c31d, 0x68533d005bf21a0c, 0x0bd7626e75c79ec9,
+       0xca17754742c69d54},
+      {0xcc6edafff6d2dbb2, 0xfd0d8cbd174a9d18, 0x875e8793aa4578e8,
+       0xa976a7139cab2ce6}},
+     {{0xce37ab11b43ea1db, 0x0a7ff1a95259d292, 0x851b02218f84f186,
+       0xa7222beadefaad13},
+      {0xa2ac78ec2b0a9144, 0x5a024051f2fa59c5, 0x91d1eca56147ce38,
+       0xbe94d523bc2ac690}},
+     {{0x2d8daefd79ec1a0f, 0x3bbcd6fdceb39c97, 0xf5575ffc58f61a95,
+       0xdbd986c4adf7b420},
+      {0x81aa881415f39eb7, 0x6ee2fcf5b98d976c, 0x5465475dcf2f717d,
+       0x8e24d3c46860bbd0}}}};
+#else
+static const fiat_p256_felem fiat_p256_g_pre_comp[2][15][2] = {
+    {{{0x18a9143c, 0x79e730d4, 0x5fedb601, 0x75ba95fc, 0x77622510, 0x79fb732b,
+       0xa53755c6, 0x18905f76},
+      {0xce95560a, 0xddf25357, 0xba19e45c, 0x8b4ab8e4, 0xdd21f325, 0xd2e88688,
+       0x25885d85, 0x8571ff18}},
+     {{0x16a0d2bb, 0x4f922fc5, 0x1a623499, 0x0d5cc16c, 0x57c62c8b, 0x9241cf3a,
+       0xfd1b667f, 0x2f5e6961},
+      {0xf5a01797, 0x5c15c70b, 0x60956192, 0x3d20b44d, 0x071fdb52, 0x04911b37,
+       0x8d6f0f7b, 0xf648f916}},
+     {{0xe137bbbc, 0x9e566847, 0x8a6a0bec, 0xe434469e, 0x79d73463, 0xb1c42761,
+       0x133d0015, 0x5abe0285},
+      {0xc04c7dab, 0x92aa837c, 0x43260c07, 0x573d9f4c, 0x78e6cc37, 0x0c931562,
+       0x6b6f7383, 0x94bb725b}},
+     {{0xbfe20925, 0x62a8c244, 0x8fdce867, 0x91c19ac3, 0xdd387063, 0x5a96a5d5,
+       0x21d324f6, 0x61d587d4},
+      {0xa37173ea, 0xe87673a2, 0x53778b65, 0x23848008, 0x05bab43e, 0x10f8441e,
+       0x4621efbe, 0xfa11fe12}},
+     {{0x2cb19ffd, 0x1c891f2b, 0xb1923c23, 0x01ba8d5b, 0x8ac5ca8e, 0xb6d03d67,
+       0x1f13bedc, 0x586eb04c},
+      {0x27e8ed09, 0x0c35c6e5, 0x1819ede2, 0x1e81a33c, 0x56c652fa, 0x278fd6c0,
+       0x70864f11, 0x19d5ac08}},
+     {{0xd2b533d5, 0x62577734, 0xa1bdddc0, 0x673b8af6, 0xa79ec293, 0x577e7c9a,
+       0xc3b266b1, 0xbb6de651},
+      {0xb65259b3, 0xe7e9303a, 0xd03a7480, 0xd6a0afd3, 0x9b3cfc27, 0xc5ac83d1,
+       0x5d18b99b, 0x60b4619a}},
+     {{0x1ae5aa1c, 0xbd6a38e1, 0x49e73658, 0xb8b7652b, 0xee5f87ed, 0x0b130014,
+       0xaeebffcd, 0x9d0f27b2},
+      {0x7a730a55, 0xca924631, 0xddbbc83a, 0x9c955b2f, 0xac019a71, 0x07c1dfe0,
+       0x356ec48d, 0x244a566d}},
+     {{0xf4f8b16a, 0x56f8410e, 0xc47b266a, 0x97241afe, 0x6d9c87c1, 0x0a406b8e,
+       0xcd42ab1b, 0x803f3e02},
+      {0x04dbec69, 0x7f0309a8, 0x3bbad05f, 0xa83b85f7, 0xad8e197f, 0xc6097273,
+       0x5067adc1, 0xc097440e}},
+     {{0xc379ab34, 0x846a56f2, 0x841df8d1, 0xa8ee068b, 0x176c68ef, 0x20314459,
+       0x915f1f30, 0xf1af32d5},
+      {0x5d75bd50, 0x99c37531, 0xf72f67bc, 0x837cffba, 0x48d7723f, 0x0613a418,
+       0xe2d41c8b, 0x23d0f130}},
+     {{0xd5be5a2b, 0xed93e225, 0x5934f3c6, 0x6fe79983, 0x22626ffc, 0x43140926,
+       0x7990216a, 0x50bbb4d9},
+      {0xe57ec63e, 0x378191c6, 0x181dcdb2, 0x65422c40, 0x0236e0f6, 0x41a8099b,
+       0x01fe49c3, 0x2b100118}},
+     {{0x9b391593, 0xfc68b5c5, 0x598270fc, 0xc385f5a2, 0xd19adcbb, 0x7144f3aa,
+       0x83fbae0c, 0xdd558999},
+      {0x74b82ff4, 0x93b88b8e, 0x71e734c9, 0xd2e03c40, 0x43c0322a, 0x9a7a9eaf,
+       0x149d6041, 0xe6e4c551}},
+     {{0x80ec21fe, 0x5fe14bfe, 0xc255be82, 0xf6ce116a, 0x2f4a5d67, 0x98bc5a07,
+       0xdb7e63af, 0xfad27148},
+      {0x29ab05b3, 0x90c0b6ac, 0x4e251ae6, 0x37a9a83c, 0xc2aade7d, 0x0a7dc875,
+       0x9f0e1a84, 0x77387de3}},
+     {{0xa56c0dd7, 0x1e9ecc49, 0x46086c74, 0xa5cffcd8, 0xf505aece, 0x8f7a1408,
+       0xbef0c47e, 0xb37b85c0},
+      {0xcc0e6a8f, 0x3596b6e4, 0x6b388f23, 0xfd6d4bbf, 0xc39cef4e, 0xaba453fa,
+       0xf9f628d5, 0x9c135ac8}},
+     {{0x95c8f8be, 0x0a1c7294, 0x3bf362bf, 0x2961c480, 0xdf63d4ac, 0x9e418403,
+       0x91ece900, 0xc109f9cb},
+      {0x58945705, 0xc2d095d0, 0xddeb85c0, 0xb9083d96, 0x7a40449b, 0x84692b8d,
+       0x2eee1ee1, 0x9bc3344f}},
+     {{0x42913074, 0x0d5ae356, 0x48a542b1, 0x55491b27, 0xb310732a, 0x469ca665,
+       0x5f1a4cc1, 0x29591d52},
+      {0xb84f983f, 0xe76f5b6b, 0x9f5f84e1, 0xbe7eef41, 0x80baa189, 0x1200d496,
+       0x18ef332c, 0x6376551f}}},
+    {{{0x4147519a, 0x20288602, 0x26b372f0, 0xd0981eac, 0xa785ebc8, 0xa9d4a7ca,
+       0xdbdf58e9, 0xd953c50d},
+      {0xfd590f8f, 0x9d6361cc, 0x44e6c917, 0x72e9626b, 0x22eb64cf, 0x7fd96110,
+       0x9eb288f3, 0x863ebb7e}},
+     {{0xb0e63d34, 0x4fe7ee31, 0xa9e54fab, 0xf4600572, 0xd5e7b5a4, 0xc0493334,
+       0x06d54831, 0x8589fb92},
+      {0x6583553a, 0xaa70f5cc, 0xe25649e5, 0x0879094a, 0x10044652, 0xcc904507,
+       0x02541c4f, 0xebb0696d}},
+     {{0x3b89da99, 0xabbaa0c0, 0xb8284022, 0xa6f2d79e, 0xb81c05e8, 0x27847862,
+       0x05e54d63, 0x337a4b59},
+      {0x21f7794a, 0x3c67500d, 0x7d6d7f61, 0x207005b7, 0x04cfd6e8, 0x0a5a3781,
+       0xf4c2fbd6, 0x0d65e0d5}},
+     {{0x6d3549cf, 0xd433e50f, 0xfacd665e, 0x6f33696f, 0xce11fcb4, 0x695bfdac,
+       0xaf7c9860, 0x810ee252},
+      {0x7159bb2c, 0x65450fe1, 0x758b357b, 0xf7dfbebe, 0xd69fea72, 0x2b057e74,
+       0x92731745, 0xd485717a}},
+     {{0xe83f7669, 0xce1f69bb, 0x72877d6b, 0x09f8ae82, 0x3244278d, 0x9548ae54,
+       0xe3c2c19c, 0x207755de},
+      {0x6fef1945, 0x87bd61d9, 0xb12d28c3, 0x18813cef, 0x72df64aa, 0x9fbcd1d6,
+       0x7154b00d, 0x48dc5ee5}},
+     {{0xf49a3154, 0xef0f469e, 0x6e2b2e9a, 0x3e85a595, 0xaa924a9c, 0x45aaec1e,
+       0xa09e4719, 0xaa12dfc8},
+      {0x4df69f1d, 0x26f27227, 0xa2ff5e73, 0xe0e4c82c, 0xb7a9dd44, 0xb9d8ce73,
+       0xe48ca901, 0x6c036e73}},
+     {{0xa47153f0, 0xe1e421e1, 0x920418c9, 0xb86c3b79, 0x705d7672, 0x93bdce87,
+       0xcab79a77, 0xf25ae793},
+      {0x6d869d0c, 0x1f3194a3, 0x4986c264, 0x9d55c882, 0x096e945e, 0x49fb5ea3,
+       0x13db0a3e, 0x39b8e653}},
+     {{0x35d0b34a, 0xe3417bc0, 0x8327c0a7, 0x440b386b, 0xac0362d1, 0x8fb7262d,
+       0xe0cdf943, 0x2c41114c},
+      {0xad95a0b1, 0x2ba5cef1, 0x67d54362, 0xc09b37a8, 0x01e486c9, 0x26d6cdd2,
+       0x42ff9297, 0x20477abf}},
+     {{0xbc0a67d2, 0x0f121b41, 0x444d248a, 0x62d4760a, 0x659b4737, 0x0e044f1d,
+       0x250bb4a8, 0x08fde365},
+      {0x848bf287, 0xaceec3da, 0xd3369d6e, 0xc2a62182, 0x92449482, 0x3582dfdc,
+       0x565d6cd7, 0x2f7e2fd2}},
+     {{0x178a876b, 0x0a0122b5, 0x085104b4, 0x51ff96ff, 0x14f29f76, 0x050b31ab,
+       0x5f87d4e6, 0x84abb28b},
+      {0x8270790a, 0xd5ed439f, 0x85e3f46b, 0x2d6cb59d, 0x6c1e2212, 0x75f55c1b,
+       0x17655640, 0xe5436f67}},
+     {{0x9aeb596d, 0xc2965ecc, 0x023c92b4, 0x01ea03e7, 0x2e013961, 0x4704b4b6,
+       0x905ea367, 0x0ca8fd3f},
+      {0x551b2b61, 0x92523a42, 0x390fcd06, 0x1eb7a89c, 0x0392a63e, 0xe7f1d2be,
+       0x4ddb0c33, 0x96dca264}},
+     {{0x15339848, 0x231c210e, 0x70778c8d, 0xe87a28e8, 0x6956e170, 0x9d1de661,
+       0x2bb09c0b, 0x4ac3c938},
+      {0x6998987d, 0x19be0551, 0xae09f4d6, 0x8b2376c4, 0x1a3f933d, 0x1de0b765,
+       0xe39705f4, 0x380d94c7}},
+     {{0x8c31c31d, 0x3685954b, 0x5bf21a0c, 0x68533d00, 0x75c79ec9, 0x0bd7626e,
+       0x42c69d54, 0xca177547},
+      {0xf6d2dbb2, 0xcc6edaff, 0x174a9d18, 0xfd0d8cbd, 0xaa4578e8, 0x875e8793,
+       0x9cab2ce6, 0xa976a713}},
+     {{0xb43ea1db, 0xce37ab11, 0x5259d292, 0x0a7ff1a9, 0x8f84f186, 0x851b0221,
+       0xdefaad13, 0xa7222bea},
+      {0x2b0a9144, 0xa2ac78ec, 0xf2fa59c5, 0x5a024051, 0x6147ce38, 0x91d1eca5,
+       0xbc2ac690, 0xbe94d523}},
+     {{0x79ec1a0f, 0x2d8daefd, 0xceb39c97, 0x3bbcd6fd, 0x58f61a95, 0xf5575ffc,
+       0xadf7b420, 0xdbd986c4},
+      {0x15f39eb7, 0x81aa8814, 0xb98d976c, 0x6ee2fcf5, 0xcf2f717d, 0x5465475d,
+       0x6860bbd0, 0x8e24d3c4}}}};
+#endif