| ... | @@ -621,6 +621,23 @@ pub fn Modulus(comptime max_bits: comptime_int) type { | ... | @@ -621,6 +621,23 @@ pub fn Modulus(comptime max_bits: comptime_int) type { |
| 621 | return fe; | 621 | return fe; |
| 622 | } | 622 | } |
| 623 | | 623 | |
| | 624 | /// Returns `true` if the element is 1 |
| | 625 | pub fn isOne(self: Self, x: Fe) bool { |
| | 626 | if (x.montgomery) { |
| | 627 | var o = self.one(); |
| | 628 | self.toMontgomery(&o) catch unreachable; |
| | 629 | return x.eql(o); |
| | 630 | } |
| | 631 | return x.v.isOne(); |
| | 632 | } |
| | 633 | |
| | 634 | /// Returns `true` if the element is equivalent to -1 |
| | 635 | pub fn isMinusOne(self: Self, x: Fe) bool { |
| | 636 | var mo = self.subOne(self.zero); |
| | 637 | if (x.montgomery) self.toMontgomery(&mo) catch unreachable; |
| | 638 | return x.eql(mo); |
| | 639 | } |
| | 640 | |
| 624 | /// Creates a new modulus from a `Uint` value. | 641 | /// Creates a new modulus from a `Uint` value. |
| 625 | /// The modulus must be odd and larger than 2. | 642 | /// The modulus must be odd and larger than 2. |
| 626 | pub fn fromUint(v_: FeUint) InvalidModulusError!Self { | 643 | pub fn fromUint(v_: FeUint) InvalidModulusError!Self { |
| ... | @@ -787,6 +804,11 @@ pub fn Modulus(comptime max_bits: comptime_int) type { | ... | @@ -787,6 +804,11 @@ pub fn Modulus(comptime max_bits: comptime_int) type { |
| 787 | } | 804 | } |
| 788 | } | 805 | } |
| 789 | | 806 | |
| | 807 | /// Subtracts 1 from a field element |
| | 808 | pub fn subOne(self: Self, x: Fe) Fe { |
| | 809 | return self.sub(x, self.one()); |
| | 810 | } |
| | 811 | |
| 790 | /// Converts a field element to the Montgomery form. | 812 | /// Converts a field element to the Montgomery form. |
| 791 | pub fn toMontgomery(self: Self, x: *Fe) RepresentationError!void { | 813 | pub fn toMontgomery(self: Self, x: *Fe) RepresentationError!void { |
| 792 | if (x.montgomery) { | 814 | if (x.montgomery) { |
| ... | @@ -1511,3 +1533,32 @@ test "Uint addition and multiply-add" { | ... | @@ -1511,3 +1533,32 @@ test "Uint addition and multiply-add" { |
| 1511 | try testing.expectEqual(1, short.limbs_len); | 1533 | try testing.expectEqual(1, short.limbs_len); |
| 1512 | try testing.expect(short.isOne()); | 1534 | try testing.expect(short.isOne()); |
| 1513 | } | 1535 | } |
| | 1536 | |
| | 1537 | test "field element constants and subOne" { |
| | 1538 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| | 1539 | |
| | 1540 | const M = Modulus(256); |
| | 1541 | const m = try M.fromPrimitive(u128, (1 << t_bits) + 1); |
| | 1542 | var one = m.one(); |
| | 1543 | var minus_one = try M.Fe.fromPrimitive(u128, m, 1 << t_bits); |
| | 1544 | var other = try M.Fe.fromPrimitive(u8, m, 5); |
| | 1545 | for ([_]bool{ false, true }) |montgomery| { |
| | 1546 | if (montgomery) { |
| | 1547 | try m.toMontgomery(&one); |
| | 1548 | try m.toMontgomery(&minus_one); |
| | 1549 | try m.toMontgomery(&other); |
| | 1550 | } |
| | 1551 | try testing.expect(m.isOne(one)); |
| | 1552 | try testing.expect(!m.isOne(minus_one)); |
| | 1553 | try testing.expect(m.isMinusOne(minus_one)); |
| | 1554 | try testing.expect(!m.isMinusOne(one)); |
| | 1555 | const zero = m.subOne(one); |
| | 1556 | try testing.expect(zero.isZero()); |
| | 1557 | try testing.expect(!m.isOne(zero)); |
| | 1558 | try testing.expect(!m.isMinusOne(zero)); |
| | 1559 | try testing.expect(m.isMinusOne(m.subOne(zero))); |
| | 1560 | var four = m.subOne(other); |
| | 1561 | if (montgomery) try m.fromMontgomery(&four); |
| | 1562 | try testing.expectEqual(4, try four.toPrimitive(u8)); |
| | 1563 | } |
| | 1564 | } |