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