| ... | @@ -482,6 +482,57 @@ pub const Scalar = struct { | ... | @@ -482,6 +482,57 @@ pub const Scalar = struct { |
| 482 | | 482 | |
| 483 | return Scalar{ .limbs = .{ z04, z14, z24, z34, z44 } }; | 483 | return Scalar{ .limbs = .{ z04, z14, z24, z34, z44 } }; |
| 484 | } | 484 | } |
| | 485 | |
| | 486 | /// Return x^2 (mod l) |
| | 487 | pub fn sq(x: Scalar) Scalar { |
| | 488 | return x.mul(x); |
| | 489 | } |
| | 490 | |
| | 491 | /// Square a scalar `n` times |
| | 492 | inline fn sqn(x: Scalar, comptime n: comptime_int) Scalar { |
| | 493 | var i: usize = 0; |
| | 494 | var t = x; |
| | 495 | while (i < n) : (i += 1) { |
| | 496 | t = t.sq(); |
| | 497 | } |
| | 498 | return t; |
| | 499 | } |
| | 500 | |
| | 501 | /// Square and multiply |
| | 502 | fn sqn_mul(x: Scalar, comptime n: comptime_int, y: Scalar) Scalar { |
| | 503 | return x.sqn(n).mul(y); |
| | 504 | } |
| | 505 | |
| | 506 | /// Return the inverse of a scalar (mod l), or 0 if x=0. |
| | 507 | pub fn invert(x: Scalar) Scalar { |
| | 508 | const _10 = x.sq(); |
| | 509 | const _11 = x.mul(_10); |
| | 510 | const _100 = x.mul(_11); |
| | 511 | const _1000 = _100.sq(); |
| | 512 | const _1010 = _10.mul(_1000); |
| | 513 | const _1011 = x.mul(_1010); |
| | 514 | const _10000 = _1000.sq(); |
| | 515 | const _10110 = _1011.sq(); |
| | 516 | const _100000 = _1010.mul(_10110); |
| | 517 | const _100110 = _10000.mul(_10110); |
| | 518 | const _1000000 = _100000.sq(); |
| | 519 | const _1010000 = _10000.mul(_1000000); |
| | 520 | const _1010011 = _11.mul(_1010000); |
| | 521 | const _1100011 = _10000.mul(_1010011); |
| | 522 | const _1100111 = _100.mul(_1100011); |
| | 523 | const _1101011 = _100.mul(_1100111); |
| | 524 | const _10010011 = _1000000.mul(_1010011); |
| | 525 | const _10010111 = _100.mul(_10010011); |
| | 526 | const _10111101 = _100110.mul(_10010111); |
| | 527 | const _11010011 = _10110.mul(_10111101); |
| | 528 | const _11100111 = _1010000.mul(_10010111); |
| | 529 | const _11101011 = _100.mul(_11100111); |
| | 530 | const _11110101 = _1010.mul(_11101011); |
| | 531 | return _1011.mul(_11110101).sqn_mul(126, _1010011).sqn_mul(9, _10).mul(_11110101) |
| | 532 | .sqn_mul(7, _1100111).sqn_mul(9, _11110101).sqn_mul(11, _10111101).sqn_mul(8, _11100111) |
| | 533 | .sqn_mul(9, _1101011).sqn_mul(6, _1011).sqn_mul(14, _10010011).sqn_mul(10, _1100011) |
| | 534 | .sqn_mul(9, _10010111).sqn_mul(10, _11110101).sqn_mul(8, _11010011).sqn_mul(8, _11101011); |
| | 535 | } |
| 485 | }; | 536 | }; |
| 486 | | 537 | |
| 487 | const ScalarDouble = struct { | 538 | const ScalarDouble = struct { |
| ... | @@ -781,3 +832,11 @@ test "mulAdd overflow check" { | ... | @@ -781,3 +832,11 @@ test "mulAdd overflow check" { |
| 781 | var buf: [128]u8 = undefined; | 832 | var buf: [128]u8 = undefined; |
| 782 | try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&x)}), "D14DF91389432C25AD60FF9791B9FD1D67BEF517D273ECCE3D9A307C1B419903"); | 833 | try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&x)}), "D14DF91389432C25AD60FF9791B9FD1D67BEF517D273ECCE3D9A307C1B419903"); |
| 783 | } | 834 | } |
| | 835 | |
| | 836 | test "scalar field inversion" { |
| | 837 | 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, 8 }; |
| | 838 | const x = Scalar.fromBytes(bytes); |
| | 839 | const inv = x.invert(); |
| | 840 | const recovered_x = inv.invert(); |
| | 841 | try std.testing.expectEqualSlices(u8, &bytes, &recovered_x.toBytes()); |
| | 842 | } |