summaryrefslogtreecommitdiff
path: root/libs/libaxolotl/src/curve25519/ed25519/additions/ge_scalarmult.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libaxolotl/src/curve25519/ed25519/additions/ge_scalarmult.c')
-rw-r--r--libs/libaxolotl/src/curve25519/ed25519/additions/ge_scalarmult.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/libs/libaxolotl/src/curve25519/ed25519/additions/ge_scalarmult.c b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_scalarmult.c
new file mode 100644
index 0000000000..e4f741b8d8
--- /dev/null
+++ b/libs/libaxolotl/src/curve25519/ed25519/additions/ge_scalarmult.c
@@ -0,0 +1,140 @@
+#include "crypto_uint32.h"
+#include "ge.h"
+#include "crypto_additions.h"
+
+static unsigned char equal(signed char b,signed char c)
+{
+ unsigned char ub = b;
+ unsigned char uc = c;
+ unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
+ crypto_uint32 y = x; /* 0: yes; 1..255: no */
+ y -= 1; /* 4294967295: yes; 0..254: no */
+ y >>= 31; /* 1: yes; 0: no */
+ return y;
+}
+
+static unsigned char negative(signed char b)
+{
+ unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
+ x >>= 63; /* 1: yes; 0: no */
+ return x;
+}
+
+static void cmov(ge_cached *t,const ge_cached *u,unsigned char b)
+{
+ fe_cmov(t->YplusX,u->YplusX,b);
+ fe_cmov(t->YminusX,u->YminusX,b);
+ fe_cmov(t->Z,u->Z,b);
+ fe_cmov(t->T2d,u->T2d,b);
+}
+
+static void select(ge_cached *t,const ge_cached *pre, signed char b)
+{
+ ge_cached minust;
+ unsigned char bnegative = negative(b);
+ unsigned char babs = b - (((-bnegative) & b) << 1);
+
+ fe_1(t->YplusX);
+ fe_1(t->YminusX);
+ fe_1(t->Z);
+ fe_0(t->T2d);
+
+ cmov(t,pre+0,equal(babs,1));
+ cmov(t,pre+1,equal(babs,2));
+ cmov(t,pre+2,equal(babs,3));
+ cmov(t,pre+3,equal(babs,4));
+ cmov(t,pre+4,equal(babs,5));
+ cmov(t,pre+5,equal(babs,6));
+ cmov(t,pre+6,equal(babs,7));
+ cmov(t,pre+7,equal(babs,8));
+ fe_copy(minust.YplusX,t->YminusX);
+ fe_copy(minust.YminusX,t->YplusX);
+ fe_copy(minust.Z,t->Z);
+ fe_neg(minust.T2d,t->T2d);
+ cmov(t,&minust,bnegative);
+}
+
+/*
+h = a * B
+where a = a[0]+256*a[1]+...+256^31 a[31]
+B is the Ed25519 base point (x,4/5) with x positive.
+
+Preconditions:
+ a[31] <= 127
+*/
+
+void ge_scalarmult(ge_p3 *h, const unsigned char *a, const ge_p3 *A)
+{
+ signed char e[64];
+ signed char carry;
+ ge_p1p1 r;
+ ge_p2 s;
+ ge_p3 t0, t1, t2;
+ ge_cached t, pre[8];
+ int i;
+
+ for (i = 0;i < 32;++i) {
+ e[2 * i + 0] = (a[i] >> 0) & 15;
+ e[2 * i + 1] = (a[i] >> 4) & 15;
+ }
+ /* each e[i] is between 0 and 15 */
+ /* e[63] is between 0 and 7 */
+
+ carry = 0;
+ for (i = 0;i < 63;++i) {
+ e[i] += carry;
+ carry = e[i] + 8;
+ carry >>= 4;
+ e[i] -= carry << 4;
+ }
+ e[63] += carry;
+ /* each e[i] is between -8 and 8 */
+
+ // Precomputation:
+ ge_p3_to_cached(pre+0, A); // A
+
+ ge_p3_dbl(&r, A);
+ ge_p1p1_to_p3(&t0, &r);
+ ge_p3_to_cached(pre+1, &t0); // 2A
+
+ ge_add(&r, A, pre+1);
+ ge_p1p1_to_p3(&t1, &r);
+ ge_p3_to_cached(pre+2, &t1); // 3A
+
+ ge_p3_dbl(&r, &t0);
+ ge_p1p1_to_p3(&t0, &r);
+ ge_p3_to_cached(pre+3, &t0); // 4A
+
+ ge_add(&r, A, pre+3);
+ ge_p1p1_to_p3(&t2, &r);
+ ge_p3_to_cached(pre+4, &t2); // 5A
+
+ ge_p3_dbl(&r, &t1);
+ ge_p1p1_to_p3(&t1, &r);
+ ge_p3_to_cached(pre+5, &t1); // 6A
+
+ ge_add(&r, A, pre+5);
+ ge_p1p1_to_p3(&t1, &r);
+ ge_p3_to_cached(pre+6, &t1); // 7A
+
+ ge_p3_dbl(&r, &t0);
+ ge_p1p1_to_p3(&t0, &r);
+ ge_p3_to_cached(pre+7, &t0); // 8A
+
+ ge_p3_0(h);
+
+ for (i = 63;i > 0; i--) {
+ select(&t,pre,e[i]);
+ ge_add(&r, h, &t);
+ ge_p1p1_to_p2(&s,&r);
+
+ ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r);
+ ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r);
+ ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r);
+ ge_p2_dbl(&r,&s); ge_p1p1_to_p3(h,&r);
+
+ }
+ select(&t,pre,e[0]);
+ ge_add(&r, h, &t);
+ ge_p1p1_to_p3(h,&r);
+}