Skip to content

Commit

Permalink
std/crypto/{25519,pcurves}: make the scalar field order public (#11955)
Browse files Browse the repository at this point in the history
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()`.
  • Loading branch information
jedisct1 authored and andrewrk committed Jul 19, 2022
1 parent 4912c94 commit 61cd09f
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 12 deletions.
24 changes: 14 additions & 10 deletions lib/std/crypto/25519/scalar.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,31 @@ const mem = std.mem;

const NonCanonicalError = std.crypto.errors.NonCanonicalError;

/// 2^252 + 27742317777372353535851937790883648493
pub const field_size = [32]u8{
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
};
/// The scalar field order.
pub const field_order: u256 = 7237005577332262213973186563042994240857116359379907606001950938285454250989;

/// A compressed scalar
pub const CompressedScalar = [32]u8;

/// Zero
pub const zero = [_]u8{0} ** 32;

const field_order_s = s: {
var s: [32]u8 = undefined;
mem.writeIntLittle(u256, &s, field_order);
break :s s;
};

/// Reject a scalar whose encoding is not canonical.
pub fn rejectNonCanonical(s: CompressedScalar) NonCanonicalError!void {
var c: u8 = 0;
var n: u8 = 1;
var i: usize = 31;
while (true) : (i -= 1) {
const xs = @as(u16, s[i]);
const xfield_size = @as(u16, field_size[i]);
c |= @intCast(u8, ((xs -% xfield_size) >> 8) & n);
n &= @intCast(u8, ((xs ^ xfield_size) -% 1) >> 8);
const xfield_order_s = @as(u16, field_order_s[i]);
c |= @intCast(u8, ((xs -% xfield_order_s) >> 8) & n);
n &= @intCast(u8, ((xs ^ xfield_order_s) -% 1) >> 8);
if (i == 0) break;
}
if (c == 0) {
Expand Down Expand Up @@ -77,7 +81,7 @@ pub fn add(a: CompressedScalar, b: CompressedScalar) CompressedScalar {

/// Return -s (mod L)
pub fn neg(s: CompressedScalar) CompressedScalar {
const fs: [64]u8 = field_size ++ [_]u8{0} ** 32;
const fs: [64]u8 = field_order_s ++ [_]u8{0} ** 32;
var sx: [64]u8 = undefined;
mem.copy(u8, sx[0..32], s[0..]);
mem.set(u8, sx[32..], 0);
Expand Down Expand Up @@ -848,7 +852,7 @@ test "scalar25519" {
var buf: [128]u8 = undefined;
try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&y)}), "1E979B917937F3DE71D18077F961F6CEFF01030405060708010203040506070F");

const reduced = reduce(field_size);
const reduced = reduce(field_order_s);
try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&reduced)}), "0000000000000000000000000000000000000000000000000000000000000000");
}

Expand Down Expand Up @@ -881,7 +885,7 @@ test "random scalar" {
}

test "64-bit reduction" {
const bytes = field_size ++ [_]u8{0} ** 32;
const bytes = field_order_s ++ [_]u8{0} ** 32;
const x = Scalar.fromBytes64(bytes);
try std.testing.expect(x.isZero());
}
5 changes: 4 additions & 1 deletion lib/std/crypto/pcurves/p256/scalar.zig
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ const Fe = Field(.{
.encoded_length = encoded_length,
});

/// The scalar field order.
pub const field_order = Fe.field_order;

/// Reject a scalar whose encoding is not canonical.
pub fn rejectNonCanonical(s: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!void {
return Fe.rejectNonCanonical(s, endian);
Expand Down Expand Up @@ -61,7 +64,7 @@ pub fn neg(s: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!Co

/// Return (a-b) (mod L)
pub fn sub(a: CompressedScalar, b: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!CompressedScalar {
return (try Scalar.fromBytes(a, endian)).sub(try Scalar.fromBytes(b.endian)).toBytes(endian);
return (try Scalar.fromBytes(a, endian)).sub(try Scalar.fromBytes(b, endian)).toBytes(endian);
}

/// Return a random scalar
Expand Down
5 changes: 4 additions & 1 deletion lib/std/crypto/pcurves/p384/scalar.zig
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ const Fe = Field(.{
.encoded_length = encoded_length,
});

/// The scalar field order.
pub const field_order = Fe.field_order;

/// Reject a scalar whose encoding is not canonical.
pub fn rejectNonCanonical(s: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!void {
return Fe.rejectNonCanonical(s, endian);
Expand Down Expand Up @@ -56,7 +59,7 @@ pub fn neg(s: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!Co

/// Return (a-b) (mod L)
pub fn sub(a: CompressedScalar, b: CompressedScalar, endian: std.builtin.Endian) NonCanonicalError!CompressedScalar {
return (try Scalar.fromBytes(a, endian)).sub(try Scalar.fromBytes(b.endian)).toBytes(endian);
return (try Scalar.fromBytes(a, endian)).sub(try Scalar.fromBytes(b, endian)).toBytes(endian);
}

/// Return a random scalar
Expand Down

0 comments on commit 61cd09f

Please sign in to comment.