kXuan | b2b3ec4 | 2021-04-10 14:56:39 +0800 | [diff] [blame] | 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 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() |