authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-21 20:21:57-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-22 11:32:14-07:00
log49d6dd3ecb0b5d0547f8a70b764e38af2f24f475
tree54ebc6679cc0e3acdccce720783151b38b2bb592
parent7b3556a8cff1edb63a331c5068902254b0b2126c

std.crypto.ff: simplify implementation

* Take advantage of multi-object for loops. * Remove use of BoundedArray since it had no meaningful impact on safety or readability. * Simplify some complex expressions, such as using `!` to invert a boolean value.

1 files changed, 86 insertions(+), 91 deletions(-)

lib/std/crypto/ff.zig+86-91
...@@ -12,7 +12,6 @@ const math = std.math;...@@ -12,7 +12,6 @@ const math = std.math;
12const mem = std.mem;12const mem = std.mem;
13const meta = std.meta;13const meta = std.meta;
14const testing = std.testing;14const testing = std.testing;
15const BoundedArray = std.BoundedArray;
16const assert = std.debug.assert;15const assert = std.debug.assert;
17const Endian = std.builtin.Endian;16const Endian = std.builtin.Endian;
1817
...@@ -63,46 +62,54 @@ pub fn Uint(comptime max_bits: comptime_int) type {...@@ -63,46 +62,54 @@ pub fn Uint(comptime max_bits: comptime_int) type {
6362
64 return struct {63 return struct {
65 const Self = @This();64 const Self = @This();
66
67 const max_limbs_count = math.divCeil(usize, max_bits, t_bits) catch unreachable;65 const max_limbs_count = math.divCeil(usize, max_bits, t_bits) catch unreachable;
68 const Limbs = BoundedArray(Limb, max_limbs_count);66
69 limbs: Limbs,67 limbs_buffer: [max_limbs_count]Limb,
68 /// The number of active limbs.
69 limbs_len: usize,
7070
71 /// Number of bytes required to serialize an integer.71 /// Number of bytes required to serialize an integer.
72 pub const encoded_bytes = math.divCeil(usize, max_bits, 8) catch unreachable;72 pub const encoded_bytes = math.divCeil(usize, max_bits, 8) catch unreachable;
7373
74 // Returns the number of active limbs.74 /// Constant slice of active limbs.
75 fn limbs_count(self: Self) usize {75 fn limbsConst(self: *const Self) []const Limb {
76 return self.limbs.len;76 return self.limbs_buffer[0..self.limbs_len];
77 }
78
79 /// Mutable slice of active limbs.
80 fn limbs(self: *Self) []Limb {
81 return self.limbs_buffer[0..self.limbs_len];
77 }82 }
7883
79 // Removes limbs whose value is zero from the active limbs.84 // Removes limbs whose value is zero from the active limbs.
80 fn normalize(self: Self) Self {85 fn normalize(self: Self) Self {
81 var res = self;86 var res = self;
82 if (self.limbs_count() < 2) {87 if (self.limbs_len < 2) {
83 return res;88 return res;
84 }89 }
85 var i = self.limbs_count() - 1;90 var i = self.limbs_len - 1;
86 while (i > 0 and res.limbs.get(i) == 0) : (i -= 1) {}91 while (i > 0 and res.limbsConst()[i] == 0) : (i -= 1) {}
87 res.limbs.resize(i + 1) catch unreachable;92 res.limbs_len = i + 1;
93 assert(res.limbs_len <= res.limbs_buffer.len);
88 return res;94 return res;
89 }95 }
9096
91 /// The zero integer.97 /// The zero integer.
92 pub const zero = zero: {98 pub const zero: Self = .{
93 var limbs = Limbs.init(0) catch unreachable;99 .limbs_buffer = [1]Limb{0} ** max_limbs_count,
94 limbs.appendNTimesAssumeCapacity(0, max_limbs_count);100 .limbs_len = max_limbs_count,
95 break :zero Self{ .limbs = limbs };
96 };101 };
97102
98 /// Creates a new big integer from a primitive type.103 /// Creates a new big integer from a primitive type.
99 /// This function may not run in constant time.104 /// This function may not run in constant time.
100 pub fn fromPrimitive(comptime T: type, x_: T) OverflowError!Self {105 pub fn fromPrimitive(comptime T: type, init_value: T) OverflowError!Self {
101 var x = x_;106 var x = init_value;
102 var out = Self.zero;107 var out: Self = .{
103 for (0..out.limbs.capacity()) |i| {108 .limbs_buffer = undefined,
104 const t = if (@bitSizeOf(T) > t_bits) @as(TLimb, @truncate(x)) else x;109 .limbs_len = max_limbs_count,
105 out.limbs.set(i, t);110 };
111 for (&out.limbs_buffer) |*limb| {
112 limb.* = if (@bitSizeOf(T) > t_bits) @as(TLimb, @truncate(x)) else x;
106 x = math.shr(T, x, t_bits);113 x = math.shr(T, x, t_bits);
107 }114 }
108 if (x != 0) {115 if (x != 0) {
...@@ -115,13 +122,13 @@ pub fn Uint(comptime max_bits: comptime_int) type {...@@ -115,13 +122,13 @@ pub fn Uint(comptime max_bits: comptime_int) type {
115 /// This function may not run in constant time.122 /// This function may not run in constant time.
116 pub fn toPrimitive(self: Self, comptime T: type) OverflowError!T {123 pub fn toPrimitive(self: Self, comptime T: type) OverflowError!T {
117 var x: T = 0;124 var x: T = 0;
118 var i = self.limbs_count() - 1;125 var i = self.limbs_len - 1;
119 while (true) : (i -= 1) {126 while (true) : (i -= 1) {
120 if (@bitSizeOf(T) >= t_bits and math.shr(T, x, @bitSizeOf(T) - t_bits) != 0) {127 if (@bitSizeOf(T) >= t_bits and math.shr(T, x, @bitSizeOf(T) - t_bits) != 0) {
121 return error.Overflow;128 return error.Overflow;
122 }129 }
123 x = math.shl(T, x, t_bits);130 x = math.shl(T, x, t_bits);
124 const v = math.cast(T, self.limbs.get(i)) orelse return error.Overflow;131 const v = math.cast(T, self.limbsConst()[i]) orelse return error.Overflow;
125 x |= v;132 x |= v;
126 if (i == 0) break;133 if (i == 0) break;
127 }134 }
...@@ -140,9 +147,9 @@ pub fn Uint(comptime max_bits: comptime_int) type {...@@ -140,9 +147,9 @@ pub fn Uint(comptime max_bits: comptime_int) type {
140 .big => bytes.len - 1,147 .big => bytes.len - 1,
141 .little => 0,148 .little => 0,
142 };149 };
143 for (0..self.limbs.len) |i| {150 for (0..self.limbs_len) |i| {
144 var remaining_bits = t_bits;151 var remaining_bits = t_bits;
145 var limb = self.limbs.get(i);152 var limb = self.limbsConst()[i];
146 while (remaining_bits >= 8) {153 while (remaining_bits >= 8) {
147 bytes[out_i] |= math.shl(u8, @as(u8, @truncate(limb)), shift);154 bytes[out_i] |= math.shl(u8, @as(u8, @truncate(limb)), shift);
148 const consumed = 8 - shift;155 const consumed = 8 - shift;
...@@ -152,7 +159,7 @@ pub fn Uint(comptime max_bits: comptime_int) type {...@@ -152,7 +159,7 @@ pub fn Uint(comptime max_bits: comptime_int) type {
152 switch (endian) {159 switch (endian) {
153 .big => {160 .big => {
154 if (out_i == 0) {161 if (out_i == 0) {
155 if (i != self.limbs.len - 1 or limb != 0) {162 if (i != self.limbs_len - 1 or limb != 0) {
156 return error.Overflow;163 return error.Overflow;
157 }164 }
158 return;165 return;
...@@ -162,7 +169,7 @@ pub fn Uint(comptime max_bits: comptime_int) type {...@@ -162,7 +169,7 @@ pub fn Uint(comptime max_bits: comptime_int) type {
162 .little => {169 .little => {
163 out_i += 1;170 out_i += 1;
164 if (out_i == bytes.len) {171 if (out_i == bytes.len) {
165 if (i != self.limbs.len - 1 or limb != 0) {172 if (i != self.limbs_len - 1 or limb != 0) {
166 return error.Overflow;173 return error.Overflow;
167 }174 }
168 return;175 return;
...@@ -187,20 +194,20 @@ pub fn Uint(comptime max_bits: comptime_int) type {...@@ -187,20 +194,20 @@ pub fn Uint(comptime max_bits: comptime_int) type {
187 };194 };
188 while (true) {195 while (true) {
189 const bi = bytes[i];196 const bi = bytes[i];
190 out.limbs.set(out_i, out.limbs.get(out_i) | math.shl(Limb, bi, shift));197 out.limbs()[out_i] |= math.shl(Limb, bi, shift);
191 shift += 8;198 shift += 8;
192 if (shift >= t_bits) {199 if (shift >= t_bits) {
193 shift -= t_bits;200 shift -= t_bits;
194 out.limbs.set(out_i, @as(TLimb, @truncate(out.limbs.get(out_i))));201 out.limbs()[out_i] = @as(TLimb, @truncate(out.limbs()[out_i]));
195 const overflow = math.shr(Limb, bi, 8 - shift);202 const overflow = math.shr(Limb, bi, 8 - shift);
196 out_i += 1;203 out_i += 1;
197 if (out_i >= out.limbs.len) {204 if (out_i >= out.limbs_len) {
198 if (overflow != 0 or i != 0) {205 if (overflow != 0 or i != 0) {
199 return error.Overflow;206 return error.Overflow;
200 }207 }
201 break;208 break;
202 }209 }
203 out.limbs.set(out_i, overflow);210 out.limbs()[out_i] = overflow;
204 }211 }
205 switch (endian) {212 switch (endian) {
206 .big => {213 .big => {
...@@ -218,32 +225,31 @@ pub fn Uint(comptime max_bits: comptime_int) type {...@@ -218,32 +225,31 @@ pub fn Uint(comptime max_bits: comptime_int) type {
218225
219 /// Returns `true` if both integers are equal.226 /// Returns `true` if both integers are equal.
220 pub fn eql(x: Self, y: Self) bool {227 pub fn eql(x: Self, y: Self) bool {
221 return crypto.utils.timingSafeEql([max_limbs_count]Limb, x.limbs.buffer, y.limbs.buffer);228 return crypto.utils.timingSafeEql([max_limbs_count]Limb, x.limbs_buffer, y.limbs_buffer);
222 }229 }
223230
224 /// Compares two integers.231 /// Compares two integers.
225 pub fn compare(x: Self, y: Self) math.Order {232 pub fn compare(x: Self, y: Self) math.Order {
226 return crypto.utils.timingSafeCompare(233 return crypto.utils.timingSafeCompare(
227 Limb,234 Limb,
228 x.limbs.constSlice(),235 x.limbsConst(),
229 y.limbs.constSlice(),236 y.limbsConst(),
230 .little,237 .little,
231 );238 );
232 }239 }
233240
234 /// Returns `true` if the integer is zero.241 /// Returns `true` if the integer is zero.
235 pub fn isZero(x: Self) bool {242 pub fn isZero(x: Self) bool {
236 const x_limbs = x.limbs.constSlice();
237 var t: Limb = 0;243 var t: Limb = 0;
238 for (0..x.limbs_count()) |i| {244 for (x.limbsConst()) |elem| {
239 t |= x_limbs[i];245 t |= elem;
240 }246 }
241 return ct.eql(t, 0);247 return ct.eql(t, 0);
242 }248 }
243249
244 /// Returns `true` if the integer is odd.250 /// Returns `true` if the integer is odd.
245 pub fn isOdd(x: Self) bool {251 pub fn isOdd(x: Self) bool {
246 return @as(bool, @bitCast(@as(u1, @truncate(x.limbs.get(0)))));252 return @as(u1, @truncate(x.limbsConst()[0])) != 0;
247 }253 }
248254
249 /// Adds `y` to `x`, and returns `true` if the operation overflowed.255 /// Adds `y` to `x`, and returns `true` if the operation overflowed.
...@@ -258,39 +264,31 @@ pub fn Uint(comptime max_bits: comptime_int) type {...@@ -258,39 +264,31 @@ pub fn Uint(comptime max_bits: comptime_int) type {
258264
259 // Replaces the limbs of `x` with the limbs of `y` if `on` is `true`.265 // Replaces the limbs of `x` with the limbs of `y` if `on` is `true`.
260 fn cmov(x: *Self, on: bool, y: Self) void {266 fn cmov(x: *Self, on: bool, y: Self) void {
261 const x_limbs = x.limbs.slice();267 for (x.limbs(), y.limbsConst()) |*x_limb, y_limb| {
262 const y_limbs = y.limbs.constSlice();268 x_limb.* = ct.select(on, y_limb, x_limb.*);
263 for (0..y.limbs_count()) |i| {
264 x_limbs[i] = ct.select(on, y_limbs[i], x_limbs[i]);
265 }269 }
266 }270 }
267271
268 // Adds `y` to `x` if `on` is `true`, and returns `true` if the operation overflowed.272 // Adds `y` to `x` if `on` is `true`, and returns `true` if the
273 // operation overflowed.
269 fn conditionalAddWithOverflow(x: *Self, on: bool, y: Self) u1 {274 fn conditionalAddWithOverflow(x: *Self, on: bool, y: Self) u1 {
270 assert(x.limbs_count() == y.limbs_count()); // Operands must have the same size.
271 const x_limbs = x.limbs.slice();
272 const y_limbs = y.limbs.constSlice();
273
274 var carry: u1 = 0;275 var carry: u1 = 0;
275 for (0..x.limbs_count()) |i| {276 for (x.limbs(), y.limbsConst()) |*x_limb, y_limb| {
276 const res = x_limbs[i] + y_limbs[i] + carry;277 const res = x_limb.* + y_limb + carry;
277 x_limbs[i] = ct.select(on, @as(TLimb, @truncate(res)), x_limbs[i]);278 x_limb.* = ct.select(on, @as(TLimb, @truncate(res)), x_limb.*);
278 carry = @as(u1, @truncate(res >> t_bits));279 carry = @truncate(res >> t_bits);
279 }280 }
280 return carry;281 return carry;
281 }282 }
282283
283 // Subtracts `y` from `x` if `on` is `true`, and returns `true` if the operation overflowed.284 // Subtracts `y` from `x` if `on` is `true`, and returns `true` if the
285 // operation overflowed.
284 fn conditionalSubWithOverflow(x: *Self, on: bool, y: Self) u1 {286 fn conditionalSubWithOverflow(x: *Self, on: bool, y: Self) u1 {
285 assert(x.limbs_count() == y.limbs_count()); // Operands must have the same size.
286 const x_limbs = x.limbs.slice();
287 const y_limbs = y.limbs.constSlice();
288
289 var borrow: u1 = 0;287 var borrow: u1 = 0;
290 for (0..x.limbs_count()) |i| {288 for (x.limbs(), y.limbsConst()) |*x_limb, y_limb| {
291 const res = x_limbs[i] -% y_limbs[i] -% borrow;289 const res = x_limb.* -% y_limb -% borrow;
292 x_limbs[i] = ct.select(on, @as(TLimb, @truncate(res)), x_limbs[i]);290 x_limb.* = ct.select(on, @as(TLimb, @truncate(res)), x_limb.*);
293 borrow = @as(u1, @truncate(res >> t_bits));291 borrow = @truncate(res >> t_bits);
294 }292 }
295 return borrow;293 return borrow;
296 }294 }
...@@ -315,7 +313,7 @@ fn Fe_(comptime bits: comptime_int) type {...@@ -315,7 +313,7 @@ fn Fe_(comptime bits: comptime_int) type {
315313
316 // The number of active limbs to represent the field element.314 // The number of active limbs to represent the field element.
317 fn limbs_count(self: Self) usize {315 fn limbs_count(self: Self) usize {
318 return self.v.limbs_count();316 return self.v.limbs_len;
319 }317 }
320318
321 /// Creates a field element from a primitive.319 /// Creates a field element from a primitive.
...@@ -398,7 +396,7 @@ pub fn Modulus(comptime max_bits: comptime_int) type {...@@ -398,7 +396,7 @@ pub fn Modulus(comptime max_bits: comptime_int) type {
398396
399 // Number of active limbs in the modulus.397 // Number of active limbs in the modulus.
400 fn limbs_count(self: Self) usize {398 fn limbs_count(self: Self) usize {
401 return self.v.limbs_count();399 return self.v.limbs_len;
402 }400 }
403401
404 /// Actual size of the modulus, in bits.402 /// Actual size of the modulus, in bits.
...@@ -409,7 +407,7 @@ pub fn Modulus(comptime max_bits: comptime_int) type {...@@ -409,7 +407,7 @@ pub fn Modulus(comptime max_bits: comptime_int) type {
409 /// Returns the element `1`.407 /// Returns the element `1`.
410 pub fn one(self: Self) Fe {408 pub fn one(self: Self) Fe {
411 var fe = self.zero;409 var fe = self.zero;
412 fe.v.limbs.set(0, 1);410 fe.v.limbs()[0] = 1;
413 return fe;411 return fe;
414 }412 }
415413
...@@ -419,10 +417,10 @@ pub fn Modulus(comptime max_bits: comptime_int) type {...@@ -419,10 +417,10 @@ pub fn Modulus(comptime max_bits: comptime_int) type {
419 if (!v_.isOdd()) return error.EvenModulus;417 if (!v_.isOdd()) return error.EvenModulus;
420418
421 var v = v_.normalize();419 var v = v_.normalize();
422 const hi = v.limbs.get(v.limbs_count() - 1);420 const hi = v.limbsConst()[v.limbs_len - 1];
423 const lo = v.limbs.get(0);421 const lo = v.limbsConst()[0];
424422
425 if (v.limbs_count() < 2 and lo < 3) {423 if (v.limbs_len < 2 and lo < 3) {
426 return error.ModulusTooSmall;424 return error.ModulusTooSmall;
427 }425 }
428426
...@@ -481,18 +479,19 @@ pub fn Modulus(comptime max_bits: comptime_int) type {...@@ -481,18 +479,19 @@ pub fn Modulus(comptime max_bits: comptime_int) type {
481 const new_len = self.limbs_count();479 const new_len = self.limbs_count();
482 if (fe.limbs_count() < new_len) return error.Overflow;480 if (fe.limbs_count() < new_len) return error.Overflow;
483 var acc: Limb = 0;481 var acc: Limb = 0;
484 for (fe.v.limbs.constSlice()[new_len..]) |limb| {482 for (fe.v.limbsConst()[new_len..]) |limb| {
485 acc |= limb;483 acc |= limb;
486 }484 }
487 if (acc != 0) return error.Overflow;485 if (acc != 0) return error.Overflow;
488 try fe.v.limbs.resize(new_len);486 if (new_len > fe.v.limbs_buffer.len) return error.Overflow;
487 fe.v.limbs_len = new_len;
489 }488 }
490489
491 // Computes R^2 for the Montgomery representation.490 // Computes R^2 for the Montgomery representation.
492 fn computeRR(self: *Self) void {491 fn computeRR(self: *Self) void {
493 self.rr = self.zero;492 self.rr = self.zero;
494 const n = self.rr.limbs_count();493 const n = self.rr.limbs_count();
495 self.rr.v.limbs.set(n - 1, 1);494 self.rr.v.limbs()[n - 1] = 1;
496 for ((n - 1)..(2 * n)) |_| {495 for ((n - 1)..(2 * n)) |_| {
497 self.shiftIn(&self.rr, 0);496 self.shiftIn(&self.rr, 0);
498 }497 }
...@@ -502,9 +501,9 @@ pub fn Modulus(comptime max_bits: comptime_int) type {...@@ -502,9 +501,9 @@ pub fn Modulus(comptime max_bits: comptime_int) type {
502 /// Computes x << t_bits + y (mod m)501 /// Computes x << t_bits + y (mod m)
503 fn shiftIn(self: Self, x: *Fe, y: Limb) void {502 fn shiftIn(self: Self, x: *Fe, y: Limb) void {
504 var d = self.zero;503 var d = self.zero;
505 const x_limbs = x.v.limbs.slice();504 const x_limbs = x.v.limbs();
506 const d_limbs = d.v.limbs.slice();505 const d_limbs = d.v.limbs();
507 const m_limbs = self.v.limbs.constSlice();506 const m_limbs = self.v.limbsConst();
508507
509 var need_sub = false;508 var need_sub = false;
510 var i: usize = t_bits - 1;509 var i: usize = t_bits - 1;
...@@ -569,18 +568,18 @@ pub fn Modulus(comptime max_bits: comptime_int) type {...@@ -569,18 +568,18 @@ pub fn Modulus(comptime max_bits: comptime_int) type {
569 /// Reduces an arbitrary `Uint`, converting it to a field element.568 /// Reduces an arbitrary `Uint`, converting it to a field element.
570 pub fn reduce(self: Self, x: anytype) Fe {569 pub fn reduce(self: Self, x: anytype) Fe {
571 var out = self.zero;570 var out = self.zero;
572 var i = x.limbs_count() - 1;571 var i = x.limbs_len - 1;
573 if (self.limbs_count() >= 2) {572 if (self.limbs_count() >= 2) {
574 const start = @min(i, self.limbs_count() - 2);573 const start = @min(i, self.limbs_count() - 2);
575 var j = start;574 var j = start;
576 while (true) : (j -= 1) {575 while (true) : (j -= 1) {
577 out.v.limbs.set(j, x.limbs.get(i));576 out.v.limbs()[j] = x.limbsConst()[i];
578 i -= 1;577 i -= 1;
579 if (j == 0) break;578 if (j == 0) break;
580 }579 }
581 }580 }
582 while (true) : (i -= 1) {581 while (true) : (i -= 1) {
583 self.shiftIn(&out, x.limbs.get(i));582 self.shiftIn(&out, x.limbsConst()[i]);
584 if (i == 0) break;583 if (i == 0) break;
585 }584 }
586 return out;585 return out;
...@@ -591,10 +590,10 @@ pub fn Modulus(comptime max_bits: comptime_int) type {...@@ -591,10 +590,10 @@ pub fn Modulus(comptime max_bits: comptime_int) type {
591 assert(d.limbs_count() == y.limbs_count());590 assert(d.limbs_count() == y.limbs_count());
592 assert(d.limbs_count() == self.limbs_count());591 assert(d.limbs_count() == self.limbs_count());
593592
594 const a_limbs = x.v.limbs.constSlice();593 const a_limbs = x.v.limbsConst();
595 const b_limbs = y.v.limbs.constSlice();594 const b_limbs = y.v.limbsConst();
596 const d_limbs = d.v.limbs.slice();595 const d_limbs = d.v.limbs();
597 const m_limbs = self.v.limbs.constSlice();596 const m_limbs = self.v.limbsConst();
598597
599 var overflow: u1 = 0;598 var overflow: u1 = 0;
600 for (0..self.limbs_count()) |i| {599 for (0..self.limbs_count()) |i| {
...@@ -685,7 +684,7 @@ pub fn Modulus(comptime max_bits: comptime_int) type {...@@ -685,7 +684,7 @@ pub fn Modulus(comptime max_bits: comptime_int) type {
685 const k: u1 = @truncate(b >> j);684 const k: u1 = @truncate(b >> j);
686 if (k != 0) {685 if (k != 0) {
687 const t = self.montgomeryMul(out, x_m);686 const t = self.montgomeryMul(out, x_m);
688 @memcpy(out.v.limbs.slice(), t.v.limbs.constSlice());687 @memcpy(out.v.limbs(), t.v.limbsConst());
689 }688 }
690 if (j == 0) break;689 if (j == 0) break;
691 }690 }
...@@ -731,7 +730,7 @@ pub fn Modulus(comptime max_bits: comptime_int) type {...@@ -731,7 +730,7 @@ pub fn Modulus(comptime max_bits: comptime_int) type {
731 }730 }
732 const t1 = self.montgomeryMul(out, t0);731 const t1 = self.montgomeryMul(out, t0);
733 if (public) {732 if (public) {
734 @memcpy(out.v.limbs.slice(), t1.v.limbs.constSlice());733 @memcpy(out.v.limbs(), t1.v.limbsConst());
735 } else {734 } else {
736 out.v.cmov(!ct.eql(k, 0), t1.v);735 out.v.cmov(!ct.eql(k, 0), t1.v);
737 }736 }
...@@ -790,9 +789,9 @@ pub fn Modulus(comptime max_bits: comptime_int) type {...@@ -790,9 +789,9 @@ pub fn Modulus(comptime max_bits: comptime_int) type {
790 pub fn powPublic(self: Self, x: Fe, e: Fe) NullExponentError!Fe {789 pub fn powPublic(self: Self, x: Fe, e: Fe) NullExponentError!Fe {
791 var e_normalized = Fe{ .v = e.v.normalize() };790 var e_normalized = Fe{ .v = e.v.normalize() };
792 var buf_: [Fe.encoded_bytes]u8 = undefined;791 var buf_: [Fe.encoded_bytes]u8 = undefined;
793 var buf = buf_[0 .. math.divCeil(usize, e_normalized.v.limbs_count() * t_bits, 8) catch unreachable];792 var buf = buf_[0 .. math.divCeil(usize, e_normalized.v.limbs_len * t_bits, 8) catch unreachable];
794 e_normalized.toBytes(buf, .little) catch unreachable;793 e_normalized.toBytes(buf, .little) catch unreachable;
795 const leading = @clz(e_normalized.v.limbs.get(e_normalized.v.limbs_count() - carry_bits));794 const leading = @clz(e_normalized.v.limbsConst()[e_normalized.v.limbs_len - carry_bits]);
796 buf = buf[0 .. buf.len - leading / 8];795 buf = buf[0 .. buf.len - leading / 8];
797 return self.powWithEncodedPublicExponent(x, buf, .little);796 return self.powWithEncodedPublicExponent(x, buf, .little);
798 }797 }
...@@ -835,20 +834,16 @@ const ct_protected = struct {...@@ -835,20 +834,16 @@ const ct_protected = struct {
835834
836 // Compares two big integers in constant time, returning true if x < y.835 // Compares two big integers in constant time, returning true if x < y.
837 fn limbsCmpLt(x: anytype, y: @TypeOf(x)) bool {836 fn limbsCmpLt(x: anytype, y: @TypeOf(x)) bool {
838 assert(x.limbs_count() == y.limbs_count());
839 const x_limbs = x.limbs.constSlice();
840 const y_limbs = y.limbs.constSlice();
841
842 var c: u1 = 0;837 var c: u1 = 0;
843 for (0..x.limbs_count()) |i| {838 for (x.limbsConst(), y.limbsConst()) |x_limb, y_limb| {
844 c = @as(u1, @truncate((x_limbs[i] -% y_limbs[i] -% c) >> t_bits));839 c = @truncate((x_limb -% y_limb -% c) >> t_bits);
845 }840 }
846 return @as(bool, @bitCast(c));841 return c != 0;
847 }842 }
848843
849 // Compares two big integers in constant time, returning true if x >= y.844 // Compares two big integers in constant time, returning true if x >= y.
850 fn limbsCmpGeq(x: anytype, y: @TypeOf(x)) bool {845 fn limbsCmpGeq(x: anytype, y: @TypeOf(x)) bool {
851 return @as(bool, @bitCast(1 - @intFromBool(ct.limbsCmpLt(x, y))));846 return !ct.limbsCmpLt(x, y);
852 }847 }
853848
854 // Multiplies two limbs and returns the result as a wide limb.849 // Multiplies two limbs and returns the result as a wide limb.