| ... | @@ -12,26 +12,46 @@ pub const Fe = struct { | ... | @@ -12,26 +12,46 @@ pub const Fe = struct { |
| 12 | | 12 | |
| 13 | const MASK51: u64 = 0x7ffffffffffff; | 13 | const MASK51: u64 = 0x7ffffffffffff; |
| 14 | | 14 | |
| | 15 | /// 0 |
| 15 | pub const zero = Fe{ .limbs = .{ 0, 0, 0, 0, 0 } }; | 16 | pub const zero = Fe{ .limbs = .{ 0, 0, 0, 0, 0 } }; |
| 16 | | 17 | |
| | 18 | /// 1 |
| 17 | pub const one = Fe{ .limbs = .{ 1, 0, 0, 0, 0 } }; | 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 | pub const curve25519BasePoint = Fe{ .limbs = .{ 9, 0, 0, 0, 0 } }; | 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 | pub const edwards25519sqrtadm1 = Fe{ .limbs = .{ 2241493124984347, 425987919032274, 2207028919301688, 1220490630685848, 974799131293748 } }; | 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 | pub inline fn isZero(fe: Fe) bool { | 55 | pub inline fn isZero(fe: Fe) bool { |
| 36 | var reduced = fe; | 56 | var reduced = fe; |
| 37 | reduced.reduce(); | 57 | reduced.reduce(); |
| ... | @@ -39,10 +59,12 @@ pub const Fe = struct { | ... | @@ -39,10 +59,12 @@ pub const Fe = struct { |
| 39 | return (limbs[0] | limbs[1] | limbs[2] | limbs[3] | limbs[4]) == 0; | 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 | pub inline fn equivalent(a: Fe, b: Fe) bool { | 63 | pub inline fn equivalent(a: Fe, b: Fe) bool { |
| 43 | return a.sub(b).isZero(); | 64 | return a.sub(b).isZero(); |
| 44 | } | 65 | } |
| 45 | | 66 | |
| | 67 | /// Unpack a field element |
| 46 | pub fn fromBytes(s: [32]u8) Fe { | 68 | pub fn fromBytes(s: [32]u8) Fe { |
| 47 | var fe: Fe = undefined; | 69 | var fe: Fe = undefined; |
| 48 | fe.limbs[0] = readIntLittle(u64, s[0..8]) & MASK51; | 70 | fe.limbs[0] = readIntLittle(u64, s[0..8]) & MASK51; |
| ... | @@ -54,6 +76,7 @@ pub const Fe = struct { | ... | @@ -54,6 +76,7 @@ pub const Fe = struct { |
| 54 | return fe; | 76 | return fe; |
| 55 | } | 77 | } |
| 56 | | 78 | |
| | 79 | /// Pack a field element |
| 57 | pub fn toBytes(fe: Fe) [32]u8 { | 80 | pub fn toBytes(fe: Fe) [32]u8 { |
| 58 | var reduced = fe; | 81 | var reduced = fe; |
| 59 | reduced.reduce(); | 82 | reduced.reduce(); |
| ... | @@ -66,6 +89,29 @@ pub const Fe = struct { | ... | @@ -66,6 +89,29 @@ pub const Fe = struct { |
| 66 | return s; | 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 | pub fn rejectNonCanonical(s: [32]u8, comptime ignore_extra_bit: bool) !void { | 115 | pub fn rejectNonCanonical(s: [32]u8, comptime ignore_extra_bit: bool) !void { |
| 70 | var c: u16 = (s[31] & 0x7f) ^ 0x7f; | 116 | var c: u16 = (s[31] & 0x7f) ^ 0x7f; |
| 71 | comptime var i = 30; | 117 | comptime var i = 30; |
| ... | @@ -80,6 +126,7 @@ pub const Fe = struct { | ... | @@ -80,6 +126,7 @@ pub const Fe = struct { |
| 80 | } | 126 | } |
| 81 | } | 127 | } |
| 82 | | 128 | |
| | 129 | /// Reduce a field element mod 2^255-19 |
| 83 | fn reduce(fe: *Fe) void { | 130 | fn reduce(fe: *Fe) void { |
| 84 | comptime var i = 0; | 131 | comptime var i = 0; |
| 85 | comptime var j = 0; | 132 | comptime var j = 0; |
| ... | @@ -116,6 +163,7 @@ pub const Fe = struct { | ... | @@ -116,6 +163,7 @@ pub const Fe = struct { |
| 116 | limbs[4] &= MASK51; | 163 | limbs[4] &= MASK51; |
| 117 | } | 164 | } |
| 118 | | 165 | |
| | 166 | /// Add a field element |
| 119 | pub inline fn add(a: Fe, b: Fe) Fe { | 167 | pub inline fn add(a: Fe, b: Fe) Fe { |
| 120 | var fe: Fe = undefined; | 168 | var fe: Fe = undefined; |
| 121 | comptime var i = 0; | 169 | comptime var i = 0; |
| ... | @@ -125,6 +173,7 @@ pub const Fe = struct { | ... | @@ -125,6 +173,7 @@ pub const Fe = struct { |
| 125 | return fe; | 173 | return fe; |
| 126 | } | 174 | } |
| 127 | | 175 | |
| | 176 | /// Substract a field elememnt |
| 128 | pub inline fn sub(a: Fe, b: Fe) Fe { | 177 | pub inline fn sub(a: Fe, b: Fe) Fe { |
| 129 | var fe = b; | 178 | var fe = b; |
| 130 | comptime var i = 0; | 179 | comptime var i = 0; |
| ... | @@ -143,14 +192,17 @@ pub const Fe = struct { | ... | @@ -143,14 +192,17 @@ pub const Fe = struct { |
| 143 | return fe; | 192 | return fe; |
| 144 | } | 193 | } |
| 145 | | 194 | |
| | 195 | /// Negate a field element |
| 146 | pub inline fn neg(a: Fe) Fe { | 196 | pub inline fn neg(a: Fe) Fe { |
| 147 | return zero.sub(a); | 197 | return zero.sub(a); |
| 148 | } | 198 | } |
| 149 | | 199 | |
| | 200 | /// Return true if a field element is negative |
| 150 | pub inline fn isNegative(a: Fe) bool { | 201 | pub inline fn isNegative(a: Fe) bool { |
| 151 | return (a.toBytes()[0] & 1) != 0; | 202 | return (a.toBytes()[0] & 1) != 0; |
| 152 | } | 203 | } |
| 153 | | 204 | |
| | 205 | /// Conditonally replace a field element with `a` if `c` is positive |
| 154 | pub inline fn cMov(fe: *Fe, a: Fe, c: u64) void { | 206 | pub inline fn cMov(fe: *Fe, a: Fe, c: u64) void { |
| 155 | const mask: u64 = 0 -% c; | 207 | const mask: u64 = 0 -% c; |
| 156 | var x = fe.*; | 208 | var x = fe.*; |
| ... | @@ -168,6 +220,7 @@ pub const Fe = struct { | ... | @@ -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 | pub fn cSwap2(a0: *Fe, b0: *Fe, a1: *Fe, b1: *Fe, c: u64) void { | 224 | pub fn cSwap2(a0: *Fe, b0: *Fe, a1: *Fe, b1: *Fe, c: u64) void { |
| 172 | const mask: u64 = 0 -% c; | 225 | const mask: u64 = 0 -% c; |
| 173 | var x0 = a0.*; | 226 | var x0 = a0.*; |
| ... | @@ -211,6 +264,7 @@ pub const Fe = struct { | ... | @@ -211,6 +264,7 @@ pub const Fe = struct { |
| 211 | return .{ .limbs = rs }; | 264 | return .{ .limbs = rs }; |
| 212 | } | 265 | } |
| 213 | | 266 | |
| | 267 | /// Multiply two field elements |
| 214 | pub inline fn mul(a: Fe, b: Fe) Fe { | 268 | pub inline fn mul(a: Fe, b: Fe) Fe { |
| 215 | var ax: [5]u128 = undefined; | 269 | var ax: [5]u128 = undefined; |
| 216 | var bx: [5]u128 = undefined; | 270 | var bx: [5]u128 = undefined; |
| ... | @@ -262,14 +316,17 @@ pub const Fe = struct { | ... | @@ -262,14 +316,17 @@ pub const Fe = struct { |
| 262 | return _carry128(&r); | 316 | return _carry128(&r); |
| 263 | } | 317 | } |
| 264 | | 318 | |
| | 319 | /// Square a field element |
| 265 | pub inline fn sq(a: Fe) Fe { | 320 | pub inline fn sq(a: Fe) Fe { |
| 266 | return _sq(a, false); | 321 | return _sq(a, false); |
| 267 | } | 322 | } |
| 268 | | 323 | |
| | 324 | /// Square and double a field element |
| 269 | pub inline fn sq2(a: Fe) Fe { | 325 | pub inline fn sq2(a: Fe) Fe { |
| 270 | return _sq(a, true); | 326 | return _sq(a, true); |
| 271 | } | 327 | } |
| 272 | | 328 | |
| | 329 | /// Multiply a field element with a small (32-bit) integer |
| 273 | pub inline fn mul32(a: Fe, comptime n: u32) Fe { | 330 | pub inline fn mul32(a: Fe, comptime n: u32) Fe { |
| 274 | const sn = @intCast(u128, n); | 331 | const sn = @intCast(u128, n); |
| 275 | var fe: Fe = undefined; | 332 | var fe: Fe = undefined; |
| ... | @@ -284,6 +341,7 @@ pub const Fe = struct { | ... | @@ -284,6 +341,7 @@ pub const Fe = struct { |
| 284 | return fe; | 341 | return fe; |
| 285 | } | 342 | } |
| 286 | | 343 | |
| | 344 | /// Square a field element `n` times |
| 287 | inline fn sqn(a: Fe, comptime n: comptime_int) Fe { | 345 | inline fn sqn(a: Fe, comptime n: comptime_int) Fe { |
| 288 | var i: usize = 0; | 346 | var i: usize = 0; |
| 289 | var fe = a; | 347 | var fe = a; |
| ... | @@ -293,6 +351,7 @@ pub const Fe = struct { | ... | @@ -293,6 +351,7 @@ pub const Fe = struct { |
| 293 | return fe; | 351 | return fe; |
| 294 | } | 352 | } |
| 295 | | 353 | |
| | 354 | /// Compute the inverse of a field element |
| 296 | pub fn invert(a: Fe) Fe { | 355 | pub fn invert(a: Fe) Fe { |
| 297 | var t0 = a.sq(); | 356 | var t0 = a.sq(); |
| 298 | var t1 = t0.sqn(2).mul(a); | 357 | var t1 = t0.sqn(2).mul(a); |
| ... | @@ -306,6 +365,8 @@ pub const Fe = struct { | ... | @@ -306,6 +365,8 @@ pub const Fe = struct { |
| 306 | return t1.mul(t2.mul(t2.sqn(100)).sqn(50)).sqn(5).mul(t0); | 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 | pub fn pow2523(a: Fe) Fe { | 370 | pub fn pow2523(a: Fe) Fe { |
| 310 | var t0 = a.mul(a.sq()); | 371 | var t0 = a.mul(a.sq()); |
| 311 | var t1 = t0.mul(t0.sqn(2)).sq().mul(a); | 372 | var t1 = t0.mul(t0.sqn(2)).sq().mul(a); |
| ... | @@ -317,9 +378,47 @@ pub const Fe = struct { | ... | @@ -317,9 +378,47 @@ pub const Fe = struct { |
| 317 | return t1.sqn(120).mul(t1).sqn(10).mul(t0).sqn(2).mul(a); | 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 | pub fn abs(a: Fe) Fe { | 382 | pub fn abs(a: Fe) Fe { |
| 321 | var r = a; | 383 | var r = a; |
| 322 | r.cMov(a.neg(), @boolToInt(a.isNegative())); | 384 | r.cMov(a.neg(), @boolToInt(a.isNegative())); |
| 323 | return r; | 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 | }; |