add ecp_comb_table.py

ecp_comb_table.py generates comb table

Signed-off-by: kXuan <kxuanobj@gmail.com>
diff --git a/scripts/ecp_comb_table.py b/scripts/ecp_comb_table.py
new file mode 100755
index 0000000..bc11431
--- /dev/null
+++ b/scripts/ecp_comb_table.py
@@ -0,0 +1,249 @@
+#!/usr/bin/env python3
+"""
+Purpose
+
+This script dumps comb table of ec curve. When you add a new ec curve, you
+can use this script to generate codes to define `<curve>_T` in ecp_curves.c
+"""
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import subprocess
+import sys
+import tempfile
+
+HOW_TO_ADD_NEW_CURVE = """
+If you are trying to add new curve, you can follow these steps:
+
+1. Define curve parameters (<curve>_p, <curve>_gx, etc...) in ecp_curves.c.
+2. Add a macro to define <curve>_T to NULL following these parameters.
+3. Build mbedcrypto
+4. Run this script with an argument of new curve
+5. Copy the output of this script into ecp_curves.c and replace the macro added
+   in Step 2
+6. Rebuild and test if everything is ok
+
+Replace the <curve> in the above with the name of the curve you want to add."""
+
+CC = os.getenv('CC', 'cc')
+MBEDTLS_LIBRARY_PATH = os.getenv('MBEDTLS_LIBRARY_PATH', "library")
+
+SRC_DUMP_COMB_TABLE = r'''
+#include <stdio.h>
+#include <stdlib.h>
+#include "mbedtls/ecp.h"
+#include "mbedtls/error.h"
+
+static void dump_mpi_initialize( const char *name, const mbedtls_mpi *d )
+{
+    uint8_t buf[128] = {0};
+    size_t olen;
+    uint8_t *p;
+
+    olen = mbedtls_mpi_size( d );
+    mbedtls_mpi_write_binary_le( d, buf, olen );
+    printf("static const mbedtls_mpi_uint %s[] = {\n", name);
+    for (p = buf; p < buf + olen; p += 8) {
+        printf( "    BYTES_TO_T_UINT_8( 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X ),\n",
+                p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7] );
+    }
+    printf("};\n");
+}
+
+static void dump_T( const mbedtls_ecp_group *grp )
+{
+    char name[128];
+
+    printf( "#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1\n" );
+
+    for (size_t i = 0; i < grp->T_size; ++i) {
+        snprintf( name, sizeof(name), "%s_T_%zu_X", CURVE_NAME, i );
+        dump_mpi_initialize( name, &grp->T[i].X );
+
+        snprintf( name, sizeof(name), "%s_T_%zu_Y", CURVE_NAME, i );
+        dump_mpi_initialize( name, &grp->T[i].Y );
+    }
+    printf( "static const mbedtls_ecp_point %s_T[%zu] = {\n", CURVE_NAME, grp->T_size );
+    size_t olen;
+    for (size_t i = 0; i < grp->T_size; ++i) {
+        int z;
+        if ( mbedtls_mpi_cmp_int(&grp->T[i].Z, 0) == 0 ) {
+            z = 0;
+        } else if ( mbedtls_mpi_cmp_int(&grp->T[i].Z, 1) == 0 ) {
+            z = 1;
+        } else {
+            fprintf( stderr, "Unexpected value of Z (i = %d)\n", (int)i );
+            exit( 1 );
+        }
+        printf( "    ECP_POINT_INIT_XY_Z%d(%s_T_%zu_X, %s_T_%zu_Y),\n",
+                z,
+                CURVE_NAME, i,
+                CURVE_NAME, i
+        );
+    }
+    printf("};\n#endif\n\n");
+}
+
+int main()
+{
+    int rc;
+    mbedtls_mpi m;
+    mbedtls_ecp_point R;
+    mbedtls_ecp_group grp;
+
+    mbedtls_ecp_group_init( &grp );
+    rc = mbedtls_ecp_group_load( &grp, CURVE_ID );
+    if (rc != 0) {
+        char buf[100];
+        mbedtls_strerror( rc, buf, sizeof(buf) );
+        fprintf( stderr, "mbedtls_ecp_group_load: %s (-0x%x)\n", buf, -rc );
+        return 1;
+    }
+    grp.T = NULL;
+    mbedtls_ecp_point_init( &R );
+    mbedtls_mpi_init( &m);
+    mbedtls_mpi_lset( &m, 1 );
+    rc = mbedtls_ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL );
+    if ( rc != 0 ) {
+        char buf[100];
+        mbedtls_strerror( rc, buf, sizeof(buf) );
+        fprintf( stderr, "mbedtls_ecp_mul: %s (-0x%x)\n", buf, -rc );
+        return 1;
+    }
+    if ( grp.T == NULL ) {
+        fprintf( stderr, "grp.T is not generated. Please make sure"
+                         "MBEDTLS_ECP_FIXED_POINT_OPTIM is enabled in config.h\n" );
+        return 1;
+    }
+    dump_T( &grp );
+    return 0;
+}
+'''
+
+SRC_DUMP_KNOWN_CURVE = r'''
+#include <stdio.h>
+#include <stdlib.h>
+#include "mbedtls/ecp.h"
+
+int main() {
+    const mbedtls_ecp_curve_info *info = mbedtls_ecp_curve_list();
+    mbedtls_ecp_group grp;
+
+    mbedtls_ecp_group_init( &grp );
+    while ( info->name != NULL ) {
+        mbedtls_ecp_group_load( &grp, info->grp_id );
+        if ( mbedtls_ecp_get_type(&grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS ) {
+            printf( " %s", info->name );
+        }
+        info++;
+    }
+    printf( "\n" );
+    return 0;
+}
+'''
+
+
+def join_src_path(*args):
+    return os.path.normpath(os.path.join(os.path.dirname(__file__), "..", *args))
+
+
+def run_c_source(src, cflags):
+    """
+    Compile and run C source code
+    :param src: the c language code to run
+    :param cflags: additional cflags passing to compiler
+    :return:
+    """
+    binname = tempfile.mktemp(prefix="mbedtls")
+    fd, srcname = tempfile.mkstemp(prefix="mbedtls", suffix=".c")
+    srcfile = os.fdopen(fd, mode="w")
+    srcfile.write(src)
+    srcfile.close()
+    args = [CC,
+            *cflags,
+            '-I' + join_src_path("include"),
+            "-o", binname,
+            '-L' + MBEDTLS_LIBRARY_PATH,
+            srcname,
+            '-lmbedcrypto']
+
+    p = subprocess.run(args=args, check=False)
+    if p.returncode != 0:
+        return False
+    p = subprocess.run(args=[binname], check=False, env={
+        'LD_LIBRARY_PATH': MBEDTLS_LIBRARY_PATH
+    })
+    if p.returncode != 0:
+        return False
+    os.unlink(srcname)
+    os.unlink(binname)
+    return True
+
+
+def compute_curve(curve):
+    """compute comb table for curve"""
+    r = run_c_source(
+        SRC_DUMP_COMB_TABLE,
+        [
+            '-g',
+            '-DCURVE_ID=MBEDTLS_ECP_DP_%s' % curve.upper(),
+            '-DCURVE_NAME="%s"' % curve.lower(),
+        ])
+    if not r:
+        print("""\
+Unable to compile and run utility.""", file=sys.stderr)
+        sys.exit(1)
+
+
+def usage():
+    print("""
+Usage: python %s <curve>...
+
+Arguments:
+    curve       Specify one or more curve names (e.g secp256r1)
+
+All possible curves: """ % sys.argv[0])
+    run_c_source(SRC_DUMP_KNOWN_CURVE, [])
+    print("""
+Environment Variable:
+    CC          Specify which c compile to use to compile utility.
+    MBEDTLS_LIBRARY_PATH
+                Specify the path to mbedcrypto library. (e.g. build/library/)
+
+How to add a new curve: %s""" % HOW_TO_ADD_NEW_CURVE)
+
+
+def run_main():
+    shared_lib_path = os.path.normpath(os.path.join(MBEDTLS_LIBRARY_PATH, "libmbedcrypto.so"))
+    static_lib_path = os.path.normpath(os.path.join(MBEDTLS_LIBRARY_PATH, "libmbedcrypto.a"))
+    if not os.path.exists(shared_lib_path) and not os.path.exists(static_lib_path):
+        print("Warning: both '%s' and '%s' are not exists. This script will use "
+              "the library from your system instead of the library compiled by "
+              "this source directory.\n"
+              "You can specify library path using environment variable "
+              "'MBEDTLS_LIBRARY_PATH'." % (shared_lib_path, static_lib_path),
+              file=sys.stderr)
+
+    if len(sys.argv) <= 1:
+        usage()
+    else:
+        for curve in sys.argv[1:]:
+            compute_curve(curve)
+
+
+if __name__ == '__main__':
+    run_main()