- {
-#ifdef BN_LLONG
- BN_ULLONG t;
-#else
- BN_ULONG bl,bh;
-#endif
- BN_ULONG t1,t2;
- BN_ULONG c1,c2,c3;
-
- c1=0;
- c2=0;
- c3=0;
- mul_add_c(a[0],b[0],c1,c2,c3);
- r[0]=c1;
- c1=0;
- mul_add_c(a[0],b[1],c2,c3,c1);
- mul_add_c(a[1],b[0],c2,c3,c1);
- r[1]=c2;
- c2=0;
- mul_add_c(a[2],b[0],c3,c1,c2);
- mul_add_c(a[1],b[1],c3,c1,c2);
- mul_add_c(a[0],b[2],c3,c1,c2);
- r[2]=c3;
- c3=0;
- mul_add_c(a[0],b[3],c1,c2,c3);
- mul_add_c(a[1],b[2],c1,c2,c3);
- mul_add_c(a[2],b[1],c1,c2,c3);
- mul_add_c(a[3],b[0],c1,c2,c3);
- r[3]=c1;
- c1=0;
- mul_add_c(a[3],b[1],c2,c3,c1);
- mul_add_c(a[2],b[2],c2,c3,c1);
- mul_add_c(a[1],b[3],c2,c3,c1);
- r[4]=c2;
- c2=0;
- mul_add_c(a[2],b[3],c3,c1,c2);
- mul_add_c(a[3],b[2],c3,c1,c2);
- r[5]=c3;
- c3=0;
- mul_add_c(a[3],b[3],c1,c2,c3);
- r[6]=c1;
- r[7]=c2;
- }
-
-void bn_sqr_comba8(BN_ULONG *r, BN_ULONG *a)
- {
-#ifdef BN_LLONG
- BN_ULLONG t,tt;
-#else
- BN_ULONG bl,bh;
-#endif
- BN_ULONG t1,t2;
- BN_ULONG c1,c2,c3;
-
- c1=0;
- c2=0;
- c3=0;
- sqr_add_c(a,0,c1,c2,c3);
- r[0]=c1;
- c1=0;
- sqr_add_c2(a,1,0,c2,c3,c1);
- r[1]=c2;
- c2=0;
- sqr_add_c(a,1,c3,c1,c2);
- sqr_add_c2(a,2,0,c3,c1,c2);
- r[2]=c3;
- c3=0;
- sqr_add_c2(a,3,0,c1,c2,c3);
- sqr_add_c2(a,2,1,c1,c2,c3);
- r[3]=c1;
- c1=0;
- sqr_add_c(a,2,c2,c3,c1);
- sqr_add_c2(a,3,1,c2,c3,c1);
- sqr_add_c2(a,4,0,c2,c3,c1);
- r[4]=c2;
- c2=0;
- sqr_add_c2(a,5,0,c3,c1,c2);
- sqr_add_c2(a,4,1,c3,c1,c2);
- sqr_add_c2(a,3,2,c3,c1,c2);
- r[5]=c3;
- c3=0;
- sqr_add_c(a,3,c1,c2,c3);
- sqr_add_c2(a,4,2,c1,c2,c3);
- sqr_add_c2(a,5,1,c1,c2,c3);
- sqr_add_c2(a,6,0,c1,c2,c3);
- r[6]=c1;
- c1=0;
- sqr_add_c2(a,7,0,c2,c3,c1);
- sqr_add_c2(a,6,1,c2,c3,c1);
- sqr_add_c2(a,5,2,c2,c3,c1);
- sqr_add_c2(a,4,3,c2,c3,c1);
- r[7]=c2;
- c2=0;
- sqr_add_c(a,4,c3,c1,c2);
- sqr_add_c2(a,5,3,c3,c1,c2);
- sqr_add_c2(a,6,2,c3,c1,c2);
- sqr_add_c2(a,7,1,c3,c1,c2);
- r[8]=c3;
- c3=0;
- sqr_add_c2(a,7,2,c1,c2,c3);
- sqr_add_c2(a,6,3,c1,c2,c3);
- sqr_add_c2(a,5,4,c1,c2,c3);
- r[9]=c1;
- c1=0;
- sqr_add_c(a,5,c2,c3,c1);
- sqr_add_c2(a,6,4,c2,c3,c1);
- sqr_add_c2(a,7,3,c2,c3,c1);
- r[10]=c2;
- c2=0;
- sqr_add_c2(a,7,4,c3,c1,c2);
- sqr_add_c2(a,6,5,c3,c1,c2);
- r[11]=c3;
- c3=0;
- sqr_add_c(a,6,c1,c2,c3);
- sqr_add_c2(a,7,5,c1,c2,c3);
- r[12]=c1;
- c1=0;
- sqr_add_c2(a,7,6,c2,c3,c1);
- r[13]=c2;
- c2=0;
- sqr_add_c(a,7,c3,c1,c2);
- r[14]=c3;
- r[15]=c1;
- }
-
-void bn_sqr_comba4(BN_ULONG *r, BN_ULONG *a)
- {
-#ifdef BN_LLONG
- BN_ULLONG t,tt;
-#else
- BN_ULONG bl,bh;
-#endif
- BN_ULONG t1,t2;
- BN_ULONG c1,c2,c3;
-
- c1=0;
- c2=0;
- c3=0;
- sqr_add_c(a,0,c1,c2,c3);
- r[0]=c1;
- c1=0;
- sqr_add_c2(a,1,0,c2,c3,c1);
- r[1]=c2;
- c2=0;
- sqr_add_c(a,1,c3,c1,c2);
- sqr_add_c2(a,2,0,c3,c1,c2);
- r[2]=c3;
- c3=0;
- sqr_add_c2(a,3,0,c1,c2,c3);
- sqr_add_c2(a,2,1,c1,c2,c3);
- r[3]=c1;
- c1=0;
- sqr_add_c(a,2,c2,c3,c1);
- sqr_add_c2(a,3,1,c2,c3,c1);
- r[4]=c2;
- c2=0;
- sqr_add_c2(a,3,2,c3,c1,c2);
- r[5]=c3;
- c3=0;
- sqr_add_c(a,3,c1,c2,c3);
- r[6]=c1;
- r[7]=c2;
- }
-#else
+{
+ BN_ULONG c1, c2, c3;
+
+ c1 = 0;
+ c2 = 0;
+ c3 = 0;
+ mul_add_c(a[0], b[0], c1, c2, c3);
+ r[0] = c1;
+ c1 = 0;
+ mul_add_c(a[0], b[1], c2, c3, c1);
+ mul_add_c(a[1], b[0], c2, c3, c1);
+ r[1] = c2;
+ c2 = 0;
+ mul_add_c(a[2], b[0], c3, c1, c2);
+ mul_add_c(a[1], b[1], c3, c1, c2);
+ mul_add_c(a[0], b[2], c3, c1, c2);
+ r[2] = c3;
+ c3 = 0;
+ mul_add_c(a[0], b[3], c1, c2, c3);
+ mul_add_c(a[1], b[2], c1, c2, c3);
+ mul_add_c(a[2], b[1], c1, c2, c3);
+ mul_add_c(a[3], b[0], c1, c2, c3);
+ r[3] = c1;
+ c1 = 0;
+ mul_add_c(a[3], b[1], c2, c3, c1);
+ mul_add_c(a[2], b[2], c2, c3, c1);
+ mul_add_c(a[1], b[3], c2, c3, c1);
+ r[4] = c2;
+ c2 = 0;
+ mul_add_c(a[2], b[3], c3, c1, c2);
+ mul_add_c(a[3], b[2], c3, c1, c2);
+ r[5] = c3;
+ c3 = 0;
+ mul_add_c(a[3], b[3], c1, c2, c3);
+ r[6] = c1;
+ r[7] = c2;
+}
+
+void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a)
+{
+ BN_ULONG c1, c2, c3;
+
+ c1 = 0;
+ c2 = 0;
+ c3 = 0;
+ sqr_add_c(a, 0, c1, c2, c3);
+ r[0] = c1;
+ c1 = 0;
+ sqr_add_c2(a, 1, 0, c2, c3, c1);
+ r[1] = c2;
+ c2 = 0;
+ sqr_add_c(a, 1, c3, c1, c2);
+ sqr_add_c2(a, 2, 0, c3, c1, c2);
+ r[2] = c3;
+ c3 = 0;
+ sqr_add_c2(a, 3, 0, c1, c2, c3);
+ sqr_add_c2(a, 2, 1, c1, c2, c3);
+ r[3] = c1;
+ c1 = 0;
+ sqr_add_c(a, 2, c2, c3, c1);
+ sqr_add_c2(a, 3, 1, c2, c3, c1);
+ sqr_add_c2(a, 4, 0, c2, c3, c1);
+ r[4] = c2;
+ c2 = 0;
+ sqr_add_c2(a, 5, 0, c3, c1, c2);
+ sqr_add_c2(a, 4, 1, c3, c1, c2);
+ sqr_add_c2(a, 3, 2, c3, c1, c2);
+ r[5] = c3;
+ c3 = 0;
+ sqr_add_c(a, 3, c1, c2, c3);
+ sqr_add_c2(a, 4, 2, c1, c2, c3);
+ sqr_add_c2(a, 5, 1, c1, c2, c3);
+ sqr_add_c2(a, 6, 0, c1, c2, c3);
+ r[6] = c1;
+ c1 = 0;
+ sqr_add_c2(a, 7, 0, c2, c3, c1);
+ sqr_add_c2(a, 6, 1, c2, c3, c1);
+ sqr_add_c2(a, 5, 2, c2, c3, c1);
+ sqr_add_c2(a, 4, 3, c2, c3, c1);
+ r[7] = c2;
+ c2 = 0;
+ sqr_add_c(a, 4, c3, c1, c2);
+ sqr_add_c2(a, 5, 3, c3, c1, c2);
+ sqr_add_c2(a, 6, 2, c3, c1, c2);
+ sqr_add_c2(a, 7, 1, c3, c1, c2);
+ r[8] = c3;
+ c3 = 0;
+ sqr_add_c2(a, 7, 2, c1, c2, c3);
+ sqr_add_c2(a, 6, 3, c1, c2, c3);
+ sqr_add_c2(a, 5, 4, c1, c2, c3);
+ r[9] = c1;
+ c1 = 0;
+ sqr_add_c(a, 5, c2, c3, c1);
+ sqr_add_c2(a, 6, 4, c2, c3, c1);
+ sqr_add_c2(a, 7, 3, c2, c3, c1);
+ r[10] = c2;
+ c2 = 0;
+ sqr_add_c2(a, 7, 4, c3, c1, c2);
+ sqr_add_c2(a, 6, 5, c3, c1, c2);
+ r[11] = c3;
+ c3 = 0;
+ sqr_add_c(a, 6, c1, c2, c3);
+ sqr_add_c2(a, 7, 5, c1, c2, c3);
+ r[12] = c1;
+ c1 = 0;
+ sqr_add_c2(a, 7, 6, c2, c3, c1);
+ r[13] = c2;
+ c2 = 0;
+ sqr_add_c(a, 7, c3, c1, c2);
+ r[14] = c3;
+ r[15] = c1;
+}
+
+void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a)
+{
+ BN_ULONG c1, c2, c3;
+
+ c1 = 0;
+ c2 = 0;
+ c3 = 0;
+ sqr_add_c(a, 0, c1, c2, c3);
+ r[0] = c1;
+ c1 = 0;
+ sqr_add_c2(a, 1, 0, c2, c3, c1);
+ r[1] = c2;
+ c2 = 0;
+ sqr_add_c(a, 1, c3, c1, c2);
+ sqr_add_c2(a, 2, 0, c3, c1, c2);
+ r[2] = c3;
+ c3 = 0;
+ sqr_add_c2(a, 3, 0, c1, c2, c3);
+ sqr_add_c2(a, 2, 1, c1, c2, c3);
+ r[3] = c1;
+ c1 = 0;
+ sqr_add_c(a, 2, c2, c3, c1);
+ sqr_add_c2(a, 3, 1, c2, c3, c1);
+ r[4] = c2;
+ c2 = 0;
+ sqr_add_c2(a, 3, 2, c3, c1, c2);
+ r[5] = c3;
+ c3 = 0;
+ sqr_add_c(a, 3, c1, c2, c3);
+ r[6] = c1;
+ r[7] = c2;
+}
+
+# ifdef OPENSSL_NO_ASM
+# ifdef OPENSSL_BN_ASM_MONT
+# include <alloca.h>
+/*
+ * This is essentially reference implementation, which may or may not
+ * result in performance improvement. E.g. on IA-32 this routine was
+ * observed to give 40% faster rsa1024 private key operations and 10%
+ * faster rsa4096 ones, while on AMD64 it improves rsa1024 sign only
+ * by 10% and *worsens* rsa4096 sign by 15%. Once again, it's a
+ * reference implementation, one to be used as starting point for
+ * platform-specific assembler. Mentioned numbers apply to compiler
+ * generated code compiled with and without -DOPENSSL_BN_ASM_MONT and
+ * can vary not only from platform to platform, but even for compiler
+ * versions. Assembler vs. assembler improvement coefficients can
+ * [and are known to] differ and are to be documented elsewhere.
+ */
+int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
+ const BN_ULONG *np, const BN_ULONG *n0p, int num)
+{
+ BN_ULONG c0, c1, ml, *tp, n0;
+# ifdef mul64
+ BN_ULONG mh;
+# endif
+ volatile BN_ULONG *vp;
+ int i = 0, j;
+
+# if 0 /* template for platform-specific
+ * implementation */
+ if (ap == bp)
+ return bn_sqr_mont(rp, ap, np, n0p, num);
+# endif
+ vp = tp = alloca((num + 2) * sizeof(BN_ULONG));
+
+ n0 = *n0p;
+
+ c0 = 0;
+ ml = bp[0];
+# ifdef mul64
+ mh = HBITS(ml);
+ ml = LBITS(ml);
+ for (j = 0; j < num; ++j)
+ mul(tp[j], ap[j], ml, mh, c0);
+# else
+ for (j = 0; j < num; ++j)
+ mul(tp[j], ap[j], ml, c0);
+# endif
+
+ tp[num] = c0;
+ tp[num + 1] = 0;
+ goto enter;
+
+ for (i = 0; i < num; i++) {
+ c0 = 0;
+ ml = bp[i];
+# ifdef mul64
+ mh = HBITS(ml);
+ ml = LBITS(ml);
+ for (j = 0; j < num; ++j)
+ mul_add(tp[j], ap[j], ml, mh, c0);
+# else
+ for (j = 0; j < num; ++j)
+ mul_add(tp[j], ap[j], ml, c0);
+# endif
+ c1 = (tp[num] + c0) & BN_MASK2;
+ tp[num] = c1;
+ tp[num + 1] = (c1 < c0 ? 1 : 0);
+ enter:
+ c1 = tp[0];
+ ml = (c1 * n0) & BN_MASK2;
+ c0 = 0;
+# ifdef mul64
+ mh = HBITS(ml);
+ ml = LBITS(ml);
+ mul_add(c1, np[0], ml, mh, c0);
+# else
+ mul_add(c1, ml, np[0], c0);
+# endif
+ for (j = 1; j < num; j++) {
+ c1 = tp[j];
+# ifdef mul64
+ mul_add(c1, np[j], ml, mh, c0);
+# else
+ mul_add(c1, ml, np[j], c0);
+# endif
+ tp[j - 1] = c1 & BN_MASK2;
+ }
+ c1 = (tp[num] + c0) & BN_MASK2;
+ tp[num - 1] = c1;
+ tp[num] = tp[num + 1] + (c1 < c0 ? 1 : 0);
+ }
+
+ if (tp[num] != 0 || tp[num - 1] >= np[num - 1]) {
+ c0 = bn_sub_words(rp, tp, np, num);
+ if (tp[num] != 0 || c0 == 0) {
+ for (i = 0; i < num + 2; i++)
+ vp[i] = 0;
+ return 1;
+ }
+ }
+ for (i = 0; i < num; i++)
+ rp[i] = tp[i], vp[i] = 0;
+ vp[num] = 0;
+ vp[num + 1] = 0;
+ return 1;
+}
+# else
+/*
+ * Return value of 0 indicates that multiplication/convolution was not
+ * performed to signal the caller to fall down to alternative/original
+ * code-path.
+ */
+int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
+ const BN_ULONG *np, const BN_ULONG *n0, int num)
+{
+ return 0;
+}
+# endif /* OPENSSL_BN_ASM_MONT */
+# endif
+
+#else /* !BN_MUL_COMBA */