| ... | ... | @@ -12,26 +12,46 @@ pub const Fe = struct { |
| 12 | 12 | |
| 13 | 13 | const MASK51: u64 = 0x7ffffffffffff; |
| 14 | 14 | |
| 15 | /// 0 |
| 15 | 16 | pub const zero = Fe{ .limbs = .{ 0, 0, 0, 0, 0 } }; |
| 16 | 17 | |
| 18 | /// 1 |
| 17 | 19 | pub const one = Fe{ .limbs = .{ 1, 0, 0, 0, 0 } }; |
| 18 | 20 | |
| 19 | | pub const sqrtm1 = Fe{ .limbs = .{ 1718705420411056, 234908883556509, 2233514472574048, 2117202627021982, 765476049583133 } }; // sqrt(-1) |
| 21 | /// sqrt(-1) |
| 22 | pub const sqrtm1 = Fe{ .limbs = .{ 1718705420411056, 234908883556509, 2233514472574048, 2117202627021982, 765476049583133 } }; |
| 20 | 23 | |
| 24 | /// The Curve25519 base point |
| 21 | 25 | pub const curve25519BasePoint = Fe{ .limbs = .{ 9, 0, 0, 0, 0 } }; |
| 22 | 26 | |
| 23 | | pub const edwards25519d = Fe{ .limbs = .{ 929955233495203, 466365720129213, 1662059464998953, 2033849074728123, 1442794654840575 } }; // 37095705934669439343138083508754565189542113879843219016388785533085940283555 |
| 27 | /// Edwards25519 d = 37095705934669439343138083508754565189542113879843219016388785533085940283555 |
| 28 | pub const edwards25519d = Fe{ .limbs = .{ 929955233495203, 466365720129213, 1662059464998953, 2033849074728123, 1442794654840575 } }; |
| 24 | 29 | |
| 25 | | pub const edwards25519d2 = Fe{ .limbs = .{ 1859910466990425, 932731440258426, 1072319116312658, 1815898335770999, 633789495995903 } }; // 2d |
| 30 | /// Edwards25519 2d |
| 31 | pub const edwards25519d2 = Fe{ .limbs = .{ 1859910466990425, 932731440258426, 1072319116312658, 1815898335770999, 633789495995903 } }; |
| 26 | 32 | |
| 27 | | pub const edwards25519sqrtamd = Fe{ .limbs = .{ 278908739862762, 821645201101625, 8113234426968, 1777959178193151, 2118520810568447 } }; // 1/sqrt(a-d) |
| 33 | /// Edwards25519 1/sqrt(a-d) |
| 34 | pub const edwards25519sqrtamd = Fe{ .limbs = .{ 278908739862762, 821645201101625, 8113234426968, 1777959178193151, 2118520810568447 } }; |
| 28 | 35 | |
| 29 | | pub const edwards25519eonemsqd = Fe{ .limbs = .{ 1136626929484150, 1998550399581263, 496427632559748, 118527312129759, 45110755273534 } }; // 1-d^2 |
| 36 | /// Edwards25519 1-d^2 |
| 37 | pub const edwards25519eonemsqd = Fe{ .limbs = .{ 1136626929484150, 1998550399581263, 496427632559748, 118527312129759, 45110755273534 } }; |
| 30 | 38 | |
| 31 | | pub const edwards25519sqdmone = Fe{ .limbs = .{ 1507062230895904, 1572317787530805, 683053064812840, 317374165784489, 1572899562415810 } }; // (d-1)^2 |
| 39 | /// Edwards25519 (d-1)^2 |
| 40 | pub const edwards25519sqdmone = Fe{ .limbs = .{ 1507062230895904, 1572317787530805, 683053064812840, 317374165784489, 1572899562415810 } }; |
| 32 | 41 | |
| 42 | /// Edwards25519 sqrt(ad-1) with a = -1 (mod p) |
| 33 | 43 | pub const edwards25519sqrtadm1 = Fe{ .limbs = .{ 2241493124984347, 425987919032274, 2207028919301688, 1220490630685848, 974799131293748 } }; |
| 34 | 44 | |
| 45 | /// Edwards25519 A, as a single limb |
| 46 | pub const edwards25519a_32: u32 = 486662; |
| 47 | |
| 48 | /// Edwards25519 A |
| 49 | pub const edwards25519a = Fe{ .limbs = .{ @as(u64, edwards25519a_32), 0, 0, 0, 0 } }; |
| 50 | |
| 51 | /// Edwards25519 sqrt(A-2) |
| 52 | pub const edwards25519sqrtam2 = Fe{ .limbs = .{ 1693982333959686, 608509411481997, 2235573344831311, 947681270984193, 266558006233600 } }; |
| 53 | |
| 54 | /// Return true if the field element is zero |
| 35 | 55 | pub inline fn isZero(fe: Fe) bool { |
| 36 | 56 | var reduced = fe; |
| 37 | 57 | reduced.reduce(); |
| ... | ... | @@ -39,10 +59,12 @@ pub const Fe = struct { |
| 39 | 59 | return (limbs[0] | limbs[1] | limbs[2] | limbs[3] | limbs[4]) == 0; |
| 40 | 60 | } |
| 41 | 61 | |
| 62 | /// Return true if both field elements are equivalent |
| 42 | 63 | pub inline fn equivalent(a: Fe, b: Fe) bool { |
| 43 | 64 | return a.sub(b).isZero(); |
| 44 | 65 | } |
| 45 | 66 | |
| 67 | /// Unpack a field element |
| 46 | 68 | pub fn fromBytes(s: [32]u8) Fe { |
| 47 | 69 | var fe: Fe = undefined; |
| 48 | 70 | fe.limbs[0] = readIntLittle(u64, s[0..8]) & MASK51; |
| ... | ... | @@ -54,6 +76,7 @@ pub const Fe = struct { |
| 54 | 76 | return fe; |
| 55 | 77 | } |
| 56 | 78 | |
| 79 | /// Pack a field element |
| 57 | 80 | pub fn toBytes(fe: Fe) [32]u8 { |
| 58 | 81 | var reduced = fe; |
| 59 | 82 | reduced.reduce(); |
| ... | ... | @@ -66,6 +89,29 @@ pub const Fe = struct { |
| 66 | 89 | return s; |
| 67 | 90 | } |
| 68 | 91 | |
| 92 | /// Map a 64-bit big endian string into a field element |
| 93 | pub fn fromBytes64(s: [64]u8) Fe { |
| 94 | var fl: [32]u8 = undefined; |
| 95 | var gl: [32]u8 = undefined; |
| 96 | var i: usize = 0; |
| 97 | while (i < 32) : (i += 1) { |
| 98 | fl[i] = s[63 - i]; |
| 99 | gl[i] = s[31 - i]; |
| 100 | } |
| 101 | fl[31] &= 0x7f; |
| 102 | gl[31] &= 0x7f; |
| 103 | var fe_f = fromBytes(fl); |
| 104 | const fe_g = fromBytes(gl); |
| 105 | fe_f.limbs[0] += (s[32] >> 7) * 19; |
| 106 | i = 0; |
| 107 | while (i < 5) : (i += 1) { |
| 108 | fe_f.limbs[i] += 38 * fe_g.limbs[i]; |
| 109 | } |
| 110 | fe_f.reduce(); |
| 111 | return fe_f; |
| 112 | } |
| 113 | |
| 114 | /// Reject non-canonical encodings of an element, possibly ignoring the top bit |
| 69 | 115 | pub fn rejectNonCanonical(s: [32]u8, comptime ignore_extra_bit: bool) !void { |
| 70 | 116 | var c: u16 = (s[31] & 0x7f) ^ 0x7f; |
| 71 | 117 | comptime var i = 30; |
| ... | ... | @@ -80,6 +126,7 @@ pub const Fe = struct { |
| 80 | 126 | } |
| 81 | 127 | } |
| 82 | 128 | |
| 129 | /// Reduce a field element mod 2^255-19 |
| 83 | 130 | fn reduce(fe: *Fe) void { |
| 84 | 131 | comptime var i = 0; |
| 85 | 132 | comptime var j = 0; |
| ... | ... | @@ -116,6 +163,7 @@ pub const Fe = struct { |
| 116 | 163 | limbs[4] &= MASK51; |
| 117 | 164 | } |
| 118 | 165 | |
| 166 | /// Add a field element |
| 119 | 167 | pub inline fn add(a: Fe, b: Fe) Fe { |
| 120 | 168 | var fe: Fe = undefined; |
| 121 | 169 | comptime var i = 0; |
| ... | ... | @@ -125,6 +173,7 @@ pub const Fe = struct { |
| 125 | 173 | return fe; |
| 126 | 174 | } |
| 127 | 175 | |
| 176 | /// Substract a field elememnt |
| 128 | 177 | pub inline fn sub(a: Fe, b: Fe) Fe { |
| 129 | 178 | var fe = b; |
| 130 | 179 | comptime var i = 0; |
| ... | ... | @@ -143,14 +192,17 @@ pub const Fe = struct { |
| 143 | 192 | return fe; |
| 144 | 193 | } |
| 145 | 194 | |
| 195 | /// Negate a field element |
| 146 | 196 | pub inline fn neg(a: Fe) Fe { |
| 147 | 197 | return zero.sub(a); |
| 148 | 198 | } |
| 149 | 199 | |
| 200 | /// Return true if a field element is negative |
| 150 | 201 | pub inline fn isNegative(a: Fe) bool { |
| 151 | 202 | return (a.toBytes()[0] & 1) != 0; |
| 152 | 203 | } |
| 153 | 204 | |
| 205 | /// Conditonally replace a field element with `a` if `c` is positive |
| 154 | 206 | pub inline fn cMov(fe: *Fe, a: Fe, c: u64) void { |
| 155 | 207 | const mask: u64 = 0 -% c; |
| 156 | 208 | var x = fe.*; |
| ... | ... | @@ -168,6 +220,7 @@ pub const Fe = struct { |
| 168 | 220 | } |
| 169 | 221 | } |
| 170 | 222 | |
| 223 | /// Conditionally swap two pairs of field elements if `c` is positive |
| 171 | 224 | pub fn cSwap2(a0: *Fe, b0: *Fe, a1: *Fe, b1: *Fe, c: u64) void { |
| 172 | 225 | const mask: u64 = 0 -% c; |
| 173 | 226 | var x0 = a0.*; |
| ... | ... | @@ -211,6 +264,7 @@ pub const Fe = struct { |
| 211 | 264 | return .{ .limbs = rs }; |
| 212 | 265 | } |
| 213 | 266 | |
| 267 | /// Multiply two field elements |
| 214 | 268 | pub inline fn mul(a: Fe, b: Fe) Fe { |
| 215 | 269 | var ax: [5]u128 = undefined; |
| 216 | 270 | var bx: [5]u128 = undefined; |
| ... | ... | @@ -262,14 +316,17 @@ pub const Fe = struct { |
| 262 | 316 | return _carry128(&r); |
| 263 | 317 | } |
| 264 | 318 | |
| 319 | /// Square a field element |
| 265 | 320 | pub inline fn sq(a: Fe) Fe { |
| 266 | 321 | return _sq(a, false); |
| 267 | 322 | } |
| 268 | 323 | |
| 324 | /// Square and double a field element |
| 269 | 325 | pub inline fn sq2(a: Fe) Fe { |
| 270 | 326 | return _sq(a, true); |
| 271 | 327 | } |
| 272 | 328 | |
| 329 | /// Multiply a field element with a small (32-bit) integer |
| 273 | 330 | pub inline fn mul32(a: Fe, comptime n: u32) Fe { |
| 274 | 331 | const sn = @intCast(u128, n); |
| 275 | 332 | var fe: Fe = undefined; |
| ... | ... | @@ -284,6 +341,7 @@ pub const Fe = struct { |
| 284 | 341 | return fe; |
| 285 | 342 | } |
| 286 | 343 | |
| 344 | /// Square a field element `n` times |
| 287 | 345 | inline fn sqn(a: Fe, comptime n: comptime_int) Fe { |
| 288 | 346 | var i: usize = 0; |
| 289 | 347 | var fe = a; |
| ... | ... | @@ -293,6 +351,7 @@ pub const Fe = struct { |
| 293 | 351 | return fe; |
| 294 | 352 | } |
| 295 | 353 | |
| 354 | /// Compute the inverse of a field element |
| 296 | 355 | pub fn invert(a: Fe) Fe { |
| 297 | 356 | var t0 = a.sq(); |
| 298 | 357 | var t1 = t0.sqn(2).mul(a); |
| ... | ... | @@ -306,6 +365,8 @@ pub const Fe = struct { |
| 306 | 365 | return t1.mul(t2.mul(t2.sqn(100)).sqn(50)).sqn(5).mul(t0); |
| 307 | 366 | } |
| 308 | 367 | |
| 368 | /// Return a^((p-5)/8) = a^(2^252-3) |
| 369 | /// Used to compute square roots since we have p=5 (mod 8); see Cohen and Frey. |
| 309 | 370 | pub fn pow2523(a: Fe) Fe { |
| 310 | 371 | var t0 = a.mul(a.sq()); |
| 311 | 372 | var t1 = t0.mul(t0.sqn(2)).sq().mul(a); |
| ... | ... | @@ -317,9 +378,47 @@ pub const Fe = struct { |
| 317 | 378 | return t1.sqn(120).mul(t1).sqn(10).mul(t0).sqn(2).mul(a); |
| 318 | 379 | } |
| 319 | 380 | |
| 381 | /// Return the absolute value of a field element |
| 320 | 382 | pub fn abs(a: Fe) Fe { |
| 321 | 383 | var r = a; |
| 322 | 384 | r.cMov(a.neg(), @boolToInt(a.isNegative())); |
| 323 | 385 | return r; |
| 324 | 386 | } |
| 387 | |
| 388 | /// Return true if the field element is a square |
| 389 | pub fn isSquare(a: Fe) bool { |
| 390 | // Compute the Jacobi symbol x^((p-1)/2) |
| 391 | const _11 = a.mul(a.sq()); |
| 392 | const _1111 = _11.mul(_11.sq().sq()); |
| 393 | const _11111111 = _1111.mul(_1111.sq().sq().sq().sq()); |
| 394 | var t = _11111111.sqn(2).mul(_11); |
| 395 | const u = t; |
| 396 | t = t.sqn(10).mul(u).sqn(10).mul(u); |
| 397 | t = t.sqn(30).mul(t); |
| 398 | t = t.sqn(60).mul(t); |
| 399 | t = t.sqn(120).mul(t).sqn(10).mul(u).sqn(3).mul(_11).sq(); |
| 400 | return @bitCast(bool, @truncate(u1, ~(t.toBytes()[1] & 1))); |
| 401 | } |
| 402 | |
| 403 | fn uncheckedSqrt(x2: Fe) Fe { |
| 404 | var e = x2.pow2523(); |
| 405 | const p_root = e.mul(x2); // positive root |
| 406 | const m_root = p_root.mul(Fe.sqrtm1); // negative root |
| 407 | const m_root2 = m_root.sq(); |
| 408 | e = x2.sub(m_root2); |
| 409 | var x = p_root; |
| 410 | x.cMov(m_root, @boolToInt(e.isZero())); |
| 411 | return x; |
| 412 | } |
| 413 | |
| 414 | /// Compute the square root of `x2`, returning `error.NotSquare` if `x2` was not a square |
| 415 | pub fn sqrt(x2: Fe) !Fe { |
| 416 | var x2_copy = x2; |
| 417 | const x = x2.uncheckedSqrt(); |
| 418 | const check = x.sq().sub(x2_copy); |
| 419 | if (check.isZero()) { |
| 420 | return x; |
| 421 | } |
| 422 | return error.NotSquare; |
| 423 | } |
| 325 | 424 | }; |