| ... | @@ -12,7 +12,6 @@ const math = std.math; | ... | @@ -12,7 +12,6 @@ const math = std.math; |
| 12 | const mem = std.mem; | 12 | const mem = std.mem; |
| 13 | const meta = std.meta; | 13 | const meta = std.meta; |
| 14 | const testing = std.testing; | 14 | const testing = std.testing; |
| 15 | const BoundedArray = std.BoundedArray; | | |
| 16 | const assert = std.debug.assert; | 15 | const assert = std.debug.assert; |
| 17 | const Endian = std.builtin.Endian; | 16 | const Endian = std.builtin.Endian; |
| 18 | | 17 | |
| ... | @@ -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 { |
| 63 | | 62 | |
| 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, |
| 70 | | 70 | |
| 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; |
| 73 | | 73 | |
| 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 | } |
| 78 | | 83 | |
| 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 | } |
| 90 | | 96 | |
| 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 | }; |
| 97 | | 102 | |
| 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 { |
| 218 | | 225 | |
| 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 | } |
| 223 | | 230 | |
| 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 | } |
| 233 | | 240 | |
| 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 | } |
| 243 | | 249 | |
| 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 | } |
| 248 | | 254 | |
| 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 { |
| 258 | | 264 | |
| 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 | } |
| 267 | | 271 | |
| 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 | } |
| 282 | | 283 | |
| 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 { |
| 315 | | 313 | |
| 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 | } |
| 320 | | 318 | |
| 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 { |
| 398 | | 396 | |
| 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 | } |
| 403 | | 401 | |
| 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 | } |
| 415 | | 413 | |
| ... | @@ -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; |
| 420 | | 418 | |
| 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]; |
| 424 | | 422 | |
| 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 | } |
| 428 | | 426 | |
| ... | @@ -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 | } |
| 490 | | 489 | |
| 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(); |
| 508 | | 507 | |
| 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()); |
| 593 | | 592 | |
| 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(); |
| 598 | | 597 | |
| 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 { |
| 835 | | 834 | |
| 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 | } |
| 848 | | 843 | |
| 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 | } |
| 853 | | 848 | |
| 854 | // Multiplies two limbs and returns the result as a wide limb. | 849 | // Multiplies two limbs and returns the result as a wide limb. |