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_verify( const size_t packed_sig_len, const unsigned char *packed_sig, const size_t public_key_blob_len, const unsigned char *public_key_blob, const size_t msg_len, const unsigned char *msg) { uint16_t i; PQ_PARAM_SET *P; size_t scratch_len; unsigned char *scratch; int8_t *sp; int8_t *tp; int64_t *h; int64_t *sig; int64_t *tmpx3; uint16_t N; uint16_t padN; int64_t q; int8_t p; uint16_t error = 0; int result; result = get_blob_params(&P, public_key_blob_len, public_key_blob); if(PQNTRU_ERROR == result) { return PQNTRU_ERROR; } N = P->N; padN = P->padded_N; p = P->p; q = P->q; scratch_len = 2 * N + 5 * POLYNOMIAL_BYTES(P); if(!(scratch = malloc(scratch_len))) { return PQNTRU_ERROR; } memset(scratch, 0, scratch_len); sig = (int64_t*)scratch; h = (int64_t*)(scratch + POLYNOMIAL_BYTES(P)); tmpx3 = (int64_t*)(scratch + 2*POLYNOMIAL_BYTES(P)); sp = (int8_t*)(scratch + 5*POLYNOMIAL_BYTES(P)); tp = (int8_t*)(scratch + 5*POLYNOMIAL_BYTES(P) + N); result = unpack_public_key(P, h, public_key_blob_len, public_key_blob); if(PQNTRU_ERROR == result) { free(scratch); return PQNTRU_ERROR; } challenge(sp, tp, public_key_blob_len, public_key_blob, msg_len, msg); result = unpack_signature(P, sig, sp, packed_sig_len, packed_sig); if(PQNTRU_ERROR == result) { free(scratch); return PQNTRU_ERROR; } for(i=0; i<N; i++) { error |= (cmod(sig[i] - sp[i], p)); error |= (sig[i] > P->norm_bound_s) || (-sig[i] > P->norm_bound_s); } pol_mul_coefficients(tmpx3, sig, h, N, padN, q, tmpx3); for(i=0; i<N; i++) { error |= (cmod(tmpx3[i], p) - tp[i]); error |= (tmpx3[i] > P->norm_bound_t) || (-tmpx3[i] > P->norm_bound_t) ; } free(scratch); if(0 == error) { return PQNTRU_OK; } return PQNTRU_ERROR; }
static int testKeyGen(PQ_PARAM_SET_ID id) { uint16_t i; uint16_t j; PQ_PARAM_SET *P; size_t privkey_blob_len; size_t pubkey_blob_len; unsigned char *privkey_blob; unsigned char *pubkey_blob; unsigned char *scratch; size_t scratch_len; int rc; if(!(P = pq_get_param_set_by_id(id))) { return -1; } size_t prod = 2*(P->d1 + P->d2 + P->d3)*sizeof(uint16_t); size_t full = POLYNOMIAL_BYTES(P); scratch_len = 2*prod + 6*full; scratch = malloc(scratch_len); size_t offset = 0; uint16_t *f = (uint16_t*)(scratch); offset += prod; uint16_t *g = (uint16_t*)(scratch+offset); offset += prod; int64_t *ginv = (int64_t*)(scratch+offset); offset += full; int64_t *h = (int64_t*)(scratch+offset); offset += full; int64_t *a1 = (int64_t*)(scratch+offset); offset += full; int64_t *a2 = (int64_t*)(scratch+offset); offset += 3*full; for(i=0; i<TIMES; i++) { memset(scratch, 0, scratch_len); /* Generate a key */ pq_gen_key(P, &privkey_blob_len, NULL, &pubkey_blob_len, NULL); privkey_blob = malloc(privkey_blob_len); pubkey_blob = malloc(pubkey_blob_len); if(PQNTRU_ERROR == pq_gen_key(P, &privkey_blob_len, privkey_blob, &pubkey_blob_len, pubkey_blob)) { fprintf(stderr, "\t fail in keygen\n"); } /* Unpack the key */ rc = unpack_private_key(P, f, g, ginv, privkey_blob_len, privkey_blob); if(PQNTRU_ERROR == rc) { printf("Private key unpack error\n"); return -1; } rc = unpack_public_key(P, h, pubkey_blob_len, pubkey_blob); if(PQNTRU_ERROR == rc) { printf("Public key unpack error\n"); return -1; } /* Multiply h by f mod q, should have g in a1 */ pol_mul_product(a1, h, P->d1, P->d2, P->d3, f, P->N, a2); for(j=0; j<P->N; j++) { a1[j] = cmod(P->p * (h[j] + a1[j]), P->q); } /* Multiply a1 by g inverse mod p, should have 1 in a2 */ pol_mul_coefficients(a2, a1, ginv, P->N, P->padded_N, P->p, a2); for(j=1; j<P->N; j++) { if(a2[0] != 1 || a2[j] != 0) { fprintf(stderr, "\t bad key"); free(privkey_blob); free(pubkey_blob); free(scratch); return -1; } } free(privkey_blob); free(pubkey_blob); } free(scratch); return 0; }
int pq_sign( size_t *packed_sig_len, unsigned char *packed_sig, const size_t private_key_len, const unsigned char *private_key_blob, const size_t public_key_len, const unsigned char *public_key_blob, const size_t msg_len, const unsigned char *msg) { uint16_t i; int error = 0; uint16_t N; uint16_t padN; int64_t q; int8_t p; uint16_t d1; uint16_t d2; uint16_t d3; int64_t m; size_t scratch_len; unsigned char *scratch; size_t offset; uint16_t *f; /* Private key product form f indices */ uint16_t *g; /* .. product form g indices */ int64_t *ginv; /* Private key; coefficients of g^{-1} */ int64_t *h; /* Public key coefficients */ int64_t *s0; /* scratch space for random lattice point */ int64_t *t0; int64_t *a; /* scratch space for 3 polynomials */ int64_t *tmpx2;/* scratch space for 2 polynomials (aliased by a) */ int8_t *sp; /* Document hash */ int8_t *tp; PQ_PARAM_SET *P; int rc = PQNTRU_OK; if(!private_key_blob || !public_key_blob || !packed_sig_len) { return PQNTRU_ERROR; } rc = get_blob_params(&P, private_key_len, private_key_blob); if(PQNTRU_ERROR == rc) { return PQNTRU_ERROR; } if(!packed_sig) /* Return signature size in packed_sig_len */ { *packed_sig_len = SIGNATURE_BYTES(P); return PQNTRU_OK; } if(!msg || msg_len == 0) { 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; scratch_len = 2 * PRODUCT_FORM_BYTES(P) /* f and g */ + 7 * POLYNOMIAL_BYTES(P) /* h, ginv, and 5 scratch polys */ + 2 * N; /* sp, tp */ 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); ginv = (int64_t*)(scratch + offset); offset += POLYNOMIAL_BYTES(P); s0 = (int64_t*)(scratch + offset); offset += POLYNOMIAL_BYTES(P); t0 = (int64_t*)(scratch + offset); offset += POLYNOMIAL_BYTES(P); /* a is treated as 3 polynomials, aliases tmpx2 */ a = (int64_t*)(scratch + offset); offset += POLYNOMIAL_BYTES(P); tmpx2= (int64_t*)(scratch + offset); offset += 2* POLYNOMIAL_BYTES(P); sp = (int8_t*)(scratch + offset); offset += N; tp = (int8_t*)(scratch + offset); /* Unpack the keys */ rc = unpack_private_key(P, f, g, ginv, private_key_len, private_key_blob); if(PQNTRU_ERROR == rc) { shred(scratch, scratch_len); free(scratch); return PQNTRU_ERROR; } rc = unpack_public_key(P, h, public_key_len, public_key_blob); if(PQNTRU_ERROR == rc) { shred(scratch, scratch_len); free(scratch); return PQNTRU_ERROR; } /* Generate a document hash to sign */ challenge(sp, tp, public_key_len, public_key_blob, msg_len, msg); int64_t *t = (int64_t *)malloc(N*sizeof(int64_t)); int64_t *s = (int64_t *)malloc(N*sizeof(int64_t)); do { error = 0; /* Choose random s0 satisfying s0 = sp (mod p) */ pol_unidrnd_pZ(s0, N, q, p); for(i=0; i<N; i++) { s0[i] += sp[i]; } /* Load h into a zero padded polynomial */ memcpy(t0, h, N*sizeof(int64_t)); /* t0 = h*s0 */ pol_mul_coefficients(t0, t0, s0, N, padN, q, a); /* t0 = tp - (s0*h) */ for(i=0; i<N; i++) { t0[i] *= -1; t0[i] += tp[i]; } /* a = ginv * (tp - t0) (mod p) */ pol_mul_coefficients(a, t0, ginv, N, padN, p, a); /* tmpx2 = a * F = (a * (f-1)/p) */ pol_mul_product(tmpx2, a, d1, d2, d3, f, N, tmpx2); for(i=0; i<N; i++) { m = p * (a[i] + tmpx2[i]); error |= (m > P->B_s) || (-m > P->B_s); s[i] = m; /* s0 = s0 + p*(a + tmpx2) = s0 + a*f */ s0[i] += m; error |= (cmod(s0[i], p) - sp[i]); /* Not necessary to check this */ error |= (s0[i] > P->norm_bound_s) || (-s0[i] > P->norm_bound_s); } /* tmpx2 = a * G = (a * (g - 1)) */ pol_mul_product(tmpx2, a, d1, d2, d3, g, N, tmpx2); for(i=0; i<N; i++) { m = (a[i] + tmpx2[i]); error |= (m > P->B_t) || (-m > P->B_t); t[i] = m; /* t0 = (a + tmpx2) - t0 + tp = a*g - tp + s0*h + tp = s0*h + a*g */ t0[i] = m - t0[i] + tp[i]; error |= (cmod(t0[i], p) - tp[i]); /* Not necessary to check this */ error |= (t0[i] > P->norm_bound_t) || (-t0[i] > P->norm_bound_t) ; } // attempts ++; } while(0 != error); for (i=0; i<N; i++) { if (s[i] > P->B_s || -s[i] > P->B_s) printf("s\tholy shit\n"); if (t[i] > P->B_t || -t[i] > P->B_t) printf("t\tholy shit\n"); } for(i=0; i<N; i++) { s0[i] = (s0[i] - sp[i])/P->p; s0[i] += P->q / (2*P->p); } pack_signature(P, s0, *packed_sig_len, packed_sig); shred(scratch, scratch_len); free(scratch); return PQNTRU_OK; }