| ... | ... | @@ -49,21 +49,26 @@ pub const P256 = struct { |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | 51 | /// Create a point from affine coordinates after checking that they match the curve equation. |
| 52 | | pub fn fromAffineCoordinates(x: Fe, y: Fe) EncodingError!P256 { |
| 52 | pub fn fromAffineCoordinates(p: AffineCoordinates) EncodingError!P256 { |
| 53 | const x = p.x; |
| 54 | const y = p.y; |
| 53 | 55 | const x3AxB = x.sq().mul(x).sub(x).sub(x).sub(x).add(B); |
| 54 | 56 | const yy = y.sq(); |
| 55 | | if (!x3AxB.equivalent(yy)) { |
| 57 | const on_curve = @boolToInt(x3AxB.equivalent(yy)); |
| 58 | const is_identity = @boolToInt(x.equivalent(AffineCoordinates.identityElement.x)) & @boolToInt(y.equivalent(AffineCoordinates.identityElement.y)); |
| 59 | if ((on_curve | is_identity) == 0) { |
| 56 | 60 | return error.InvalidEncoding; |
| 57 | 61 | } |
| 58 | | const p: P256 = .{ .x = x, .y = y, .z = Fe.one }; |
| 59 | | return p; |
| 62 | var ret = P256{ .x = x, .y = y, .z = Fe.one }; |
| 63 | ret.z.cMov(P256.identityElement.z, is_identity); |
| 64 | return ret; |
| 60 | 65 | } |
| 61 | 66 | |
| 62 | 67 | /// Create a point from serialized affine coordinates. |
| 63 | 68 | pub fn fromSerializedAffineCoordinates(xs: [32]u8, ys: [32]u8, endian: builtin.Endian) (NonCanonicalError || EncodingError)!P256 { |
| 64 | 69 | const x = try Fe.fromBytes(xs, endian); |
| 65 | 70 | const y = try Fe.fromBytes(ys, endian); |
| 66 | | return fromAffineCoordinates(x, y); |
| 71 | return fromAffineCoordinates(.{ .x = x, .y = y }); |
| 67 | 72 | } |
| 68 | 73 | |
| 69 | 74 | /// Recover the Y coordinate from the X coordinate. |
| ... | ... | @@ -96,7 +101,7 @@ pub const P256 = struct { |
| 96 | 101 | if (encoded.len != 64) return error.InvalidEncoding; |
| 97 | 102 | const x = try Fe.fromBytes(encoded[0..32].*, .Big); |
| 98 | 103 | const y = try Fe.fromBytes(encoded[32..64].*, .Big); |
| 99 | | return P256.fromAffineCoordinates(x, y); |
| 104 | return P256.fromAffineCoordinates(.{ .x = x, .y = y }); |
| 100 | 105 | }, |
| 101 | 106 | else => return error.InvalidEncoding, |
| 102 | 107 | } |
| ... | ... | @@ -177,7 +182,7 @@ pub const P256 = struct { |
| 177 | 182 | |
| 178 | 183 | /// Add P256 points, the second being specified using affine coordinates. |
| 179 | 184 | // Algorithm 5 from https://eprint.iacr.org/2015/1060.pdf |
| 180 | | pub fn addMixed(p: P256, q: struct { x: Fe, y: Fe }) P256 { |
| 185 | pub fn addMixed(p: P256, q: AffineCoordinates) P256 { |
| 181 | 186 | var t0 = p.x.mul(q.x); |
| 182 | 187 | var t1 = p.y.mul(q.y); |
| 183 | 188 | var t3 = q.x.add(q.y); |
| ... | ... | @@ -194,9 +199,9 @@ pub const P256 = struct { |
| 194 | 199 | Z3 = X3.dbl(); |
| 195 | 200 | X3 = X3.add(Z3); |
| 196 | 201 | Z3 = t1.sub(X3); |
| 197 | | X3 = t1.dbl(); |
| 202 | X3 = t1.add(X3); |
| 198 | 203 | Y3 = B.mul(Y3); |
| 199 | | t1 = p.z.add(p.z); |
| 204 | t1 = p.z.dbl(); |
| 200 | 205 | var t2 = t1.add(p.z); |
| 201 | 206 | Y3 = Y3.sub(t2); |
| 202 | 207 | Y3 = Y3.sub(t0); |
| ... | ... | @@ -214,14 +219,16 @@ pub const P256 = struct { |
| 214 | 219 | Z3 = t4.mul(Z3); |
| 215 | 220 | t1 = t3.mul(t0); |
| 216 | 221 | Z3 = Z3.add(t1); |
| 217 | | return .{ |
| 222 | var ret = P256{ |
| 218 | 223 | .x = X3, |
| 219 | 224 | .y = Y3, |
| 220 | 225 | .z = Z3, |
| 221 | 226 | }; |
| 227 | ret.cMov(p, @boolToInt(q.x.isZero())); |
| 228 | return ret; |
| 222 | 229 | } |
| 223 | 230 | |
| 224 | | // Add P256 points. |
| 231 | /// Add P256 points. |
| 225 | 232 | // Algorithm 4 from https://eprint.iacr.org/2015/1060.pdf |
| 226 | 233 | pub fn add(p: P256, q: P256) P256 { |
| 227 | 234 | var t0 = p.x.mul(q.x); |
| ... | ... | @@ -274,18 +281,19 @@ pub const P256 = struct { |
| 274 | 281 | }; |
| 275 | 282 | } |
| 276 | 283 | |
| 277 | | // Subtract P256 points. |
| 284 | /// Subtract P256 points. |
| 278 | 285 | pub fn sub(p: P256, q: P256) P256 { |
| 279 | 286 | return p.add(q.neg()); |
| 280 | 287 | } |
| 281 | 288 | |
| 282 | 289 | /// Return affine coordinates. |
| 283 | | pub fn affineCoordinates(p: P256) struct { x: Fe, y: Fe } { |
| 290 | pub fn affineCoordinates(p: P256) AffineCoordinates { |
| 284 | 291 | const zinv = p.z.invert(); |
| 285 | | const ret = .{ |
| 292 | var ret = AffineCoordinates{ |
| 286 | 293 | .x = p.x.mul(zinv), |
| 287 | 294 | .y = p.y.mul(zinv), |
| 288 | 295 | }; |
| 296 | ret.cMov(AffineCoordinates.identityElement, @boolToInt(p.x.isZero())); |
| 289 | 297 | return ret; |
| 290 | 298 | } |
| 291 | 299 | |
| ... | ... | @@ -382,11 +390,21 @@ pub const P256 = struct { |
| 382 | 390 | return pc; |
| 383 | 391 | } |
| 384 | 392 | |
| 393 | const basePointPc = comptime pc: { |
| 394 | @setEvalBranchQuota(50000); |
| 395 | break :pc precompute(P256.basePoint, 15); |
| 396 | }; |
| 397 | |
| 398 | const basePointPc8 = comptime pc: { |
| 399 | @setEvalBranchQuota(50000); |
| 400 | break :pc precompute(P256.basePoint, 8); |
| 401 | }; |
| 402 | |
| 385 | 403 | /// Multiply an elliptic curve point by a scalar. |
| 386 | 404 | /// Return error.IdentityElement if the result is the identity element. |
| 387 | 405 | pub fn mul(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 { |
| 388 | 406 | const s = if (endian == .Little) s_ else Fe.orderSwap(s_); |
| 389 | | const pc = if (p.is_base) precompute(P256.basePoint, 15) else pc: { |
| 407 | const pc = if (p.is_base) basePointPc else pc: { |
| 390 | 408 | try p.rejectIdentity(); |
| 391 | 409 | const xpc = precompute(p, 15); |
| 392 | 410 | break :pc xpc; |
| ... | ... | @@ -398,7 +416,7 @@ pub const P256 = struct { |
| 398 | 416 | /// This can be used for signature verification. |
| 399 | 417 | pub fn mulPublic(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 { |
| 400 | 418 | const s = if (endian == .Little) s_ else Fe.orderSwap(s_); |
| 401 | | const pc = if (p.is_base) precompute(P256.basePoint, 8) else pc: { |
| 419 | const pc = if (p.is_base) basePointPc8 else pc: { |
| 402 | 420 | try p.rejectIdentity(); |
| 403 | 421 | const xpc = precompute(p, 8); |
| 404 | 422 | break :pc xpc; |
| ... | ... | @@ -407,6 +425,20 @@ pub const P256 = struct { |
| 407 | 425 | } |
| 408 | 426 | }; |
| 409 | 427 | |
| 428 | /// A point in affine coordinates. |
| 429 | pub const AffineCoordinates = struct { |
| 430 | x: P256.Fe, |
| 431 | y: P256.Fe, |
| 432 | |
| 433 | /// Identity element in affine coordinates. |
| 434 | pub const identityElement = AffineCoordinates{ .x = P256.identityElement.x, .y = P256.identityElement.y }; |
| 435 | |
| 436 | fn cMov(p: *AffineCoordinates, a: AffineCoordinates, c: u1) void { |
| 437 | p.x.cMov(a.x, c); |
| 438 | p.y.cMov(a.y, c); |
| 439 | } |
| 440 | }; |
| 441 | |
| 410 | 442 | test "p256" { |
| 411 | 443 | _ = @import("tests.zig"); |
| 412 | 444 | } |