tls

tls.git
git clone git://git.lenczewski.org/tls.git
Log | Files | Refs

x25519.h (4782B)


      1 // https://martin.kleppmann.com/papers/curve25519.pdf
      2 
      3 #include <stdint.h>
      4 #include <string.h>
      5 
      6 struct x25519_point {
      7 	uint8_t vs[32];
      8 };
      9 
     10 struct x25519_field_element {
     11 	int64_t vs[16]; // array of 16, 16-bit numbers (stored as 64-bit)
     12 };
     13 
     14 static inline void
     15 x25519_unpack(struct x25519_field_element *out, struct x25519_point const *in)
     16 {
     17 	for (size_t i = 0; i < 16; i++) {
     18 		out->vs[i] = in->vs[2*i] + ((int64_t) in->vs[(2*i) + 1] << 8);
     19 	}
     20 
     21 	out->vs[15] &= 0x7fff;
     22 }
     23 
     24 static inline void
     25 x25519_carry(struct x25519_field_element *elem)
     26 {
     27 	int64_t carry;
     28 	for (size_t i = 0; i < 16; i++) {
     29 		carry = elem->vs[i] >> 16;
     30 
     31 		elem->vs[i] -= carry << 16;
     32 
     33 		if (i < 15) {
     34 			elem->vs[i + 1] += carry;
     35 		} else { // i == 15
     36 			elem->vs[0] += 38 * carry;
     37 		}
     38 	}
     39 }
     40 
     41 static inline void
     42 x25519_fadd(struct x25519_field_element *out,
     43 	    struct x25519_field_element const *a,
     44 	    struct x25519_field_element const *b)
     45 {
     46 	for (size_t i = 0; i < 16; i++) {
     47 		out->vs[i] = a->vs[i] + b->vs[i];
     48 	}
     49 }
     50 
     51 static inline void
     52 x25519_fsub(struct x25519_field_element *out,
     53 	    struct x25519_field_element const *a,
     54 	    struct x25519_field_element const *b)
     55 {
     56 	for (size_t i = 0; i < 16; i++) {
     57 		out->vs[i] = a->vs[i] - b->vs[i];
     58 	}
     59 }
     60 
     61 static inline void
     62 x25519_fmul(struct x25519_field_element *out,
     63 	    struct x25519_field_element const *a,
     64 	    struct x25519_field_element const *b)
     65 {
     66 	int64_t product[31];
     67 	memset(product, 0, sizeof product); // TODO: is this elided?
     68 
     69 	for (size_t i = 0; i < 16; i++) {
     70 		for (size_t j = 0; j < 16; j++) {
     71 			product[i + j] = a->vs[i] * b->vs[j];
     72 		}
     73 	}
     74 
     75 	for (size_t i = 0; i < 15; i++) {
     76 		product[i] += 38 * product[i + 16];
     77 	}
     78 
     79 	memcpy(out->vs, product, sizeof out->vs);
     80 	x25519_carry(out);
     81 	x25519_carry(out);
     82 }
     83 
     84 static inline void
     85 x25519_finv(struct x25519_field_element *out,
     86 	    struct x25519_field_element const *in)
     87 {
     88 	struct x25519_field_element c;
     89 	memcpy(&c, in, sizeof c);
     90 
     91 	for (int i = 253; i >= 0; i--) {
     92 		x25519_fmul(&c, &c, &c);
     93 
     94 		if (i != 2 && i != 4)
     95 			x25519_fmul(&c, &c, in);
     96 	}
     97 
     98 	memcpy(out, &c, sizeof c);
     99 }
    100 
    101 static inline void
    102 x25519_swap(struct x25519_field_element *p,
    103 	    struct x25519_field_element *q,
    104 	    size_t bit)
    105 {
    106 	int64_t c = ~(bit - 1);
    107 	for (size_t i = 0; i < 16; i++) {
    108 		int64_t t = c & (p->vs[i] ^ q->vs[i]);
    109 		p->vs[i] ^= t;
    110 		q->vs[i] ^= t;
    111 	}
    112 }
    113 
    114 static inline void
    115 x25519_pack(struct x25519_point *out, struct x25519_field_element const *in)
    116 {
    117 	int carry;
    118 	struct x25519_field_element m, t;
    119 	memcpy(&t, in, sizeof t);
    120 
    121 	// reduce module p
    122 	x25519_carry(&t); x25519_carry(&t); x25519_carry(&t);
    123 
    124 	for (size_t j = 0; j < 2; j++) {
    125 		m.vs[0] = t.vs[0] - 0xffed;
    126 		for (size_t i = 1; i < 15; i++) {
    127 			m.vs[i] = t.vs[i] - 0xffff - ((m.vs[i - 1] >> 16) & 1);
    128 			m.vs[i - 1] &= 0xffff;
    129 		}
    130 
    131 		m.vs[15] = t.vs[15] - 0x7fff - ((m.vs[14] >> 16) & 1);
    132 		carry = (m.vs[15] >> 16) & 1;
    133 		m.vs[14] &= 0xffff;
    134 
    135 		x25519_swap(&t, &m, 1 - carry);
    136 	}
    137 
    138 	for (size_t i = 0; i < 16; i++) {
    139 		out->vs[2*i] = t.vs[i] & 0xff;
    140 		out->vs[(2*i) + 1] = t.vs[i] >> 8;
    141 	}
    142 }
    143 
    144 static inline void
    145 x25519_scalarmult(struct x25519_point *restrict out,
    146 		  struct x25519_point const *restrict scalar,
    147 		  struct x25519_point const *restrict point)
    148 {
    149 	static const struct x25519_field_element _121665 = {
    150 		.vs = { 0xdb41, 1 }
    151 	};
    152 
    153 	uint8_t clamped[32];
    154 	int64_t bit;
    155 
    156 	struct x25519_field_element a, b, c, d, e, f, x;
    157 
    158 	memcpy(clamped, scalar, sizeof clamped);
    159 	clamped[0] &= 0xf8;
    160 	clamped[31] = (clamped[31] & 0x7f) | 0x40;
    161 
    162 	x25519_unpack(&x, point);
    163 
    164 	memcpy(&b, &x, sizeof b);
    165 	memset(&d, 0, sizeof d);
    166 	memset(&c, 0, sizeof c);
    167 	memset(&a, 0, sizeof a);
    168 	a.vs[0] = d.vs[0] = 1;
    169 
    170 	for (int i = 254; i >= 0; i--) {
    171 		bit = (clamped[i >> 3] >> (i & 7)) & 1;
    172 
    173 		x25519_swap(&a, &b, bit);
    174 		x25519_swap(&c, &d, bit);
    175 
    176 		x25519_fadd(&e, &a, &c);
    177 		x25519_fsub(&a, &a, &c);
    178 		x25519_fadd(&c, &b, &d);
    179 		x25519_fsub(&b, &b, &d);
    180 		x25519_fmul(&d, &e, &f);
    181 		x25519_fmul(&f, &a, &a);
    182 		x25519_fmul(&a, &c, &a);
    183 		x25519_fmul(&c, &b, &e);
    184 		x25519_fadd(&e, &a, &c);
    185 		x25519_fsub(&a, &a, &c);
    186 		x25519_fmul(&b, &a, &a);
    187 		x25519_fsub(&c, &d, &f);
    188 		x25519_fmul(&a, &c, &_121665);
    189 		x25519_fadd(&a, &a, &d);
    190 		x25519_fmul(&c, &c, &a);
    191 		x25519_fmul(&a, &d, &f);
    192 		x25519_fmul(&d, &b, &x);
    193 		x25519_fmul(&b, &e, &e);
    194 
    195 		x25519_swap(&a, &b, bit);
    196 		x25519_swap(&c, &d, bit);
    197 	}
    198 
    199 	x25519_finv(&c, &c);
    200 	x25519_fmul(&a, &a, &c);
    201 	x25519_pack(out, &a);
    202 }
    203 
    204 static inline void
    205 x25519_genpubkey(struct x25519_point *restrict pk,
    206 		 struct x25519_point const *restrict sk)
    207 {
    208 	static const struct x25519_point _9 = { .vs = {9} };
    209 	x25519_scalarmult(pk, sk, &_9);
    210 }
    211 
    212 static inline void
    213 x25519(struct x25519_point *restrict out,
    214        struct x25519_point const *restrict pk,
    215        struct x25519_point const *restrict sk)
    216 {
    217 	x25519_scalarmult(out, sk, pk);
    218 }