static int testPack(PQ_PARAM_SET_ID id) { int i; int T; int rc; PQ_PARAM_SET *P; if(!(P = pq_get_param_set_by_id(id))) { return -1; } unsigned char *scratch; uint16_t *iF; uint16_t *oF; uint16_t *ig; uint16_t *og; int64_t *iginv; int64_t *oginv; int64_t *ih; int64_t *oh; int64_t *isig; int64_t *osig; unsigned char *priv_blob; unsigned char *pub_blob; unsigned char *sig_blob; size_t prod = 2*(P->d1 + P->d2 + P->d3)*sizeof(uint16_t); size_t full = P->N*sizeof(int64_t); size_t priv_blob_len = PRIVKEY_PACKED_BYTES(P); size_t pub_blob_len = PUBKEY_PACKED_BYTES(P); size_t sig_len = SIGNATURE_BYTES(P); size_t offset; scratch = malloc(4*prod + 6*full + priv_blob_len + pub_blob_len + sig_len); offset = 0; iF = (uint16_t*)(scratch + offset); offset += prod; oF = (uint16_t*)(scratch + offset); offset += prod; ig = (uint16_t*)(scratch + offset); offset += prod; og = (uint16_t*)(scratch + offset); offset += prod; iginv = (int64_t*)(scratch + offset); offset += full; oginv = (int64_t*)(scratch + offset); offset += full; isig = (int64_t*)(scratch + offset); offset += full; osig = (int64_t*)(scratch + offset); offset += full; ih = (int64_t*)(scratch + offset); offset += full; oh = (int64_t*)(scratch + offset); offset += full; priv_blob = (unsigned char*)(scratch + offset); offset += priv_blob_len; pub_blob = (unsigned char*)(scratch + offset); offset += pub_blob_len; sig_blob = (unsigned char*)(scratch + offset); offset += sig_len; for(T=0; T<TIMES; T++) { fastrandombytes(scratch, 4*prod + 6*full + priv_blob_len + pub_blob_len + sig_len); for(i = 0; i < prod; i++) { iF[i] = iF[i] % P->N; ig[i] = ig[i] % P->N; } for(i=0; i < P->N; i++) { iginv[i] = cmod(iginv[i], P->p); ih[i] = cmod(ih[i], P->q); isig[i] = isig[i] % P->q; isig[i] = (isig[i] + P->q) % P->q; isig[i] -= isig[i] % P->p; isig[i] /= P->p; } rc = pack_private_key(P, iF, ig, iginv, priv_blob_len, priv_blob); if(PQNTRU_ERROR == rc) { printf("Private key pack error\n"); return -1; } rc = unpack_private_key(P, oF, og, oginv, priv_blob_len, priv_blob); if(PQNTRU_ERROR == rc) { printf("Private key unpack error\n"); return -1; } rc = pack_public_key(P, ih, pub_blob_len, pub_blob); if(PQNTRU_ERROR == rc) { printf("Public key pack error\n"); return -1; } rc = unpack_public_key(P, oh, pub_blob_len, pub_blob); if(PQNTRU_ERROR == rc) { printf("Public key unpack error\n"); return -1; } rc = pack_signature(P, isig, sig_len, sig_blob); if(PQNTRU_ERROR == rc) { printf("Signature pack error\n"); return -1; } rc = unpack_signature(P, osig, sig_len, sig_blob); if(PQNTRU_ERROR == rc) { printf("Signature unpack error\n"); return -1; } for(i=0; i<2*(P->d1 + P->d2 + P->d3); i++) { if(iF[i] != oF[i] || ig[i] != og[i]) { printf("product form keys not equal\n"); break; } } for(i=0; i<P->N; i++) { oh[i] = cmod(oh[i], P->q); oginv[i] = cmod(oginv[i], P->p); if(ih[i] != oh[i] || iginv[i] != oginv[i]) { printf("%d %ld %ld %ld %ld\n", i, ih[i], oh[i], iginv[i], oginv[i]); printf("public key or iginv not equal\n"); return -1; } if(isig[i] != osig[i]) { printf("%d %ld %ld\n", i, isig[i], osig[i]); printf("signatures not equal\n"); return -1; } } } }
int pq_gen_key( PQ_PARAM_SET *P, size_t *privkey_blob_len, unsigned char *privkey_blob, size_t *pubkey_blob_len, unsigned char *pubkey_blob) { uint16_t i; uint16_t m; uint16_t N; uint16_t padN; int64_t q; int8_t p; uint16_t d1; uint16_t d2; uint16_t d3; size_t private_key_blob_len; size_t public_key_blob_len; uint16_t *f; uint16_t *g; int64_t *h; size_t scratch_len; size_t offset; unsigned char *scratch; int64_t *a1; int64_t *a2; int64_t *tmpx3; if(!P || !privkey_blob_len || !pubkey_blob_len) { return PQNTRU_ERROR; } N = P->N; padN = P->padded_N; q = P->q; p = P->p; d1 = P->d1; d2 = P->d2; d3 = P->d3; /* TODO: Standardize packed key formats */ private_key_blob_len = PRIVKEY_PACKED_BYTES(P); public_key_blob_len = PUBKEY_PACKED_BYTES(P); if(!privkey_blob || !pubkey_blob) { if(!privkey_blob && privkey_blob_len != NULL) { *privkey_blob_len = private_key_blob_len; } if(!pubkey_blob && pubkey_blob_len != NULL) { *pubkey_blob_len = public_key_blob_len; } return PQNTRU_OK; } if((*privkey_blob_len != private_key_blob_len) || (*pubkey_blob_len != public_key_blob_len)) { return PQNTRU_ERROR; } scratch_len = 2 * PRODUCT_FORM_BYTES(P) + 6 * POLYNOMIAL_BYTES(P); if(!(scratch = malloc(scratch_len))) { return PQNTRU_ERROR; } memset(scratch, 0, scratch_len); offset = 0; f = (uint16_t*)(scratch); offset += PRODUCT_FORM_BYTES(P); g = (uint16_t*)(scratch + offset); offset += PRODUCT_FORM_BYTES(P); h = (int64_t*)(scratch + offset); offset += POLYNOMIAL_BYTES(P); a1 = (int64_t*)(scratch + offset); offset += POLYNOMIAL_BYTES(P); a2 = (int64_t*)(scratch + offset); offset += POLYNOMIAL_BYTES(P); tmpx3 = (int64_t*)(scratch + offset); /* Find invertible pf mod q */ /* TODO: Better sampling of product form keys * Try to avoid keys with f(1) = 0 */ do { pol_gen_product(f, d1, d2, d3, N); /* f = p * (1 + product form poly) */ memset(a1, 0, POLYNOMIAL_BYTES(P)); a1[0] = p; pol_mul_product(a1, a1, d1, d2, d3, f, N, tmpx3); a1[0] += p; } while(PQNTRU_ERROR == pol_inv_mod2(a2, a1, N)); /* Lift from (Z/2Z)[X]/(X^N - 1) to (Z/qZ)[X]/(X^N -1) */ for (m = 0; m < 5; ++m) /* assumes 2^16 < q <= 2^32 */ { /* a^-1 = a^-1 * (2 - a * a^-1) mod q */ pol_mul_product(a1, a2, d1, d2, d3, f, N, tmpx3); for (i = 0; i < N; ++i) { a1[i] = -p*(a1[i] + a2[i]); } a1[0] = a1[0] + 2; pol_mul_coefficients(a2, a2, a1, N, padN, q, tmpx3); } /* Find invertible g mod p */ do { /* Generate product form g, * then expand it to find inverse mod p */ pol_gen_product(g, d1, d2, d3, N); memset(a1, 0, POLYNOMIAL_BYTES(P)); a1[0] = 1; pol_mul_product(a1, a1, d1, d2, d3, g, N, tmpx3); a1[0] += 1; } while(PQNTRU_ERROR == pol_inv_modp(tmpx3, a1, N, p)); pack_private_key(P, f, g, tmpx3, private_key_blob_len, privkey_blob); /* Calculate public key, h = g/f mod q */ pol_mul_product(h, a2, d1, d2, d3, g, N, tmpx3); for(i=0; i<N; i++) { h[i] = cmod(h[i] + a2[i], q); } /* int j; for (i=0; i<d1; i++) { for (j=d1; j<2*d1; j++) { if (f[i] == f[j]) { printf("stupid key f: %d, %d, %d!\n", i, j, f[i]); break; } if (g[i] == g[j]) { printf("stupid key g: %d, %d, %d!\n", i, j, g[i]); break; } } } for (i=2*d1; i<2*d1+d2; i++) { for (j=2*d1+d2; j<2*(d1+d2); j++) { if (f[i] == f[j]) { printf("stupid key f: %d, %d, %d!\n", i, j, f[i]); break; } if (g[i] == g[j]) { printf("stupid key g: %d, %d, %d!\n", i, j, g[i]); break; } } } for (i=2*(d1+d2); i<2*(d1+d2)+d3; i++) { for (j=2*(d1+d2)+d3; j<2*(d1+d2+d3); j++) { if (f[i] == f[j]) { printf("stupid key f: %d, %d, %d!\n", i, j, f[i]); break; } if (g[i] == g[j]) { printf("stupid key g: %d, %d, %d!\n", i, j, g[i]); break; } } }*/ pack_public_key(P, h, public_key_blob_len, pubkey_blob); shred(scratch, scratch_len); free(scratch); return PQNTRU_OK; }