authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2026-10-12 09:55:45+02:00
committergravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2026-10-12 09:55:45+02:00
log26450ba0f6c48a445beca483141605b9a2407d20
treedba8f6cb9e78b9c7ad82f39b41151537bfa01880
parentab3825e026d96d99527e701674aabe3b9bae810f
parentbfb20fe2163a54a96d962b6985e75d480648ab60

Merge pull request 'crypto.ff: specialize full-width Montgomery multiplication' (#37080) from jedisct1/zig:ff-fixes12 into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/37080

1 files changed, 22 insertions(+), 14 deletions(-)

lib/std/crypto/ff.zig+22-14
......@@ -857,23 +857,33 @@ pub fn Modulus(comptime max_bits: comptime_int) type {
857857 return out;
858858 }
859859
860 fn montgomeryLoop(self: Self, d: *Fe, x: Fe, y: Fe) u1 {
860 fn montgomeryLoop(self: *const Self, noalias d: *Fe, x: *const Fe, y: *const Fe) u1 {
861 if (self.limbs_count() == FeUint.max_limbs_count) {
862 return montgomeryLoopWithWidth(true, self, d, x, y);
863 }
864 return montgomeryLoopWithWidth(false, self, d, x, y);
865 }
866
867 fn montgomeryLoopWithWidth(comptime full_width: bool, self: *const Self, noalias d: *Fe, x: *const Fe, y: *const Fe) u1 {
868 assert(d != x and d != y);
861869 assert(d.limbs_count() == x.limbs_count());
862870 assert(d.limbs_count() == y.limbs_count());
863871 assert(d.limbs_count() == self.limbs_count());
872 assert(self.v.isOdd());
864873
865 const a_limbs = x.v.limbsConst();
866 const b_limbs = y.v.limbsConst();
867 const d_limbs = d.v.limbs();
868 const m_limbs = self.v.limbsConst();
874 const n = if (full_width) FeUint.max_limbs_count else self.limbs_count();
875 const a_limbs = x.v.limbs_buffer[0..n];
876 const b_limbs = y.v.limbs_buffer[0..n];
877 const d_limbs = d.v.limbs_buffer[0..n];
878 const m_limbs = self.v.limbs_buffer[0..n];
869879
870880 var overflow: u1 = 0;
871 for (0..self.limbs_count()) |i| {
881 for (0..n) |i| {
872882 var carry: Limb = 0;
873883
874884 var wide = ct.mulWide(a_limbs[i], b_limbs[0]);
875885 var z_lo = @addWithOverflow(d_limbs[0], wide.lo);
876 const f = @as(TLimb, @truncate(z_lo[0] *% self.m0inv));
886 const f: TLimb = @truncate(z_lo[0] *% self.m0inv);
877887 var z_hi = wide.hi +% z_lo[1];
878888 wide = ct.mulWide(f, m_limbs[0]);
879889 z_lo = @addWithOverflow(z_lo[0], wide.lo);
......@@ -881,7 +891,7 @@ pub fn Modulus(comptime max_bits: comptime_int) type {
881891 z_hi +%= wide.hi;
882892 carry = (z_hi << 1) | (z_lo[0] >> t_bits);
883893
884 for (1..self.limbs_count()) |j| {
894 for (1..n) |j| {
885895 wide = ct.mulWide(a_limbs[i], b_limbs[j]);
886896 z_lo = @addWithOverflow(d_limbs[j], wide.lo);
887897 z_hi = wide.hi +% z_lo[1];
......@@ -897,18 +907,17 @@ pub fn Modulus(comptime max_bits: comptime_int) type {
897907 carry = (z_hi << 1) | (z_lo[0] >> t_bits);
898908 }
899909 const z = overflow + carry;
900 d_limbs[self.limbs_count() - 1] = @as(TLimb, @truncate(z));
901 overflow = @as(u1, @truncate(z >> t_bits));
910 d_limbs[n - 1] = @as(TLimb, @truncate(z));
911 overflow = @truncate(z >> t_bits);
902912 }
903913 return overflow;
904914 }
905915
906 // Montgomery multiplication.
907916 fn montgomeryMul(self: Self, x: Fe, y: Fe) Fe {
908917 var d = self.zero;
909918 assert(x.limbs_count() == self.limbs_count());
910919 assert(y.limbs_count() == self.limbs_count());
911 const overflow = self.montgomeryLoop(&d, x, y);
920 const overflow = self.montgomeryLoop(&d, &x, &y);
912921 const underflow = 1 -% @intFromBool(ct.limbsCmpGeq(d.v, self.v));
913922 const need_sub = ct.eql(overflow, underflow);
914923 _ = d.v.conditionalSubWithOverflow(need_sub, self.v);
......@@ -916,11 +925,10 @@ pub fn Modulus(comptime max_bits: comptime_int) type {
916925 return d;
917926 }
918927
919 // Montgomery squaring.
920928 fn montgomerySq(self: Self, x: Fe) Fe {
921929 var d = self.zero;
922930 assert(x.limbs_count() == self.limbs_count());
923 const overflow = self.montgomeryLoop(&d, x, x);
931 const overflow = self.montgomeryLoop(&d, &x, &x);
924932 const underflow = 1 -% @intFromBool(ct.limbsCmpGeq(d.v, self.v));
925933 const need_sub = ct.eql(overflow, underflow);
926934 _ = d.v.conditionalSubWithOverflow(need_sub, self.v);