2 * implement x25519 diffie-hellman from [1].
4 * This code is public domain.
6 * Philipp Lay <philipp.lay@illunis.net>
9 * [1] Curve25519: new Diffie-Hellman speed records, 2006/02/09, Bernstein.
18 #include "burnstack.h"
24 * structure for a point of the elliptic curve in montgomery form
25 * without it's y-coordinate.
34 * ctmemswap - helper function to conditionally swap a with b
37 ctmemswap(void *a, void *b, size_t len, uint8_t mask)
39 uint8_t *pa = (uint8_t*)a;
40 uint8_t *pb = (uint8_t*)b;
41 uint8_t *endp = pa + len;
45 delta = (*pa ^ *pb) & mask;
54 * montgomery - calculate montgomery's double-and-add formula
56 * input: A, B, C := A-B with z=1
57 * output: A <- 2*A, B <- A+B
61 montgomery(struct mg *A, struct mg *B, const struct mg *C)
63 fld_t sumA, subA, sqsumA, sqsubA;
68 fld_add(sumA, A->x, A->z);
71 fld_sub(subA, A->x, A->z);
74 fld_mul(A->x, sqsubA, sqsumA);
76 fld_sub(T1, sqsumA, sqsubA);
77 fld_scale(T2, T1, 121665);
78 fld_add(T2, T2, sqsumA);
79 fld_mul(A->z, T1, T2);
82 fld_add(sumB, B->x, B->z);
83 fld_sub(subB, B->x, B->z);
85 fld_mul(T1, subA, sumB);
86 fld_mul(T2, sumA, subB);
93 fld_mul(B->z, T3, C->x);
98 * mg_scale - calculates x * P with montgomery formula.
105 mg_scale(struct mg *out, const struct mg *P, const uint8_t x[X25519_KEY_LEN])
113 memcpy(&T, P, sizeof(struct mg));
115 for (i = X25519_KEY_LEN-1; i >= 0; i--) {
117 for (j = 8; j > 0; j--, foo <<= 1) {
118 ctmemswap(out, &T, sizeof(struct mg), foo >> 7);
119 montgomery(out, &T, P);
120 ctmemswap(out, &T, sizeof(struct mg), foo >> 7);
127 * do_x25519 - calculates x25519 diffie-hellman using montgomery form
130 do_x25519(uint8_t out[X25519_KEY_LEN],
131 const uint8_t scalar[X25519_KEY_LEN],
132 const uint8_t point[X25519_KEY_LEN])
135 uint8_t s[X25519_KEY_LEN];
137 memcpy(s, scalar, X25519_KEY_LEN);
142 fld_import(P.x, point);
145 mg_scale(&res, &P, s);
147 fld_inv(res.z, res.z);
148 fld_mul(res.x, res.x, res.z);
149 fld_export(out, res.x);
154 * do_x25519_base - calculate a x25519 diffie-hellman public value
159 do_x25519_base(uint8_t out[X25519_KEY_LEN],
160 const uint8_t scalar[X25519_KEY_LEN])
162 uint8_t tmp[X25519_KEY_LEN];
169 * clear bits on input and import it as x
171 memcpy(tmp, scalar, X25519_KEY_LEN);
176 sc_import(x, tmp, sizeof(tmp));
180 * scale our base point on edwards curve
182 ed_scale_base(&R, x);
186 * extract montgomery coordinate u from edwards point R
189 /* u <- (z + y) / (z - y) */
190 fld_sub(t, R.z, R.y);
192 fld_add(u, R.z, R.y);
201 * x25519_base - wrapper around do_x25519_base with stack cleaning
204 x25519_base(uint8_t out[X25519_KEY_LEN],
205 const uint8_t scalar[X25519_KEY_LEN])
207 do_x25519_base(out, scalar);
214 /* x25519 - wrapper for do_x25519 with stack-cleanup */
216 x25519(uint8_t out[X25519_KEY_LEN],
217 const uint8_t scalar[X25519_KEY_LEN],
218 const uint8_t point[X25519_KEY_LEN])
220 do_x25519(out, scalar, point);
229 * Obsolete Interface, this will be removed in the future.
234 * DH - stack-cleanup wrapper for do_x25519 (obsolete interface)
237 DH(uint8_t out[X25519_KEY_LEN],
238 const uint8_t sec[X25519_KEY_LEN],
239 const uint8_t point[X25519_KEY_LEN])
241 do_x25519(out, sec, point);