authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2022-06-29 07:44:43+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-06-29 07:44:43+02:00
log41533fa6a1fa5e9e9b38a59403930501fd61a259
treee19551646b2e1ac917990a6842c298e3c49b765e
parentb2e4dda0018b83819c9539609eff7e420eca3202
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

std/crypto/{25519,pcurves}: make the scalar field order public (#11955)

For 25519, it's very likely that applications would ever need the serialized representation. Expose the value as an integer as in other curves. Rename the internal representation from `field_size` to `field_order` for consistency. Also fix a common typo in `scalar.sub()`.

3 files changed, 22 insertions(+), 12 deletions(-)

lib/std/crypto/25519/scalar.zig+14-10
...@@ -4,10 +4,8 @@ const mem = std.mem;...@@ -4,10 +4,8 @@ const mem = std.mem;
44
5const NonCanonicalError = std.crypto.errors.NonCanonicalError;5const NonCanonicalError = std.crypto.errors.NonCanonicalError;
66
7/// 2^252 + 277423177773723535358519377908836484937/// The scalar field order.
8pub const field_size = [32]u8{8pub const field_order: u256 = 7237005577332262213973186563042994240857116359379907606001950938285454250989;
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};
119
12/// A compressed scalar10/// A compressed scalar
13pub const CompressedScalar = [32]u8;11pub const CompressedScalar = [32]u8;
...@@ -15,6 +13,12 @@ pub const CompressedScalar = [32]u8;...@@ -15,6 +13,12 @@ pub const CompressedScalar = [32]u8;
15/// Zero13/// Zero
16pub const zero = [_]u8{0} ** 32;14pub const zero = [_]u8{0} ** 32;
1715
16const field_order_s = s: {
17 var s: [32]u8 = undefined;
18 mem.writeIntLittle(u256, &s, field_order);
19 break :s s;
20};
21
18/// Reject a scalar whose encoding is not canonical.22/// Reject a scalar whose encoding is not canonical.
19pub fn rejectNonCanonical(s: CompressedScalar) NonCanonicalError!void {23pub fn rejectNonCanonical(s: CompressedScalar) NonCanonicalError!void {
20 var c: u8 = 0;24 var c: u8 = 0;
...@@ -22,9 +26,9 @@ pub fn rejectNonCanonical(s: CompressedScalar) NonCanonicalError!void {...@@ -22,9 +26,9 @@ pub fn rejectNonCanonical(s: CompressedScalar) NonCanonicalError!void {
22 var i: usize = 31;26 var i: usize = 31;
23 while (true) : (i -= 1) {27 while (true) : (i -= 1) {
24 const xs = @as(u16, s[i]);28 const xs = @as(u16, s[i]);
25 const xfield_size = @as(u16, field_size[i]);29 const xfield_order_s = @as(u16, field_order_s[i]);
26 c |= @intCast(u8, ((xs -% xfield_size) >> 8) & n);30 c |= @intCast(u8, ((xs -% xfield_order_s) >> 8) & n);
27 n &= @intCast(u8, ((xs ^ xfield_size) -% 1) >> 8);31 n &= @intCast(u8, ((xs ^ xfield_order_s) -% 1) >> 8);
28 if (i == 0) break;32 if (i == 0) break;
29 }33 }
30 if (c == 0) {34 if (c == 0) {
...@@ -77,7 +81,7 @@ pub fn add(a: CompressedScalar, b: CompressedScalar) CompressedScalar {...@@ -77,7 +81,7 @@ pub fn add(a: CompressedScalar, b: CompressedScalar) CompressedScalar {
7781
78/// Return -s (mod L)82/// Return -s (mod L)
79pub fn neg(s: CompressedScalar) CompressedScalar {83pub 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 var sx: [64]u8 = undefined;85 var sx: [64]u8 = undefined;
82 mem.copy(u8, sx[0..32], s[0..]);86 mem.copy(u8, sx[0..32], s[0..]);
83 mem.set(u8, sx[32..], 0);87 mem.set(u8, sx[32..], 0);
...@@ -848,7 +852,7 @@ test "scalar25519" {...@@ -848,7 +852,7 @@ test "scalar25519" {
848 var buf: [128]u8 = undefined;852 var buf: [128]u8 = undefined;
849 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&y)}), "1E979B917937F3DE71D18077F961F6CEFF01030405060708010203040506070F");853 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&y)}), "1E979B917937F3DE71D18077F961F6CEFF01030405060708010203040506070F");
850854
851 const reduced = reduce(field_size);855 const reduced = reduce(field_order_s);
852 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&reduced)}), "0000000000000000000000000000000000000000000000000000000000000000");856 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&reduced)}), "0000000000000000000000000000000000000000000000000000000000000000");
853}857}
854858
...@@ -881,7 +885,7 @@ test "random scalar" {...@@ -881,7 +885,7 @@ test "random scalar" {
881}885}
882886
883test "64-bit reduction" {887test "64-bit reduction" {
884 const bytes = field_size ++ [_]u8{0} ** 32;888 const bytes = field_order_s ++ [_]u8{0} ** 32;
885 const x = Scalar.fromBytes64(bytes);889 const x = Scalar.fromBytes64(bytes);
886 try std.testing.expect(x.isZero());890 try std.testing.expect(x.isZero());
887}891}
lib/std/crypto/pcurves/p256/scalar.zig+4-1
...@@ -24,6 +24,9 @@ const Fe = Field(.{...@@ -24,6 +24,9 @@ const Fe = Field(.{
24 .encoded_length = encoded_length,24 .encoded_length = encoded_length,
25});25});
2626
27/// The scalar field order.
28pub const field_order = Fe.field_order;
29
27/// Reject a scalar whose encoding is not canonical.30/// Reject a scalar whose encoding is not canonical.
28pub fn rejectNonCanonical(s: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!void {31pub fn rejectNonCanonical(s: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!void {
29 return Fe.rejectNonCanonical(s, endian);32 return Fe.rejectNonCanonical(s, endian);
...@@ -61,7 +64,7 @@ pub fn neg(s: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!Co...@@ -61,7 +64,7 @@ pub fn neg(s: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!Co
6164
62/// Return (a-b) (mod L)65/// Return (a-b) (mod L)
63pub fn sub(a: CompressedScalar, b: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!CompressedScalar {66pub fn sub(a: CompressedScalar, b: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!CompressedScalar {
64 return (try Scalar.fromBytes(a, endian)).sub(try Scalar.fromBytes(b.endian)).toBytes(endian);67 return (try Scalar.fromBytes(a, endian)).sub(try Scalar.fromBytes(b, endian)).toBytes(endian);
65}68}
6669
67/// Return a random scalar70/// Return a random scalar
lib/std/crypto/pcurves/p384/scalar.zig+4-1
...@@ -24,6 +24,9 @@ const Fe = Field(.{...@@ -24,6 +24,9 @@ const Fe = Field(.{
24 .encoded_length = encoded_length,24 .encoded_length = encoded_length,
25});25});
2626
27/// The scalar field order.
28pub const field_order = Fe.field_order;
29
27/// Reject a scalar whose encoding is not canonical.30/// Reject a scalar whose encoding is not canonical.
28pub fn rejectNonCanonical(s: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!void {31pub fn rejectNonCanonical(s: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!void {
29 return Fe.rejectNonCanonical(s, endian);32 return Fe.rejectNonCanonical(s, endian);
...@@ -56,7 +59,7 @@ pub fn neg(s: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!Co...@@ -56,7 +59,7 @@ pub fn neg(s: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!Co
5659
57/// Return (a-b) (mod L)60/// Return (a-b) (mod L)
58pub fn sub(a: CompressedScalar, b: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!CompressedScalar {61pub fn sub(a: CompressedScalar, b: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!CompressedScalar {
59 return (try Scalar.fromBytes(a, endian)).sub(try Scalar.fromBytes(b.endian)).toBytes(endian);62 return (try Scalar.fromBytes(a, endian)).sub(try Scalar.fromBytes(b, endian)).toBytes(endian);
60}63}
6164
62/// Return a random scalar65/// Return a random scalar