| ... | ... | @@ -621,6 +621,23 @@ pub fn Modulus(comptime max_bits: comptime_int) type { |
| 621 | 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 | 641 | /// Creates a new modulus from a `Uint` value. |
| 625 | 642 | /// The modulus must be odd and larger than 2. |
| 626 | 643 | pub fn fromUint(v_: FeUint) InvalidModulusError!Self { |
| ... | ... | @@ -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 | 812 | /// Converts a field element to the Montgomery form. |
| 791 | 813 | pub fn toMontgomery(self: Self, x: *Fe) RepresentationError!void { |
| 792 | 814 | if (x.montgomery) { |
| ... | ... | @@ -1511,3 +1533,32 @@ test "Uint addition and multiply-add" { |
| 1511 | 1533 | try testing.expectEqual(1, short.limbs_len); |
| 1512 | 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 | } |