1 /* $OpenBSD: bn_cmp.c,v 1.2 2023/06/21 07:16:08 jsing Exp $ */ 2 /* 3 * Copyright (c) 2022 Joel Sing <jsing@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <stdio.h> 19 20 #include <openssl/bn.h> 21 22 struct bn_cmp_test { 23 const char *a; 24 const char *b; 25 int cmp; 26 int ucmp; 27 }; 28 29 struct bn_cmp_test bn_cmp_tests[] = { 30 { 31 .a = "0", 32 .b = "0", 33 .cmp = 0, 34 .ucmp = 0, 35 }, 36 { 37 .a = "-1", 38 .b = "0", 39 .cmp = -1, 40 .ucmp = 1, 41 }, 42 { 43 .a = "1ffffffffffffffff", 44 .b = "1ffffffffffffffff", 45 .cmp = 0, 46 .ucmp = 0, 47 }, 48 { 49 .a = "1fffffffffffffffe", 50 .b = "1ffffffffffffffff", 51 .cmp = -1, 52 .ucmp = -1, 53 }, 54 { 55 .a = "1ffffffffffffffff", 56 .b = "1fffffffffffffffe", 57 .cmp = 1, 58 .ucmp = 1, 59 }, 60 { 61 .a = "0", 62 .b = "1ffffffffffffffff", 63 .cmp = -1, 64 .ucmp = -1, 65 }, 66 { 67 .a = "1ffffffffffffffff", 68 .b = "0", 69 .cmp = 1, 70 .ucmp = 1, 71 }, 72 { 73 .a = "-1ffffffffffffffff", 74 .b = "0", 75 .cmp = -1, 76 .ucmp = 1, 77 }, 78 { 79 .a = "1ffffffffffffffff", 80 .b = "00000000000000001ffffffffffffffff", 81 .cmp = 0, 82 .ucmp = 0, 83 }, 84 { 85 .a = "-1ffffffffffffffff", 86 .b = "-00000000000000001ffffffffffffffff", 87 .cmp = 0, 88 .ucmp = 0, 89 }, 90 { 91 .a = "1ffffffffffffffff", 92 .b = "-00000000000000001ffffffffffffffff", 93 .cmp = 1, 94 .ucmp = 0, 95 }, 96 { 97 .a = "-1ffffffffffffffff", 98 .b = "00000000000000001ffffffffffffffff", 99 .cmp = -1, 100 .ucmp = 0, 101 }, 102 }; 103 104 #define N_BN_CMP_TESTS \ 105 (sizeof(bn_cmp_tests) / sizeof(*bn_cmp_tests)) 106 107 static int 108 test_bn_cmp(void) 109 { 110 struct bn_cmp_test *bct; 111 BIGNUM *a = NULL, *b = NULL; 112 size_t i; 113 int ret; 114 int failed = 1; 115 116 if ((a = BN_new()) == NULL) { 117 fprintf(stderr, "FAIL: failed to create BN\n"); 118 goto failure; 119 } 120 if ((b = BN_new()) == NULL) { 121 fprintf(stderr, "FAIL: failed to create BN\n"); 122 goto failure; 123 } 124 125 for (i = 0; i < N_BN_CMP_TESTS; i++) { 126 bct = &bn_cmp_tests[i]; 127 128 if (!BN_hex2bn(&a, bct->a)) { 129 fprintf(stderr, "FAIL: failed to set a from hex\n"); 130 goto failure; 131 } 132 if (!BN_hex2bn(&b, bct->b)) { 133 fprintf(stderr, "FAIL: failed to set b from hex\n"); 134 goto failure; 135 } 136 137 if ((ret = BN_cmp(a, b)) != bct->cmp) { 138 fprintf(stderr, "FAIL: BN_cmp(%s, %s) = %d, want %d\n", 139 bct->a, bct->b, ret, bct->cmp); 140 goto failure; 141 } 142 if ((ret = BN_ucmp(a, b)) != bct->ucmp) { 143 fprintf(stderr, "FAIL: BN_ucmp(%s, %s) = %d, want %d\n", 144 bct->a, bct->b, ret, bct->ucmp); 145 goto failure; 146 } 147 } 148 149 failed = 0; 150 151 failure: 152 BN_free(a); 153 BN_free(b); 154 155 return failed; 156 } 157 158 static int 159 test_bn_cmp_null(void) 160 { 161 BIGNUM *a = NULL; 162 int ret; 163 int failed = 1; 164 165 if ((a = BN_new()) == NULL) { 166 fprintf(stderr, "FAIL: failed to create BN\n"); 167 goto failure; 168 } 169 170 /* 171 * Comparison to NULL. 172 */ 173 if ((ret = BN_cmp(NULL, NULL)) != 0) { 174 fprintf(stderr, "FAIL: BN_cmp(NULL, NULL) == %d, want 0\n", ret); 175 goto failure; 176 } 177 178 if ((ret = BN_cmp(a, NULL)) != -1) { 179 fprintf(stderr, "FAIL: BN_cmp(0, NULL) == %d, want -1\n", ret); 180 goto failure; 181 } 182 if ((ret = BN_cmp(NULL, a)) != 1) { 183 fprintf(stderr, "FAIL: BN_cmp(NULL, 0) == %d, want 1\n", ret); 184 goto failure; 185 } 186 187 if (!BN_set_word(a, 1)) { 188 fprintf(stderr, "FAIL: failed to set BN to 1\n"); 189 goto failure; 190 } 191 if ((ret = BN_cmp(a, NULL)) != -1) { 192 fprintf(stderr, "FAIL: BN_cmp(1, NULL) == %d, want -1\n", ret); 193 goto failure; 194 } 195 if ((ret = BN_cmp(NULL, a)) != 1) { 196 fprintf(stderr, "FAIL: BN_cmp(NULL, 1) == %d, want 1\n", ret); 197 goto failure; 198 } 199 200 BN_set_negative(a, 1); 201 if ((ret = BN_cmp(a, NULL)) != -1) { 202 fprintf(stderr, "FAIL: BN_cmp(-1, NULL) == %d, want -1\n", ret); 203 goto failure; 204 } 205 if ((ret = BN_cmp(NULL, a)) != 1) { 206 fprintf(stderr, "FAIL: BN_cmp(NULL, -1) == %d, want 1\n", ret); 207 goto failure; 208 } 209 210 failed = 0; 211 212 failure: 213 BN_free(a); 214 215 return failed; 216 } 217 218 struct bn_cmp_word_test { 219 int a; 220 int b; 221 int cmp; 222 int ucmp; 223 }; 224 225 struct bn_cmp_word_test bn_cmp_word_tests[] = { 226 { 227 .a = -1, 228 .b = -1, 229 .cmp = 0, 230 .ucmp = 0, 231 }, 232 { 233 .a = 0, 234 .b = 0, 235 .cmp = 0, 236 .ucmp = 0, 237 }, 238 { 239 .a = 1, 240 .b = 1, 241 .cmp = 0, 242 .ucmp = 0, 243 }, 244 { 245 .a = 0, 246 .b = 1, 247 .cmp = -1, 248 .ucmp = -1, 249 }, 250 { 251 .a = 1, 252 .b = 0, 253 .cmp = 1, 254 .ucmp = 1, 255 }, 256 { 257 .a = -1, 258 .b = 0, 259 .cmp = -1, 260 .ucmp = 1, 261 }, 262 { 263 .a = 0, 264 .b = -1, 265 .cmp = 1, 266 .ucmp = -1, 267 }, 268 { 269 .a = -1, 270 .b = 1, 271 .cmp = -1, 272 .ucmp = 0, 273 }, 274 { 275 .a = 1, 276 .b = -1, 277 .cmp = 1, 278 .ucmp = 0, 279 }, 280 }; 281 282 #define N_BN_CMP_WORD_TESTS \ 283 (sizeof(bn_cmp_word_tests) / sizeof(*bn_cmp_word_tests)) 284 285 static int 286 test_bn_cmp_word(void) 287 { 288 struct bn_cmp_word_test *bcwt; 289 BIGNUM *a = NULL, *b = NULL; 290 BN_ULONG v; 291 size_t i; 292 int ret; 293 int failed = 1; 294 295 if ((a = BN_new()) == NULL) { 296 fprintf(stderr, "FAIL: failed to create BN\n"); 297 goto failure; 298 } 299 if ((b = BN_new()) == NULL) { 300 fprintf(stderr, "FAIL: failed to create BN\n"); 301 goto failure; 302 } 303 304 for (i = 0; i < N_BN_CMP_WORD_TESTS; i++) { 305 bcwt = &bn_cmp_word_tests[i]; 306 307 if (bcwt->a >= 0) { 308 v = bcwt->a; 309 } else { 310 v = 0 - bcwt->a; 311 } 312 if (!BN_set_word(a, v)) { 313 fprintf(stderr, "FAIL: failed to set a\n"); 314 goto failure; 315 } 316 BN_set_negative(a, (bcwt->a < 0)); 317 318 if (bcwt->b >= 0) { 319 v = bcwt->b; 320 } else { 321 v = 0 - bcwt->b; 322 } 323 if (!BN_set_word(b, v)) { 324 fprintf(stderr, "FAIL: failed to set b\n"); 325 goto failure; 326 } 327 BN_set_negative(b, (bcwt->b < 0)); 328 329 if ((ret = BN_cmp(a, b)) != bcwt->cmp) { 330 fprintf(stderr, "FAIL: BN_cmp(%d, %d) = %d, want %d\n", 331 bcwt->a, bcwt->b, ret, bcwt->cmp); 332 goto failure; 333 } 334 if ((ret = BN_ucmp(a, b)) != bcwt->ucmp) { 335 fprintf(stderr, "FAIL: BN_ucmp(%d, %d) = %d, want %d\n", 336 bcwt->a, bcwt->b, ret, bcwt->ucmp); 337 goto failure; 338 } 339 } 340 341 failed = 0; 342 343 failure: 344 BN_free(a); 345 BN_free(b); 346 347 return failed; 348 } 349 350 int 351 main(int argc, char **argv) 352 { 353 int failed = 0; 354 355 failed |= test_bn_cmp(); 356 failed |= test_bn_cmp_null(); 357 failed |= test_bn_cmp_word(); 358 359 return failed; 360 } 361