diff options
Diffstat (limited to 'libs/libaxolotl/src/curve25519/ed25519/additions/ge_scalarmult.c')
-rw-r--r-- | libs/libaxolotl/src/curve25519/ed25519/additions/ge_scalarmult.c | 140 |
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); +} |