| ... | @@ -15,6 +15,8 @@ const maxInt = std.math.maxInt; | ... | @@ -15,6 +15,8 @@ const maxInt = std.math.maxInt; |
| 15 | const minInt = std.math.minInt; | 15 | const minInt = std.math.minInt; |
| 16 | const assert = std.debug.assert; | 16 | const assert = std.debug.assert; |
| 17 | | 17 | |
| | 18 | const debug_safety = false; |
| | 19 | |
| 18 | /// Returns the number of limbs needed to store `scalar`, which must be a | 20 | /// Returns the number of limbs needed to store `scalar`, which must be a |
| 19 | /// primitive integer value. | 21 | /// primitive integer value. |
| 20 | pub fn calcLimbLen(scalar: anytype) usize { | 22 | pub fn calcLimbLen(scalar: anytype) usize { |
| ... | @@ -57,7 +59,7 @@ pub fn calcSetStringLimbCount(base: u8, string_len: usize) usize { | ... | @@ -57,7 +59,7 @@ pub fn calcSetStringLimbCount(base: u8, string_len: usize) usize { |
| 57 | | 59 | |
| 58 | /// a + b * c + *carry, sets carry to the overflow bits | 60 | /// a + b * c + *carry, sets carry to the overflow bits |
| 59 | pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb { | 61 | pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb { |
| 60 | @setRuntimeSafety(false); | 62 | @setRuntimeSafety(debug_safety); |
| 61 | var r1: Limb = undefined; | 63 | var r1: Limb = undefined; |
| 62 | | 64 | |
| 63 | // r1 = a + *carry | 65 | // r1 = a + *carry |
| ... | @@ -1529,8 +1531,7 @@ pub const Managed = struct { | ... | @@ -1529,8 +1531,7 @@ pub const Managed = struct { |
| 1529 | /// self's allocator is used for temporary storage to boost multiplication performance. | 1531 | /// self's allocator is used for temporary storage to boost multiplication performance. |
| 1530 | pub fn setString(self: *Managed, base: u8, value: []const u8) !void { | 1532 | pub fn setString(self: *Managed, base: u8, value: []const u8) !void { |
| 1531 | if (base < 2 or base > 16) return error.InvalidBase; | 1533 | if (base < 2 or base > 16) return error.InvalidBase; |
| 1532 | const den = (@sizeOf(Limb) * 8 / base); | 1534 | try self.ensureCapacity(calcSetStringLimbCount(base, value.len)); |
| 1533 | try self.ensureCapacity((value.len + (den - 1)) / den); | | |
| 1534 | const limbs_buffer = try self.allocator.alloc(Limb, calcSetStringLimbsBufferLen(base, value.len)); | 1535 | const limbs_buffer = try self.allocator.alloc(Limb, calcSetStringLimbsBufferLen(base, value.len)); |
| 1535 | defer self.allocator.free(limbs_buffer); | 1536 | defer self.allocator.free(limbs_buffer); |
| 1536 | var m = self.toMutable(); | 1537 | var m = self.toMutable(); |
| ... | @@ -1646,17 +1647,19 @@ pub const Managed = struct { | ... | @@ -1646,17 +1647,19 @@ pub const Managed = struct { |
| 1646 | /// rma = a * b | 1647 | /// rma = a * b |
| 1647 | /// | 1648 | /// |
| 1648 | /// rma, a and b may be aliases. However, it is more efficient if rma does not alias a or b. | 1649 | /// rma, a and b may be aliases. However, it is more efficient if rma does not alias a or b. |
| | 1650 | /// If rma aliases a or b, then caller must call `rma.ensureMulCapacity` prior to calling `mul`. |
| 1649 | /// | 1651 | /// |
| 1650 | /// Returns an error if memory could not be allocated. | 1652 | /// Returns an error if memory could not be allocated. |
| 1651 | /// | 1653 | /// |
| 1652 | /// rma's allocator is used for temporary storage to speed up the multiplication. | 1654 | /// rma's allocator is used for temporary storage to speed up the multiplication. |
| 1653 | pub fn mul(rma: *Managed, a: Const, b: Const) !void { | 1655 | pub fn mul(rma: *Managed, a: Const, b: Const) !void { |
| 1654 | try rma.ensureCapacity(a.limbs.len + b.limbs.len + 1); | | |
| 1655 | var alias_count: usize = 0; | 1656 | var alias_count: usize = 0; |
| 1656 | if (rma.limbs.ptr == a.limbs.ptr) | 1657 | if (rma.limbs.ptr == a.limbs.ptr) |
| 1657 | alias_count += 1; | 1658 | alias_count += 1; |
| 1658 | if (rma.limbs.ptr == b.limbs.ptr) | 1659 | if (rma.limbs.ptr == b.limbs.ptr) |
| 1659 | alias_count += 1; | 1660 | alias_count += 1; |
| | 1661 | assert(alias_count == 0 or rma.limbs.len >= a.limbs.len + b.limbs.len + 1); |
| | 1662 | try rma.ensureMulCapacity(a, b); |
| 1660 | var m = rma.toMutable(); | 1663 | var m = rma.toMutable(); |
| 1661 | if (alias_count == 0) { | 1664 | if (alias_count == 0) { |
| 1662 | m.mulNoAlias(a, b, rma.allocator); | 1665 | m.mulNoAlias(a, b, rma.allocator); |
| ... | @@ -1669,6 +1672,10 @@ pub const Managed = struct { | ... | @@ -1669,6 +1672,10 @@ pub const Managed = struct { |
| 1669 | rma.setMetadata(m.positive, m.len); | 1672 | rma.setMetadata(m.positive, m.len); |
| 1670 | } | 1673 | } |
| 1671 | | 1674 | |
| | 1675 | pub fn ensureMulCapacity(rma: *Managed, a: Const, b: Const) !void { |
| | 1676 | try rma.ensureCapacity(a.limbs.len + b.limbs.len + 1); |
| | 1677 | } |
| | 1678 | |
| 1672 | /// q = a / b (rem r) | 1679 | /// q = a / b (rem r) |
| 1673 | /// | 1680 | /// |
| 1674 | /// a / b are floored (rounded towards 0). | 1681 | /// a / b are floored (rounded towards 0). |
| ... | @@ -1773,7 +1780,7 @@ pub const Managed = struct { | ... | @@ -1773,7 +1780,7 @@ pub const Managed = struct { |
| 1773 | /// | 1780 | /// |
| 1774 | /// r MUST NOT alias any of a or b. | 1781 | /// r MUST NOT alias any of a or b. |
| 1775 | fn llmulacc(opt_allocator: ?*Allocator, r: []Limb, a: []const Limb, b: []const Limb) void { | 1782 | fn llmulacc(opt_allocator: ?*Allocator, r: []Limb, a: []const Limb, b: []const Limb) void { |
| 1776 | @setRuntimeSafety(false); | 1783 | @setRuntimeSafety(debug_safety); |
| 1777 | | 1784 | |
| 1778 | const a_norm = a[0..llnormalize(a)]; | 1785 | const a_norm = a[0..llnormalize(a)]; |
| 1779 | const b_norm = b[0..llnormalize(b)]; | 1786 | const b_norm = b[0..llnormalize(b)]; |
| ... | @@ -1806,7 +1813,7 @@ fn llmulacc(opt_allocator: ?*Allocator, r: []Limb, a: []const Limb, b: []const L | ... | @@ -1806,7 +1813,7 @@ fn llmulacc(opt_allocator: ?*Allocator, r: []Limb, a: []const Limb, b: []const L |
| 1806 | /// | 1813 | /// |
| 1807 | /// r MUST NOT alias any of a or b. | 1814 | /// r MUST NOT alias any of a or b. |
| 1808 | fn llmulacc_karatsuba(allocator: *Allocator, r: []Limb, x: []const Limb, y: []const Limb) error{OutOfMemory}!void { | 1815 | fn llmulacc_karatsuba(allocator: *Allocator, r: []Limb, x: []const Limb, y: []const Limb) error{OutOfMemory}!void { |
| 1809 | @setRuntimeSafety(false); | 1816 | @setRuntimeSafety(debug_safety); |
| 1810 | | 1817 | |
| 1811 | assert(r.len >= x.len + y.len + 1); | 1818 | assert(r.len >= x.len + y.len + 1); |
| 1812 | | 1819 | |
| ... | @@ -1873,7 +1880,7 @@ fn llmulacc_karatsuba(allocator: *Allocator, r: []Limb, x: []const Limb, y: []co | ... | @@ -1873,7 +1880,7 @@ fn llmulacc_karatsuba(allocator: *Allocator, r: []Limb, x: []const Limb, y: []co |
| 1873 | | 1880 | |
| 1874 | // r = r + a | 1881 | // r = r + a |
| 1875 | fn llaccum(r: []Limb, a: []const Limb) Limb { | 1882 | fn llaccum(r: []Limb, a: []const Limb) Limb { |
| 1876 | @setRuntimeSafety(false); | 1883 | @setRuntimeSafety(debug_safety); |
| 1877 | assert(r.len != 0 and a.len != 0); | 1884 | assert(r.len != 0 and a.len != 0); |
| 1878 | assert(r.len >= a.len); | 1885 | assert(r.len >= a.len); |
| 1879 | | 1886 | |
| ... | @@ -1896,7 +1903,7 @@ fn llaccum(r: []Limb, a: []const Limb) Limb { | ... | @@ -1896,7 +1903,7 @@ fn llaccum(r: []Limb, a: []const Limb) Limb { |
| 1896 | | 1903 | |
| 1897 | /// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively for limbs. | 1904 | /// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively for limbs. |
| 1898 | pub fn llcmp(a: []const Limb, b: []const Limb) i8 { | 1905 | pub fn llcmp(a: []const Limb, b: []const Limb) i8 { |
| 1899 | @setRuntimeSafety(false); | 1906 | @setRuntimeSafety(debug_safety); |
| 1900 | const a_len = llnormalize(a); | 1907 | const a_len = llnormalize(a); |
| 1901 | const b_len = llnormalize(b); | 1908 | const b_len = llnormalize(b); |
| 1902 | if (a_len < b_len) { | 1909 | if (a_len < b_len) { |
| ... | @@ -1923,12 +1930,12 @@ pub fn llcmp(a: []const Limb, b: []const Limb) i8 { | ... | @@ -1923,12 +1930,12 @@ pub fn llcmp(a: []const Limb, b: []const Limb) i8 { |
| 1923 | } | 1930 | } |
| 1924 | | 1931 | |
| 1925 | fn llmulDigit(acc: []Limb, y: []const Limb, xi: Limb) void { | 1932 | fn llmulDigit(acc: []Limb, y: []const Limb, xi: Limb) void { |
| 1926 | @setRuntimeSafety(false); | 1933 | @setRuntimeSafety(debug_safety); |
| 1927 | if (xi == 0) { | 1934 | if (xi == 0) { |
| 1928 | return; | 1935 | return; |
| 1929 | } | 1936 | } |
| 1930 | | 1937 | |
| 1931 | var carry: usize = 0; | 1938 | var carry: Limb = 0; |
| 1932 | var a_lo = acc[0..y.len]; | 1939 | var a_lo = acc[0..y.len]; |
| 1933 | var a_hi = acc[y.len..]; | 1940 | var a_hi = acc[y.len..]; |
| 1934 | | 1941 | |
| ... | @@ -1945,7 +1952,7 @@ fn llmulDigit(acc: []Limb, y: []const Limb, xi: Limb) void { | ... | @@ -1945,7 +1952,7 @@ fn llmulDigit(acc: []Limb, y: []const Limb, xi: Limb) void { |
| 1945 | | 1952 | |
| 1946 | /// returns the min length the limb could be. | 1953 | /// returns the min length the limb could be. |
| 1947 | fn llnormalize(a: []const Limb) usize { | 1954 | fn llnormalize(a: []const Limb) usize { |
| 1948 | @setRuntimeSafety(false); | 1955 | @setRuntimeSafety(debug_safety); |
| 1949 | var j = a.len; | 1956 | var j = a.len; |
| 1950 | while (j > 0) : (j -= 1) { | 1957 | while (j > 0) : (j -= 1) { |
| 1951 | if (a[j - 1] != 0) { | 1958 | if (a[j - 1] != 0) { |
| ... | @@ -1959,7 +1966,7 @@ fn llnormalize(a: []const Limb) usize { | ... | @@ -1959,7 +1966,7 @@ fn llnormalize(a: []const Limb) usize { |
| 1959 | | 1966 | |
| 1960 | /// Knuth 4.3.1, Algorithm S. | 1967 | /// Knuth 4.3.1, Algorithm S. |
| 1961 | fn llsub(r: []Limb, a: []const Limb, b: []const Limb) void { | 1968 | fn llsub(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 1962 | @setRuntimeSafety(false); | 1969 | @setRuntimeSafety(debug_safety); |
| 1963 | assert(a.len != 0 and b.len != 0); | 1970 | assert(a.len != 0 and b.len != 0); |
| 1964 | assert(a.len > b.len or (a.len == b.len and a[a.len - 1] >= b[b.len - 1])); | 1971 | assert(a.len > b.len or (a.len == b.len and a[a.len - 1] >= b[b.len - 1])); |
| 1965 | assert(r.len >= a.len); | 1972 | assert(r.len >= a.len); |
| ... | @@ -1983,7 +1990,7 @@ fn llsub(r: []Limb, a: []const Limb, b: []const Limb) void { | ... | @@ -1983,7 +1990,7 @@ fn llsub(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 1983 | | 1990 | |
| 1984 | /// Knuth 4.3.1, Algorithm A. | 1991 | /// Knuth 4.3.1, Algorithm A. |
| 1985 | fn lladd(r: []Limb, a: []const Limb, b: []const Limb) void { | 1992 | fn lladd(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 1986 | @setRuntimeSafety(false); | 1993 | @setRuntimeSafety(debug_safety); |
| 1987 | assert(a.len != 0 and b.len != 0); | 1994 | assert(a.len != 0 and b.len != 0); |
| 1988 | assert(a.len >= b.len); | 1995 | assert(a.len >= b.len); |
| 1989 | assert(r.len >= a.len + 1); | 1996 | assert(r.len >= a.len + 1); |
| ... | @@ -2007,7 +2014,7 @@ fn lladd(r: []Limb, a: []const Limb, b: []const Limb) void { | ... | @@ -2007,7 +2014,7 @@ fn lladd(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 2007 | | 2014 | |
| 2008 | /// Knuth 4.3.1, Exercise 16. | 2015 | /// Knuth 4.3.1, Exercise 16. |
| 2009 | fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void { | 2016 | fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void { |
| 2010 | @setRuntimeSafety(false); | 2017 | @setRuntimeSafety(debug_safety); |
| 2011 | assert(a.len > 1 or a[0] >= b); | 2018 | assert(a.len > 1 or a[0] >= b); |
| 2012 | assert(quo.len >= a.len); | 2019 | assert(quo.len >= a.len); |
| 2013 | | 2020 | |
| ... | @@ -2033,7 +2040,7 @@ fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void { | ... | @@ -2033,7 +2040,7 @@ fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void { |
| 2033 | } | 2040 | } |
| 2034 | | 2041 | |
| 2035 | fn llshl(r: []Limb, a: []const Limb, shift: usize) void { | 2042 | fn llshl(r: []Limb, a: []const Limb, shift: usize) void { |
| 2036 | @setRuntimeSafety(false); | 2043 | @setRuntimeSafety(debug_safety); |
| 2037 | assert(a.len >= 1); | 2044 | assert(a.len >= 1); |
| 2038 | assert(r.len >= a.len + (shift / Limb.bit_count) + 1); | 2045 | assert(r.len >= a.len + (shift / Limb.bit_count) + 1); |
| 2039 | | 2046 | |
| ... | @@ -2060,7 +2067,7 @@ fn llshl(r: []Limb, a: []const Limb, shift: usize) void { | ... | @@ -2060,7 +2067,7 @@ fn llshl(r: []Limb, a: []const Limb, shift: usize) void { |
| 2060 | } | 2067 | } |
| 2061 | | 2068 | |
| 2062 | fn llshr(r: []Limb, a: []const Limb, shift: usize) void { | 2069 | fn llshr(r: []Limb, a: []const Limb, shift: usize) void { |
| 2063 | @setRuntimeSafety(false); | 2070 | @setRuntimeSafety(debug_safety); |
| 2064 | assert(a.len >= 1); | 2071 | assert(a.len >= 1); |
| 2065 | assert(r.len >= a.len - (shift / Limb.bit_count)); | 2072 | assert(r.len >= a.len - (shift / Limb.bit_count)); |
| 2066 | | 2073 | |
| ... | @@ -2084,7 +2091,7 @@ fn llshr(r: []Limb, a: []const Limb, shift: usize) void { | ... | @@ -2084,7 +2091,7 @@ fn llshr(r: []Limb, a: []const Limb, shift: usize) void { |
| 2084 | } | 2091 | } |
| 2085 | | 2092 | |
| 2086 | fn llor(r: []Limb, a: []const Limb, b: []const Limb) void { | 2093 | fn llor(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 2087 | @setRuntimeSafety(false); | 2094 | @setRuntimeSafety(debug_safety); |
| 2088 | assert(r.len >= a.len); | 2095 | assert(r.len >= a.len); |
| 2089 | assert(a.len >= b.len); | 2096 | assert(a.len >= b.len); |
| 2090 | | 2097 | |
| ... | @@ -2098,7 +2105,7 @@ fn llor(r: []Limb, a: []const Limb, b: []const Limb) void { | ... | @@ -2098,7 +2105,7 @@ fn llor(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 2098 | } | 2105 | } |
| 2099 | | 2106 | |
| 2100 | fn lland(r: []Limb, a: []const Limb, b: []const Limb) void { | 2107 | fn lland(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 2101 | @setRuntimeSafety(false); | 2108 | @setRuntimeSafety(debug_safety); |
| 2102 | assert(r.len >= b.len); | 2109 | assert(r.len >= b.len); |
| 2103 | assert(a.len >= b.len); | 2110 | assert(a.len >= b.len); |
| 2104 | | 2111 | |