|
|
|
/* 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() {
|
P-256 assembly optimisations for Aarch64.
The ARMv8 assembly code in this commit is mostly taken from OpenSSL's `ecp_nistz256-armv8.pl` at https://github.com/openssl/openssl/blob/19e277dd19f2897f6a7b7eb236abe46655e575bf/crypto/ec/asm/ecp_nistz256-armv8.pl (see Note 1), adapting it to the implementation in p256-x86_64.c.
Most of the assembly functions found in `crypto/fipsmodule/ec/asm/p256-x86_64-asm.pl` required to support that code have their analogous functions in the imported OpenSSL ARMv8 Perl assembly implementation with the exception of the functions:
- ecp_nistz256_select_w5
- ecp_nistz256_select_w7
An implementation for these functions was added.
Summary of modifications to the imported code:
* Renamed to `p256-armv8-asm.pl`
* Modified the location of `arm-xlate.pl` and `arm_arch.h`
* Replaced the `scatter-gather subroutines` with `select subroutines`. The `select subroutines` are implemented for ARMv8 similarly to their x86_64 counterparts, `ecp_nistz256_select_w5` and `ecp_nistz256_select_w7`.
* `ecp_nistz256_add` is removed because it was conflicting during the static build with the function of the same name in p256-nistz.c. The latter calls another assembly function, `ecp_nistz256_point_add`.
* `__ecp_nistz256_add` renamed to `__ecp_nistz256_add_to` to avoid the conflict with the function `ecp_nistz256_add` during the static build.
* l. 924 `add sp,sp,#256` the calculation of the constant, 32*(12-4), is not left for the assembler to perform.
Other modifications:
* `beeu_mod_inverse_vartime()` was implemented for AArch64 in `p256_beeu-armv8-asm.pl` similarly to its implementation in `p256_beeu-x86_64-asm.pl`.
* The files containing `p256-x86_64` in their name were renamed to, `p256-nistz` since the functions and tests defined in them are hereby running on ARMv8 as well, if enabled.
* Updated `delocate.go` and `delocate.peg` to handle the offset calculation in the assembly instructions.
* Regenerated `delocate.peg.go`.
Notes:
1- The last commit in the history of the file is in master only, the previous commits are in OpenSSL 3.0.1
2- This change focuses on AArch64 (64-bit architecture of ARMv8). It does not support ARMv4 or ARMv7.
Testing the performance on Armv8 platform using -DCMAKE_BUILD_TYPE=Release:
Before:
```
Did 2596 ECDH P-256 operations in 1093956us (2373.0 ops/sec)
Did 6996 ECDSA P-256 signing operations in 1044630us (6697.1 ops/sec)
Did 2970 ECDSA P-256 verify operations in 1084848us (2737.7 ops/sec)
```
After:
```
Did 6699 ECDH P-256 operations in 1091684us (6136.4 ops/sec)
Did 20000 ECDSA P-256 signing operations in 1012944us (19744.4 ops/sec)
Did 7051 ECDSA P-256 verify operations in 1060000us (6651.9 ops/sec)
```
Change-Id: I9fdef12db365967a9264b5b32c07967b55ea48bd
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/51805
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
3 years ago
|
|
|
if err := writeP256NistzTable("p256-nistz-table.h"); err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "Error writing p256-nistz-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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
P-256 assembly optimisations for Aarch64.
The ARMv8 assembly code in this commit is mostly taken from OpenSSL's `ecp_nistz256-armv8.pl` at https://github.com/openssl/openssl/blob/19e277dd19f2897f6a7b7eb236abe46655e575bf/crypto/ec/asm/ecp_nistz256-armv8.pl (see Note 1), adapting it to the implementation in p256-x86_64.c.
Most of the assembly functions found in `crypto/fipsmodule/ec/asm/p256-x86_64-asm.pl` required to support that code have their analogous functions in the imported OpenSSL ARMv8 Perl assembly implementation with the exception of the functions:
- ecp_nistz256_select_w5
- ecp_nistz256_select_w7
An implementation for these functions was added.
Summary of modifications to the imported code:
* Renamed to `p256-armv8-asm.pl`
* Modified the location of `arm-xlate.pl` and `arm_arch.h`
* Replaced the `scatter-gather subroutines` with `select subroutines`. The `select subroutines` are implemented for ARMv8 similarly to their x86_64 counterparts, `ecp_nistz256_select_w5` and `ecp_nistz256_select_w7`.
* `ecp_nistz256_add` is removed because it was conflicting during the static build with the function of the same name in p256-nistz.c. The latter calls another assembly function, `ecp_nistz256_point_add`.
* `__ecp_nistz256_add` renamed to `__ecp_nistz256_add_to` to avoid the conflict with the function `ecp_nistz256_add` during the static build.
* l. 924 `add sp,sp,#256` the calculation of the constant, 32*(12-4), is not left for the assembler to perform.
Other modifications:
* `beeu_mod_inverse_vartime()` was implemented for AArch64 in `p256_beeu-armv8-asm.pl` similarly to its implementation in `p256_beeu-x86_64-asm.pl`.
* The files containing `p256-x86_64` in their name were renamed to, `p256-nistz` since the functions and tests defined in them are hereby running on ARMv8 as well, if enabled.
* Updated `delocate.go` and `delocate.peg` to handle the offset calculation in the assembly instructions.
* Regenerated `delocate.peg.go`.
Notes:
1- The last commit in the history of the file is in master only, the previous commits are in OpenSSL 3.0.1
2- This change focuses on AArch64 (64-bit architecture of ARMv8). It does not support ARMv4 or ARMv7.
Testing the performance on Armv8 platform using -DCMAKE_BUILD_TYPE=Release:
Before:
```
Did 2596 ECDH P-256 operations in 1093956us (2373.0 ops/sec)
Did 6996 ECDSA P-256 signing operations in 1044630us (6697.1 ops/sec)
Did 2970 ECDSA P-256 verify operations in 1084848us (2737.7 ops/sec)
```
After:
```
Did 6699 ECDH P-256 operations in 1091684us (6136.4 ops/sec)
Did 20000 ECDSA P-256 signing operations in 1012944us (19744.4 ops/sec)
Did 7051 ECDSA P-256 verify operations in 1060000us (6651.9 ops/sec)
```
Change-Id: I9fdef12db365967a9264b5b32c07967b55ea48bd
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/51805
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
3 years ago
|
|
|
func writeP256NistzTable(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
|
P-256 assembly optimisations for Aarch64.
The ARMv8 assembly code in this commit is mostly taken from OpenSSL's `ecp_nistz256-armv8.pl` at https://github.com/openssl/openssl/blob/19e277dd19f2897f6a7b7eb236abe46655e575bf/crypto/ec/asm/ecp_nistz256-armv8.pl (see Note 1), adapting it to the implementation in p256-x86_64.c.
Most of the assembly functions found in `crypto/fipsmodule/ec/asm/p256-x86_64-asm.pl` required to support that code have their analogous functions in the imported OpenSSL ARMv8 Perl assembly implementation with the exception of the functions:
- ecp_nistz256_select_w5
- ecp_nistz256_select_w7
An implementation for these functions was added.
Summary of modifications to the imported code:
* Renamed to `p256-armv8-asm.pl`
* Modified the location of `arm-xlate.pl` and `arm_arch.h`
* Replaced the `scatter-gather subroutines` with `select subroutines`. The `select subroutines` are implemented for ARMv8 similarly to their x86_64 counterparts, `ecp_nistz256_select_w5` and `ecp_nistz256_select_w7`.
* `ecp_nistz256_add` is removed because it was conflicting during the static build with the function of the same name in p256-nistz.c. The latter calls another assembly function, `ecp_nistz256_point_add`.
* `__ecp_nistz256_add` renamed to `__ecp_nistz256_add_to` to avoid the conflict with the function `ecp_nistz256_add` during the static build.
* l. 924 `add sp,sp,#256` the calculation of the constant, 32*(12-4), is not left for the assembler to perform.
Other modifications:
* `beeu_mod_inverse_vartime()` was implemented for AArch64 in `p256_beeu-armv8-asm.pl` similarly to its implementation in `p256_beeu-x86_64-asm.pl`.
* The files containing `p256-x86_64` in their name were renamed to, `p256-nistz` since the functions and tests defined in them are hereby running on ARMv8 as well, if enabled.
* Updated `delocate.go` and `delocate.peg` to handle the offset calculation in the assembly instructions.
* Regenerated `delocate.peg.go`.
Notes:
1- The last commit in the history of the file is in master only, the previous commits are in OpenSSL 3.0.1
2- This change focuses on AArch64 (64-bit architecture of ARMv8). It does not support ARMv4 or ARMv7.
Testing the performance on Armv8 platform using -DCMAKE_BUILD_TYPE=Release:
Before:
```
Did 2596 ECDH P-256 operations in 1093956us (2373.0 ops/sec)
Did 6996 ECDSA P-256 signing operations in 1044630us (6697.1 ops/sec)
Did 2970 ECDSA P-256 verify operations in 1084848us (2737.7 ops/sec)
```
After:
```
Did 6699 ECDH P-256 operations in 1091684us (6136.4 ops/sec)
Did 20000 ECDSA P-256 signing operations in 1012944us (19744.4 ops/sec)
Did 7051 ECDSA P-256 verify operations in 1060000us (6651.9 ops/sec)
```
Change-Id: I9fdef12db365967a9264b5b32c07967b55ea48bd
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/51805
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
3 years ago
|
|
|
// p256-nistz.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
|
|
|
|
}
|
|
|
|
if err := writeTables(f, curve, tables, true, 4, 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
|
|
|
|
}
|