blob: 760890b455a962827aa34618c4bcbb4c15959075 [file] [log] [blame]
Paul Bakker33b43f12013-08-20 11:48:36 +02001/* BEGIN_HEADER */
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +00002#include "mbedtls/ecdsa.h"
Andrzej Kurek9f42c062022-08-08 03:49:10 -04003#include "legacy_or_psa.h"
4#if ( defined(MBEDTLS_ECDSA_DETERMINISTIC) && defined(MBEDTLS_SHA256_C) ) || \
5 ( !defined(MBEDTLS_ECDSA_DETERMINISTIC) && defined(MBEDTLS_HAS_ALG_SHA_256_VIA_LOWLEVEL_OR_PSA) )
6#define MBEDTLS_HAS_ALG_SHA_256_VIA_MD_IF_DETERMINISTIC
7#endif
Andrzej Kurek1af61cb2022-08-11 09:19:42 -04008#define MBEDTLS_TEST_HASH_MAX_SIZE 64
Paul Bakker33b43f12013-08-20 11:48:36 +02009/* END_HEADER */
Manuel Pégourié-Gonnardd1c71502013-01-26 19:09:07 +010010
Paul Bakker33b43f12013-08-20 11:48:36 +020011/* BEGIN_DEPENDENCIES
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020012 * depends_on:MBEDTLS_ECDSA_C
Paul Bakker33b43f12013-08-20 11:48:36 +020013 * END_DEPENDENCIES
14 */
Manuel Pégourié-Gonnardd1c71502013-01-26 19:09:07 +010015
Paul Bakker33b43f12013-08-20 11:48:36 +020016/* BEGIN_CASE */
TRodziewicz40de3c92021-04-07 19:16:18 +020017void ecdsa_prim_zero( int id )
Manuel Pégourié-Gonnardd1c71502013-01-26 19:09:07 +010018{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020019 mbedtls_ecp_group grp;
20 mbedtls_ecp_point Q;
21 mbedtls_mpi d, r, s;
Ronald Cron351f0ee2020-06-10 12:12:18 +020022 mbedtls_test_rnd_pseudo_info rnd_info;
Andrzej Kurek1af61cb2022-08-11 09:19:42 -040023 unsigned char buf[MBEDTLS_TEST_HASH_MAX_SIZE];
Manuel Pégourié-Gonnardd1c71502013-01-26 19:09:07 +010024
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020025 mbedtls_ecp_group_init( &grp );
26 mbedtls_ecp_point_init( &Q );
27 mbedtls_mpi_init( &d ); mbedtls_mpi_init( &r ); mbedtls_mpi_init( &s );
Ronald Cron351f0ee2020-06-10 12:12:18 +020028 memset( &rnd_info, 0x00, sizeof( mbedtls_test_rnd_pseudo_info ) );
Manuel Pégourié-Gonnard450a1632013-01-27 09:08:18 +010029 memset( buf, 0, sizeof( buf ) );
Manuel Pégourié-Gonnardd1c71502013-01-26 19:09:07 +010030
TRodziewicz40de3c92021-04-07 19:16:18 +020031 TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
32 TEST_ASSERT( mbedtls_ecp_gen_keypair( &grp, &d, &Q,
33 &mbedtls_test_rnd_pseudo_rand,
34 &rnd_info ) == 0 );
Manuel Pégourié-Gonnardd1c71502013-01-26 19:09:07 +010035
TRodziewicz40de3c92021-04-07 19:16:18 +020036 TEST_ASSERT( mbedtls_ecdsa_sign( &grp, &r, &s, &d, buf, sizeof( buf ),
37 &mbedtls_test_rnd_pseudo_rand,
38 &rnd_info ) == 0 );
39 TEST_ASSERT( mbedtls_ecdsa_verify( &grp, buf, sizeof( buf ), &Q, &r, &s ) == 0 );
TRodziewicz5feb6702021-04-06 19:55:17 +020040
TRodziewicz40de3c92021-04-07 19:16:18 +020041exit:
42 mbedtls_ecp_group_free( &grp );
43 mbedtls_ecp_point_free( &Q );
44 mbedtls_mpi_free( &d ); mbedtls_mpi_free( &r ); mbedtls_mpi_free( &s );
45}
46/* END_CASE */
47
48/* BEGIN_CASE */
49void ecdsa_prim_random( int id )
50{
51 mbedtls_ecp_group grp;
52 mbedtls_ecp_point Q;
53 mbedtls_mpi d, r, s;
54 mbedtls_test_rnd_pseudo_info rnd_info;
Andrzej Kurek1af61cb2022-08-11 09:19:42 -040055 unsigned char buf[MBEDTLS_TEST_HASH_MAX_SIZE];
TRodziewicz40de3c92021-04-07 19:16:18 +020056
57 mbedtls_ecp_group_init( &grp );
58 mbedtls_ecp_point_init( &Q );
59 mbedtls_mpi_init( &d ); mbedtls_mpi_init( &r ); mbedtls_mpi_init( &s );
60 memset( &rnd_info, 0x00, sizeof( mbedtls_test_rnd_pseudo_info ) );
61 memset( buf, 0, sizeof( buf ) );
62
63 /* prepare material for signature */
64 TEST_ASSERT( mbedtls_test_rnd_pseudo_rand( &rnd_info,
65 buf, sizeof( buf ) ) == 0 );
66 TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
67 TEST_ASSERT( mbedtls_ecp_gen_keypair( &grp, &d, &Q,
68 &mbedtls_test_rnd_pseudo_rand,
69 &rnd_info ) == 0 );
70
71 TEST_ASSERT( mbedtls_ecdsa_sign( &grp, &r, &s, &d, buf, sizeof( buf ),
72 &mbedtls_test_rnd_pseudo_rand,
73 &rnd_info ) == 0 );
74 TEST_ASSERT( mbedtls_ecdsa_verify( &grp, buf, sizeof( buf ), &Q, &r, &s ) == 0 );
Manuel Pégourié-Gonnardd1c71502013-01-26 19:09:07 +010075
Paul Bakkerbd51b262014-07-10 15:26:12 +020076exit:
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020077 mbedtls_ecp_group_free( &grp );
78 mbedtls_ecp_point_free( &Q );
79 mbedtls_mpi_free( &d ); mbedtls_mpi_free( &r ); mbedtls_mpi_free( &s );
Manuel Pégourié-Gonnardd1c71502013-01-26 19:09:07 +010080}
Paul Bakker33b43f12013-08-20 11:48:36 +020081/* END_CASE */
Manuel Pégourié-Gonnard602a8972013-01-27 08:10:28 +010082
Paul Bakker33b43f12013-08-20 11:48:36 +020083/* BEGIN_CASE */
Azim Khanf1aaec92017-05-30 14:23:15 +010084void ecdsa_prim_test_vectors( int id, char * d_str, char * xQ_str,
Azim Khan5fcca462018-06-29 11:05:32 +010085 char * yQ_str, data_t * rnd_buf,
86 data_t * hash, char * r_str, char * s_str,
Azim Khanf1aaec92017-05-30 14:23:15 +010087 int result )
Manuel Pégourié-Gonnard602a8972013-01-27 08:10:28 +010088{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020089 mbedtls_ecp_group grp;
90 mbedtls_ecp_point Q;
Manuel Pégourié-Gonnardec528932022-04-21 09:25:23 +020091 mbedtls_mpi d, r, s, r_check, s_check, zero;
Ronald Cron351f0ee2020-06-10 12:12:18 +020092 mbedtls_test_rnd_buf_info rnd_info;
Manuel Pégourié-Gonnard602a8972013-01-27 08:10:28 +010093
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020094 mbedtls_ecp_group_init( &grp );
95 mbedtls_ecp_point_init( &Q );
96 mbedtls_mpi_init( &d ); mbedtls_mpi_init( &r ); mbedtls_mpi_init( &s );
97 mbedtls_mpi_init( &r_check ); mbedtls_mpi_init( &s_check );
Manuel Pégourié-Gonnardec528932022-04-21 09:25:23 +020098 mbedtls_mpi_init( &zero );
Manuel Pégourié-Gonnard602a8972013-01-27 08:10:28 +010099
Manuel Pégourié-Gonnarde3a062b2015-05-11 18:46:47 +0200100 TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200101 TEST_ASSERT( mbedtls_ecp_point_read_string( &Q, 16, xQ_str, yQ_str ) == 0 );
Werner Lewis19b4cd82022-07-07 11:02:27 +0100102 TEST_ASSERT( mbedtls_test_read_mpi( &d, d_str ) == 0 );
103 TEST_ASSERT( mbedtls_test_read_mpi( &r_check, r_str ) == 0 );
104 TEST_ASSERT( mbedtls_test_read_mpi( &s_check, s_str ) == 0 );
Gilles Peskineecacc3c2021-03-24 00:48:57 +0100105 rnd_info.fallback_f_rng = mbedtls_test_rnd_std_rand;
106 rnd_info.fallback_p_rng = NULL;
Azim Khand30ca132017-06-09 04:32:58 +0100107 rnd_info.buf = rnd_buf->x;
108 rnd_info.length = rnd_buf->len;
Manuel Pégourié-Gonnard602a8972013-01-27 08:10:28 +0100109
Azim Khand30ca132017-06-09 04:32:58 +0100110 /* Fix rnd_buf->x by shifting it left if necessary */
Manuel Pégourié-Gonnardfae079e2014-01-06 11:00:07 +0100111 if( grp.nbits % 8 != 0 )
112 {
113 unsigned char shift = 8 - ( grp.nbits % 8 );
114 size_t i;
115
116 for( i = 0; i < rnd_info.length - 1; i++ )
Azim Khand30ca132017-06-09 04:32:58 +0100117 rnd_buf->x[i] = rnd_buf->x[i] << shift | rnd_buf->x[i+1] >> ( 8 - shift );
Manuel Pégourié-Gonnardfae079e2014-01-06 11:00:07 +0100118
Azim Khand30ca132017-06-09 04:32:58 +0100119 rnd_buf->x[rnd_info.length-1] <<= shift;
Manuel Pégourié-Gonnardfae079e2014-01-06 11:00:07 +0100120 }
121
Azim Khand30ca132017-06-09 04:32:58 +0100122 TEST_ASSERT( mbedtls_ecdsa_sign( &grp, &r, &s, &d, hash->x, hash->len,
Ronald Cron351f0ee2020-06-10 12:12:18 +0200123 mbedtls_test_rnd_buffer_rand, &rnd_info ) == result );
Manuel Pégourié-Gonnard602a8972013-01-27 08:10:28 +0100124
Darryl Greenf5bcbed2017-11-17 17:09:31 +0000125 if ( result == 0)
126 {
Manuel Pégourié-Gonnardec528932022-04-21 09:25:23 +0200127 /* Check we generated the expected values */
Manuel Pégourié-Gonnardd8d19de2022-04-20 10:34:22 +0200128 TEST_EQUAL( mbedtls_mpi_cmp_mpi( &r, &r_check ), 0 );
129 TEST_EQUAL( mbedtls_mpi_cmp_mpi( &s, &s_check ), 0 );
Manuel Pégourié-Gonnard602a8972013-01-27 08:10:28 +0100130
Manuel Pégourié-Gonnardd8d19de2022-04-20 10:34:22 +0200131 /* Valid signature */
132 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len,
133 &Q, &r_check, &s_check ), 0 );
Manuel Pégourié-Gonnardd0a66cc2018-06-13 09:53:21 +0200134
Manuel Pégourié-Gonnardd8d19de2022-04-20 10:34:22 +0200135 /* Invalid signature: wrong public key (G instead of Q) */
136 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len,
137 &grp.G, &r_check, &s_check ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
Manuel Pégourié-Gonnardd0a66cc2018-06-13 09:53:21 +0200138
Manuel Pégourié-Gonnardd8d19de2022-04-20 10:34:22 +0200139 /* Invalid signatures: r or s or both one off */
Manuel Pégourié-Gonnardec528932022-04-21 09:25:23 +0200140 TEST_EQUAL( mbedtls_mpi_sub_int( &r, &r_check, 1 ), 0 );
141 TEST_EQUAL( mbedtls_mpi_add_int( &s, &s_check, 1 ), 0 );
Manuel Pégourié-Gonnardd8d19de2022-04-20 10:34:22 +0200142
143 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
144 &r, &s_check ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
145 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
146 &r_check, &s ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
147 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
148 &r, &s ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
149
150 /* Invalid signatures: r, s or both (CVE-2022-21449) are zero */
Manuel Pégourié-Gonnardec528932022-04-21 09:25:23 +0200151 TEST_EQUAL( mbedtls_mpi_lset( &zero, 0 ), 0 );
Manuel Pégourié-Gonnardd8d19de2022-04-20 10:34:22 +0200152
153 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
Manuel Pégourié-Gonnardec528932022-04-21 09:25:23 +0200154 &zero, &s_check ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
Manuel Pégourié-Gonnardd8d19de2022-04-20 10:34:22 +0200155 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
Manuel Pégourié-Gonnardec528932022-04-21 09:25:23 +0200156 &r_check, &zero ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
Manuel Pégourié-Gonnardd8d19de2022-04-20 10:34:22 +0200157 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
Manuel Pégourié-Gonnardec528932022-04-21 09:25:23 +0200158 &zero, &zero ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
Manuel Pégourié-Gonnardd8d19de2022-04-20 10:34:22 +0200159
160 /* Invalid signatures: r, s or both are == N */
Manuel Pégourié-Gonnardec528932022-04-21 09:25:23 +0200161 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
162 &grp.N, &s_check ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
163 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
164 &r_check, &grp.N ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
165 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
166 &grp.N, &grp.N ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
167
168 /* Invalid signatures: r, s or both are negative */
169 TEST_EQUAL( mbedtls_mpi_sub_mpi( &r, &r_check, &grp.N ), 0 );
170 TEST_EQUAL( mbedtls_mpi_sub_mpi( &s, &s_check, &grp.N ), 0 );
Manuel Pégourié-Gonnardd8d19de2022-04-20 10:34:22 +0200171
172 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
173 &r, &s_check ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
174 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
175 &r_check, &s ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
176 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
177 &r, &s ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
178
179 /* Invalid signatures: r or s or both are > N */
Manuel Pégourié-Gonnardec528932022-04-21 09:25:23 +0200180 TEST_EQUAL( mbedtls_mpi_add_mpi( &r, &r_check, &grp.N ), 0 );
181 TEST_EQUAL( mbedtls_mpi_add_mpi( &s, &s_check, &grp.N ), 0 );
Manuel Pégourié-Gonnardd8d19de2022-04-20 10:34:22 +0200182
183 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
184 &r, &s_check ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
185 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
186 &r_check, &s ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
187 TEST_EQUAL( mbedtls_ecdsa_verify( &grp, hash->x, hash->len, &Q,
188 &r, &s ), MBEDTLS_ERR_ECP_VERIFY_FAILED );
Darryl Greenf5bcbed2017-11-17 17:09:31 +0000189 }
Manuel Pégourié-Gonnard602a8972013-01-27 08:10:28 +0100190
Paul Bakkerbd51b262014-07-10 15:26:12 +0200191exit:
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200192 mbedtls_ecp_group_free( &grp );
193 mbedtls_ecp_point_free( &Q );
194 mbedtls_mpi_free( &d ); mbedtls_mpi_free( &r ); mbedtls_mpi_free( &s );
195 mbedtls_mpi_free( &r_check ); mbedtls_mpi_free( &s_check );
Manuel Pégourié-Gonnardec528932022-04-21 09:25:23 +0200196 mbedtls_mpi_free( &zero );
Manuel Pégourié-Gonnard602a8972013-01-27 08:10:28 +0100197}
Paul Bakker33b43f12013-08-20 11:48:36 +0200198/* END_CASE */
Manuel Pégourié-Gonnardb694b482013-08-08 13:30:57 +0200199
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200200/* BEGIN_CASE depends_on:MBEDTLS_ECDSA_DETERMINISTIC */
Neil Armstrong5ea65172022-07-19 16:54:28 +0200201void ecdsa_det_test_vectors( int id, char * d_str, int md_alg, data_t * hash,
Azim Khanf1aaec92017-05-30 14:23:15 +0100202 char * r_str, char * s_str )
Manuel Pégourié-Gonnard4daaef72014-01-06 14:25:56 +0100203{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200204 mbedtls_ecp_group grp;
205 mbedtls_mpi d, r, s, r_check, s_check;
Manuel Pégourié-Gonnard4daaef72014-01-06 14:25:56 +0100206
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200207 mbedtls_ecp_group_init( &grp );
208 mbedtls_mpi_init( &d ); mbedtls_mpi_init( &r ); mbedtls_mpi_init( &s );
209 mbedtls_mpi_init( &r_check ); mbedtls_mpi_init( &s_check );
Manuel Pégourié-Gonnard4daaef72014-01-06 14:25:56 +0100210
Manuel Pégourié-Gonnarde3a062b2015-05-11 18:46:47 +0200211 TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 );
Werner Lewis19b4cd82022-07-07 11:02:27 +0100212 TEST_ASSERT( mbedtls_test_read_mpi( &d, d_str ) == 0 );
213 TEST_ASSERT( mbedtls_test_read_mpi( &r_check, r_str ) == 0 );
214 TEST_ASSERT( mbedtls_test_read_mpi( &s_check, s_str ) == 0 );
Manuel Pégourié-Gonnard4daaef72014-01-06 14:25:56 +0100215
Janos Follath651eac82019-01-04 15:51:24 +0000216 TEST_ASSERT(
Neil Armstrong5ea65172022-07-19 16:54:28 +0200217 mbedtls_ecdsa_sign_det_ext( &grp, &r, &s, &d,
218 hash->x, hash->len, md_alg,
219 mbedtls_test_rnd_std_rand,
Ronald Cron6c5bd7f2020-06-10 14:08:26 +0200220 NULL )
Janos Follath651eac82019-01-04 15:51:24 +0000221 == 0 );
Manuel Pégourié-Gonnard4daaef72014-01-06 14:25:56 +0100222
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200223 TEST_ASSERT( mbedtls_mpi_cmp_mpi( &r, &r_check ) == 0 );
224 TEST_ASSERT( mbedtls_mpi_cmp_mpi( &s, &s_check ) == 0 );
Manuel Pégourié-Gonnard4daaef72014-01-06 14:25:56 +0100225
Paul Bakkerbd51b262014-07-10 15:26:12 +0200226exit:
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200227 mbedtls_ecp_group_free( &grp );
228 mbedtls_mpi_free( &d ); mbedtls_mpi_free( &r ); mbedtls_mpi_free( &s );
229 mbedtls_mpi_free( &r_check ); mbedtls_mpi_free( &s_check );
Manuel Pégourié-Gonnard4daaef72014-01-06 14:25:56 +0100230}
231/* END_CASE */
232
Andrzej Kurek9f42c062022-08-08 03:49:10 -0400233/* BEGIN_CASE depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_IF_DETERMINISTIC */
TRodziewicz40de3c92021-04-07 19:16:18 +0200234void ecdsa_write_read_zero( int id )
235{
236 mbedtls_ecdsa_context ctx;
237 mbedtls_test_rnd_pseudo_info rnd_info;
238 unsigned char hash[32];
239 unsigned char sig[200];
240 size_t sig_len, i;
241
242 mbedtls_ecdsa_init( &ctx );
243 memset( &rnd_info, 0x00, sizeof( mbedtls_test_rnd_pseudo_info ) );
244 memset( hash, 0, sizeof( hash ) );
245 memset( sig, 0x2a, sizeof( sig ) );
TRodziewicz40de3c92021-04-07 19:16:18 +0200246
247 /* generate signing key */
248 TEST_ASSERT( mbedtls_ecdsa_genkey( &ctx, id,
249 &mbedtls_test_rnd_pseudo_rand,
250 &rnd_info ) == 0 );
251
252 /* generate and write signature, then read and verify it */
253 TEST_ASSERT( mbedtls_ecdsa_write_signature( &ctx, MBEDTLS_MD_SHA256,
254 hash, sizeof( hash ),
Gilles Peskinef00f1522021-06-22 00:09:00 +0200255 sig, sizeof( sig ), &sig_len, &mbedtls_test_rnd_pseudo_rand,
TRodziewicz40de3c92021-04-07 19:16:18 +0200256 &rnd_info ) == 0 );
257 TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
258 sig, sig_len ) == 0 );
259
260 /* check we didn't write past the announced length */
261 for( i = sig_len; i < sizeof( sig ); i++ )
262 TEST_ASSERT( sig[i] == 0x2a );
263
264 /* try verification with invalid length */
265 TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
266 sig, sig_len - 1 ) != 0 );
267 TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
268 sig, sig_len + 1 ) != 0 );
269
270 /* try invalid sequence tag */
271 sig[0]++;
272 TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
273 sig, sig_len ) != 0 );
274 sig[0]--;
275
276 /* try modifying r */
277 sig[10]++;
278 TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
279 sig, sig_len ) == MBEDTLS_ERR_ECP_VERIFY_FAILED );
280 sig[10]--;
281
282 /* try modifying s */
283 sig[sig_len - 1]++;
284 TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
285 sig, sig_len ) == MBEDTLS_ERR_ECP_VERIFY_FAILED );
286 sig[sig_len - 1]--;
287
288exit:
289 mbedtls_ecdsa_free( &ctx );
290}
291/* END_CASE */
292
Andrzej Kurek9f42c062022-08-08 03:49:10 -0400293/* BEGIN_CASE depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_IF_DETERMINISTIC */
Manuel Pégourié-Gonnardb694b482013-08-08 13:30:57 +0200294void ecdsa_write_read_random( int id )
295{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200296 mbedtls_ecdsa_context ctx;
Ronald Cron351f0ee2020-06-10 12:12:18 +0200297 mbedtls_test_rnd_pseudo_info rnd_info;
Manuel Pégourié-Gonnarddfdcac92015-03-31 11:41:42 +0200298 unsigned char hash[32];
Manuel Pégourié-Gonnardb694b482013-08-08 13:30:57 +0200299 unsigned char sig[200];
300 size_t sig_len, i;
301
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200302 mbedtls_ecdsa_init( &ctx );
Ronald Cron351f0ee2020-06-10 12:12:18 +0200303 memset( &rnd_info, 0x00, sizeof( mbedtls_test_rnd_pseudo_info ) );
Manuel Pégourié-Gonnardb694b482013-08-08 13:30:57 +0200304 memset( hash, 0, sizeof( hash ) );
TRodziewicz40de3c92021-04-07 19:16:18 +0200305 memset( sig, 0x2a, sizeof( sig ) );
Manuel Pégourié-Gonnardb694b482013-08-08 13:30:57 +0200306
TRodziewicz40de3c92021-04-07 19:16:18 +0200307 /* prepare material for signature */
308 TEST_ASSERT( mbedtls_test_rnd_pseudo_rand( &rnd_info,
309 hash, sizeof( hash ) ) == 0 );
Manuel Pégourié-Gonnardb694b482013-08-08 13:30:57 +0200310
TRodziewicz40de3c92021-04-07 19:16:18 +0200311 /* generate signing key */
312 TEST_ASSERT( mbedtls_ecdsa_genkey( &ctx, id,
313 &mbedtls_test_rnd_pseudo_rand,
314 &rnd_info ) == 0 );
Manuel Pégourié-Gonnardb694b482013-08-08 13:30:57 +0200315
TRodziewicz40de3c92021-04-07 19:16:18 +0200316 /* generate and write signature, then read and verify it */
317 TEST_ASSERT( mbedtls_ecdsa_write_signature( &ctx, MBEDTLS_MD_SHA256,
318 hash, sizeof( hash ),
Gilles Peskinef00f1522021-06-22 00:09:00 +0200319 sig, sizeof( sig ), &sig_len, &mbedtls_test_rnd_pseudo_rand,
TRodziewicz40de3c92021-04-07 19:16:18 +0200320 &rnd_info ) == 0 );
321 TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
322 sig, sig_len ) == 0 );
Manuel Pégourié-Gonnardb694b482013-08-08 13:30:57 +0200323
TRodziewicz40de3c92021-04-07 19:16:18 +0200324 /* check we didn't write past the announced length */
325 for( i = sig_len; i < sizeof( sig ); i++ )
326 TEST_ASSERT( sig[i] == 0x2a );
Manuel Pégourié-Gonnardb694b482013-08-08 13:30:57 +0200327
TRodziewicz40de3c92021-04-07 19:16:18 +0200328 /* try verification with invalid length */
329 TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
330 sig, sig_len - 1 ) != 0 );
331 TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
332 sig, sig_len + 1 ) != 0 );
Manuel Pégourié-Gonnardb694b482013-08-08 13:30:57 +0200333
TRodziewicz40de3c92021-04-07 19:16:18 +0200334 /* try invalid sequence tag */
335 sig[0]++;
336 TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
337 sig, sig_len ) != 0 );
338 sig[0]--;
Manuel Pégourié-Gonnardb694b482013-08-08 13:30:57 +0200339
TRodziewicz40de3c92021-04-07 19:16:18 +0200340 /* try modifying r */
341 sig[10]++;
342 TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
343 sig, sig_len ) == MBEDTLS_ERR_ECP_VERIFY_FAILED );
344 sig[10]--;
Manuel Pégourié-Gonnardb694b482013-08-08 13:30:57 +0200345
TRodziewicz40de3c92021-04-07 19:16:18 +0200346 /* try modifying s */
347 sig[sig_len - 1]++;
348 TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ),
349 sig, sig_len ) == MBEDTLS_ERR_ECP_VERIFY_FAILED );
350 sig[sig_len - 1]--;
Manuel Pégourié-Gonnardb694b482013-08-08 13:30:57 +0200351
Paul Bakkerbd51b262014-07-10 15:26:12 +0200352exit:
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200353 mbedtls_ecdsa_free( &ctx );
Manuel Pégourié-Gonnardb694b482013-08-08 13:30:57 +0200354}
355/* END_CASE */
Manuel Pégourié-Gonnard937340b2014-01-06 10:27:16 +0100356
Manuel Pégourié-Gonnard722e5152017-04-21 11:04:47 +0200357/* BEGIN_CASE depends_on:MBEDTLS_ECP_RESTARTABLE */
Ronald Cron9ed40732020-06-25 09:03:34 +0200358void ecdsa_read_restart( int id, data_t *pk, data_t *hash, data_t *sig,
Manuel Pégourié-Gonnard722e5152017-04-21 11:04:47 +0200359 int max_ops, int min_restart, int max_restart )
360{
361 mbedtls_ecdsa_context ctx;
362 mbedtls_ecdsa_restart_ctx rs_ctx;
Manuel Pégourié-Gonnard722e5152017-04-21 11:04:47 +0200363 int ret, cnt_restart;
364
365 mbedtls_ecdsa_init( &ctx );
366 mbedtls_ecdsa_restart_init( &rs_ctx );
367
Manuel Pégourié-Gonnard722e5152017-04-21 11:04:47 +0200368 TEST_ASSERT( mbedtls_ecp_group_load( &ctx.grp, id ) == 0 );
Ronald Cron9ed40732020-06-25 09:03:34 +0200369 TEST_ASSERT( mbedtls_ecp_point_read_binary( &ctx.grp, &ctx.Q,
370 pk->x, pk->len ) == 0 );
Manuel Pégourié-Gonnard722e5152017-04-21 11:04:47 +0200371
372 mbedtls_ecp_set_max_ops( max_ops );
373
374 cnt_restart = 0;
375 do {
376 ret = mbedtls_ecdsa_read_signature_restartable( &ctx,
Ronald Cron9ed40732020-06-25 09:03:34 +0200377 hash->x, hash->len, sig->x, sig->len, &rs_ctx );
Manuel Pégourié-Gonnard722e5152017-04-21 11:04:47 +0200378 } while( ret == MBEDTLS_ERR_ECP_IN_PROGRESS && ++cnt_restart );
379
380 TEST_ASSERT( ret == 0 );
381 TEST_ASSERT( cnt_restart >= min_restart );
382 TEST_ASSERT( cnt_restart <= max_restart );
383
384 /* try modifying r */
Ronald Cron9ed40732020-06-25 09:03:34 +0200385
386 TEST_ASSERT( sig->len > 10 );
387 sig->x[10]++;
Manuel Pégourié-Gonnard722e5152017-04-21 11:04:47 +0200388 do {
389 ret = mbedtls_ecdsa_read_signature_restartable( &ctx,
Ronald Cron9ed40732020-06-25 09:03:34 +0200390 hash->x, hash->len, sig->x, sig->len, &rs_ctx );
Manuel Pégourié-Gonnard722e5152017-04-21 11:04:47 +0200391 } while( ret == MBEDTLS_ERR_ECP_IN_PROGRESS );
392 TEST_ASSERT( ret == MBEDTLS_ERR_ECP_VERIFY_FAILED );
Ronald Cron9ed40732020-06-25 09:03:34 +0200393 sig->x[10]--;
Manuel Pégourié-Gonnard722e5152017-04-21 11:04:47 +0200394
395 /* try modifying s */
Ronald Cron9ed40732020-06-25 09:03:34 +0200396 sig->x[sig->len - 1]++;
Manuel Pégourié-Gonnard722e5152017-04-21 11:04:47 +0200397 do {
398 ret = mbedtls_ecdsa_read_signature_restartable( &ctx,
Ronald Cron9ed40732020-06-25 09:03:34 +0200399 hash->x, hash->len, sig->x, sig->len, &rs_ctx );
Manuel Pégourié-Gonnard722e5152017-04-21 11:04:47 +0200400 } while( ret == MBEDTLS_ERR_ECP_IN_PROGRESS );
401 TEST_ASSERT( ret == MBEDTLS_ERR_ECP_VERIFY_FAILED );
Ronald Cron9ed40732020-06-25 09:03:34 +0200402 sig->x[sig->len - 1]--;
Manuel Pégourié-Gonnard722e5152017-04-21 11:04:47 +0200403
Manuel Pégourié-Gonnard46ba7f32017-08-28 12:20:39 +0200404 /* Do we leak memory when aborting an operation?
405 * This test only makes sense when we actually restart */
406 if( min_restart > 0 )
407 {
408 ret = mbedtls_ecdsa_read_signature_restartable( &ctx,
Ronald Cron9ed40732020-06-25 09:03:34 +0200409 hash->x, hash->len, sig->x, sig->len, &rs_ctx );
Manuel Pégourié-Gonnard46ba7f32017-08-28 12:20:39 +0200410 TEST_ASSERT( ret == MBEDTLS_ERR_ECP_IN_PROGRESS );
411 }
Manuel Pégourié-Gonnard722e5152017-04-21 11:04:47 +0200412
413exit:
414 mbedtls_ecdsa_free( &ctx );
415 mbedtls_ecdsa_restart_free( &rs_ctx );
416}
417/* END_CASE */
Manuel Pégourié-Gonnardeb402f32017-04-25 10:57:30 +0200418
419/* BEGIN_CASE depends_on:MBEDTLS_ECP_RESTARTABLE:MBEDTLS_ECDSA_DETERMINISTIC */
420void ecdsa_write_restart( int id, char *d_str, int md_alg,
Neil Armstrong5ea65172022-07-19 16:54:28 +0200421 data_t *hash, data_t *sig_check,
Manuel Pégourié-Gonnardeb402f32017-04-25 10:57:30 +0200422 int max_ops, int min_restart, int max_restart )
423{
424 int ret, cnt_restart;
425 mbedtls_ecdsa_restart_ctx rs_ctx;
426 mbedtls_ecdsa_context ctx;
Manuel Pégourié-Gonnardeb402f32017-04-25 10:57:30 +0200427 unsigned char sig[MBEDTLS_ECDSA_MAX_LEN];
Neil Armstrong5ea65172022-07-19 16:54:28 +0200428 size_t slen;
Manuel Pégourié-Gonnardeb402f32017-04-25 10:57:30 +0200429
430 mbedtls_ecdsa_restart_init( &rs_ctx );
431 mbedtls_ecdsa_init( &ctx );
Manuel Pégourié-Gonnardeb402f32017-04-25 10:57:30 +0200432 memset( sig, 0, sizeof( sig ) );
Manuel Pégourié-Gonnardeb402f32017-04-25 10:57:30 +0200433
434 TEST_ASSERT( mbedtls_ecp_group_load( &ctx.grp, id ) == 0 );
Werner Lewis19b4cd82022-07-07 11:02:27 +0100435 TEST_ASSERT( mbedtls_test_read_mpi( &ctx.d, d_str ) == 0 );
Manuel Pégourié-Gonnardeb402f32017-04-25 10:57:30 +0200436
Manuel Pégourié-Gonnardeb402f32017-04-25 10:57:30 +0200437 mbedtls_ecp_set_max_ops( max_ops );
438
439 slen = sizeof( sig );
440 cnt_restart = 0;
441 do {
442 ret = mbedtls_ecdsa_write_signature_restartable( &ctx,
Neil Armstrong5ea65172022-07-19 16:54:28 +0200443 md_alg, hash->x, hash->len, sig, sizeof( sig ), &slen,
Gilles Peskinef00f1522021-06-22 00:09:00 +0200444 mbedtls_test_rnd_std_rand, NULL, &rs_ctx );
Manuel Pégourié-Gonnardeb402f32017-04-25 10:57:30 +0200445 } while( ret == MBEDTLS_ERR_ECP_IN_PROGRESS && ++cnt_restart );
446
447 TEST_ASSERT( ret == 0 );
Ronald Cron9ed40732020-06-25 09:03:34 +0200448 TEST_ASSERT( slen == sig_check->len );
449 TEST_ASSERT( memcmp( sig, sig_check->x, slen ) == 0 );
Manuel Pégourié-Gonnardeb402f32017-04-25 10:57:30 +0200450
451 TEST_ASSERT( cnt_restart >= min_restart );
452 TEST_ASSERT( cnt_restart <= max_restart );
453
Manuel Pégourié-Gonnard46ba7f32017-08-28 12:20:39 +0200454 /* Do we leak memory when aborting an operation?
455 * This test only makes sense when we actually restart */
456 if( min_restart > 0 )
457 {
458 ret = mbedtls_ecdsa_write_signature_restartable( &ctx,
Neil Armstrong5ea65172022-07-19 16:54:28 +0200459 md_alg, hash->x, hash->len, sig, sizeof( sig ), &slen,
Gilles Peskinef00f1522021-06-22 00:09:00 +0200460 mbedtls_test_rnd_std_rand, NULL, &rs_ctx );
Manuel Pégourié-Gonnard46ba7f32017-08-28 12:20:39 +0200461 TEST_ASSERT( ret == MBEDTLS_ERR_ECP_IN_PROGRESS );
462 }
Manuel Pégourié-Gonnardeb402f32017-04-25 10:57:30 +0200463
464exit:
465 mbedtls_ecdsa_restart_free( &rs_ctx );
466 mbedtls_ecdsa_free( &ctx );
467}
468/* END_CASE */
Dave Rodgman1fdb8e82022-08-10 11:32:07 +0100469
470/* BEGIN_CASE */
471void ecdsa_verify( int grp_id, char * x, char * y, char * r, char * s, int len, int key_is_valid, int expected )
472{
473 uint8_t FUZZ_DATA[] = {
474 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 32, 136, 251, 46, 240, 45, 45, 27, 62, 60, 0, 0, 0, 32, 32, 32, 32, 124, 102, 235, 242, 220, 21, 68, 255, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 121, 1, 0, 0, 0, 91, 1, 0, 0, 0, 151, 1, 0, 0, 0, 32, 32, 255, 32, 32, 150, 14, 240, 249, 163, 174, 190, 100, 0, 0, 0, 0, 32, 32, 32, 32, 51, 48, 79, 125, 229, 21, 223, 118, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
475 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
476 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
477 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
478 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
479 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
480 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
481 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
482 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
483 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
484 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
485 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
486 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
487 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
488 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
489 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
490 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
491 };
492
493 mbedtls_ecdsa_context ctx;
494 mbedtls_mpi sig_r, sig_s;
495 const mbedtls_ecp_curve_info *curve_info;
496
497 mbedtls_ecdsa_init( &ctx );
498 mbedtls_mpi_init( &sig_r );
499 mbedtls_mpi_init( &sig_s );
500
501 /* Prepare ECP group context */
502 curve_info = mbedtls_ecp_curve_info_from_grp_id( grp_id );
503 TEST_ASSERT( curve_info != NULL );
504 TEST_EQUAL( mbedtls_ecp_group_load( &ctx.grp, curve_info->grp_id ), 0 );
505
506 /* Prepare public key */
Dave Rodgmanb44c7282022-08-11 13:47:35 +0100507 TEST_EQUAL( mbedtls_test_read_mpi( &ctx.Q.X, x ), 0 );
508 TEST_EQUAL( mbedtls_test_read_mpi( &ctx.Q.Y, y ), 0 );
Dave Rodgman1fdb8e82022-08-10 11:32:07 +0100509 TEST_EQUAL( mbedtls_mpi_lset( &ctx.Q.Z, 1 ), 0 );
510
511 /* Prepare signature R & S */
Dave Rodgmanb44c7282022-08-11 13:47:35 +0100512 TEST_EQUAL( mbedtls_test_read_mpi( &sig_r, r ), 0 );
513 TEST_EQUAL( mbedtls_test_read_mpi( &sig_s, s ), 0 );
Dave Rodgman1fdb8e82022-08-10 11:32:07 +0100514
515 /* Test whether public key has expected validity */
516 TEST_EQUAL( mbedtls_ecp_check_pubkey( &ctx.grp, &ctx.Q ), key_is_valid ? 0 : MBEDTLS_ERR_ECP_INVALID_KEY );
517
518 /* Verification */
Dave Rodgmanb44c7282022-08-11 13:47:35 +0100519 int result = mbedtls_ecdsa_verify( &ctx.grp, FUZZ_DATA, (size_t)len, &ctx.Q, &sig_r, &sig_s );
Dave Rodgman1fdb8e82022-08-10 11:32:07 +0100520
521 TEST_EQUAL( result, expected );
522
523 if ( !key_is_valid ) {
524 /* Invalid public key must always fail */
525 TEST_ASSERT( result != 0 );
526 }
527
528exit:
529 mbedtls_ecdsa_free( &ctx );
530 mbedtls_mpi_free( &sig_r );
531 mbedtls_mpi_free( &sig_s );
532}
Dave Rodgman56cfb312022-08-10 12:21:23 +0100533/* END_CASE */