| ... | @@ -482,12 +482,15 @@ fn Fe_(comptime bits: comptime_int) type { | ... | @@ -482,12 +482,15 @@ fn Fe_(comptime bits: comptime_int) type { |
| 482 | } | 482 | } |
| 483 | | 483 | |
| 484 | /// Returns `true` if the field elements are equal, in constant time. | 484 | /// Returns `true` if the field elements are equal, in constant time. |
| | 485 | /// Elements in different representations compare unequal; convert them to the same form to compare values. |
| 485 | pub fn eql(x: Self, y: Self) bool { | 486 | pub fn eql(x: Self, y: Self) bool { |
| 486 | return x.v.eql(y.v); | 487 | const values_equal = x.v.eql(y.v); |
| | 488 | return x.montgomery == y.montgomery and values_equal; |
| 487 | } | 489 | } |
| 488 | | 490 | |
| 489 | /// Compares two field elements in constant time. | 491 | /// Compares two field elements in constant time. |
| 490 | pub fn compare(x: Self, y: Self) math.Order { | 492 | pub fn compare(x: Self, y: Self) math.Order { |
| | 493 | assert(!x.montgomery and !y.montgomery); |
| 491 | return x.v.compare(y.v); | 494 | return x.v.compare(y.v); |
| 492 | } | 495 | } |
| 493 | | 496 | |
| ... | @@ -497,7 +500,9 @@ fn Fe_(comptime bits: comptime_int) type { | ... | @@ -497,7 +500,9 @@ fn Fe_(comptime bits: comptime_int) type { |
| 497 | } | 500 | } |
| 498 | | 501 | |
| 499 | /// Returns `true` is the element is odd. | 502 | /// Returns `true` is the element is odd. |
| | 503 | /// Requires plain form because Montgomery encoding doesn't preserve parity. |
| 500 | pub fn isOdd(self: Self) bool { | 504 | pub fn isOdd(self: Self) bool { |
| | 505 | assert(!self.montgomery); |
| 501 | return self.v.isOdd(); | 506 | return self.v.isOdd(); |
| 502 | } | 507 | } |
| 503 | }; | 508 | }; |
| ... | @@ -576,6 +581,7 @@ pub fn Modulus(comptime max_bits: comptime_int) type { | ... | @@ -576,6 +581,7 @@ pub fn Modulus(comptime max_bits: comptime_int) type { |
| 576 | const Self = @This(); | 581 | const Self = @This(); |
| 577 | | 582 | |
| 578 | /// A field element, representing a value within the field defined by this modulus. | 583 | /// A field element, representing a value within the field defined by this modulus. |
| | 584 | /// Use elements only with the modulus that created them, even if another modulus has the same size. |
| 579 | pub const Fe = Fe_(max_bits); | 585 | pub const Fe = Fe_(max_bits); |
| 580 | | 586 | |
| 581 | const FeUint = Fe.FeUint; | 587 | const FeUint = Fe.FeUint; |
| ... | @@ -1172,7 +1178,7 @@ test "finite field arithmetic" { | ... | @@ -1172,7 +1178,7 @@ test "finite field arithmetic" { |
| 1172 | const M = Modulus(256); | 1178 | const M = Modulus(256); |
| 1173 | const m = try M.fromPrimitive(u256, 3429938563481314093726330772853735541133072814650493833233); | 1179 | const m = try M.fromPrimitive(u256, 3429938563481314093726330772853735541133072814650493833233); |
| 1174 | var x = try M.Fe.fromPrimitive(u256, m, 80169837251094269539116136208111827396136208141182357733); | 1180 | var x = try M.Fe.fromPrimitive(u256, m, 80169837251094269539116136208111827396136208141182357733); |
| 1175 | var y = try M.Fe.fromPrimitive(u256, m, 24620149608466364616251608466389896540098571); | 1181 | const y = try M.Fe.fromPrimitive(u256, m, 24620149608466364616251608466389896540098571); |
| 1176 | | 1182 | |
| 1177 | const x_ = try x.toPrimitive(u256); | 1183 | const x_ = try x.toPrimitive(u256); |
| 1178 | try testing.expect((try M.Fe.fromPrimitive(@TypeOf(x_), m, x_)).eql(x)); | 1184 | try testing.expect((try M.Fe.fromPrimitive(@TypeOf(x_), m, x_)).eql(x)); |
| ... | @@ -1243,10 +1249,10 @@ test "finite field arithmetic" { | ... | @@ -1243,10 +1249,10 @@ test "finite field arithmetic" { |
| 1243 | try testing.expect(add_nm_m.eql(add_m_nm)); | 1249 | try testing.expect(add_nm_m.eql(add_m_nm)); |
| 1244 | | 1250 | |
| 1245 | // Non-montgomery - montgomery | 1251 | // Non-montgomery - montgomery |
| 1246 | const sub_nm_m = m.sub(x, y); | | |
| 1247 | try testing.expect(!sub_nm_m.montgomery); | | |
| 1248 | var y_mont = y; | 1252 | var y_mont = y; |
| 1249 | try m.toMontgomery(&y_mont); | 1253 | try m.toMontgomery(&y_mont); |
| | 1254 | const sub_nm_m = m.sub(x, y_mont); |
| | 1255 | try testing.expect(!sub_nm_m.montgomery); |
| 1250 | var sub_m_nm = m.sub(x_mont, y); | 1256 | var sub_m_nm = m.sub(x_mont, y); |
| 1251 | try testing.expect(sub_m_nm.montgomery); | 1257 | try testing.expect(sub_m_nm.montgomery); |
| 1252 | try m.fromMontgomery(&sub_m_nm); | 1258 | try m.fromMontgomery(&sub_m_nm); |