Commit 43ce879808 for openssl.org
commit 43ce87980856287164e197a095311c742b22bd00
Author: Alexander Troosh <trush@yandex.ru>
Date: Thu Oct 9 18:03:15 2025 +0300
Implement the BN acceleration for Elbrus2000
Co-authored-by: Gleb Popov <arrowd@FreeBSD.org>
Reviewed-by: Andrew Dinh <andrewd@openssl.org>
Reviewed-by: Igor Ustinov <igus@openssl.foundation>
MergeDate: Fri Jul 31 16:49:47 2026
(Merged from https://github.com/openssl/openssl/pull/31269)
diff --git a/crypto/bn/asm/e2k-bn-asm.c b/crypto/bn/asm/e2k-bn-asm.c
new file mode 100644
index 0000000000..2a21a30af0
--- /dev/null
+++ b/crypto/bn/asm/e2k-bn-asm.c
@@ -0,0 +1,825 @@
+/*
+ * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../bn_local.h"
+
+#include <assert.h>
+#include <e2kbuiltin.h>
+
+/*
+ * E2Kv5+ BIGNUM accelerator
+ *
+ * Implemented by Alexander Troosh <trush@yandex.ru>
+ *
+ */
+
+#undef mul_add
+#undef mul
+#undef sqr
+
+#if __iset__ < 5
+#define mul_add(r, a, w, c) \
+ { \
+ BN_ULONG high, low, ret, tmp = (a); \
+ ret = (r); \
+ high = __builtin_e2k_umulhd(w, tmp); \
+ ret += (c); \
+ low = (w) * tmp; \
+ (c) = (ret < (c)) ? 1 : 0; \
+ (c) += high; \
+ ret += low; \
+ (c) += (ret < low) ? 1 : 0; \
+ (r) = ret; \
+ }
+
+#define mul(r, a, w, c) \
+ { \
+ BN_ULONG high, low, ret, ta = (a); \
+ low = (w) * ta; \
+ high = __builtin_e2k_umulhd(w, ta); \
+ ret = low + (c); \
+ (c) = high; \
+ (c) += (ret < low) ? 1 : 0; \
+ (r) = ret; \
+ }
+#else
+/* { c_out[64], r_out[64] } = (r[64] + c[64]) + a[64]*w[64] */
+#define mul_add(r, a, w, c) \
+ { \
+ BN_ULONG high, low, ret, ta = (a), tc = (c), q; \
+ ret = (r); \
+ high = __builtin_e2k_umulhd(w, ta); \
+ low = (w) * ta; \
+ q = __builtin_e2k_addcd_c(ret, tc, 0); \
+ ret += tc; \
+ c = __builtin_e2k_addcd_c(ret, low, 0); \
+ r = ret + low; \
+ c += high + q; \
+ }
+
+#define mul(r, a, w, c) \
+ { \
+ BN_ULONG high, low, q, ta = (a); \
+ low = (w) * ta; \
+ high = __builtin_e2k_umulhd(w, ta); \
+ q = __builtin_e2k_addcd_c(low, c, 0); \
+ r = low + (c); \
+ c = high + q; \
+ }
+#endif
+
+#define sqr(r0, r1, a) \
+ { \
+ BN_ULONG tmp = (a); \
+ (r0) = tmp * tmp; \
+ (r1) = __builtin_e2k_umulhd(tmp, tmp); \
+ }
+
+BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
+ BN_ULONG w)
+{
+ BN_ULONG c1 = 0;
+
+ assert(num >= 0);
+ if (num <= 0)
+ return c1;
+
+#ifndef OPENSSL_SMALL_FOOTPRINT
+ while (num & ~3) {
+ mul_add(rp[0], ap[0], w, c1);
+ mul_add(rp[1], ap[1], w, c1);
+ mul_add(rp[2], ap[2], w, c1);
+ mul_add(rp[3], ap[3], w, c1);
+ ap += 4;
+ rp += 4;
+ num -= 4;
+ }
+#endif
+ while (num) {
+ mul_add(rp[0], ap[0], w, c1);
+ ap++;
+ rp++;
+ num--;
+ }
+
+ return c1;
+}
+
+BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w)
+{
+ BN_ULONG c1 = 0;
+
+ assert(num >= 0);
+ if (num <= 0)
+ return c1;
+
+#ifndef OPENSSL_SMALL_FOOTPRINT
+ while (num & ~3) {
+ mul(rp[0], ap[0], w, c1);
+ mul(rp[1], ap[1], w, c1);
+ mul(rp[2], ap[2], w, c1);
+ mul(rp[3], ap[3], w, c1);
+ ap += 4;
+ rp += 4;
+ num -= 4;
+ }
+#endif
+ while (num) {
+ mul(rp[0], ap[0], w, c1);
+ ap++;
+ rp++;
+ num--;
+ }
+ return c1;
+}
+
+void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n)
+{
+ assert(n >= 0);
+ if (n <= 0)
+ return;
+
+#ifndef OPENSSL_SMALL_FOOTPRINT
+ while (n & ~3) {
+ sqr(r[0], r[1], a[0]);
+ sqr(r[2], r[3], a[1]);
+ sqr(r[4], r[5], a[2]);
+ sqr(r[6], r[7], a[3]);
+ a += 4;
+ r += 8;
+ n -= 4;
+ }
+#endif
+ while (n) {
+ sqr(r[0], r[1], a[0]);
+ a++;
+ r += 2;
+ n--;
+ }
+}
+
+/* Divide h,l by d and return the result. */
+BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d)
+{
+ BN_ULONG dh, dl, q, ret = 0, th, tl, t;
+ int i, count = 2;
+
+ if (d == 0)
+ return BN_MASK2;
+
+ i = BN_num_bits_word(d);
+ assert((i == BN_BITS2) || (h <= (BN_ULONG)1 << i));
+
+ i = BN_BITS2 - i;
+ if (h >= d)
+ h -= d;
+
+ if (i) {
+ d <<= i;
+ h = (h << i) | (l >> (BN_BITS2 - i));
+ l <<= i;
+ }
+ dh = (d & BN_MASK2h) >> BN_BITS4;
+ dl = (d & BN_MASK2l);
+ for (;;) {
+ if ((h >> BN_BITS4) == dh)
+ q = BN_MASK2l;
+ else
+ q = h / dh;
+
+ th = q * dh;
+ tl = dl * q;
+ for (;;) {
+ t = h - th;
+ if ((t & BN_MASK2h) || ((tl) <= ((t << BN_BITS4) | ((l & BN_MASK2h) >> BN_BITS4))))
+ break;
+ q--;
+ th -= dh;
+ tl -= dl;
+ }
+ t = (tl >> BN_BITS4);
+ tl = (tl << BN_BITS4) & BN_MASK2h;
+ th += t;
+
+ if (l < tl)
+ th++;
+ l -= tl;
+ if (h < th) {
+ h += d;
+ q--;
+ }
+ h -= th;
+
+ if (--count == 0)
+ break;
+
+ ret = q << BN_BITS4;
+ h = ((h << BN_BITS4) | (l >> BN_BITS4)) & BN_MASK2;
+ l = (l & BN_MASK2l) << BN_BITS4;
+ }
+ ret |= q;
+ return ret;
+}
+
+BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
+ int n)
+{
+ BN_ULONG c, l, t;
+
+ assert(n >= 0);
+ if (n <= 0)
+ return (BN_ULONG)0;
+
+ c = 0;
+#ifndef OPENSSL_SMALL_FOOTPRINT
+ while (n & ~3) {
+#if __iset__ < 5
+ t = a[0];
+ t = (t + c) & BN_MASK2;
+ c = (t < c);
+ l = (t + b[0]) & BN_MASK2;
+ c += (l < t);
+ r[0] = l;
+ t = a[1];
+ t = (t + c) & BN_MASK2;
+ c = (t < c);
+ l = (t + b[1]) & BN_MASK2;
+ c += (l < t);
+ r[1] = l;
+ t = a[2];
+ t = (t + c) & BN_MASK2;
+ c = (t < c);
+ l = (t + b[2]) & BN_MASK2;
+ c += (l < t);
+ r[2] = l;
+ t = a[3];
+ t = (t + c) & BN_MASK2;
+ c = (t < c);
+ l = (t + b[3]) & BN_MASK2;
+ c += (l < t);
+ r[3] = l;
+#else
+ BN_ULONG t = __builtin_e2k_addcd_c(a[0], b[0], c);
+ r[0] = __builtin_e2k_addcd(a[0], b[0], c);
+ c = t;
+ t = __builtin_e2k_addcd_c(a[1], b[1], c);
+ r[1] = __builtin_e2k_addcd(a[1], b[1], c);
+ c = t;
+ t = __builtin_e2k_addcd_c(a[2], b[2], c);
+ r[2] = __builtin_e2k_addcd(a[2], b[2], c);
+ c = t;
+ t = __builtin_e2k_addcd_c(a[3], b[3], c);
+ r[3] = __builtin_e2k_addcd(a[3], b[3], c);
+ c = t;
+#endif
+ a += 4;
+ b += 4;
+ r += 4;
+ n -= 4;
+ }
+#endif
+ while (n) {
+#if __iset__ < 5
+ t = a[0];
+ t = (t + c) & BN_MASK2;
+ c = (t < c);
+ l = (t + b[0]) & BN_MASK2;
+ c += (l < t);
+ r[0] = l;
+#else
+ BN_ULONG t = __builtin_e2k_addcd_c(a[0], b[0], c);
+ r[0] = __builtin_e2k_addcd(a[0], b[0], c);
+ c = t;
+#endif
+ a++;
+ b++;
+ r++;
+ n--;
+ }
+ return (BN_ULONG)c;
+}
+
+BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
+ int n)
+{
+#if __iset__ < 5
+ BN_ULONG t1, t2;
+#endif
+ int c = 0;
+
+ assert(n >= 0);
+ if (n <= 0)
+ return (BN_ULONG)0;
+
+#ifndef OPENSSL_SMALL_FOOTPRINT
+ while (n & ~3) {
+#if __iset__ < 5
+ t1 = a[0];
+ t2 = (t1 - c) & BN_MASK2;
+ c = (t2 > t1);
+ t1 = b[0];
+ t1 = (t2 - t1) & BN_MASK2;
+ r[0] = t1;
+ c += (t1 > t2);
+ t1 = a[1];
+ t2 = (t1 - c) & BN_MASK2;
+ c = (t2 > t1);
+ t1 = b[1];
+ t1 = (t2 - t1) & BN_MASK2;
+ r[1] = t1;
+ c += (t1 > t2);
+ t1 = a[2];
+ t2 = (t1 - c) & BN_MASK2;
+ c = (t2 > t1);
+ t1 = b[2];
+ t1 = (t2 - t1) & BN_MASK2;
+ r[2] = t1;
+ c += (t1 > t2);
+ t1 = a[3];
+ t2 = (t1 - c) & BN_MASK2;
+ c = (t2 > t1);
+ t1 = b[3];
+ t1 = (t2 - t1) & BN_MASK2;
+ r[3] = t1;
+ c += (t1 > t2);
+#else
+ BN_ULONG t = __builtin_e2k_subcd_c(a[0], b[0], c);
+ r[0] = __builtin_e2k_subcd(a[0], b[0], c);
+ c = t;
+ t = __builtin_e2k_subcd_c(a[1], b[1], c);
+ r[1] = __builtin_e2k_subcd(a[1], b[1], c);
+ c = t;
+ t = __builtin_e2k_subcd_c(a[2], b[2], c);
+ r[2] = __builtin_e2k_subcd(a[2], b[2], c);
+ c = t;
+ t = __builtin_e2k_subcd_c(a[3], b[3], c);
+ r[3] = __builtin_e2k_subcd(a[3], b[3], c);
+ c = t;
+#endif
+ a += 4;
+ b += 4;
+ r += 4;
+ n -= 4;
+ }
+#endif
+ while (n) {
+#if __iset__ < 5
+ t1 = a[0];
+ t2 = (t1 - c) & BN_MASK2;
+ c = (t2 > t1);
+ t1 = b[0];
+ t1 = (t2 - t1) & BN_MASK2;
+ r[0] = t1;
+ c += (t1 > t2);
+#else
+ BN_ULONG t = __builtin_e2k_subcd_c(a[0], b[0], c);
+ r[0] = __builtin_e2k_subcd(a[0], b[0], c);
+ c = t;
+#endif
+ a++;
+ b++;
+ r++;
+ n--;
+ }
+ return c;
+}
+
+#ifndef OPENSSL_SMALL_FOOTPRINT
+
+/* mul_add_c(a,b,c0,c1,c2) -- c+=a*b for three word number c=(c2,c1,c0) */
+/* mul_add_c2(a,b,c0,c1,c2) -- c+=2*a*b for three word number c=(c2,c1,c0) */
+/* sqr_add_c(a,i,c0,c1,c2) -- c+=a[i]^2 for three word number c=(c2,c1,c0) */
+/*
+ * sqr_add_c2(a,i,c0,c1,c2) -- c+=2*a[i]*a[j] for three word number
+ * c=(c2,c1,c0)
+ */
+
+#if __iset__ < 5
+/*
+ * Keep in mind that carrying into high part of multiplication result
+ * can not overflow, because it cannot be all-ones.
+ */
+#define mul_add_c(a, b, c0, c1, c2) \
+ do { \
+ BN_ULONG ta = (a), tb = (b); \
+ BN_ULONG lo, hi; \
+ BN_UMULT_LOHI(lo, hi, ta, tb); \
+ c0 += lo; \
+ hi += (c0 < lo); \
+ c1 += hi; \
+ c2 += (c1 < hi); \
+ } while (0)
+
+#define mul_add_c2(a, b, c0, c1, c2) \
+ do { \
+ BN_ULONG ta = (a), tb = (b); \
+ BN_ULONG lo, hi, tt; \
+ BN_UMULT_LOHI(lo, hi, ta, tb); \
+ c0 += lo; \
+ tt = hi + (c0 < lo); \
+ c1 += tt; \
+ c2 += (c1 < tt); \
+ c0 += lo; \
+ hi += (c0 < lo); \
+ c1 += hi; \
+ c2 += (c1 < hi); \
+ } while (0)
+
+#define sqr_add_c(a, i, c0, c1, c2) \
+ do { \
+ BN_ULONG ta = (a)[i]; \
+ BN_ULONG lo, hi; \
+ BN_UMULT_LOHI(lo, hi, ta, ta); \
+ c0 += lo; \
+ hi += (c0 < lo); \
+ c1 += hi; \
+ c2 += (c1 < hi); \
+ } while (0)
+#else /* __iset__ >= 5 */
+#define mul_add_c(a, b, c0, c1, c2) \
+ do { \
+ BN_ULONG ta = (a), tb = (b); \
+ BN_ULONG lo, hi; \
+ int q; \
+ lo = ta * tb; \
+ hi = __builtin_e2k_umulhd(ta, tb); \
+ q = __builtin_e2k_addcd_c(c0, lo, 0); \
+ c0 += lo; \
+ c2 += __builtin_e2k_addcd_c(c1, hi, q); \
+ c1 = __builtin_e2k_addcd(c1, hi, q); \
+ } while (0)
+
+#define mul_add_c2(a, b, c0, c1, c2) \
+ do { \
+ BN_ULONG ta = (a), tb = (b); \
+ BN_ULONG lo, hi, lo_msb; \
+ int q; \
+ lo = ta * tb; \
+ hi = __builtin_e2k_umulhd(ta, tb); \
+ \
+ lo_msb = lo >> 63; \
+ lo <<= 1; \
+ c2 += hi >> 63; \
+ hi = __builtin_e2k_insfd(hi, 0x7f, lo_msb); \
+ \
+ q = __builtin_e2k_addcd_c(c0, lo, 0); \
+ c0 += lo; \
+ c2 += __builtin_e2k_addcd_c(c1, hi, q); \
+ c1 = __builtin_e2k_addcd(c1, hi, q); \
+ } while (0)
+
+#define sqr_add_c(a, i, c0, c1, c2) \
+ do { \
+ BN_ULONG ta = (a)[i]; \
+ BN_ULONG lo, hi; \
+ int q; \
+ lo = ta * ta; \
+ hi = __builtin_e2k_umulhd(ta, ta); \
+ q = __builtin_e2k_addcd_c(c0, lo, 0); \
+ c0 += lo; \
+ c2 += __builtin_e2k_addcd_c(c1, hi, q); \
+ c1 = __builtin_e2k_addcd(c1, hi, q); \
+ } while (0)
+#endif /* __iset__ */
+
+#define sqr_add_c2(a, i, j, c0, c1, c2) \
+ mul_add_c2((a)[i], (a)[j], c0, c1, c2)
+
+void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
+{
+ 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[4], b[0], c2, c3, c1);
+ 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);
+ mul_add_c(a[0], b[4], c2, c3, c1);
+ r[4] = c2;
+ c2 = 0;
+ mul_add_c(a[0], b[5], c3, c1, c2);
+ mul_add_c(a[1], b[4], c3, c1, c2);
+ mul_add_c(a[2], b[3], c3, c1, c2);
+ mul_add_c(a[3], b[2], c3, c1, c2);
+ mul_add_c(a[4], b[1], c3, c1, c2);
+ mul_add_c(a[5], b[0], c3, c1, c2);
+ r[5] = c3;
+ c3 = 0;
+ mul_add_c(a[6], b[0], c1, c2, c3);
+ mul_add_c(a[5], b[1], c1, c2, c3);
+ mul_add_c(a[4], b[2], c1, c2, c3);
+ mul_add_c(a[3], b[3], c1, c2, c3);
+ mul_add_c(a[2], b[4], c1, c2, c3);
+ mul_add_c(a[1], b[5], c1, c2, c3);
+ mul_add_c(a[0], b[6], c1, c2, c3);
+ r[6] = c1;
+ c1 = 0;
+ mul_add_c(a[0], b[7], c2, c3, c1);
+ mul_add_c(a[1], b[6], c2, c3, c1);
+ mul_add_c(a[2], b[5], c2, c3, c1);
+ mul_add_c(a[3], b[4], c2, c3, c1);
+ mul_add_c(a[4], b[3], c2, c3, c1);
+ mul_add_c(a[5], b[2], c2, c3, c1);
+ mul_add_c(a[6], b[1], c2, c3, c1);
+ mul_add_c(a[7], b[0], c2, c3, c1);
+ r[7] = c2;
+ c2 = 0;
+ mul_add_c(a[7], b[1], c3, c1, c2);
+ mul_add_c(a[6], b[2], c3, c1, c2);
+ mul_add_c(a[5], b[3], c3, c1, c2);
+ mul_add_c(a[4], b[4], c3, c1, c2);
+ mul_add_c(a[3], b[5], c3, c1, c2);
+ mul_add_c(a[2], b[6], c3, c1, c2);
+ mul_add_c(a[1], b[7], c3, c1, c2);
+ r[8] = c3;
+ c3 = 0;
+ mul_add_c(a[2], b[7], c1, c2, c3);
+ mul_add_c(a[3], b[6], c1, c2, c3);
+ mul_add_c(a[4], b[5], c1, c2, c3);
+ mul_add_c(a[5], b[4], c1, c2, c3);
+ mul_add_c(a[6], b[3], c1, c2, c3);
+ mul_add_c(a[7], b[2], c1, c2, c3);
+ r[9] = c1;
+ c1 = 0;
+ mul_add_c(a[7], b[3], c2, c3, c1);
+ mul_add_c(a[6], b[4], c2, c3, c1);
+ mul_add_c(a[5], b[5], c2, c3, c1);
+ mul_add_c(a[4], b[6], c2, c3, c1);
+ mul_add_c(a[3], b[7], c2, c3, c1);
+ r[10] = c2;
+ c2 = 0;
+ mul_add_c(a[4], b[7], c3, c1, c2);
+ mul_add_c(a[5], b[6], c3, c1, c2);
+ mul_add_c(a[6], b[5], c3, c1, c2);
+ mul_add_c(a[7], b[4], c3, c1, c2);
+ r[11] = c3;
+ c3 = 0;
+ mul_add_c(a[7], b[5], c1, c2, c3);
+ mul_add_c(a[6], b[6], c1, c2, c3);
+ mul_add_c(a[5], b[7], c1, c2, c3);
+ r[12] = c1;
+ c1 = 0;
+ mul_add_c(a[6], b[7], c2, c3, c1);
+ mul_add_c(a[7], b[6], c2, c3, c1);
+ r[13] = c2;
+ c2 = 0;
+ mul_add_c(a[7], b[7], c3, c1, c2);
+ r[14] = c3;
+ r[15] = c1;
+}
+
+void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
+{
+ 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;
+}
+
+#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;
+ 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];
+
+ for (j = 0; j < num; ++j)
+ mul(tp[j], ap[j], ml, c0);
+
+ tp[num] = c0;
+ tp[num + 1] = 0;
+ goto enter;
+
+ for (i = 0; i < num; i++) {
+ c0 = 0;
+ ml = bp[i];
+
+ for (j = 0; j < num; ++j)
+ mul_add(tp[j], ap[j], ml, c0);
+
+ 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;
+
+ mul_add(c1, ml, np[0], c0);
+
+ for (j = 1; j < num; j++) {
+ c1 = tp[j];
+ mul_add(c1, ml, np[j], c0);
+ 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;
+}
+#endif /* !OPENSSL_SMALL_FOOTPRINT */
diff --git a/crypto/bn/bn_local.h b/crypto/bn/bn_local.h
index 4602cdcaba..506fcaa2b8 100644
--- a/crypto/bn/bn_local.h
+++ b/crypto/bn/bn_local.h
@@ -443,6 +443,8 @@ unsigned __int64 _umul128(unsigned __int64 a, unsigned __int64 b,
: "r"(a), "r"(b)); \
ret; })
#endif
+#elif defined(__e2k__) && __iset__ >= 5
+#define BN_UMULT_HIGH(a, b) __builtin_e2k_umulhd(a, b)
#endif /* cpu */
#endif /* OPENSSL_NO_ASM */
diff --git a/crypto/bn/build.info b/crypto/bn/build.info
index c895354346..d8db8547db 100644
--- a/crypto/bn/build.info
+++ b/crypto/bn/build.info
@@ -90,10 +90,12 @@ IF[{- !$disabled{asm} -}]
$BNASM_c64xplus_ec2m=c64xplus-gf2m.s
$BNDEF_c64xplus_ec2m=OPENSSL_BN_ASM_GF2m
- $BNASM_e2kv6=asm/e2kv6-gf2m.c
- $BNDEF_e2kv6=OPENSSL_BN_ASM_GF2m
- $BNASM_e2kv7=asm/e2kv6-gf2m.c
- $BNDEF_e2kv7=OPENSSL_BN_ASM_GF2m
+ $BNASM_e2k=asm/e2k-bn-asm.c
+ $BNDEF_e2k=OPENSSL_BN_ASM_MONT
+ $BNASM_e2kv6=asm/e2kv6-gf2m.c $BNASM_e2k
+ $BNDEF_e2kv6=OPENSSL_BN_ASM_GF2m $BNDEF_e2k
+ $BNASM_e2kv7=asm/e2kv6-gf2m.c $BNASM_e2k
+ $BNDEF_e2kv7=OPENSSL_BN_ASM_GF2m $BNDEF_e2k
# Now that we have defined all the arch specific variables, use the
# appropriate ones, and define the appropriate macros