authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2020-08-14 16:45:03+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-16 22:35:27-07:00
logdd8f7b396c24d78168d9582364ab5b3b4606ccc5
treef9ed891c7ac5d483463c4861ca7ad9881bb0c0de
parentc483bf4f97504f3c9174ec9fd516d8995971023c

Rename the field and scalar modules

Suggested by @kubkon

7 files changed, 518 insertions(+), 518 deletions(-)

lib/std/crypto.zig+2-2
...@@ -63,8 +63,8 @@ test "crypto" {...@@ -63,8 +63,8 @@ test "crypto" {
63 _ = @import("crypto/25519/curve25519.zig");63 _ = @import("crypto/25519/curve25519.zig");
64 _ = @import("crypto/25519/ed25519.zig");64 _ = @import("crypto/25519/ed25519.zig");
65 _ = @import("crypto/25519/edwards25519.zig");65 _ = @import("crypto/25519/edwards25519.zig");
66 _ = @import("crypto/25519/field25519.zig");66 _ = @import("crypto/25519/field.zig");
67 _ = @import("crypto/25519/scalar25519.zig");67 _ = @import("crypto/25519/scalar.zig");
68 _ = @import("crypto/25519/x25519.zig");68 _ = @import("crypto/25519/x25519.zig");
69 _ = @import("crypto/25519/ristretto255.zig");69 _ = @import("crypto/25519/ristretto255.zig");
70}70}
lib/std/crypto/25519/curve25519.zig+2-2
...@@ -3,9 +3,9 @@ const std = @import("std");...@@ -3,9 +3,9 @@ const std = @import("std");
3/// Group operations over Curve25519.3/// Group operations over Curve25519.
4pub const Curve25519 = struct {4pub const Curve25519 = struct {
5 /// The underlying prime field.5 /// The underlying prime field.
6 pub const Fe = @import("field25519.zig").Fe;6 pub const Fe = @import("field.zig").Fe;
7 /// Field arithmetic mod the order of the main subgroup.7 /// Field arithmetic mod the order of the main subgroup.
8 pub const scalar = @import("scalar25519.zig");8 pub const scalar = @import("scalar.zig");
99
10 x: Fe,10 x: Fe,
1111
lib/std/crypto/25519/edwards25519.zig+2-2
...@@ -4,9 +4,9 @@ const fmt = std.fmt;...@@ -4,9 +4,9 @@ const fmt = std.fmt;
4/// Group operations over Edwards25519.4/// Group operations over Edwards25519.
5pub const Edwards25519 = struct {5pub const Edwards25519 = struct {
6 /// The underlying prime field.6 /// The underlying prime field.
7 pub const Fe = @import("field25519.zig").Fe;7 pub const Fe = @import("field.zig").Fe;
8 /// Field arithmetic mod the order of the main subgroup.8 /// Field arithmetic mod the order of the main subgroup.
9 pub const scalar = @import("scalar25519.zig");9 pub const scalar = @import("scalar.zig");
1010
11 x: Fe,11 x: Fe,
12 y: Fe,12 y: Fe,
lib/std/crypto/25519/field.zig created+327
...@@ -0,0 +1,327 @@
1const std = @import("std");
2const readIntLittle = std.mem.readIntLittle;
3const writeIntLittle = std.mem.writeIntLittle;
4
5pub const Fe = struct {
6 limbs: [5]u64,
7
8 const MASK51: u64 = 0x7ffffffffffff;
9
10 pub inline fn zero() Fe {
11 return .{ .limbs = .{ 0, 0, 0, 0, 0 } };
12 }
13
14 pub inline fn one() Fe {
15 return .{ .limbs = .{ 1, 0, 0, 0, 0 } };
16 }
17
18 pub inline fn sqrtm1() Fe {
19 return .{ .limbs = .{ 1718705420411056, 234908883556509, 2233514472574048, 2117202627021982, 765476049583133 } }; // sqrt(-1)
20 }
21
22 pub inline fn curve25519BasePoint() Fe {
23 return .{ .limbs = .{ 9, 0, 0, 0, 0 } };
24 }
25
26 pub inline fn edwards25519d() Fe {
27 return .{ .limbs = .{ 929955233495203, 466365720129213, 1662059464998953, 2033849074728123, 1442794654840575 } }; // 37095705934669439343138083508754565189542113879843219016388785533085940283555
28 }
29
30 pub inline fn edwards25519d2() Fe {
31 return .{ .limbs = .{ 1859910466990425, 932731440258426, 1072319116312658, 1815898335770999, 633789495995903 } }; // 2d
32 }
33
34 // 1/sqrt(a-d)
35 pub inline fn edwards25519sqrtamd() Fe {
36 return .{ .limbs = .{ 278908739862762, 821645201101625, 8113234426968, 1777959178193151, 2118520810568447 } };
37 }
38
39 pub inline fn isZero(fe: Fe) bool {
40 var reduced = fe;
41 reduced.reduce();
42 const limbs = reduced.limbs;
43 return (limbs[0] | limbs[1] | limbs[2] | limbs[3] | limbs[4]) == 0;
44 }
45
46 pub inline fn equivalent(a: Fe, b: Fe) bool {
47 return a.sub(b).isZero();
48 }
49
50 pub fn fromBytes(s: [32]u8) Fe {
51 var fe: Fe = undefined;
52 fe.limbs[0] = readIntLittle(u64, s[0..8]) & MASK51;
53 fe.limbs[1] = (readIntLittle(u64, s[6..14]) >> 3) & MASK51;
54 fe.limbs[2] = (readIntLittle(u64, s[12..20]) >> 6) & MASK51;
55 fe.limbs[3] = (readIntLittle(u64, s[19..27]) >> 1) & MASK51;
56 fe.limbs[4] = (readIntLittle(u64, s[24..32]) >> 12) & MASK51;
57
58 return fe;
59 }
60
61 pub fn toBytes(fe: Fe) [32]u8 {
62 var reduced = fe;
63 reduced.reduce();
64 var s: [32]u8 = undefined;
65 writeIntLittle(u64, s[0..8], reduced.limbs[0] | (reduced.limbs[1] << 51));
66 writeIntLittle(u64, s[8..16], (reduced.limbs[1] >> 13) | (reduced.limbs[2] << 38));
67 writeIntLittle(u64, s[16..24], (reduced.limbs[2] >> 26) | (reduced.limbs[3] << 25));
68 writeIntLittle(u64, s[24..32], (reduced.limbs[3] >> 39) | (reduced.limbs[4] << 12));
69
70 return s;
71 }
72
73 pub fn rejectNonCanonical(s: [32]u8, comptime ignore_extra_bit: bool) !void {
74 var c: u16 = (s[31] & 0x7f) ^ 0x7f;
75 comptime var i = 30;
76 inline while (i > 0) : (i -= 1) {
77 c |= s[i] ^ 0xff;
78 }
79 c = (c -% 1) >> 8;
80 const d = (@intCast(u16, 0xed - 1) -% @intCast(u16, s[0])) >> 8;
81 const x = if (ignore_extra_bit) 0 else s[31] >> 7;
82 if ((((c & d) | x) & 1) != 0) {
83 return error.NonCanonical;
84 }
85 }
86
87 fn reduce(fe: *Fe) void {
88 comptime var i = 0;
89 comptime var j = 0;
90 const limbs = &fe.limbs;
91 inline while (j < 2) : (j += 1) {
92 i = 0;
93 inline while (i < 4) : (i += 1) {
94 limbs[i + 1] += limbs[i] >> 51;
95 limbs[i] &= MASK51;
96 }
97 limbs[0] += 19 * (limbs[4] >> 51);
98 limbs[4] &= MASK51;
99 }
100 limbs[0] += 19;
101 i = 0;
102 inline while (i < 4) : (i += 1) {
103 limbs[i + 1] += limbs[i] >> 51;
104 limbs[i] &= MASK51;
105 }
106 limbs[0] += 19 * (limbs[4] >> 51);
107 limbs[4] &= MASK51;
108
109 limbs[0] += 0x8000000000000 - 19;
110 limbs[1] += 0x8000000000000 - 1;
111 limbs[2] += 0x8000000000000 - 1;
112 limbs[3] += 0x8000000000000 - 1;
113 limbs[4] += 0x8000000000000 - 1;
114
115 i = 0;
116 inline while (i < 4) : (i += 1) {
117 limbs[i + 1] += limbs[i] >> 51;
118 limbs[i] &= MASK51;
119 }
120 limbs[4] &= MASK51;
121 }
122
123 pub inline fn add(a: Fe, b: Fe) Fe {
124 var fe: Fe = undefined;
125 comptime var i = 0;
126 inline while (i < 5) : (i += 1) {
127 fe.limbs[i] = a.limbs[i] + b.limbs[i];
128 }
129 return fe;
130 }
131
132 pub fn sub(a: Fe, b: Fe) Fe {
133 var fe = b;
134 comptime var i = 0;
135 inline while (i < 4) : (i += 1) {
136 fe.limbs[i + 1] += fe.limbs[i] >> 51;
137 fe.limbs[i] &= MASK51;
138 }
139 fe.limbs[0] += 19 * (fe.limbs[4] >> 51);
140 fe.limbs[4] &= MASK51;
141 fe.limbs[0] = (a.limbs[0] + 0xfffffffffffda) - fe.limbs[0];
142 fe.limbs[1] = (a.limbs[1] + 0xffffffffffffe) - fe.limbs[1];
143 fe.limbs[2] = (a.limbs[2] + 0xffffffffffffe) - fe.limbs[2];
144 fe.limbs[3] = (a.limbs[3] + 0xffffffffffffe) - fe.limbs[3];
145 fe.limbs[4] = (a.limbs[4] + 0xffffffffffffe) - fe.limbs[4];
146
147 return fe;
148 }
149
150 pub inline fn neg(a: Fe) Fe {
151 return zero().sub(a);
152 }
153
154 pub inline fn isNegative(a: Fe) bool {
155 return (a.toBytes()[0] & 1) != 0;
156 }
157
158 pub inline fn cMov(fe: *Fe, a: Fe, c: u64) void {
159 const mask: u64 = 0 -% c;
160 var x = fe.*;
161 comptime var i = 0;
162 inline while (i < 5) : (i += 1) {
163 x.limbs[i] ^= a.limbs[i];
164 }
165 i = 0;
166 inline while (i < 5) : (i += 1) {
167 x.limbs[i] &= mask;
168 }
169 i = 0;
170 inline while (i < 5) : (i += 1) {
171 fe.limbs[i] ^= x.limbs[i];
172 }
173 }
174
175 pub fn cSwap2(a0: *Fe, b0: *Fe, a1: *Fe, b1: *Fe, c: u64) void {
176 const mask: u64 = 0 -% c;
177 var x0 = a0.*;
178 var x1 = a1.*;
179 comptime var i = 0;
180 inline while (i < 5) : (i += 1) {
181 x0.limbs[i] ^= b0.limbs[i];
182 x1.limbs[i] ^= b1.limbs[i];
183 }
184 i = 0;
185 inline while (i < 5) : (i += 1) {
186 x0.limbs[i] &= mask;
187 x1.limbs[i] &= mask;
188 }
189 i = 0;
190 inline while (i < 5) : (i += 1) {
191 a0.limbs[i] ^= x0.limbs[i];
192 b0.limbs[i] ^= x0.limbs[i];
193 a1.limbs[i] ^= x1.limbs[i];
194 b1.limbs[i] ^= x1.limbs[i];
195 }
196 }
197
198 inline fn _carry128(r: *[5]u128) Fe {
199 var rs: [5]u64 = undefined;
200 comptime var i = 0;
201 inline while (i < 4) : (i += 1) {
202 rs[i] = @truncate(u64, r[i]) & MASK51;
203 r[i + 1] += @intCast(u64, r[i] >> 51);
204 }
205 rs[4] = @truncate(u64, r[4]) & MASK51;
206 var carry = @intCast(u64, r[4] >> 51);
207 rs[0] += 19 * carry;
208 carry = rs[0] >> 51;
209 rs[0] &= MASK51;
210 rs[1] += carry;
211 carry = rs[1] >> 51;
212 rs[1] &= MASK51;
213 rs[2] += carry;
214
215 return .{ .limbs = rs };
216 }
217
218 pub fn mul(a: Fe, b: Fe) Fe {
219 var ax: [5]u128 = undefined;
220 var bx: [5]u128 = undefined;
221 var a19: [5]u128 = undefined;
222 var r: [5]u128 = undefined;
223 comptime var i = 0;
224 inline while (i < 5) : (i += 1) {
225 ax[i] = @intCast(u128, a.limbs[i]);
226 bx[i] = @intCast(u128, b.limbs[i]);
227 }
228 i = 1;
229 inline while (i < 5) : (i += 1) {
230 a19[i] = 19 * ax[i];
231 }
232 r[0] = ax[0] * bx[0] + a19[1] * bx[4] + a19[2] * bx[3] + a19[3] * bx[2] + a19[4] * bx[1];
233 r[1] = ax[0] * bx[1] + ax[1] * bx[0] + a19[2] * bx[4] + a19[3] * bx[3] + a19[4] * bx[2];
234 r[2] = ax[0] * bx[2] + ax[1] * bx[1] + ax[2] * bx[0] + a19[3] * bx[4] + a19[4] * bx[3];
235 r[3] = ax[0] * bx[3] + ax[1] * bx[2] + ax[2] * bx[1] + ax[3] * bx[0] + a19[4] * bx[4];
236 r[4] = ax[0] * bx[4] + ax[1] * bx[3] + ax[2] * bx[2] + ax[3] * bx[1] + ax[4] * bx[0];
237
238 return _carry128(&r);
239 }
240
241 fn _sq(a: Fe, double: comptime bool) Fe {
242 var ax: [5]u128 = undefined;
243 var r: [5]u128 = undefined;
244 comptime var i = 0;
245 inline while (i < 5) : (i += 1) {
246 ax[i] = @intCast(u128, a.limbs[i]);
247 }
248 const a0_2 = 2 * ax[0];
249 const a1_2 = 2 * ax[1];
250 const a1_38 = 38 * ax[1];
251 const a2_38 = 38 * ax[2];
252 const a3_38 = 38 * ax[3];
253 const a3_19 = 19 * ax[3];
254 const a4_19 = 19 * ax[4];
255 r[0] = ax[0] * ax[0] + a1_38 * ax[4] + a2_38 * ax[3];
256 r[1] = a0_2 * ax[1] + a2_38 * ax[4] + a3_19 * ax[3];
257 r[2] = a0_2 * ax[2] + ax[1] * ax[1] + a3_38 * ax[4];
258 r[3] = a0_2 * ax[3] + a1_2 * ax[2] + a4_19 * ax[4];
259 r[4] = a0_2 * ax[4] + a1_2 * ax[3] + ax[2] * ax[2];
260 if (double) {
261 i = 0;
262 inline while (i < 5) : (i += 1) {
263 r[i] *= 2;
264 }
265 }
266 return _carry128(&r);
267 }
268
269 pub inline fn sq(a: Fe) Fe {
270 return _sq(a, false);
271 }
272
273 pub inline fn sq2(a: Fe) Fe {
274 return _sq(a, true);
275 }
276
277 pub inline fn mul32(a: Fe, comptime n: u32) Fe {
278 const sn = @intCast(u128, n);
279 var fe: Fe = undefined;
280 var x: u128 = 0;
281 comptime var i = 0;
282 inline while (i < 5) : (i += 1) {
283 x = a.limbs[i] * sn + (x >> 51);
284 fe.limbs[i] = @truncate(u64, x) & MASK51;
285 }
286 fe.limbs[0] += @intCast(u64, x >> 51) * 19;
287
288 return fe;
289 }
290
291 inline fn sqn(a: Fe, comptime n: comptime_int) Fe {
292 var i: usize = 0;
293 var fe = a;
294 while (i < n) : (i += 1) {
295 fe = fe.sq();
296 }
297 return fe;
298 }
299
300 pub fn invert(a: Fe) Fe {
301 var t0 = a.sq();
302 var t1 = t0.sqn(2).mul(a);
303 t0 = t0.mul(t1);
304 t1 = t1.mul(t0.sq());
305 t1 = t1.mul(t1.sqn(5));
306 var t2 = t1.sqn(10).mul(t1);
307 t2 = t2.mul(t2.sqn(20)).sqn(10);
308 t1 = t1.mul(t2);
309 t2 = t1.sqn(50).mul(t1);
310 return t1.mul(t2.mul(t2.sqn(100)).sqn(50)).sqn(5).mul(t0);
311 }
312
313 pub fn pow2523(a: Fe) Fe {
314 var c = a;
315 var i: usize = 0;
316 while (i < 249) : (i += 1) {
317 c = c.sq().mul(a);
318 }
319 return c.sq().sq().mul(a);
320 }
321
322 pub fn abs(a: Fe) Fe {
323 var r = a;
324 r.cMov(a.neg(), @boolToInt(a.isNegative()));
325 return r;
326 }
327};
lib/std/crypto/25519/field25519.zig deleted-327
...@@ -1,327 +0,0 @@
1const std = @import("std");
2const readIntLittle = std.mem.readIntLittle;
3const writeIntLittle = std.mem.writeIntLittle;
4
5pub const Fe = struct {
6 limbs: [5]u64,
7
8 const MASK51: u64 = 0x7ffffffffffff;
9
10 pub inline fn zero() Fe {
11 return .{ .limbs = .{ 0, 0, 0, 0, 0 } };
12 }
13
14 pub inline fn one() Fe {
15 return .{ .limbs = .{ 1, 0, 0, 0, 0 } };
16 }
17
18 pub inline fn sqrtm1() Fe {
19 return .{ .limbs = .{ 1718705420411056, 234908883556509, 2233514472574048, 2117202627021982, 765476049583133 } }; // sqrt(-1)
20 }
21
22 pub inline fn curve25519BasePoint() Fe {
23 return .{ .limbs = .{ 9, 0, 0, 0, 0 } };
24 }
25
26 pub inline fn edwards25519d() Fe {
27 return .{ .limbs = .{ 929955233495203, 466365720129213, 1662059464998953, 2033849074728123, 1442794654840575 } }; // 37095705934669439343138083508754565189542113879843219016388785533085940283555
28 }
29
30 pub inline fn edwards25519d2() Fe {
31 return .{ .limbs = .{ 1859910466990425, 932731440258426, 1072319116312658, 1815898335770999, 633789495995903 } }; // 2d
32 }
33
34 // 1/sqrt(a-d)
35 pub inline fn edwards25519sqrtamd() Fe {
36 return .{ .limbs = .{ 278908739862762, 821645201101625, 8113234426968, 1777959178193151, 2118520810568447 } };
37 }
38
39 pub inline fn isZero(fe: Fe) bool {
40 var reduced = fe;
41 reduced.reduce();
42 const limbs = reduced.limbs;
43 return (limbs[0] | limbs[1] | limbs[2] | limbs[3] | limbs[4]) == 0;
44 }
45
46 pub inline fn equivalent(a: Fe, b: Fe) bool {
47 return a.sub(b).isZero();
48 }
49
50 pub fn fromBytes(s: [32]u8) Fe {
51 var fe: Fe = undefined;
52 fe.limbs[0] = readIntLittle(u64, s[0..8]) & MASK51;
53 fe.limbs[1] = (readIntLittle(u64, s[6..14]) >> 3) & MASK51;
54 fe.limbs[2] = (readIntLittle(u64, s[12..20]) >> 6) & MASK51;
55 fe.limbs[3] = (readIntLittle(u64, s[19..27]) >> 1) & MASK51;
56 fe.limbs[4] = (readIntLittle(u64, s[24..32]) >> 12) & MASK51;
57
58 return fe;
59 }
60
61 pub fn toBytes(fe: Fe) [32]u8 {
62 var reduced = fe;
63 reduced.reduce();
64 var s: [32]u8 = undefined;
65 writeIntLittle(u64, s[0..8], reduced.limbs[0] | (reduced.limbs[1] << 51));
66 writeIntLittle(u64, s[8..16], (reduced.limbs[1] >> 13) | (reduced.limbs[2] << 38));
67 writeIntLittle(u64, s[16..24], (reduced.limbs[2] >> 26) | (reduced.limbs[3] << 25));
68 writeIntLittle(u64, s[24..32], (reduced.limbs[3] >> 39) | (reduced.limbs[4] << 12));
69
70 return s;
71 }
72
73 pub fn rejectNonCanonical(s: [32]u8, comptime ignore_extra_bit: bool) !void {
74 var c: u16 = (s[31] & 0x7f) ^ 0x7f;
75 comptime var i = 30;
76 inline while (i > 0) : (i -= 1) {
77 c |= s[i] ^ 0xff;
78 }
79 c = (c -% 1) >> 8;
80 const d = (@intCast(u16, 0xed - 1) -% @intCast(u16, s[0])) >> 8;
81 const x = if (ignore_extra_bit) 0 else s[31] >> 7;
82 if ((((c & d) | x) & 1) != 0) {
83 return error.NonCanonical;
84 }
85 }
86
87 fn reduce(fe: *Fe) void {
88 comptime var i = 0;
89 comptime var j = 0;
90 const limbs = &fe.limbs;
91 inline while (j < 2) : (j += 1) {
92 i = 0;
93 inline while (i < 4) : (i += 1) {
94 limbs[i + 1] += limbs[i] >> 51;
95 limbs[i] &= MASK51;
96 }
97 limbs[0] += 19 * (limbs[4] >> 51);
98 limbs[4] &= MASK51;
99 }
100 limbs[0] += 19;
101 i = 0;
102 inline while (i < 4) : (i += 1) {
103 limbs[i + 1] += limbs[i] >> 51;
104 limbs[i] &= MASK51;
105 }
106 limbs[0] += 19 * (limbs[4] >> 51);
107 limbs[4] &= MASK51;
108
109 limbs[0] += 0x8000000000000 - 19;
110 limbs[1] += 0x8000000000000 - 1;
111 limbs[2] += 0x8000000000000 - 1;
112 limbs[3] += 0x8000000000000 - 1;
113 limbs[4] += 0x8000000000000 - 1;
114
115 i = 0;
116 inline while (i < 4) : (i += 1) {
117 limbs[i + 1] += limbs[i] >> 51;
118 limbs[i] &= MASK51;
119 }
120 limbs[4] &= MASK51;
121 }
122
123 pub inline fn add(a: Fe, b: Fe) Fe {
124 var fe: Fe = undefined;
125 comptime var i = 0;
126 inline while (i < 5) : (i += 1) {
127 fe.limbs[i] = a.limbs[i] + b.limbs[i];
128 }
129 return fe;
130 }
131
132 pub fn sub(a: Fe, b: Fe) Fe {
133 var fe = b;
134 comptime var i = 0;
135 inline while (i < 4) : (i += 1) {
136 fe.limbs[i + 1] += fe.limbs[i] >> 51;
137 fe.limbs[i] &= MASK51;
138 }
139 fe.limbs[0] += 19 * (fe.limbs[4] >> 51);
140 fe.limbs[4] &= MASK51;
141 fe.limbs[0] = (a.limbs[0] + 0xfffffffffffda) - fe.limbs[0];
142 fe.limbs[1] = (a.limbs[1] + 0xffffffffffffe) - fe.limbs[1];
143 fe.limbs[2] = (a.limbs[2] + 0xffffffffffffe) - fe.limbs[2];
144 fe.limbs[3] = (a.limbs[3] + 0xffffffffffffe) - fe.limbs[3];
145 fe.limbs[4] = (a.limbs[4] + 0xffffffffffffe) - fe.limbs[4];
146
147 return fe;
148 }
149
150 pub inline fn neg(a: Fe) Fe {
151 return zero().sub(a);
152 }
153
154 pub inline fn isNegative(a: Fe) bool {
155 return (a.toBytes()[0] & 1) != 0;
156 }
157
158 pub inline fn cMov(fe: *Fe, a: Fe, c: u64) void {
159 const mask: u64 = 0 -% c;
160 var x = fe.*;
161 comptime var i = 0;
162 inline while (i < 5) : (i += 1) {
163 x.limbs[i] ^= a.limbs[i];
164 }
165 i = 0;
166 inline while (i < 5) : (i += 1) {
167 x.limbs[i] &= mask;
168 }
169 i = 0;
170 inline while (i < 5) : (i += 1) {
171 fe.limbs[i] ^= x.limbs[i];
172 }
173 }
174
175 pub fn cSwap2(a0: *Fe, b0: *Fe, a1: *Fe, b1: *Fe, c: u64) void {
176 const mask: u64 = 0 -% c;
177 var x0 = a0.*;
178 var x1 = a1.*;
179 comptime var i = 0;
180 inline while (i < 5) : (i += 1) {
181 x0.limbs[i] ^= b0.limbs[i];
182 x1.limbs[i] ^= b1.limbs[i];
183 }
184 i = 0;
185 inline while (i < 5) : (i += 1) {
186 x0.limbs[i] &= mask;
187 x1.limbs[i] &= mask;
188 }
189 i = 0;
190 inline while (i < 5) : (i += 1) {
191 a0.limbs[i] ^= x0.limbs[i];
192 b0.limbs[i] ^= x0.limbs[i];
193 a1.limbs[i] ^= x1.limbs[i];
194 b1.limbs[i] ^= x1.limbs[i];
195 }
196 }
197
198 inline fn _carry128(r: *[5]u128) Fe {
199 var rs: [5]u64 = undefined;
200 comptime var i = 0;
201 inline while (i < 4) : (i += 1) {
202 rs[i] = @truncate(u64, r[i]) & MASK51;
203 r[i + 1] += @intCast(u64, r[i] >> 51);
204 }
205 rs[4] = @truncate(u64, r[4]) & MASK51;
206 var carry = @intCast(u64, r[4] >> 51);
207 rs[0] += 19 * carry;
208 carry = rs[0] >> 51;
209 rs[0] &= MASK51;
210 rs[1] += carry;
211 carry = rs[1] >> 51;
212 rs[1] &= MASK51;
213 rs[2] += carry;
214
215 return .{ .limbs = rs };
216 }
217
218 pub fn mul(a: Fe, b: Fe) Fe {
219 var ax: [5]u128 = undefined;
220 var bx: [5]u128 = undefined;
221 var a19: [5]u128 = undefined;
222 var r: [5]u128 = undefined;
223 comptime var i = 0;
224 inline while (i < 5) : (i += 1) {
225 ax[i] = @intCast(u128, a.limbs[i]);
226 bx[i] = @intCast(u128, b.limbs[i]);
227 }
228 i = 1;
229 inline while (i < 5) : (i += 1) {
230 a19[i] = 19 * ax[i];
231 }
232 r[0] = ax[0] * bx[0] + a19[1] * bx[4] + a19[2] * bx[3] + a19[3] * bx[2] + a19[4] * bx[1];
233 r[1] = ax[0] * bx[1] + ax[1] * bx[0] + a19[2] * bx[4] + a19[3] * bx[3] + a19[4] * bx[2];
234 r[2] = ax[0] * bx[2] + ax[1] * bx[1] + ax[2] * bx[0] + a19[3] * bx[4] + a19[4] * bx[3];
235 r[3] = ax[0] * bx[3] + ax[1] * bx[2] + ax[2] * bx[1] + ax[3] * bx[0] + a19[4] * bx[4];
236 r[4] = ax[0] * bx[4] + ax[1] * bx[3] + ax[2] * bx[2] + ax[3] * bx[1] + ax[4] * bx[0];
237
238 return _carry128(&r);
239 }
240
241 fn _sq(a: Fe, double: comptime bool) Fe {
242 var ax: [5]u128 = undefined;
243 var r: [5]u128 = undefined;
244 comptime var i = 0;
245 inline while (i < 5) : (i += 1) {
246 ax[i] = @intCast(u128, a.limbs[i]);
247 }
248 const a0_2 = 2 * ax[0];
249 const a1_2 = 2 * ax[1];
250 const a1_38 = 38 * ax[1];
251 const a2_38 = 38 * ax[2];
252 const a3_38 = 38 * ax[3];
253 const a3_19 = 19 * ax[3];
254 const a4_19 = 19 * ax[4];
255 r[0] = ax[0] * ax[0] + a1_38 * ax[4] + a2_38 * ax[3];
256 r[1] = a0_2 * ax[1] + a2_38 * ax[4] + a3_19 * ax[3];
257 r[2] = a0_2 * ax[2] + ax[1] * ax[1] + a3_38 * ax[4];
258 r[3] = a0_2 * ax[3] + a1_2 * ax[2] + a4_19 * ax[4];
259 r[4] = a0_2 * ax[4] + a1_2 * ax[3] + ax[2] * ax[2];
260 if (double) {
261 i = 0;
262 inline while (i < 5) : (i += 1) {
263 r[i] *= 2;
264 }
265 }
266 return _carry128(&r);
267 }
268
269 pub inline fn sq(a: Fe) Fe {
270 return _sq(a, false);
271 }
272
273 pub inline fn sq2(a: Fe) Fe {
274 return _sq(a, true);
275 }
276
277 pub inline fn mul32(a: Fe, comptime n: u32) Fe {
278 const sn = @intCast(u128, n);
279 var fe: Fe = undefined;
280 var x: u128 = 0;
281 comptime var i = 0;
282 inline while (i < 5) : (i += 1) {
283 x = a.limbs[i] * sn + (x >> 51);
284 fe.limbs[i] = @truncate(u64, x) & MASK51;
285 }
286 fe.limbs[0] += @intCast(u64, x >> 51) * 19;
287
288 return fe;
289 }
290
291 inline fn sqn(a: Fe, comptime n: comptime_int) Fe {
292 var i: usize = 0;
293 var fe = a;
294 while (i < n) : (i += 1) {
295 fe = fe.sq();
296 }
297 return fe;
298 }
299
300 pub fn invert(a: Fe) Fe {
301 var t0 = a.sq();
302 var t1 = t0.sqn(2).mul(a);
303 t0 = t0.mul(t1);
304 t1 = t1.mul(t0.sq());
305 t1 = t1.mul(t1.sqn(5));
306 var t2 = t1.sqn(10).mul(t1);
307 t2 = t2.mul(t2.sqn(20)).sqn(10);
308 t1 = t1.mul(t2);
309 t2 = t1.sqn(50).mul(t1);
310 return t1.mul(t2.mul(t2.sqn(100)).sqn(50)).sqn(5).mul(t0);
311 }
312
313 pub fn pow2523(a: Fe) Fe {
314 var c = a;
315 var i: usize = 0;
316 while (i < 249) : (i += 1) {
317 c = c.sq().mul(a);
318 }
319 return c.sq().sq().mul(a);
320 }
321
322 pub fn abs(a: Fe) Fe {
323 var r = a;
324 r.cMov(a.neg(), @boolToInt(a.isNegative()));
325 return r;
326 }
327};
lib/std/crypto/25519/scalar.zig created+185
...@@ -0,0 +1,185 @@
1const std = @import("std");
2const mem = std.mem;
3
4inline fn fieldSize() [32]u8 {
5 return .{
6 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, // 2^252+27742317777372353535851937790883648493
7 };
8}
9
10const ScalarExpanded = struct {
11 const L = fieldSize();
12 limbs: [64]i64 = [_]i64{0} ** 64,
13
14 fn fromBytes(s: [32]u8) ScalarExpanded {
15 var limbs: [64]i64 = undefined;
16 for (s) |x, idx| {
17 limbs[idx] = @intCast(i64, x);
18 }
19 mem.set(i64, limbs[32..], 0);
20 return .{ .limbs = limbs };
21 }
22
23 fn fromBytes64(s: [64]u8) ScalarExpanded {
24 var limbs: [64]i64 = undefined;
25 for (s) |x, idx| {
26 limbs[idx] = @intCast(i64, x);
27 }
28 return .{ .limbs = limbs };
29 }
30
31 fn reduce(e: *ScalarExpanded) void {
32 const limbs = &e.limbs;
33 var carry: i64 = undefined;
34 var i: usize = 63;
35 while (i >= 32) : (i -= 1) {
36 carry = 0;
37 const k = i - 12;
38 const xi = limbs[i];
39 var j = i - 32;
40 while (j < k) : (j += 1) {
41 const xj = limbs[j] + carry - 16 * xi * @intCast(i64, L[j - (i - 32)]);
42 carry = (xj + 128) >> 8;
43 limbs[j] = xj - carry * 256;
44 }
45 limbs[k] += carry;
46 limbs[i] = 0;
47 }
48 carry = 0;
49 comptime var j: usize = 0;
50 inline while (j < 32) : (j += 1) {
51 const xi = limbs[j] + carry - (limbs[31] >> 4) * @intCast(i64, L[j]);
52 carry = xi >> 8;
53 limbs[j] = xi & 255;
54 }
55 j = 0;
56 inline while (j < 32) : (j += 1) {
57 limbs[j] -= carry * @intCast(i64, L[j]);
58 }
59 j = 0;
60 inline while (j < 32) : (j += 1) {
61 limbs[j + 1] += limbs[j] >> 8;
62 }
63 }
64
65 fn toBytes(e: *ScalarExpanded) [32]u8 {
66 e.reduce();
67 var r: [32]u8 = undefined;
68 var i: usize = 0;
69 while (i < 32) : (i += 1) {
70 r[i] = @intCast(u8, e.limbs[i]);
71 }
72 return r;
73 }
74
75 fn add(a: ScalarExpanded, b: ScalarExpanded) ScalarExpanded {
76 var r = ScalarExpanded{};
77 comptime var i = 0;
78 inline while (i < 64) : (i += 1) {
79 r.limbs[i] = a.limbs[i] + b.limbs[i];
80 }
81 return r;
82 }
83
84 fn mul(a: ScalarExpanded, b: ScalarExpanded) ScalarExpanded {
85 var r = ScalarExpanded{};
86 var i: usize = 0;
87 while (i < 32) : (i += 1) {
88 const ai = a.limbs[i];
89 comptime var j = 0;
90 inline while (j < 32) : (j += 1) {
91 r.limbs[i + j] += ai * b.limbs[j];
92 }
93 }
94 r.reduce();
95 return r;
96 }
97
98 fn sq(a: ScalarExpanded) ScalarExpanded {
99 return a.mul(a);
100 }
101
102 fn mulAdd(a: ScalarExpanded, b: ScalarExpanded, c: ScalarExpanded) ScalarExpanded {
103 var r: ScalarExpanded = .{ .limbs = c.limbs };
104 var i: usize = 0;
105 while (i < 32) : (i += 1) {
106 const ai = a.limbs[i];
107 comptime var j = 0;
108 inline while (j < 32) : (j += 1) {
109 r.limbs[i + j] += ai * b.limbs[j];
110 }
111 }
112 r.reduce();
113 return r;
114 }
115};
116
117/// Reject a scalar whose encoding is not canonical.
118pub fn rejectNonCanonical(s: [32]u8) !void {
119 const L = fieldSize();
120 var c: u8 = 0;
121 var n: u8 = 1;
122 var i: usize = 31;
123 while (true) {
124 const xs = @intCast(u16, s[i]);
125 const xL = @intCast(u16, L[i]);
126 c |= @intCast(u8, ((xs -% xL) >> 8) & n);
127 n &= @intCast(u8, ((xs ^ xL) -% 1) >> 8);
128 if (i == 0) break;
129 i -= 1;
130 }
131 if (c == 0) {
132 return error.NonCanonical;
133 }
134}
135
136/// Reduce a scalar to the field size.
137pub fn reduce(s: [32]u8) [32]u8 {
138 return ScalarExpanded.fromBytes(s).toBytes();
139}
140
141/// Reduce a 64-bytes scalar to the field size.
142pub fn reduce64(s: [64]u8) [32]u8 {
143 return ScalarExpanded.fromBytes64(s).toBytes();
144}
145
146/// Perform the X25519 "clamping" operation.
147/// The scalar is then guaranteed to be a multiple of the cofactor.
148pub inline fn clamp(s: *[32]u8) void {
149 s[0] &= 248;
150 s[31] = (s[31] & 127) | 64;
151}
152
153/// Return a*b+c (mod L)
154pub fn mulAdd(a: [32]u8, b: [32]u8, c: [32]u8) [32]u8 {
155 return ScalarExpanded.fromBytes(a).mulAdd(ScalarExpanded.fromBytes(b), ScalarExpanded.fromBytes(c)).toBytes();
156}
157
158test "scalar25519" {
159 const bytes: [32]u8 = .{ 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 255 };
160 var x = ScalarExpanded.fromBytes(bytes);
161 var y = x.toBytes();
162 try rejectNonCanonical(y);
163 var buf: [128]u8 = undefined;
164 const alloc = &std.heap.FixedBufferAllocator.init(&buf).allocator;
165 std.testing.expectEqualStrings(try std.fmt.allocPrint(alloc, "{X}", .{y}), "1E979B917937F3DE71D18077F961F6CEFF01030405060708010203040506070F");
166
167 const field_size = fieldSize();
168 const reduced = reduce(field_size);
169 std.testing.expectEqualStrings(try std.fmt.allocPrint(alloc, "{X}", .{reduced}), "0000000000000000000000000000000000000000000000000000000000000000");
170}
171
172test "non-canonical scalar25519" {
173 const too_targe: [32]u8 = .{ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 };
174 std.testing.expectError(error.NonCanonical, rejectNonCanonical(too_targe));
175}
176
177test "scalar25519 mulAdd overflow check" {
178 const a: [32]u8 = [_]u8{0xff} ** 32;
179 const b: [32]u8 = [_]u8{0xff} ** 32;
180 const c: [32]u8 = [_]u8{0xff} ** 32;
181 const x = mulAdd(a, b, c);
182 var buf: [128]u8 = undefined;
183 const alloc = &std.heap.FixedBufferAllocator.init(&buf).allocator;
184 std.testing.expectEqualStrings(try std.fmt.allocPrint(alloc, "{X}", .{x}), "D14DF91389432C25AD60FF9791B9FD1D67BEF517D273ECCE3D9A307C1B419903");
185}
lib/std/crypto/25519/scalar25519.zig deleted-185
...@@ -1,185 +0,0 @@
1const std = @import("std");
2const mem = std.mem;
3
4inline fn fieldSize() [32]u8 {
5 return .{
6 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, // 2^252+27742317777372353535851937790883648493
7 };
8}
9
10const ScalarExpanded = struct {
11 const L = fieldSize();
12 limbs: [64]i64 = [_]i64{0} ** 64,
13
14 fn fromBytes(s: [32]u8) ScalarExpanded {
15 var limbs: [64]i64 = undefined;
16 for (s) |x, idx| {
17 limbs[idx] = @intCast(i64, x);
18 }
19 mem.set(i64, limbs[32..], 0);
20 return .{ .limbs = limbs };
21 }
22
23 fn fromBytes64(s: [64]u8) ScalarExpanded {
24 var limbs: [64]i64 = undefined;
25 for (s) |x, idx| {
26 limbs[idx] = @intCast(i64, x);
27 }
28 return .{ .limbs = limbs };
29 }
30
31 fn reduce(e: *ScalarExpanded) void {
32 const limbs = &e.limbs;
33 var carry: i64 = undefined;
34 var i: usize = 63;
35 while (i >= 32) : (i -= 1) {
36 carry = 0;
37 const k = i - 12;
38 const xi = limbs[i];
39 var j = i - 32;
40 while (j < k) : (j += 1) {
41 const xj = limbs[j] + carry - 16 * xi * @intCast(i64, L[j - (i - 32)]);
42 carry = (xj + 128) >> 8;
43 limbs[j] = xj - carry * 256;
44 }
45 limbs[k] += carry;
46 limbs[i] = 0;
47 }
48 carry = 0;
49 comptime var j: usize = 0;
50 inline while (j < 32) : (j += 1) {
51 const xi = limbs[j] + carry - (limbs[31] >> 4) * @intCast(i64, L[j]);
52 carry = xi >> 8;
53 limbs[j] = xi & 255;
54 }
55 j = 0;
56 inline while (j < 32) : (j += 1) {
57 limbs[j] -= carry * @intCast(i64, L[j]);
58 }
59 j = 0;
60 inline while (j < 32) : (j += 1) {
61 limbs[j + 1] += limbs[j] >> 8;
62 }
63 }
64
65 fn toBytes(e: *ScalarExpanded) [32]u8 {
66 e.reduce();
67 var r: [32]u8 = undefined;
68 var i: usize = 0;
69 while (i < 32) : (i += 1) {
70 r[i] = @intCast(u8, e.limbs[i]);
71 }
72 return r;
73 }
74
75 fn add(a: ScalarExpanded, b: ScalarExpanded) ScalarExpanded {
76 var r = ScalarExpanded{};
77 comptime var i = 0;
78 inline while (i < 64) : (i += 1) {
79 r.limbs[i] = a.limbs[i] + b.limbs[i];
80 }
81 return r;
82 }
83
84 fn mul(a: ScalarExpanded, b: ScalarExpanded) ScalarExpanded {
85 var r = ScalarExpanded{};
86 var i: usize = 0;
87 while (i < 32) : (i += 1) {
88 const ai = a.limbs[i];
89 comptime var j = 0;
90 inline while (j < 32) : (j += 1) {
91 r.limbs[i + j] += ai * b.limbs[j];
92 }
93 }
94 r.reduce();
95 return r;
96 }
97
98 fn sq(a: ScalarExpanded) ScalarExpanded {
99 return a.mul(a);
100 }
101
102 fn mulAdd(a: ScalarExpanded, b: ScalarExpanded, c: ScalarExpanded) ScalarExpanded {
103 var r: ScalarExpanded = .{ .limbs = c.limbs };
104 var i: usize = 0;
105 while (i < 32) : (i += 1) {
106 const ai = a.limbs[i];
107 comptime var j = 0;
108 inline while (j < 32) : (j += 1) {
109 r.limbs[i + j] += ai * b.limbs[j];
110 }
111 }
112 r.reduce();
113 return r;
114 }
115};
116
117/// Reject a scalar whose encoding is not canonical.
118pub fn rejectNonCanonical(s: [32]u8) !void {
119 const L = fieldSize();
120 var c: u8 = 0;
121 var n: u8 = 1;
122 var i: usize = 31;
123 while (true) {
124 const xs = @intCast(u16, s[i]);
125 const xL = @intCast(u16, L[i]);
126 c |= @intCast(u8, ((xs -% xL) >> 8) & n);
127 n &= @intCast(u8, ((xs ^ xL) -% 1) >> 8);
128 if (i == 0) break;
129 i -= 1;
130 }
131 if (c == 0) {
132 return error.NonCanonical;
133 }
134}
135
136/// Reduce a scalar to the field size.
137pub fn reduce(s: [32]u8) [32]u8 {
138 return ScalarExpanded.fromBytes(s).toBytes();
139}
140
141/// Reduce a 64-bytes scalar to the field size.
142pub fn reduce64(s: [64]u8) [32]u8 {
143 return ScalarExpanded.fromBytes64(s).toBytes();
144}
145
146/// Perform the X25519 "clamping" operation.
147/// The scalar is then guaranteed to be a multiple of the cofactor.
148pub inline fn clamp(s: *[32]u8) void {
149 s[0] &= 248;
150 s[31] = (s[31] & 127) | 64;
151}
152
153/// Return a*b+c (mod L)
154pub fn mulAdd(a: [32]u8, b: [32]u8, c: [32]u8) [32]u8 {
155 return ScalarExpanded.fromBytes(a).mulAdd(ScalarExpanded.fromBytes(b), ScalarExpanded.fromBytes(c)).toBytes();
156}
157
158test "scalar25519" {
159 const bytes: [32]u8 = .{ 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 255 };
160 var x = ScalarExpanded.fromBytes(bytes);
161 var y = x.toBytes();
162 try rejectNonCanonical(y);
163 var buf: [128]u8 = undefined;
164 const alloc = &std.heap.FixedBufferAllocator.init(&buf).allocator;
165 std.testing.expectEqualStrings(try std.fmt.allocPrint(alloc, "{X}", .{y}), "1E979B917937F3DE71D18077F961F6CEFF01030405060708010203040506070F");
166
167 const field_size = fieldSize();
168 const reduced = reduce(field_size);
169 std.testing.expectEqualStrings(try std.fmt.allocPrint(alloc, "{X}", .{reduced}), "0000000000000000000000000000000000000000000000000000000000000000");
170}
171
172test "non-canonical scalar25519" {
173 const too_targe: [32]u8 = .{ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 };
174 std.testing.expectError(error.NonCanonical, rejectNonCanonical(too_targe));
175}
176
177test "mulAdd overflow check" {
178 const a: [32]u8 = [_]u8{0xff} ** 32;
179 const b: [32]u8 = [_]u8{0xff} ** 32;
180 const c: [32]u8 = [_]u8{0xff} ** 32;
181 const x = mulAdd(a, b, c);
182 var buf: [128]u8 = undefined;
183 const alloc = &std.heap.FixedBufferAllocator.init(&buf).allocator;
184 std.testing.expectEqualStrings(try std.fmt.allocPrint(alloc, "{X}", .{x}), "D14DF91389432C25AD60FF9791B9FD1D67BEF517D273ECCE3D9A307C1B419903");
185}