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 }