| ... | ... | @@ -656,6 +656,101 @@ pub fn Modulus(comptime max_bits: comptime_int) type { |
| 656 | 656 | return d; |
| 657 | 657 | } |
| 658 | 658 | |
| 659 | // Returns x^e (mod m), with the exponent provided as a byte string. |
| 660 | // `public` must be set to `false` if the exponent it secret. |
| 661 | fn powWithEncodedExponentInternal(self: Self, x: Fe, e: []const u8, endian: builtin.Endian, comptime public: bool) NullExponentError!Fe { |
| 662 | var acc: u8 = 0; |
| 663 | for (e) |b| acc |= b; |
| 664 | if (acc == 0) return error.NullExponent; |
| 665 | |
| 666 | var out = self.one(); |
| 667 | self.toMontgomery(&out) catch unreachable; |
| 668 | |
| 669 | if (public and e.len < 3 or (e.len == 3 and e[if (endian == .Big) 0 else 2] <= 0b1111)) { |
| 670 | // Do not use a precomputation table for short, public exponents |
| 671 | var x_m = x; |
| 672 | if (x.montgomery == false) { |
| 673 | self.toMontgomery(&x_m) catch unreachable; |
| 674 | } |
| 675 | var s = switch (endian) { |
| 676 | .Big => 0, |
| 677 | .Little => e.len - 1, |
| 678 | }; |
| 679 | while (true) { |
| 680 | const b = e[s]; |
| 681 | var j: u3 = 7; |
| 682 | while (true) : (j -= 1) { |
| 683 | out = self.montgomerySq(out); |
| 684 | const k: u1 = @truncate(b >> j); |
| 685 | if (k != 0) { |
| 686 | const t = self.montgomeryMul(out, x_m); |
| 687 | @memcpy(out.v.limbs.slice(), t.v.limbs.constSlice()); |
| 688 | } |
| 689 | if (j == 0) break; |
| 690 | } |
| 691 | switch (endian) { |
| 692 | .Big => { |
| 693 | s += 1; |
| 694 | if (s == e.len) break; |
| 695 | }, |
| 696 | .Little => { |
| 697 | if (s == 0) break; |
| 698 | s -= 1; |
| 699 | }, |
| 700 | } |
| 701 | } |
| 702 | } else { |
| 703 | // Use a precomputation table for large exponents |
| 704 | var pc = [1]Fe{x} ++ [_]Fe{self.zero} ** 14; |
| 705 | if (x.montgomery == false) { |
| 706 | self.toMontgomery(&pc[0]) catch unreachable; |
| 707 | } |
| 708 | for (1..pc.len) |i| { |
| 709 | pc[i] = self.montgomeryMul(pc[i - 1], pc[0]); |
| 710 | } |
| 711 | var t0 = self.zero; |
| 712 | var s = switch (endian) { |
| 713 | .Big => 0, |
| 714 | .Little => e.len - 1, |
| 715 | }; |
| 716 | while (true) { |
| 717 | const b = e[s]; |
| 718 | for ([_]u3{ 4, 0 }) |j| { |
| 719 | for (0..4) |_| { |
| 720 | out = self.montgomerySq(out); |
| 721 | } |
| 722 | const k = (b >> j) & 0b1111; |
| 723 | if (public or std.options.side_channels_mitigations == .none) { |
| 724 | if (k == 0) continue; |
| 725 | t0 = pc[k - 1]; |
| 726 | } else { |
| 727 | for (pc, 0..) |t, i| { |
| 728 | t0.v.cmov(ct.eql(k, @as(u8, @truncate(i + 1))), t.v); |
| 729 | } |
| 730 | } |
| 731 | const t1 = self.montgomeryMul(out, t0); |
| 732 | if (public) { |
| 733 | @memcpy(out.v.limbs.slice(), t1.v.limbs.constSlice()); |
| 734 | } else { |
| 735 | out.v.cmov(!ct.eql(k, 0), t1.v); |
| 736 | } |
| 737 | } |
| 738 | switch (endian) { |
| 739 | .Big => { |
| 740 | s += 1; |
| 741 | if (s == e.len) break; |
| 742 | }, |
| 743 | .Little => { |
| 744 | if (s == 0) break; |
| 745 | s -= 1; |
| 746 | }, |
| 747 | } |
| 748 | } |
| 749 | } |
| 750 | self.fromMontgomery(&out) catch unreachable; |
| 751 | return out; |
| 752 | } |
| 753 | |
| 659 | 754 | /// Multiplies two field elements. |
| 660 | 755 | pub fn mul(self: Self, x: Fe, y: Fe) Fe { |
| 661 | 756 | if (x.montgomery != y.montgomery) { |
| ... | ... | @@ -698,62 +793,25 @@ pub fn Modulus(comptime max_bits: comptime_int) type { |
| 698 | 793 | e_normalized.toBytes(buf, .Little) catch unreachable; |
| 699 | 794 | const leading = @clz(e_normalized.v.limbs.get(e_normalized.v.limbs_count() - carry_bits)); |
| 700 | 795 | buf = buf[0 .. buf.len - leading / 8]; |
| 701 | | return self.powWithEncodedExponent(x, buf, .Little); |
| 796 | return self.powWithEncodedPublicExponent(x, buf, .Little); |
| 702 | 797 | } |
| 703 | 798 | |
| 704 | | /// Returns x^e (mod m), assuming that the exponent is public, and provided as a byte string. |
| 799 | /// Returns x^e (mod m), with the exponent provided as a byte string. |
| 705 | 800 | /// Exponents are usually small, so this function is faster than `powPublic` as a field element |
| 706 | 801 | /// doesn't have to be created if a serialized representation is already available. |
| 802 | /// |
| 803 | /// If the exponent is public, `powWithEncodedPublicExponent()` can be used instead for a slight speedup. |
| 707 | 804 | pub fn powWithEncodedExponent(self: Self, x: Fe, e: []const u8, endian: builtin.Endian) NullExponentError!Fe { |
| 708 | | var acc: u8 = 0; |
| 709 | | for (e) |b| acc |= b; |
| 710 | | if (acc == 0) return error.NullExponent; |
| 805 | return self.powWithEncodedExponentInternal(x, e, endian, false); |
| 806 | } |
| 711 | 807 | |
| 712 | | var pc = [1]Fe{x} ++ [_]Fe{self.zero} ** 14; |
| 713 | | if (x.montgomery == false) { |
| 714 | | self.toMontgomery(&pc[0]) catch unreachable; |
| 715 | | } |
| 716 | | for (1..pc.len) |i| { |
| 717 | | pc[i] = self.montgomeryMul(pc[i - 1], pc[0]); |
| 718 | | } |
| 719 | | var out = self.one(); |
| 720 | | self.toMontgomery(&out) catch unreachable; |
| 721 | | var t0 = self.zero; |
| 722 | | var s = switch (endian) { |
| 723 | | .Big => 0, |
| 724 | | .Little => e.len - 1, |
| 725 | | }; |
| 726 | | while (true) { |
| 727 | | const b = e[s]; |
| 728 | | for ([_]u3{ 4, 0 }) |j| { |
| 729 | | for (0..4) |_| { |
| 730 | | out = self.montgomerySq(out); |
| 731 | | } |
| 732 | | const k = (b >> j) & 0b1111; |
| 733 | | if (std.options.side_channels_mitigations == .none) { |
| 734 | | if (k == 0) continue; |
| 735 | | t0 = pc[k - 1]; |
| 736 | | } else { |
| 737 | | for (pc, 0..) |t, i| { |
| 738 | | t0.v.cmov(ct.eql(k, @as(u8, @truncate(i + 1))), t.v); |
| 739 | | } |
| 740 | | } |
| 741 | | const t1 = self.montgomeryMul(out, t0); |
| 742 | | out.v.cmov(!ct.eql(k, 0), t1.v); |
| 743 | | } |
| 744 | | switch (endian) { |
| 745 | | .Big => { |
| 746 | | s += 1; |
| 747 | | if (s == e.len) break; |
| 748 | | }, |
| 749 | | .Little => { |
| 750 | | if (s == 0) break; |
| 751 | | s -= 1; |
| 752 | | }, |
| 753 | | } |
| 754 | | } |
| 755 | | self.fromMontgomery(&out) catch unreachable; |
| 756 | | return out; |
| 808 | /// Returns x^e (mod m), the exponent being public and provided as a byte string. |
| 809 | /// Exponents are usually small, so this function is faster than `powPublic` as a field element |
| 810 | /// doesn't have to be created if a serialized representation is already available. |
| 811 | /// |
| 812 | /// If the exponent is secret, `powWithEncodedExponent` must be used instead. |
| 813 | pub fn powWithEncodedPublicExponent(self: Self, x: Fe, e: []const u8, endian: builtin.Endian) NullExponentError!Fe { |
| 814 | return self.powWithEncodedExponentInternal(x, e, endian, true); |
| 757 | 815 | } |
| 758 | 816 | }; |
| 759 | 817 | } |