authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2022-01-20 22:50:39+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-24 23:09:45+01:00
log4e5495e443f8978f1e0fd8ccb6670a95f014f3b1
tree15e13ab3feb22ff2b8c7055ae71c7453a3afa67f
parent40b3c9a5926f70db2dcf41971342a7e191d036af

std.crypto.25519.scalar: implement edwards25519 scalar field inversion

This operation is extremely useful for multiplicative blinding.

1 files changed, 59 insertions(+), 0 deletions(-)

lib/std/crypto/25519/scalar.zig+59
......@@ -482,6 +482,57 @@ pub const Scalar = struct {
482482
483483 return Scalar{ .limbs = .{ z04, z14, z24, z34, z44 } };
484484 }
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 }
485536};
486537
487538const ScalarDouble = struct {
......@@ -781,3 +832,11 @@ test "mulAdd overflow check" {
781832 var buf: [128]u8 = undefined;
782833 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&x)}), "D14DF91389432C25AD60FF9791B9FD1D67BEF517D273ECCE3D9A307C1B419903");
783834}
835
836test "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}