1a8e1175bSopenharmony_ci#!/usr/bin/env python3
2a8e1175bSopenharmony_ci"""
3a8e1175bSopenharmony_ciPurpose
4a8e1175bSopenharmony_ci
5a8e1175bSopenharmony_ciThis script dumps comb table of ec curve. When you add a new ec curve, you
6a8e1175bSopenharmony_cican use this script to generate codes to define `<curve>_T` in ecp_curves.c
7a8e1175bSopenharmony_ci"""
8a8e1175bSopenharmony_ci
9a8e1175bSopenharmony_ci# Copyright The Mbed TLS Contributors
10a8e1175bSopenharmony_ci# SPDX-License-Identifier: Apache-2.0
11a8e1175bSopenharmony_ci#
12a8e1175bSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); you may
13a8e1175bSopenharmony_ci# not use this file except in compliance with the License.
14a8e1175bSopenharmony_ci# You may obtain a copy of the License at
15a8e1175bSopenharmony_ci#
16a8e1175bSopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0
17a8e1175bSopenharmony_ci#
18a8e1175bSopenharmony_ci# Unless required by applicable law or agreed to in writing, software
19a8e1175bSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
20a8e1175bSopenharmony_ci# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21a8e1175bSopenharmony_ci# See the License for the specific language governing permissions and
22a8e1175bSopenharmony_ci# limitations under the License.
23a8e1175bSopenharmony_ci
24a8e1175bSopenharmony_ciimport os
25a8e1175bSopenharmony_ciimport subprocess
26a8e1175bSopenharmony_ciimport sys
27a8e1175bSopenharmony_ciimport tempfile
28a8e1175bSopenharmony_ci
29a8e1175bSopenharmony_ciHOW_TO_ADD_NEW_CURVE = """
30a8e1175bSopenharmony_ciIf you are trying to add new curve, you can follow these steps:
31a8e1175bSopenharmony_ci
32a8e1175bSopenharmony_ci1. Define curve parameters (<curve>_p, <curve>_gx, etc...) in ecp_curves.c.
33a8e1175bSopenharmony_ci2. Add a macro to define <curve>_T to NULL following these parameters.
34a8e1175bSopenharmony_ci3. Build mbedcrypto
35a8e1175bSopenharmony_ci4. Run this script with an argument of new curve
36a8e1175bSopenharmony_ci5. Copy the output of this script into ecp_curves.c and replace the macro added
37a8e1175bSopenharmony_ci   in Step 2
38a8e1175bSopenharmony_ci6. Rebuild and test if everything is ok
39a8e1175bSopenharmony_ci
40a8e1175bSopenharmony_ciReplace the <curve> in the above with the name of the curve you want to add."""
41a8e1175bSopenharmony_ci
42a8e1175bSopenharmony_ciCC = os.getenv('CC', 'cc')
43a8e1175bSopenharmony_ciMBEDTLS_LIBRARY_PATH = os.getenv('MBEDTLS_LIBRARY_PATH', "library")
44a8e1175bSopenharmony_ci
45a8e1175bSopenharmony_ciSRC_DUMP_COMB_TABLE = r'''
46a8e1175bSopenharmony_ci#include <stdio.h>
47a8e1175bSopenharmony_ci#include <stdlib.h>
48a8e1175bSopenharmony_ci#include "mbedtls/ecp.h"
49a8e1175bSopenharmony_ci#include "mbedtls/error.h"
50a8e1175bSopenharmony_ci
51a8e1175bSopenharmony_cistatic void dump_mpi_initialize( const char *name, const mbedtls_mpi *d )
52a8e1175bSopenharmony_ci{
53a8e1175bSopenharmony_ci    uint8_t buf[128] = {0};
54a8e1175bSopenharmony_ci    size_t olen;
55a8e1175bSopenharmony_ci    uint8_t *p;
56a8e1175bSopenharmony_ci
57a8e1175bSopenharmony_ci    olen = mbedtls_mpi_size( d );
58a8e1175bSopenharmony_ci    mbedtls_mpi_write_binary_le( d, buf, olen );
59a8e1175bSopenharmony_ci    printf("static const mbedtls_mpi_uint %s[] = {\n", name);
60a8e1175bSopenharmony_ci    for (p = buf; p < buf + olen; p += 8) {
61a8e1175bSopenharmony_ci        printf( "    BYTES_TO_T_UINT_8( 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X ),\n",
62a8e1175bSopenharmony_ci                p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7] );
63a8e1175bSopenharmony_ci    }
64a8e1175bSopenharmony_ci    printf("};\n");
65a8e1175bSopenharmony_ci}
66a8e1175bSopenharmony_ci
67a8e1175bSopenharmony_cistatic void dump_T( const mbedtls_ecp_group *grp )
68a8e1175bSopenharmony_ci{
69a8e1175bSopenharmony_ci    char name[128];
70a8e1175bSopenharmony_ci
71a8e1175bSopenharmony_ci    printf( "#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1\n" );
72a8e1175bSopenharmony_ci
73a8e1175bSopenharmony_ci    for (size_t i = 0; i < grp->T_size; ++i) {
74a8e1175bSopenharmony_ci        snprintf( name, sizeof(name), "%s_T_%zu_X", CURVE_NAME, i );
75a8e1175bSopenharmony_ci        dump_mpi_initialize( name, &grp->T[i].X );
76a8e1175bSopenharmony_ci
77a8e1175bSopenharmony_ci        snprintf( name, sizeof(name), "%s_T_%zu_Y", CURVE_NAME, i );
78a8e1175bSopenharmony_ci        dump_mpi_initialize( name, &grp->T[i].Y );
79a8e1175bSopenharmony_ci    }
80a8e1175bSopenharmony_ci    printf( "static const mbedtls_ecp_point %s_T[%zu] = {\n", CURVE_NAME, grp->T_size );
81a8e1175bSopenharmony_ci    size_t olen;
82a8e1175bSopenharmony_ci    for (size_t i = 0; i < grp->T_size; ++i) {
83a8e1175bSopenharmony_ci        int z;
84a8e1175bSopenharmony_ci        if ( mbedtls_mpi_cmp_int(&grp->T[i].Z, 0) == 0 ) {
85a8e1175bSopenharmony_ci            z = 0;
86a8e1175bSopenharmony_ci        } else if ( mbedtls_mpi_cmp_int(&grp->T[i].Z, 1) == 0 ) {
87a8e1175bSopenharmony_ci            z = 1;
88a8e1175bSopenharmony_ci        } else {
89a8e1175bSopenharmony_ci            fprintf( stderr, "Unexpected value of Z (i = %d)\n", (int)i );
90a8e1175bSopenharmony_ci            exit( 1 );
91a8e1175bSopenharmony_ci        }
92a8e1175bSopenharmony_ci        printf( "    ECP_POINT_INIT_XY_Z%d(%s_T_%zu_X, %s_T_%zu_Y),\n",
93a8e1175bSopenharmony_ci                z,
94a8e1175bSopenharmony_ci                CURVE_NAME, i,
95a8e1175bSopenharmony_ci                CURVE_NAME, i
96a8e1175bSopenharmony_ci        );
97a8e1175bSopenharmony_ci    }
98a8e1175bSopenharmony_ci    printf("};\n#endif\n\n");
99a8e1175bSopenharmony_ci}
100a8e1175bSopenharmony_ci
101a8e1175bSopenharmony_ciint main()
102a8e1175bSopenharmony_ci{
103a8e1175bSopenharmony_ci    int rc;
104a8e1175bSopenharmony_ci    mbedtls_mpi m;
105a8e1175bSopenharmony_ci    mbedtls_ecp_point R;
106a8e1175bSopenharmony_ci    mbedtls_ecp_group grp;
107a8e1175bSopenharmony_ci
108a8e1175bSopenharmony_ci    mbedtls_ecp_group_init( &grp );
109a8e1175bSopenharmony_ci    rc = mbedtls_ecp_group_load( &grp, CURVE_ID );
110a8e1175bSopenharmony_ci    if (rc != 0) {
111a8e1175bSopenharmony_ci        char buf[100];
112a8e1175bSopenharmony_ci        mbedtls_strerror( rc, buf, sizeof(buf) );
113a8e1175bSopenharmony_ci        fprintf( stderr, "mbedtls_ecp_group_load: %s (-0x%x)\n", buf, -rc );
114a8e1175bSopenharmony_ci        return 1;
115a8e1175bSopenharmony_ci    }
116a8e1175bSopenharmony_ci    grp.T = NULL;
117a8e1175bSopenharmony_ci    mbedtls_ecp_point_init( &R );
118a8e1175bSopenharmony_ci    mbedtls_mpi_init( &m);
119a8e1175bSopenharmony_ci    mbedtls_mpi_lset( &m, 1 );
120a8e1175bSopenharmony_ci    rc = mbedtls_ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL );
121a8e1175bSopenharmony_ci    if ( rc != 0 ) {
122a8e1175bSopenharmony_ci        char buf[100];
123a8e1175bSopenharmony_ci        mbedtls_strerror( rc, buf, sizeof(buf) );
124a8e1175bSopenharmony_ci        fprintf( stderr, "mbedtls_ecp_mul: %s (-0x%x)\n", buf, -rc );
125a8e1175bSopenharmony_ci        return 1;
126a8e1175bSopenharmony_ci    }
127a8e1175bSopenharmony_ci    if ( grp.T == NULL ) {
128a8e1175bSopenharmony_ci        fprintf( stderr, "grp.T is not generated. Please make sure"
129a8e1175bSopenharmony_ci                         "MBEDTLS_ECP_FIXED_POINT_OPTIM is enabled in mbedtls_config.h\n" );
130a8e1175bSopenharmony_ci        return 1;
131a8e1175bSopenharmony_ci    }
132a8e1175bSopenharmony_ci    dump_T( &grp );
133a8e1175bSopenharmony_ci    return 0;
134a8e1175bSopenharmony_ci}
135a8e1175bSopenharmony_ci'''
136a8e1175bSopenharmony_ci
137a8e1175bSopenharmony_ciSRC_DUMP_KNOWN_CURVE = r'''
138a8e1175bSopenharmony_ci#include <stdio.h>
139a8e1175bSopenharmony_ci#include <stdlib.h>
140a8e1175bSopenharmony_ci#include "mbedtls/ecp.h"
141a8e1175bSopenharmony_ci
142a8e1175bSopenharmony_ciint main() {
143a8e1175bSopenharmony_ci    const mbedtls_ecp_curve_info *info = mbedtls_ecp_curve_list();
144a8e1175bSopenharmony_ci    mbedtls_ecp_group grp;
145a8e1175bSopenharmony_ci
146a8e1175bSopenharmony_ci    mbedtls_ecp_group_init( &grp );
147a8e1175bSopenharmony_ci    while ( info->name != NULL ) {
148a8e1175bSopenharmony_ci        mbedtls_ecp_group_load( &grp, info->grp_id );
149a8e1175bSopenharmony_ci        if ( mbedtls_ecp_get_type(&grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS ) {
150a8e1175bSopenharmony_ci            printf( " %s", info->name );
151a8e1175bSopenharmony_ci        }
152a8e1175bSopenharmony_ci        info++;
153a8e1175bSopenharmony_ci    }
154a8e1175bSopenharmony_ci    printf( "\n" );
155a8e1175bSopenharmony_ci    return 0;
156a8e1175bSopenharmony_ci}
157a8e1175bSopenharmony_ci'''
158a8e1175bSopenharmony_ci
159a8e1175bSopenharmony_ci
160a8e1175bSopenharmony_cidef join_src_path(*args):
161a8e1175bSopenharmony_ci    return os.path.normpath(os.path.join(os.path.dirname(__file__), "..", *args))
162a8e1175bSopenharmony_ci
163a8e1175bSopenharmony_ci
164a8e1175bSopenharmony_cidef run_c_source(src, cflags):
165a8e1175bSopenharmony_ci    """
166a8e1175bSopenharmony_ci    Compile and run C source code
167a8e1175bSopenharmony_ci    :param src: the c language code to run
168a8e1175bSopenharmony_ci    :param cflags: additional cflags passing to compiler
169a8e1175bSopenharmony_ci    :return:
170a8e1175bSopenharmony_ci    """
171a8e1175bSopenharmony_ci    binname = tempfile.mktemp(prefix="mbedtls")
172a8e1175bSopenharmony_ci    fd, srcname = tempfile.mkstemp(prefix="mbedtls", suffix=".c")
173a8e1175bSopenharmony_ci    srcfile = os.fdopen(fd, mode="w")
174a8e1175bSopenharmony_ci    srcfile.write(src)
175a8e1175bSopenharmony_ci    srcfile.close()
176a8e1175bSopenharmony_ci    args = [CC,
177a8e1175bSopenharmony_ci            *cflags,
178a8e1175bSopenharmony_ci            '-I' + join_src_path("include"),
179a8e1175bSopenharmony_ci            "-o", binname,
180a8e1175bSopenharmony_ci            '-L' + MBEDTLS_LIBRARY_PATH,
181a8e1175bSopenharmony_ci            srcname,
182a8e1175bSopenharmony_ci            '-lmbedcrypto']
183a8e1175bSopenharmony_ci
184a8e1175bSopenharmony_ci    p = subprocess.run(args=args, check=False)
185a8e1175bSopenharmony_ci    if p.returncode != 0:
186a8e1175bSopenharmony_ci        return False
187a8e1175bSopenharmony_ci    p = subprocess.run(args=[binname], check=False, env={
188a8e1175bSopenharmony_ci        'LD_LIBRARY_PATH': MBEDTLS_LIBRARY_PATH
189a8e1175bSopenharmony_ci    })
190a8e1175bSopenharmony_ci    if p.returncode != 0:
191a8e1175bSopenharmony_ci        return False
192a8e1175bSopenharmony_ci    os.unlink(srcname)
193a8e1175bSopenharmony_ci    os.unlink(binname)
194a8e1175bSopenharmony_ci    return True
195a8e1175bSopenharmony_ci
196a8e1175bSopenharmony_ci
197a8e1175bSopenharmony_cidef compute_curve(curve):
198a8e1175bSopenharmony_ci    """compute comb table for curve"""
199a8e1175bSopenharmony_ci    r = run_c_source(
200a8e1175bSopenharmony_ci        SRC_DUMP_COMB_TABLE,
201a8e1175bSopenharmony_ci        [
202a8e1175bSopenharmony_ci            '-g',
203a8e1175bSopenharmony_ci            '-DCURVE_ID=MBEDTLS_ECP_DP_%s' % curve.upper(),
204a8e1175bSopenharmony_ci            '-DCURVE_NAME="%s"' % curve.lower(),
205a8e1175bSopenharmony_ci        ])
206a8e1175bSopenharmony_ci    if not r:
207a8e1175bSopenharmony_ci        print("""\
208a8e1175bSopenharmony_ciUnable to compile and run utility.""", file=sys.stderr)
209a8e1175bSopenharmony_ci        sys.exit(1)
210a8e1175bSopenharmony_ci
211a8e1175bSopenharmony_ci
212a8e1175bSopenharmony_cidef usage():
213a8e1175bSopenharmony_ci    print("""
214a8e1175bSopenharmony_ciUsage: python %s <curve>...
215a8e1175bSopenharmony_ci
216a8e1175bSopenharmony_ciArguments:
217a8e1175bSopenharmony_ci    curve       Specify one or more curve names (e.g secp256r1)
218a8e1175bSopenharmony_ci
219a8e1175bSopenharmony_ciAll possible curves: """ % sys.argv[0])
220a8e1175bSopenharmony_ci    run_c_source(SRC_DUMP_KNOWN_CURVE, [])
221a8e1175bSopenharmony_ci    print("""
222a8e1175bSopenharmony_ciEnvironment Variable:
223a8e1175bSopenharmony_ci    CC          Specify which c compile to use to compile utility.
224a8e1175bSopenharmony_ci    MBEDTLS_LIBRARY_PATH
225a8e1175bSopenharmony_ci                Specify the path to mbedcrypto library. (e.g. build/library/)
226a8e1175bSopenharmony_ci
227a8e1175bSopenharmony_ciHow to add a new curve: %s""" % HOW_TO_ADD_NEW_CURVE)
228a8e1175bSopenharmony_ci
229a8e1175bSopenharmony_ci
230a8e1175bSopenharmony_cidef run_main():
231a8e1175bSopenharmony_ci    shared_lib_path = os.path.normpath(os.path.join(MBEDTLS_LIBRARY_PATH, "libmbedcrypto.so"))
232a8e1175bSopenharmony_ci    static_lib_path = os.path.normpath(os.path.join(MBEDTLS_LIBRARY_PATH, "libmbedcrypto.a"))
233a8e1175bSopenharmony_ci    if not os.path.exists(shared_lib_path) and not os.path.exists(static_lib_path):
234a8e1175bSopenharmony_ci        print("Warning: both '%s' and '%s' are not exists. This script will use "
235a8e1175bSopenharmony_ci              "the library from your system instead of the library compiled by "
236a8e1175bSopenharmony_ci              "this source directory.\n"
237a8e1175bSopenharmony_ci              "You can specify library path using environment variable "
238a8e1175bSopenharmony_ci              "'MBEDTLS_LIBRARY_PATH'." % (shared_lib_path, static_lib_path),
239a8e1175bSopenharmony_ci              file=sys.stderr)
240a8e1175bSopenharmony_ci
241a8e1175bSopenharmony_ci    if len(sys.argv) <= 1:
242a8e1175bSopenharmony_ci        usage()
243a8e1175bSopenharmony_ci    else:
244a8e1175bSopenharmony_ci        for curve in sys.argv[1:]:
245a8e1175bSopenharmony_ci            compute_curve(curve)
246a8e1175bSopenharmony_ci
247a8e1175bSopenharmony_ci
248a8e1175bSopenharmony_ciif __name__ == '__main__':
249a8e1175bSopenharmony_ci    run_main()
250