1/* $OpenBSD: schnorr.c,v 1.5 2010/12/03 23:49:26 djm Exp $ */ 2/* 3 * Copyright (c) 2008 Damien Miller. All rights reserved. 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/* 19 * Implementation of Schnorr signatures / zero-knowledge proofs, based on 20 * description in: 21 * 22 * F. Hao, P. Ryan, "Password Authenticated Key Exchange by Juggling", 23 * 16th Workshop on Security Protocols, Cambridge, April 2008 24 * 25 * http://grouper.ieee.org/groups/1363/Research/contributions/hao-ryan-2008.pdf 26 */ 27 28#include "includes.h" 29 30#ifdef JPAKE 31 32#include <sys/types.h> 33 34#include <string.h> 35#include <stdarg.h> 36#include <stdio.h> 37 38#include <openssl/evp.h> 39#include <openssl/bn.h> 40 41#include "xmalloc.h" 42#include "buffer.h" 43#include "log.h" 44 45#include "schnorr.h" 46 47#include "openbsd-compat/openssl-compat.h" 48 49/* #define SCHNORR_DEBUG */ /* Privacy-violating debugging */ 50/* #define SCHNORR_MAIN */ /* Include main() selftest */ 51 52#ifndef SCHNORR_DEBUG 53# define SCHNORR_DEBUG_BN(a) 54# define SCHNORR_DEBUG_BUF(a) 55#else 56# define SCHNORR_DEBUG_BN(a) debug3_bn a 57# define SCHNORR_DEBUG_BUF(a) debug3_buf a 58#endif /* SCHNORR_DEBUG */ 59 60/* 61 * Calculate hash component of Schnorr signature H(g || g^v || g^x || id) 62 * using the hash function defined by "evp_md". Returns signature as 63 * bignum or NULL on error. 64 */ 65static BIGNUM * 66schnorr_hash(const BIGNUM *p, const BIGNUM *q, const BIGNUM *g, 67 const EVP_MD *evp_md, const BIGNUM *g_v, const BIGNUM *g_x, 68 const u_char *id, u_int idlen) 69{ 70 u_char *digest; 71 u_int digest_len; 72 BIGNUM *h; 73 Buffer b; 74 int success = -1; 75 76 if ((h = BN_new()) == NULL) { 77 error("%s: BN_new", __func__); 78 return NULL; 79 } 80 81 buffer_init(&b); 82 83 /* h = H(g || p || q || g^v || g^x || id) */ 84 buffer_put_bignum2(&b, g); 85 buffer_put_bignum2(&b, p); 86 buffer_put_bignum2(&b, q); 87 buffer_put_bignum2(&b, g_v); 88 buffer_put_bignum2(&b, g_x); 89 buffer_put_string(&b, id, idlen); 90 91 SCHNORR_DEBUG_BUF((buffer_ptr(&b), buffer_len(&b), 92 "%s: hashblob", __func__)); 93 if (hash_buffer(buffer_ptr(&b), buffer_len(&b), evp_md, 94 &digest, &digest_len) != 0) { 95 error("%s: hash_buffer", __func__); 96 goto out; 97 } 98 if (BN_bin2bn(digest, (int)digest_len, h) == NULL) { 99 error("%s: BN_bin2bn", __func__); 100 goto out; 101 } 102 success = 0; 103 SCHNORR_DEBUG_BN((h, "%s: h = ", __func__)); 104 out: 105 buffer_free(&b); 106 bzero(digest, digest_len); 107 xfree(digest); 108 digest_len = 0; 109 if (success == 0) 110 return h; 111 BN_clear_free(h); 112 return NULL; 113} 114 115/* 116 * Generate Schnorr signature to prove knowledge of private value 'x' used 117 * in public exponent g^x, under group defined by 'grp_p', 'grp_q' and 'grp_g' 118 * using the hash function "evp_md". 119 * 'idlen' bytes from 'id' will be included in the signature hash as an anti- 120 * replay salt. 121 * 122 * On success, 0 is returned. The signature values are returned as *e_p 123 * (g^v mod p) and *r_p (v - xh mod q). The caller must free these values. 124 * On failure, -1 is returned. 125 */ 126int 127schnorr_sign(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, 128 const EVP_MD *evp_md, const BIGNUM *x, const BIGNUM *g_x, 129 const u_char *id, u_int idlen, BIGNUM **r_p, BIGNUM **e_p) 130{ 131 int success = -1; 132 BIGNUM *h, *tmp, *v, *g_v, *r; 133 BN_CTX *bn_ctx; 134 135 SCHNORR_DEBUG_BN((x, "%s: x = ", __func__)); 136 SCHNORR_DEBUG_BN((g_x, "%s: g_x = ", __func__)); 137 138 /* Avoid degenerate cases: g^0 yields a spoofable signature */ 139 if (BN_cmp(g_x, BN_value_one()) <= 0) { 140 error("%s: g_x < 1", __func__); 141 return -1; 142 } 143 if (BN_cmp(g_x, grp_p) >= 0) { 144 error("%s: g_x > g", __func__); 145 return -1; 146 } 147 148 h = g_v = r = tmp = v = NULL; 149 if ((bn_ctx = BN_CTX_new()) == NULL) { 150 error("%s: BN_CTX_new", __func__); 151 goto out; 152 } 153 if ((g_v = BN_new()) == NULL || 154 (r = BN_new()) == NULL || 155 (tmp = BN_new()) == NULL) { 156 error("%s: BN_new", __func__); 157 goto out; 158 } 159 160 /* 161 * v must be a random element of Zq, so 1 <= v < q 162 * we also exclude v = 1, since g^1 looks dangerous 163 */ 164 if ((v = bn_rand_range_gt_one(grp_p)) == NULL) { 165 error("%s: bn_rand_range2", __func__); 166 goto out; 167 } 168 SCHNORR_DEBUG_BN((v, "%s: v = ", __func__)); 169 170 /* g_v = g^v mod p */ 171 if (BN_mod_exp(g_v, grp_g, v, grp_p, bn_ctx) == -1) { 172 error("%s: BN_mod_exp (g^v mod p)", __func__); 173 goto out; 174 } 175 SCHNORR_DEBUG_BN((g_v, "%s: g_v = ", __func__)); 176 177 /* h = H(g || g^v || g^x || id) */ 178 if ((h = schnorr_hash(grp_p, grp_q, grp_g, evp_md, g_v, g_x, 179 id, idlen)) == NULL) { 180 error("%s: schnorr_hash failed", __func__); 181 goto out; 182 } 183 184 /* r = v - xh mod q */ 185 if (BN_mod_mul(tmp, x, h, grp_q, bn_ctx) == -1) { 186 error("%s: BN_mod_mul (tmp = xv mod q)", __func__); 187 goto out; 188 } 189 if (BN_mod_sub(r, v, tmp, grp_q, bn_ctx) == -1) { 190 error("%s: BN_mod_mul (r = v - tmp)", __func__); 191 goto out; 192 } 193 SCHNORR_DEBUG_BN((g_v, "%s: e = ", __func__)); 194 SCHNORR_DEBUG_BN((r, "%s: r = ", __func__)); 195 196 *e_p = g_v; 197 *r_p = r; 198 199 success = 0; 200 out: 201 BN_CTX_free(bn_ctx); 202 if (h != NULL) 203 BN_clear_free(h); 204 if (v != NULL) 205 BN_clear_free(v); 206 BN_clear_free(tmp); 207 208 return success; 209} 210 211/* 212 * Generate Schnorr signature to prove knowledge of private value 'x' used 213 * in public exponent g^x, under group defined by 'grp_p', 'grp_q' and 'grp_g' 214 * using a SHA256 hash. 215 * 'idlen' bytes from 'id' will be included in the signature hash as an anti- 216 * replay salt. 217 * On success, 0 is returned and *siglen bytes of signature are returned in 218 * *sig (caller to free). Returns -1 on failure. 219 */ 220int 221schnorr_sign_buf(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, 222 const BIGNUM *x, const BIGNUM *g_x, const u_char *id, u_int idlen, 223 u_char **sig, u_int *siglen) 224{ 225 Buffer b; 226 BIGNUM *r, *e; 227 228 if (schnorr_sign(grp_p, grp_q, grp_g, EVP_sha256(), 229 x, g_x, id, idlen, &r, &e) != 0) 230 return -1; 231 232 /* Signature is (e, r) */ 233 buffer_init(&b); 234 /* XXX sigtype-hash as string? */ 235 buffer_put_bignum2(&b, e); 236 buffer_put_bignum2(&b, r); 237 *siglen = buffer_len(&b); 238 *sig = xmalloc(*siglen); 239 memcpy(*sig, buffer_ptr(&b), *siglen); 240 SCHNORR_DEBUG_BUF((buffer_ptr(&b), buffer_len(&b), 241 "%s: sigblob", __func__)); 242 buffer_free(&b); 243 244 BN_clear_free(r); 245 BN_clear_free(e); 246 247 return 0; 248} 249 250/* 251 * Verify Schnorr signature { r (v - xh mod q), e (g^v mod p) } against 252 * public exponent g_x (g^x) under group defined by 'grp_p', 'grp_q' and 253 * 'grp_g' using hash "evp_md". 254 * Signature hash will be salted with 'idlen' bytes from 'id'. 255 * Returns -1 on failure, 0 on incorrect signature or 1 on matching signature. 256 */ 257int 258schnorr_verify(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, 259 const EVP_MD *evp_md, const BIGNUM *g_x, const u_char *id, u_int idlen, 260 const BIGNUM *r, const BIGNUM *e) 261{ 262 int success = -1; 263 BIGNUM *h = NULL, *g_xh = NULL, *g_r = NULL, *gx_q = NULL; 264 BIGNUM *expected = NULL; 265 BN_CTX *bn_ctx; 266 267 SCHNORR_DEBUG_BN((g_x, "%s: g_x = ", __func__)); 268 269 /* Avoid degenerate cases: g^0 yields a spoofable signature */ 270 if (BN_cmp(g_x, BN_value_one()) <= 0) { 271 error("%s: g_x <= 1", __func__); 272 return -1; 273 } 274 if (BN_cmp(g_x, grp_p) >= 0) { 275 error("%s: g_x >= p", __func__); 276 return -1; 277 } 278 279 h = g_xh = g_r = expected = NULL; 280 if ((bn_ctx = BN_CTX_new()) == NULL) { 281 error("%s: BN_CTX_new", __func__); 282 goto out; 283 } 284 if ((g_xh = BN_new()) == NULL || 285 (g_r = BN_new()) == NULL || 286 (gx_q = BN_new()) == NULL || 287 (expected = BN_new()) == NULL) { 288 error("%s: BN_new", __func__); 289 goto out; 290 } 291 292 SCHNORR_DEBUG_BN((e, "%s: e = ", __func__)); 293 SCHNORR_DEBUG_BN((r, "%s: r = ", __func__)); 294 295 /* gx_q = (g^x)^q must === 1 mod p */ 296 if (BN_mod_exp(gx_q, g_x, grp_q, grp_p, bn_ctx) == -1) { 297 error("%s: BN_mod_exp (g_x^q mod p)", __func__); 298 goto out; 299 } 300 if (BN_cmp(gx_q, BN_value_one()) != 0) { 301 error("%s: Invalid signature (g^x)^q != 1 mod p", __func__); 302 goto out; 303 } 304 305 SCHNORR_DEBUG_BN((g_xh, "%s: g_xh = ", __func__)); 306 /* h = H(g || g^v || g^x || id) */ 307 if ((h = schnorr_hash(grp_p, grp_q, grp_g, evp_md, e, g_x, 308 id, idlen)) == NULL) { 309 error("%s: schnorr_hash failed", __func__); 310 goto out; 311 } 312 313 /* g_xh = (g^x)^h */ 314 if (BN_mod_exp(g_xh, g_x, h, grp_p, bn_ctx) == -1) { 315 error("%s: BN_mod_exp (g_x^h mod p)", __func__); 316 goto out; 317 } 318 SCHNORR_DEBUG_BN((g_xh, "%s: g_xh = ", __func__)); 319 320 /* g_r = g^r */ 321 if (BN_mod_exp(g_r, grp_g, r, grp_p, bn_ctx) == -1) { 322 error("%s: BN_mod_exp (g_x^h mod p)", __func__); 323 goto out; 324 } 325 SCHNORR_DEBUG_BN((g_r, "%s: g_r = ", __func__)); 326 327 /* expected = g^r * g_xh */ 328 if (BN_mod_mul(expected, g_r, g_xh, grp_p, bn_ctx) == -1) { 329 error("%s: BN_mod_mul (expected = g_r mod p)", __func__); 330 goto out; 331 } 332 SCHNORR_DEBUG_BN((expected, "%s: expected = ", __func__)); 333 334 /* Check e == expected */ 335 success = BN_cmp(expected, e) == 0; 336 out: 337 BN_CTX_free(bn_ctx); 338 if (h != NULL) 339 BN_clear_free(h); 340 if (gx_q != NULL) 341 BN_clear_free(gx_q); 342 if (g_xh != NULL) 343 BN_clear_free(g_xh); 344 if (g_r != NULL) 345 BN_clear_free(g_r); 346 if (expected != NULL) 347 BN_clear_free(expected); 348 return success; 349} 350 351/* 352 * Verify Schnorr signature 'sig' of length 'siglen' against public exponent 353 * g_x (g^x) under group defined by 'grp_p', 'grp_q' and 'grp_g' using a 354 * SHA256 hash. 355 * Signature hash will be salted with 'idlen' bytes from 'id'. 356 * Returns -1 on failure, 0 on incorrect signature or 1 on matching signature. 357 */ 358int 359schnorr_verify_buf(const BIGNUM *grp_p, const BIGNUM *grp_q, 360 const BIGNUM *grp_g, 361 const BIGNUM *g_x, const u_char *id, u_int idlen, 362 const u_char *sig, u_int siglen) 363{ 364 Buffer b; 365 int ret = -1; 366 u_int rlen; 367 BIGNUM *r, *e; 368 369 e = r = NULL; 370 if ((e = BN_new()) == NULL || 371 (r = BN_new()) == NULL) { 372 error("%s: BN_new", __func__); 373 goto out; 374 } 375 376 /* Extract g^v and r from signature blob */ 377 buffer_init(&b); 378 buffer_append(&b, sig, siglen); 379 SCHNORR_DEBUG_BUF((buffer_ptr(&b), buffer_len(&b), 380 "%s: sigblob", __func__)); 381 buffer_get_bignum2(&b, e); 382 buffer_get_bignum2(&b, r); 383 rlen = buffer_len(&b); 384 buffer_free(&b); 385 if (rlen != 0) { 386 error("%s: remaining bytes in signature %d", __func__, rlen); 387 goto out; 388 } 389 390 ret = schnorr_verify(grp_p, grp_q, grp_g, EVP_sha256(), 391 g_x, id, idlen, r, e); 392 out: 393 BN_clear_free(e); 394 BN_clear_free(r); 395 396 return ret; 397} 398 399/* Helper functions */ 400 401/* 402 * Generate uniformly distributed random number in range (1, high). 403 * Return number on success, NULL on failure. 404 */ 405BIGNUM * 406bn_rand_range_gt_one(const BIGNUM *high) 407{ 408 BIGNUM *r, *tmp; 409 int success = -1; 410 411 if ((tmp = BN_new()) == NULL) { 412 error("%s: BN_new", __func__); 413 return NULL; 414 } 415 if ((r = BN_new()) == NULL) { 416 error("%s: BN_new failed", __func__); 417 goto out; 418 } 419 if (BN_set_word(tmp, 2) != 1) { 420 error("%s: BN_set_word(tmp, 2)", __func__); 421 goto out; 422 } 423 if (BN_sub(tmp, high, tmp) == -1) { 424 error("%s: BN_sub failed (tmp = high - 2)", __func__); 425 goto out; 426 } 427 if (BN_rand_range(r, tmp) == -1) { 428 error("%s: BN_rand_range failed", __func__); 429 goto out; 430 } 431 if (BN_set_word(tmp, 2) != 1) { 432 error("%s: BN_set_word(tmp, 2)", __func__); 433 goto out; 434 } 435 if (BN_add(r, r, tmp) == -1) { 436 error("%s: BN_add failed (r = r + 2)", __func__); 437 goto out; 438 } 439 success = 0; 440 out: 441 BN_clear_free(tmp); 442 if (success == 0) 443 return r; 444 BN_clear_free(r); 445 return NULL; 446} 447 448/* 449 * Hash contents of buffer 'b' with hash 'md'. Returns 0 on success, 450 * with digest via 'digestp' (caller to free) and length via 'lenp'. 451 * Returns -1 on failure. 452 */ 453int 454hash_buffer(const u_char *buf, u_int len, const EVP_MD *md, 455 u_char **digestp, u_int *lenp) 456{ 457 u_char digest[EVP_MAX_MD_SIZE]; 458 u_int digest_len; 459 EVP_MD_CTX evp_md_ctx; 460 int success = -1; 461 462 EVP_MD_CTX_init(&evp_md_ctx); 463 464 if (EVP_DigestInit_ex(&evp_md_ctx, md, NULL) != 1) { 465 error("%s: EVP_DigestInit_ex", __func__); 466 goto out; 467 } 468 if (EVP_DigestUpdate(&evp_md_ctx, buf, len) != 1) { 469 error("%s: EVP_DigestUpdate", __func__); 470 goto out; 471 } 472 if (EVP_DigestFinal_ex(&evp_md_ctx, digest, &digest_len) != 1) { 473 error("%s: EVP_DigestFinal_ex", __func__); 474 goto out; 475 } 476 *digestp = xmalloc(digest_len); 477 *lenp = digest_len; 478 memcpy(*digestp, digest, *lenp); 479 success = 0; 480 out: 481 EVP_MD_CTX_cleanup(&evp_md_ctx); 482 bzero(digest, sizeof(digest)); 483 digest_len = 0; 484 return success; 485} 486 487/* print formatted string followed by bignum */ 488void 489debug3_bn(const BIGNUM *n, const char *fmt, ...) 490{ 491 char *out, *h; 492 va_list args; 493 494 out = NULL; 495 va_start(args, fmt); 496 vasprintf(&out, fmt, args); 497 va_end(args); 498 if (out == NULL) 499 fatal("%s: vasprintf failed", __func__); 500 501 if (n == NULL) 502 debug3("%s(null)", out); 503 else { 504 h = BN_bn2hex(n); 505 debug3("%s0x%s", out, h); 506 free(h); 507 } 508 free(out); 509} 510 511/* print formatted string followed by buffer contents in hex */ 512void 513debug3_buf(const u_char *buf, u_int len, const char *fmt, ...) 514{ 515 char *out, h[65]; 516 u_int i, j; 517 va_list args; 518 519 out = NULL; 520 va_start(args, fmt); 521 vasprintf(&out, fmt, args); 522 va_end(args); 523 if (out == NULL) 524 fatal("%s: vasprintf failed", __func__); 525 526 debug3("%s length %u%s", out, len, buf == NULL ? " (null)" : ""); 527 free(out); 528 if (buf == NULL) 529 return; 530 531 *h = '\0'; 532 for (i = j = 0; i < len; i++) { 533 snprintf(h + j, sizeof(h) - j, "%02x", buf[i]); 534 j += 2; 535 if (j >= sizeof(h) - 1 || i == len - 1) { 536 debug3(" %s", h); 537 *h = '\0'; 538 j = 0; 539 } 540 } 541} 542 543/* 544 * Construct a MODP group from hex strings p (which must be a safe 545 * prime) and g, automatically calculating subgroup q as (p / 2) 546 */ 547struct modp_group * 548modp_group_from_g_and_safe_p(const char *grp_g, const char *grp_p) 549{ 550 struct modp_group *ret; 551 552 ret = xmalloc(sizeof(*ret)); 553 ret->p = ret->q = ret->g = NULL; 554 if (BN_hex2bn(&ret->p, grp_p) == 0 || 555 BN_hex2bn(&ret->g, grp_g) == 0) 556 fatal("%s: BN_hex2bn", __func__); 557 /* Subgroup order is p/2 (p is a safe prime) */ 558 if ((ret->q = BN_new()) == NULL) 559 fatal("%s: BN_new", __func__); 560 if (BN_rshift1(ret->q, ret->p) != 1) 561 fatal("%s: BN_rshift1", __func__); 562 563 return ret; 564} 565 566void 567modp_group_free(struct modp_group *grp) 568{ 569 if (grp->g != NULL) 570 BN_clear_free(grp->g); 571 if (grp->p != NULL) 572 BN_clear_free(grp->p); 573 if (grp->q != NULL) 574 BN_clear_free(grp->q); 575 bzero(grp, sizeof(*grp)); 576 xfree(grp); 577} 578 579/* main() function for self-test */ 580 581#ifdef SCHNORR_MAIN 582static void 583schnorr_selftest_one(const BIGNUM *grp_p, const BIGNUM *grp_q, 584 const BIGNUM *grp_g, const BIGNUM *x) 585{ 586 BIGNUM *g_x; 587 u_char *sig; 588 u_int siglen; 589 BN_CTX *bn_ctx; 590 591 if ((bn_ctx = BN_CTX_new()) == NULL) 592 fatal("%s: BN_CTX_new", __func__); 593 if ((g_x = BN_new()) == NULL) 594 fatal("%s: BN_new", __func__); 595 596 if (BN_mod_exp(g_x, grp_g, x, grp_p, bn_ctx) == -1) 597 fatal("%s: g_x", __func__); 598 if (schnorr_sign_buf(grp_p, grp_q, grp_g, x, g_x, "junk", 4, 599 &sig, &siglen)) 600 fatal("%s: schnorr_sign", __func__); 601 if (schnorr_verify_buf(grp_p, grp_q, grp_g, g_x, "junk", 4, 602 sig, siglen) != 1) 603 fatal("%s: verify fail", __func__); 604 if (schnorr_verify_buf(grp_p, grp_q, grp_g, g_x, "JUNK", 4, 605 sig, siglen) != 0) 606 fatal("%s: verify should have failed (bad ID)", __func__); 607 sig[4] ^= 1; 608 if (schnorr_verify_buf(grp_p, grp_q, grp_g, g_x, "junk", 4, 609 sig, siglen) != 0) 610 fatal("%s: verify should have failed (bit error)", __func__); 611 xfree(sig); 612 BN_free(g_x); 613 BN_CTX_free(bn_ctx); 614} 615 616static void 617schnorr_selftest(void) 618{ 619 BIGNUM *x; 620 struct modp_group *grp; 621 u_int i; 622 char *hh; 623 624 grp = jpake_default_group(); 625 if ((x = BN_new()) == NULL) 626 fatal("%s: BN_new", __func__); 627 SCHNORR_DEBUG_BN((grp->p, "%s: grp->p = ", __func__)); 628 SCHNORR_DEBUG_BN((grp->q, "%s: grp->q = ", __func__)); 629 SCHNORR_DEBUG_BN((grp->g, "%s: grp->g = ", __func__)); 630 631 /* [1, 20) */ 632 for (i = 1; i < 20; i++) { 633 printf("x = %u\n", i); 634 fflush(stdout); 635 if (BN_set_word(x, i) != 1) 636 fatal("%s: set x word", __func__); 637 schnorr_selftest_one(grp->p, grp->q, grp->g, x); 638 } 639 640 /* 100 x random [0, p) */ 641 for (i = 0; i < 100; i++) { 642 if (BN_rand_range(x, grp->p) != 1) 643 fatal("%s: BN_rand_range", __func__); 644 hh = BN_bn2hex(x); 645 printf("x = (random) 0x%s\n", hh); 646 free(hh); 647 fflush(stdout); 648 schnorr_selftest_one(grp->p, grp->q, grp->g, x); 649 } 650 651 /* [q-20, q) */ 652 if (BN_set_word(x, 20) != 1) 653 fatal("%s: BN_set_word (x = 20)", __func__); 654 if (BN_sub(x, grp->q, x) != 1) 655 fatal("%s: BN_sub (q - x)", __func__); 656 for (i = 0; i < 19; i++) { 657 hh = BN_bn2hex(x); 658 printf("x = (q - %d) 0x%s\n", 20 - i, hh); 659 free(hh); 660 fflush(stdout); 661 schnorr_selftest_one(grp->p, grp->q, grp->g, x); 662 if (BN_add(x, x, BN_value_one()) != 1) 663 fatal("%s: BN_add (x + 1)", __func__); 664 } 665 BN_free(x); 666} 667 668int 669main(int argc, char **argv) 670{ 671 log_init(argv[0], SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_USER, 1); 672 673 schnorr_selftest(); 674 return 0; 675} 676#endif 677 678#endif /* JPAKE */ 679