| author | |
| committer | |
| log | dd8f7b396c24d78168d9582364ab5b3b4606ccc5 |
| tree | f9ed891c7ac5d483463c4861ca7ad9881bb0c0de |
| parent | c483bf4f97504f3c9174ec9fd516d8995971023c |
Suggested by @kubkon7 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. |
| 4 | pub const Curve25519 = struct { | 4 | pub 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"); |
| 9 | 9 | ||
| 10 | x: Fe, | 10 | x: Fe, |
| 11 | 11 |
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. |
| 5 | pub const Edwards25519 = struct { | 5 | pub 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"); |
| 10 | 10 | ||
| 11 | x: Fe, | 11 | x: Fe, |
| 12 | y: Fe, | 12 | y: Fe, |
lib/std/crypto/25519/field.zig created+327| ... | @@ -0,0 +1,327 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const readIntLittle = std.mem.readIntLittle; | ||
| 3 | const writeIntLittle = std.mem.writeIntLittle; | ||
| 4 | |||
| 5 | pub 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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const readIntLittle = std.mem.readIntLittle; | ||
| 3 | const writeIntLittle = std.mem.writeIntLittle; | ||
| 4 | |||
| 5 | pub 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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const mem = std.mem; | ||
| 3 | |||
| 4 | inline 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 | |||
| 10 | const 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. | ||
| 118 | pub 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. | ||
| 137 | pub 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. | ||
| 142 | pub 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. | ||
| 148 | pub 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) | ||
| 154 | pub 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 | |||
| 158 | test "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 | |||
| 172 | test "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 | |||
| 177 | test "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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const mem = std.mem; | ||
| 3 | |||
| 4 | inline 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 | |||
| 10 | const 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. | ||
| 118 | pub 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. | ||
| 137 | pub 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. | ||
| 142 | pub 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. | ||
| 148 | pub 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) | ||
| 154 | pub 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 | |||
| 158 | test "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 | |||
| 172 | test "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 | |||
| 177 | test "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 | } | ||