| ... | ... | @@ -4,10 +4,8 @@ const mem = std.mem; |
| 4 | 4 | |
| 5 | 5 | const NonCanonicalError = std.crypto.errors.NonCanonicalError; |
| 6 | 6 | |
| 7 | | /// 2^252 + 27742317777372353535851937790883648493 |
| 8 | | pub const field_size = [32]u8{ |
| 9 | | 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, // 2^252+27742317777372353535851937790883648493 |
| 10 | | }; |
| 7 | /// The scalar field order. |
| 8 | pub const field_order: u256 = 7237005577332262213973186563042994240857116359379907606001950938285454250989; |
| 11 | 9 | |
| 12 | 10 | /// A compressed scalar |
| 13 | 11 | pub const CompressedScalar = [32]u8; |
| ... | ... | @@ -15,6 +13,12 @@ pub const CompressedScalar = [32]u8; |
| 15 | 13 | /// Zero |
| 16 | 14 | pub const zero = [_]u8{0} ** 32; |
| 17 | 15 | |
| 16 | const field_order_s = s: { |
| 17 | var s: [32]u8 = undefined; |
| 18 | mem.writeIntLittle(u256, &s, field_order); |
| 19 | break :s s; |
| 20 | }; |
| 21 | |
| 18 | 22 | /// Reject a scalar whose encoding is not canonical. |
| 19 | 23 | pub fn rejectNonCanonical(s: CompressedScalar) NonCanonicalError!void { |
| 20 | 24 | var c: u8 = 0; |
| ... | ... | @@ -22,9 +26,9 @@ pub fn rejectNonCanonical(s: CompressedScalar) NonCanonicalError!void { |
| 22 | 26 | var i: usize = 31; |
| 23 | 27 | while (true) : (i -= 1) { |
| 24 | 28 | const xs = @as(u16, s[i]); |
| 25 | | const xfield_size = @as(u16, field_size[i]); |
| 26 | | c |= @intCast(u8, ((xs -% xfield_size) >> 8) & n); |
| 27 | | n &= @intCast(u8, ((xs ^ xfield_size) -% 1) >> 8); |
| 29 | const xfield_order_s = @as(u16, field_order_s[i]); |
| 30 | c |= @intCast(u8, ((xs -% xfield_order_s) >> 8) & n); |
| 31 | n &= @intCast(u8, ((xs ^ xfield_order_s) -% 1) >> 8); |
| 28 | 32 | if (i == 0) break; |
| 29 | 33 | } |
| 30 | 34 | if (c == 0) { |
| ... | ... | @@ -77,7 +81,7 @@ pub fn add(a: CompressedScalar, b: CompressedScalar) CompressedScalar { |
| 77 | 81 | |
| 78 | 82 | /// Return -s (mod L) |
| 79 | 83 | pub fn neg(s: CompressedScalar) CompressedScalar { |
| 80 | | const fs: [64]u8 = field_size ++ [_]u8{0} ** 32; |
| 84 | const fs: [64]u8 = field_order_s ++ [_]u8{0} ** 32; |
| 81 | 85 | var sx: [64]u8 = undefined; |
| 82 | 86 | mem.copy(u8, sx[0..32], s[0..]); |
| 83 | 87 | mem.set(u8, sx[32..], 0); |
| ... | ... | @@ -848,7 +852,7 @@ test "scalar25519" { |
| 848 | 852 | var buf: [128]u8 = undefined; |
| 849 | 853 | try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&y)}), "1E979B917937F3DE71D18077F961F6CEFF01030405060708010203040506070F"); |
| 850 | 854 | |
| 851 | | const reduced = reduce(field_size); |
| 855 | const reduced = reduce(field_order_s); |
| 852 | 856 | try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&reduced)}), "0000000000000000000000000000000000000000000000000000000000000000"); |
| 853 | 857 | } |
| 854 | 858 | |
| ... | ... | @@ -881,7 +885,7 @@ test "random scalar" { |
| 881 | 885 | } |
| 882 | 886 | |
| 883 | 887 | test "64-bit reduction" { |
| 884 | | const bytes = field_size ++ [_]u8{0} ** 32; |
| 888 | const bytes = field_order_s ++ [_]u8{0} ** 32; |
| 885 | 889 | const x = Scalar.fromBytes64(bytes); |
| 886 | 890 | try std.testing.expect(x.isZero()); |
| 887 | 891 | } |