mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
Merge remote-tracking branch 'origin/master' into stage2-whole-file-astgen
Conflicts: * build.zig * lib/std/array_list.zig * lib/std/c/ast.zig * lib/std/c/parse.zig * lib/std/os/bits/linux.zig
This commit is contained in:
@@ -36,7 +36,7 @@ pub fn build(b: *Builder) !void {
|
||||
const docs_step = b.step("docs", "Build documentation");
|
||||
docs_step.dependOn(&docgen_cmd.step);
|
||||
|
||||
const test_step = b.step("test", "Run all the tests");
|
||||
const toolchain_step = b.step("test-toolchain", "Run the tests for the toolchain");
|
||||
|
||||
var test_stage2 = b.addTest("src/test.zig");
|
||||
test_stage2.setBuildMode(mode);
|
||||
@@ -99,7 +99,7 @@ pub fn build(b: *Builder) !void {
|
||||
exe.install();
|
||||
exe.setBuildMode(mode);
|
||||
exe.setTarget(target);
|
||||
test_step.dependOn(&exe.step);
|
||||
toolchain_step.dependOn(&exe.step);
|
||||
b.default_step.dependOn(&exe.step);
|
||||
|
||||
exe.addBuildOption(u32, "mem_leak_frames", mem_leak_frames);
|
||||
@@ -244,7 +244,7 @@ pub fn build(b: *Builder) !void {
|
||||
const test_stage2_step = b.step("test-stage2", "Run the stage2 compiler tests");
|
||||
test_stage2_step.dependOn(&test_stage2.step);
|
||||
if (!skip_stage2_tests) {
|
||||
test_step.dependOn(test_stage2_step);
|
||||
toolchain_step.dependOn(test_stage2_step);
|
||||
}
|
||||
|
||||
var chosen_modes: [4]builtin.Mode = undefined;
|
||||
@@ -268,33 +268,37 @@ pub fn build(b: *Builder) !void {
|
||||
const modes = chosen_modes[0..chosen_mode_index];
|
||||
|
||||
// run stage1 `zig fmt` on this build.zig file just to make sure it works
|
||||
test_step.dependOn(&fmt_build_zig.step);
|
||||
toolchain_step.dependOn(&fmt_build_zig.step);
|
||||
const fmt_step = b.step("test-fmt", "Run zig fmt against build.zig to make sure it works");
|
||||
fmt_step.dependOn(&fmt_build_zig.step);
|
||||
|
||||
// TODO for the moment, skip wasm32-wasi until bugs are sorted out.
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", modes, false, skip_non_native, skip_libc, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));
|
||||
toolchain_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", modes, false, skip_non_native, skip_libc, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));
|
||||
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/std.zig", "std", "Run the standard library tests", modes, false, skip_non_native, skip_libc, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));
|
||||
toolchain_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/special/compiler_rt.zig", "compiler-rt", "Run the compiler_rt tests", modes, true, skip_non_native, true, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));
|
||||
toolchain_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/special/c.zig", "minilibc", "Run the mini libc tests", modes, true, skip_non_native, true, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));
|
||||
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/special/compiler_rt.zig", "compiler-rt", "Run the compiler_rt tests", modes, true, skip_non_native, true, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/special/c.zig", "minilibc", "Run the mini libc tests", modes, true, skip_non_native, true, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));
|
||||
|
||||
test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
|
||||
test_step.dependOn(tests.addStandaloneTests(b, test_filter, modes));
|
||||
test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
|
||||
test_step.dependOn(tests.addCliTests(b, test_filter, modes));
|
||||
test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
|
||||
test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));
|
||||
test_step.dependOn(tests.addTranslateCTests(b, test_filter));
|
||||
toolchain_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
|
||||
toolchain_step.dependOn(tests.addStandaloneTests(b, test_filter, modes));
|
||||
toolchain_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
|
||||
toolchain_step.dependOn(tests.addCliTests(b, test_filter, modes));
|
||||
toolchain_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
|
||||
toolchain_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));
|
||||
toolchain_step.dependOn(tests.addTranslateCTests(b, test_filter));
|
||||
if (!skip_run_translated_c) {
|
||||
test_step.dependOn(tests.addRunTranslatedCTests(b, test_filter, target));
|
||||
toolchain_step.dependOn(tests.addRunTranslatedCTests(b, test_filter, target));
|
||||
}
|
||||
// tests for this feature are disabled until we have the self-hosted compiler available
|
||||
// test_step.dependOn(tests.addGenHTests(b, test_filter));
|
||||
// toolchain_step.dependOn(tests.addGenHTests(b, test_filter));
|
||||
if (!skip_compile_errors) {
|
||||
test_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes));
|
||||
toolchain_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes));
|
||||
}
|
||||
|
||||
const std_step = tests.addPkgTests(b, test_filter, "lib/std/std.zig", "std", "Run the standard library tests", modes, false, skip_non_native, skip_libc, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir);
|
||||
|
||||
const test_step = b.step("test", "Run all the tests");
|
||||
test_step.dependOn(toolchain_step);
|
||||
test_step.dependOn(std_step);
|
||||
test_step.dependOn(docs_step);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,9 @@ make $JOBS install
|
||||
cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig"
|
||||
make $JOBS install
|
||||
|
||||
release/bin/zig build test -Denable-qemu -Denable-wasmtime
|
||||
for step in test-toolchain test-std docs; do
|
||||
release/bin/zig build $step -Denable-qemu -Denable-wasmtime
|
||||
done
|
||||
|
||||
# Look for HTML errors.
|
||||
tidy -qe ../zig-cache/langref.html
|
||||
|
||||
@@ -18,7 +18,7 @@ tar xf "$CACHE_BASENAME.tar.xz"
|
||||
|
||||
ZIG="$PREFIX/bin/zig"
|
||||
NATIVE_LIBC_TXT="$HOME/native_libc.txt"
|
||||
$ZIG libc > "$NATIVE_LIBC_TXT"
|
||||
$ZIG libc >"$NATIVE_LIBC_TXT"
|
||||
export ZIG_LIBC="$NATIVE_LIBC_TXT"
|
||||
export CC="$ZIG cc"
|
||||
export CXX="$ZIG c++"
|
||||
@@ -55,7 +55,9 @@ make $JOBS install
|
||||
cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig" -DZIG_TARGET_MCPU="x86_64_v2"
|
||||
make $JOBS install
|
||||
|
||||
release/bin/zig build test
|
||||
for step in test-toolchain test-std docs; do
|
||||
release/bin/zig build $step
|
||||
done
|
||||
|
||||
if [ "${BUILD_REASON}" != "PullRequest" ]; then
|
||||
mv ../LICENSE release/
|
||||
|
||||
@@ -26,20 +26,8 @@ cd %ZIGBUILDDIR%
|
||||
cmake.exe .. -Thost=x64 -G"Visual Studio 16 2019" -A x64 "-DCMAKE_INSTALL_PREFIX=%ZIGINSTALLDIR%" "-DCMAKE_PREFIX_PATH=%ZIGPREFIXPATH%" -DCMAKE_BUILD_TYPE=Release -DZIG_OMIT_STAGE2=ON || exit /b
|
||||
msbuild /maxcpucount /p:Configuration=Release INSTALL.vcxproj || exit /b
|
||||
|
||||
"%ZIGINSTALLDIR%\bin\zig.exe" build test-behavior -Dskip-non-native || exit /b
|
||||
REM Disabled to prevent OOM
|
||||
REM "%ZIGINSTALLDIR%\bin\zig.exe" build test-stage2 -Dskip-non-native || exit /b
|
||||
"%ZIGINSTALLDIR%\bin\zig.exe" build test-fmt -Dskip-non-native || exit /b
|
||||
"%ZIGINSTALLDIR%\bin\zig.exe" build test-toolchain -Dskip-non-native -Dskip-stage2-tests || exit /b
|
||||
"%ZIGINSTALLDIR%\bin\zig.exe" build test-std -Dskip-non-native || exit /b
|
||||
"%ZIGINSTALLDIR%\bin\zig.exe" build test-compiler-rt -Dskip-non-native || exit /b
|
||||
"%ZIGINSTALLDIR%\bin\zig.exe" build test-compare-output -Dskip-non-native || exit /b
|
||||
"%ZIGINSTALLDIR%\bin\zig.exe" build test-standalone -Dskip-non-native || exit /b
|
||||
"%ZIGINSTALLDIR%\bin\zig.exe" build test-stack-traces -Dskip-non-native || exit /b
|
||||
"%ZIGINSTALLDIR%\bin\zig.exe" build test-cli -Dskip-non-native || exit /b
|
||||
"%ZIGINSTALLDIR%\bin\zig.exe" build test-asm-link -Dskip-non-native || exit /b
|
||||
"%ZIGINSTALLDIR%\bin\zig.exe" build test-runtime-safety -Dskip-non-native || exit /b
|
||||
"%ZIGINSTALLDIR%\bin\zig.exe" build test-translate-c -Dskip-non-native || exit /b
|
||||
"%ZIGINSTALLDIR%\bin\zig.exe" build test-run-translated-c -Dskip-non-native || exit /b
|
||||
"%ZIGINSTALLDIR%\bin\zig.exe" build docs || exit /b
|
||||
|
||||
set "PATH=%CD:~0,2%\msys64\usr\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem"
|
||||
|
||||
@@ -4,7 +4,7 @@ set -x
|
||||
set -e
|
||||
|
||||
sudo pkg update -fq
|
||||
sudo pkg install -y cmake py37-s3cmd wget curl jq samurai
|
||||
sudo pkg install -y cmake py38-s3cmd wget curl jq samurai
|
||||
|
||||
ZIGDIR="$(pwd)"
|
||||
CACHE_BASENAME="zig+llvm+lld+clang-x86_64-freebsd-gnu-0.8.0-dev.1939+5a3ea9bec"
|
||||
|
||||
+23
-4
@@ -68,11 +68,30 @@ else switch (std.Target.current.os.tag) {
|
||||
};
|
||||
|
||||
/// Signals the processor that it is inside a busy-wait spin-loop ("spin lock").
|
||||
pub fn spinLoopHint() void {
|
||||
pub fn spinLoopHint() callconv(.Inline) void {
|
||||
switch (std.Target.current.cpu.arch) {
|
||||
.i386, .x86_64 => asm volatile ("pause" ::: "memory"),
|
||||
.arm, .aarch64 => asm volatile ("yield" ::: "memory"),
|
||||
else => {},
|
||||
.i386, .x86_64 => {
|
||||
asm volatile ("pause" ::: "memory");
|
||||
},
|
||||
.arm, .armeb, .thumb, .thumbeb => {
|
||||
// `yield` was introduced in v6k but are also available on v6m.
|
||||
const can_yield = comptime std.Target.arm.featureSetHasAny(std.Target.current.cpu.features, .{ .has_v6k, .has_v6m });
|
||||
if (can_yield) asm volatile ("yield" ::: "memory")
|
||||
// Fallback.
|
||||
else asm volatile ("" ::: "memory");
|
||||
},
|
||||
.aarch64, .aarch64_be, .aarch64_32 => {
|
||||
asm volatile ("isb" ::: "memory");
|
||||
},
|
||||
.powerpc64, .powerpc64le => {
|
||||
// No-op that serves as `yield` hint.
|
||||
asm volatile ("or 27, 27, 27" ::: "memory");
|
||||
},
|
||||
else => {
|
||||
// Do nothing but prevent the compiler from optimizing away the
|
||||
// spinning loop.
|
||||
asm volatile ("" ::: "memory");
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+55
-29
@@ -50,7 +50,6 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
|
||||
allocator: *Allocator,
|
||||
|
||||
pub const Slice = if (alignment) |a| ([]align(a) T) else []T;
|
||||
pub const SliceConst = if (alignment) |a| ([]align(a) const T) else []const T;
|
||||
|
||||
/// Deinitialize with `deinit` or use `toOwnedSlice`.
|
||||
pub fn init(allocator: *Allocator) Self {
|
||||
@@ -141,7 +140,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
|
||||
|
||||
/// Insert slice `items` at index `i` by moving `list[i .. list.len]` to make room.
|
||||
/// This operation is O(N).
|
||||
pub fn insertSlice(self: *Self, i: usize, items: SliceConst) !void {
|
||||
pub fn insertSlice(self: *Self, i: usize, items: []const T) !void {
|
||||
try self.ensureUnusedCapacity(items.len);
|
||||
self.items.len += items.len;
|
||||
|
||||
@@ -153,7 +152,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
|
||||
/// Grows list if `len < new_items.len`.
|
||||
/// Shrinks list if `len > new_items.len`.
|
||||
/// Invalidates pointers if this ArrayList is resized.
|
||||
pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: SliceConst) !void {
|
||||
pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) !void {
|
||||
const after_range = start + len;
|
||||
const range = self.items[start..after_range];
|
||||
|
||||
@@ -220,14 +219,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
|
||||
|
||||
/// Append the slice of items to the list. Allocates more
|
||||
/// memory as necessary.
|
||||
pub fn appendSlice(self: *Self, items: SliceConst) !void {
|
||||
pub fn appendSlice(self: *Self, items: []const T) !void {
|
||||
try self.ensureUnusedCapacity(items.len);
|
||||
self.appendSliceAssumeCapacity(items);
|
||||
}
|
||||
|
||||
/// Append the slice of items to the list, asserting the capacity is already
|
||||
/// enough to store the new items. **Does not** invalidate pointers.
|
||||
pub fn appendSliceAssumeCapacity(self: *Self, items: SliceConst) void {
|
||||
pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {
|
||||
const oldlen = self.items.len;
|
||||
const newlen = self.items.len + items.len;
|
||||
self.items.len = newlen;
|
||||
@@ -438,7 +437,6 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
|
||||
capacity: usize = 0,
|
||||
|
||||
pub const Slice = if (alignment) |a| ([]align(a) T) else []T;
|
||||
pub const SliceConst = if (alignment) |a| ([]align(a) const T) else []const T;
|
||||
|
||||
/// Initialize with capacity to hold at least num elements.
|
||||
/// Deinitialize with `deinit` or use `toOwnedSlice`.
|
||||
@@ -492,7 +490,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
|
||||
/// Insert slice `items` at index `i`. Moves `list[i .. list.len]` to
|
||||
/// higher indicices make room.
|
||||
/// This operation is O(N).
|
||||
pub fn insertSlice(self: *Self, allocator: *Allocator, i: usize, items: SliceConst) !void {
|
||||
pub fn insertSlice(self: *Self, allocator: *Allocator, i: usize, items: []const T) !void {
|
||||
try self.ensureUnusedCapacity(allocator, items.len);
|
||||
self.items.len += items.len;
|
||||
|
||||
@@ -504,7 +502,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
|
||||
/// Grows list if `len < new_items.len`.
|
||||
/// Shrinks list if `len > new_items.len`
|
||||
/// Invalidates pointers if this ArrayList is resized.
|
||||
pub fn replaceRange(self: *Self, allocator: *Allocator, start: usize, len: usize, new_items: SliceConst) !void {
|
||||
pub fn replaceRange(self: *Self, allocator: *Allocator, start: usize, len: usize, new_items: []const T) !void {
|
||||
var managed = self.toManaged(allocator);
|
||||
try managed.replaceRange(start, len, new_items);
|
||||
self.* = managed.toUnmanaged();
|
||||
@@ -552,14 +550,14 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
|
||||
|
||||
/// Append the slice of items to the list. Allocates more
|
||||
/// memory as necessary.
|
||||
pub fn appendSlice(self: *Self, allocator: *Allocator, items: SliceConst) !void {
|
||||
pub fn appendSlice(self: *Self, allocator: *Allocator, items: []const T) !void {
|
||||
try self.ensureUnusedCapacity(allocator, items.len);
|
||||
self.appendSliceAssumeCapacity(items);
|
||||
}
|
||||
|
||||
/// Append the slice of items to the list, asserting the capacity is enough
|
||||
/// to store the new items.
|
||||
pub fn appendSliceAssumeCapacity(self: *Self, items: SliceConst) void {
|
||||
pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {
|
||||
const oldlen = self.items.len;
|
||||
const newlen = self.items.len + items.len;
|
||||
|
||||
@@ -1150,15 +1148,31 @@ test "std.ArrayList/ArrayListUnmanaged: ArrayList(T) of struct T" {
|
||||
}
|
||||
}
|
||||
|
||||
test "std.ArrayList(u8) implements writer" {
|
||||
var buffer = ArrayList(u8).init(std.testing.allocator);
|
||||
defer buffer.deinit();
|
||||
test "std.ArrayList(u8)/ArrayListAligned implements writer" {
|
||||
const a = testing.allocator;
|
||||
|
||||
const x: i32 = 42;
|
||||
const y: i32 = 1234;
|
||||
try buffer.writer().print("x: {}\ny: {}\n", .{ x, y });
|
||||
{
|
||||
var buffer = ArrayList(u8).init(a);
|
||||
defer buffer.deinit();
|
||||
|
||||
testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", buffer.items);
|
||||
const x: i32 = 42;
|
||||
const y: i32 = 1234;
|
||||
try buffer.writer().print("x: {}\ny: {}\n", .{ x, y });
|
||||
|
||||
testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", buffer.items);
|
||||
}
|
||||
{
|
||||
var list = ArrayListAligned(u8, 2).init(a);
|
||||
defer list.deinit();
|
||||
|
||||
const writer = list.writer();
|
||||
try writer.writeAll("a");
|
||||
try writer.writeAll("bc");
|
||||
try writer.writeAll("d");
|
||||
try writer.writeAll("efg");
|
||||
|
||||
testing.expectEqualSlices(u8, list.items, "abcdefg");
|
||||
}
|
||||
}
|
||||
|
||||
test "std.ArrayList/ArrayListUnmanaged.shrink still sets length on error.OutOfMemory" {
|
||||
@@ -1189,18 +1203,6 @@ test "std.ArrayList/ArrayListUnmanaged.shrink still sets length on error.OutOfMe
|
||||
}
|
||||
}
|
||||
|
||||
test "std.ArrayList.writer" {
|
||||
var list = ArrayList(u8).init(std.testing.allocator);
|
||||
defer list.deinit();
|
||||
|
||||
const writer = list.writer();
|
||||
try writer.writeAll("a");
|
||||
try writer.writeAll("bc");
|
||||
try writer.writeAll("d");
|
||||
try writer.writeAll("efg");
|
||||
testing.expectEqualSlices(u8, list.items, "abcdefg");
|
||||
}
|
||||
|
||||
test "std.ArrayList/ArrayListUnmanaged.addManyAsArray" {
|
||||
const a = std.testing.allocator;
|
||||
{
|
||||
@@ -1248,3 +1250,27 @@ test "std.ArrayList/ArrayListUnmanaged.toOwnedSliceSentinel" {
|
||||
testing.expectEqualStrings(result, mem.spanZ(result.ptr));
|
||||
}
|
||||
}
|
||||
|
||||
test "ArrayListAligned/ArrayListAlignedUnmanaged accepts unaligned slices" {
|
||||
const a = testing.allocator;
|
||||
{
|
||||
var list = std.ArrayListAligned(u8, 8).init(a);
|
||||
defer list.deinit();
|
||||
|
||||
try list.appendSlice(&.{ 0, 1, 2, 3 });
|
||||
try list.insertSlice(2, &.{ 4, 5, 6, 7 });
|
||||
try list.replaceRange(1, 3, &.{ 8, 9 });
|
||||
|
||||
testing.expectEqualSlices(u8, list.items, &.{ 0, 8, 9, 6, 7, 2, 3 });
|
||||
}
|
||||
{
|
||||
var list = std.ArrayListAlignedUnmanaged(u8, 8){};
|
||||
defer list.deinit(a);
|
||||
|
||||
try list.appendSlice(a, &.{ 0, 1, 2, 3 });
|
||||
try list.insertSlice(a, 2, &.{ 4, 5, 6, 7 });
|
||||
try list.replaceRange(a, 1, 3, &.{ 8, 9 });
|
||||
|
||||
testing.expectEqualSlices(u8, list.items, &.{ 0, 8, 9, 6, 7, 2, 3 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,6 +191,13 @@ pub const RunStep = struct {
|
||||
child.stdout_behavior = stdIoActionToBehavior(self.stdout_action);
|
||||
child.stderr_behavior = stdIoActionToBehavior(self.stderr_action);
|
||||
|
||||
if (self.builder.verbose) {
|
||||
for (argv) |arg| {
|
||||
warn("{s} ", .{arg});
|
||||
}
|
||||
warn("\n", .{});
|
||||
}
|
||||
|
||||
child.spawn() catch |err| {
|
||||
warn("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) });
|
||||
return err;
|
||||
|
||||
+1
-1
@@ -166,7 +166,7 @@ pub const CallingConvention = enum {
|
||||
APCS,
|
||||
AAPCS,
|
||||
AAPCSVFP,
|
||||
SysV
|
||||
SysV,
|
||||
};
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
|
||||
@@ -10,8 +10,6 @@ const page_size = std.mem.page_size;
|
||||
pub const tokenizer = @import("c/tokenizer.zig");
|
||||
pub const Token = tokenizer.Token;
|
||||
pub const Tokenizer = tokenizer.Tokenizer;
|
||||
pub const parse = @import("c/parse.zig").parse;
|
||||
pub const ast = @import("c/ast.zig");
|
||||
pub const builtins = @import("c/builtins.zig");
|
||||
|
||||
test {
|
||||
|
||||
@@ -1,678 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2015-2021 Zig Contributors
|
||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
||||
// The MIT license requires this copyright notice to be included in all copies
|
||||
// and substantial portions of the software.
|
||||
const std = @import("std");
|
||||
const ArrayList = std.ArrayList;
|
||||
const Token = std.c.Token;
|
||||
const Source = std.c.tokenizer.Source;
|
||||
|
||||
pub const TokenIndex = usize;
|
||||
|
||||
pub const Tree = struct {
|
||||
tokens: []Token,
|
||||
sources: []Source,
|
||||
root_node: *Node.Root,
|
||||
arena_state: std.heap.ArenaAllocator.State,
|
||||
gpa: *mem.Allocator,
|
||||
msgs: []Msg,
|
||||
|
||||
pub fn deinit(self: *Tree) void {
|
||||
self.arena_state.promote(self.gpa).deinit();
|
||||
}
|
||||
|
||||
pub fn tokenSlice(tree: *Tree, token: TokenIndex) []const u8 {
|
||||
return tree.tokens.at(token).slice();
|
||||
}
|
||||
|
||||
pub fn tokenEql(tree: *Tree, a: TokenIndex, b: TokenIndex) bool {
|
||||
const atok = tree.tokens.at(a);
|
||||
const btok = tree.tokens.at(b);
|
||||
return atok.eql(btok.*);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Msg = struct {
|
||||
kind: enum {
|
||||
Error,
|
||||
Warning,
|
||||
Note,
|
||||
},
|
||||
inner: Error,
|
||||
};
|
||||
|
||||
pub const Error = union(enum) {
|
||||
InvalidToken: SingleTokenError("invalid token '{}'"),
|
||||
ExpectedToken: ExpectedToken,
|
||||
ExpectedExpr: SingleTokenError("expected expression, found '{}'"),
|
||||
ExpectedTypeName: SingleTokenError("expected type name, found '{}'"),
|
||||
ExpectedFnBody: SingleTokenError("expected function body, found '{}'"),
|
||||
ExpectedDeclarator: SingleTokenError("expected declarator, found '{}'"),
|
||||
ExpectedInitializer: SingleTokenError("expected initializer, found '{}'"),
|
||||
ExpectedEnumField: SingleTokenError("expected enum field, found '{}'"),
|
||||
ExpectedType: SingleTokenError("expected enum field, found '{}'"),
|
||||
InvalidTypeSpecifier: InvalidTypeSpecifier,
|
||||
InvalidStorageClass: SingleTokenError("invalid storage class, found '{}'"),
|
||||
InvalidDeclarator: SimpleError("invalid declarator"),
|
||||
DuplicateQualifier: SingleTokenError("duplicate type qualifier '{}'"),
|
||||
DuplicateSpecifier: SingleTokenError("duplicate declaration specifier '{}'"),
|
||||
MustUseKwToRefer: MustUseKwToRefer,
|
||||
FnSpecOnNonFn: SingleTokenError("function specifier '{}' on non function"),
|
||||
NothingDeclared: SimpleError("declaration doesn't declare anything"),
|
||||
QualifierIgnored: SingleTokenError("qualifier '{}' ignored"),
|
||||
|
||||
pub fn render(self: *const Error, tree: *Tree, stream: anytype) !void {
|
||||
switch (self.*) {
|
||||
.InvalidToken => |*x| return x.render(tree, stream),
|
||||
.ExpectedToken => |*x| return x.render(tree, stream),
|
||||
.ExpectedExpr => |*x| return x.render(tree, stream),
|
||||
.ExpectedTypeName => |*x| return x.render(tree, stream),
|
||||
.ExpectedDeclarator => |*x| return x.render(tree, stream),
|
||||
.ExpectedFnBody => |*x| return x.render(tree, stream),
|
||||
.ExpectedInitializer => |*x| return x.render(tree, stream),
|
||||
.ExpectedEnumField => |*x| return x.render(tree, stream),
|
||||
.ExpectedType => |*x| return x.render(tree, stream),
|
||||
.InvalidTypeSpecifier => |*x| return x.render(tree, stream),
|
||||
.InvalidStorageClass => |*x| return x.render(tree, stream),
|
||||
.InvalidDeclarator => |*x| return x.render(tree, stream),
|
||||
.DuplicateQualifier => |*x| return x.render(tree, stream),
|
||||
.DuplicateSpecifier => |*x| return x.render(tree, stream),
|
||||
.MustUseKwToRefer => |*x| return x.render(tree, stream),
|
||||
.FnSpecOnNonFn => |*x| return x.render(tree, stream),
|
||||
.NothingDeclared => |*x| return x.render(tree, stream),
|
||||
.QualifierIgnored => |*x| return x.render(tree, stream),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn loc(self: *const Error) TokenIndex {
|
||||
switch (self.*) {
|
||||
.InvalidToken => |x| return x.token,
|
||||
.ExpectedToken => |x| return x.token,
|
||||
.ExpectedExpr => |x| return x.token,
|
||||
.ExpectedTypeName => |x| return x.token,
|
||||
.ExpectedDeclarator => |x| return x.token,
|
||||
.ExpectedFnBody => |x| return x.token,
|
||||
.ExpectedInitializer => |x| return x.token,
|
||||
.ExpectedEnumField => |x| return x.token,
|
||||
.ExpectedType => |*x| return x.token,
|
||||
.InvalidTypeSpecifier => |x| return x.token,
|
||||
.InvalidStorageClass => |x| return x.token,
|
||||
.InvalidDeclarator => |x| return x.token,
|
||||
.DuplicateQualifier => |x| return x.token,
|
||||
.DuplicateSpecifier => |x| return x.token,
|
||||
.MustUseKwToRefer => |*x| return x.name,
|
||||
.FnSpecOnNonFn => |*x| return x.name,
|
||||
.NothingDeclared => |*x| return x.name,
|
||||
.QualifierIgnored => |*x| return x.name,
|
||||
}
|
||||
}
|
||||
|
||||
pub const ExpectedToken = struct {
|
||||
token: TokenIndex,
|
||||
expected_id: std.meta.Tag(Token.Id),
|
||||
|
||||
pub fn render(self: *const ExpectedToken, tree: *Tree, stream: anytype) !void {
|
||||
const found_token = tree.tokens.at(self.token);
|
||||
if (found_token.id == .Invalid) {
|
||||
return stream.print("expected '{s}', found invalid bytes", .{self.expected_id.symbol()});
|
||||
} else {
|
||||
const token_name = found_token.id.symbol();
|
||||
return stream.print("expected '{s}', found '{s}'", .{ self.expected_id.symbol(), token_name });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const InvalidTypeSpecifier = struct {
|
||||
token: TokenIndex,
|
||||
type_spec: *Node.TypeSpec,
|
||||
|
||||
pub fn render(self: *const ExpectedToken, tree: *Tree, stream: anytype) !void {
|
||||
try stream.write("invalid type specifier '");
|
||||
try type_spec.spec.print(tree, stream);
|
||||
const token_name = tree.tokens.at(self.token).id.symbol();
|
||||
return stream.print("{s}'", .{token_name});
|
||||
}
|
||||
};
|
||||
|
||||
pub const MustUseKwToRefer = struct {
|
||||
kw: TokenIndex,
|
||||
name: TokenIndex,
|
||||
|
||||
pub fn render(self: *const ExpectedToken, tree: *Tree, stream: anytype) !void {
|
||||
return stream.print("must use '{s}' tag to refer to type '{s}'", .{ tree.slice(kw), tree.slice(name) });
|
||||
}
|
||||
};
|
||||
|
||||
fn SingleTokenError(comptime msg: []const u8) type {
|
||||
return struct {
|
||||
token: TokenIndex,
|
||||
|
||||
pub fn render(self: *const @This(), tree: *Tree, stream: anytype) !void {
|
||||
const actual_token = tree.tokens.at(self.token);
|
||||
return stream.print(msg, .{actual_token.id.symbol()});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn SimpleError(comptime msg: []const u8) type {
|
||||
return struct {
|
||||
const ThisError = @This();
|
||||
|
||||
token: TokenIndex,
|
||||
|
||||
pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: anytype) !void {
|
||||
return stream.write(msg);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Type = struct {
|
||||
pub const TypeList = ArrayList(*Type);
|
||||
|
||||
@"const": bool = false,
|
||||
atomic: bool = false,
|
||||
@"volatile": bool = false,
|
||||
restrict: bool = false,
|
||||
|
||||
id: union(enum) {
|
||||
Int: struct {
|
||||
id: Id,
|
||||
is_signed: bool,
|
||||
|
||||
pub const Id = enum {
|
||||
Char,
|
||||
Short,
|
||||
Int,
|
||||
Long,
|
||||
LongLong,
|
||||
};
|
||||
},
|
||||
Float: struct {
|
||||
id: Id,
|
||||
|
||||
pub const Id = enum {
|
||||
Float,
|
||||
Double,
|
||||
LongDouble,
|
||||
};
|
||||
},
|
||||
Pointer: *Type,
|
||||
Function: struct {
|
||||
return_type: *Type,
|
||||
param_types: TypeList,
|
||||
},
|
||||
Typedef: *Type,
|
||||
Record: *Node.RecordType,
|
||||
Enum: *Node.EnumType,
|
||||
|
||||
/// Special case for macro parameters that can be any type.
|
||||
/// Only present if `retain_macros == true`.
|
||||
Macro,
|
||||
},
|
||||
};
|
||||
|
||||
pub const Node = struct {
|
||||
id: Id,
|
||||
|
||||
pub const Id = enum {
|
||||
Root,
|
||||
EnumField,
|
||||
RecordField,
|
||||
RecordDeclarator,
|
||||
JumpStmt,
|
||||
ExprStmt,
|
||||
LabeledStmt,
|
||||
CompoundStmt,
|
||||
IfStmt,
|
||||
SwitchStmt,
|
||||
WhileStmt,
|
||||
DoStmt,
|
||||
ForStmt,
|
||||
StaticAssert,
|
||||
Declarator,
|
||||
Pointer,
|
||||
FnDecl,
|
||||
Typedef,
|
||||
VarDecl,
|
||||
};
|
||||
|
||||
pub const Root = struct {
|
||||
base: Node = Node{ .id = .Root },
|
||||
decls: DeclList,
|
||||
eof: TokenIndex,
|
||||
|
||||
pub const DeclList = ArrayList(*Node);
|
||||
};
|
||||
|
||||
pub const DeclSpec = struct {
|
||||
storage_class: union(enum) {
|
||||
Auto: TokenIndex,
|
||||
Extern: TokenIndex,
|
||||
Register: TokenIndex,
|
||||
Static: TokenIndex,
|
||||
Typedef: TokenIndex,
|
||||
None,
|
||||
} = .None,
|
||||
thread_local: ?TokenIndex = null,
|
||||
type_spec: TypeSpec = TypeSpec{},
|
||||
fn_spec: union(enum) {
|
||||
Inline: TokenIndex,
|
||||
Noreturn: TokenIndex,
|
||||
None,
|
||||
} = .None,
|
||||
align_spec: ?struct {
|
||||
alignas: TokenIndex,
|
||||
expr: *Node,
|
||||
rparen: TokenIndex,
|
||||
} = null,
|
||||
};
|
||||
|
||||
pub const TypeSpec = struct {
|
||||
qual: TypeQual = TypeQual{},
|
||||
spec: union(enum) {
|
||||
/// error or default to int
|
||||
None,
|
||||
Void: TokenIndex,
|
||||
Char: struct {
|
||||
sign: ?TokenIndex = null,
|
||||
char: TokenIndex,
|
||||
},
|
||||
Short: struct {
|
||||
sign: ?TokenIndex = null,
|
||||
short: TokenIndex = null,
|
||||
int: ?TokenIndex = null,
|
||||
},
|
||||
Int: struct {
|
||||
sign: ?TokenIndex = null,
|
||||
int: ?TokenIndex = null,
|
||||
},
|
||||
Long: struct {
|
||||
sign: ?TokenIndex = null,
|
||||
long: TokenIndex,
|
||||
longlong: ?TokenIndex = null,
|
||||
int: ?TokenIndex = null,
|
||||
},
|
||||
Float: struct {
|
||||
float: TokenIndex,
|
||||
complex: ?TokenIndex = null,
|
||||
},
|
||||
Double: struct {
|
||||
long: ?TokenIndex = null,
|
||||
double: ?TokenIndex,
|
||||
complex: ?TokenIndex = null,
|
||||
},
|
||||
Bool: TokenIndex,
|
||||
Atomic: struct {
|
||||
atomic: TokenIndex,
|
||||
typename: *Node,
|
||||
rparen: TokenIndex,
|
||||
},
|
||||
Enum: *EnumType,
|
||||
Record: *RecordType,
|
||||
Typedef: struct {
|
||||
sym: TokenIndex,
|
||||
sym_type: *Type,
|
||||
},
|
||||
|
||||
pub fn print(self: *@This(), self: *const @This(), tree: *Tree, stream: anytype) !void {
|
||||
switch (self.spec) {
|
||||
.None => unreachable,
|
||||
.Void => |index| try stream.write(tree.slice(index)),
|
||||
.Char => |char| {
|
||||
if (char.sign) |s| {
|
||||
try stream.write(tree.slice(s));
|
||||
try stream.writeByte(' ');
|
||||
}
|
||||
try stream.write(tree.slice(char.char));
|
||||
},
|
||||
.Short => |short| {
|
||||
if (short.sign) |s| {
|
||||
try stream.write(tree.slice(s));
|
||||
try stream.writeByte(' ');
|
||||
}
|
||||
try stream.write(tree.slice(short.short));
|
||||
if (short.int) |i| {
|
||||
try stream.writeByte(' ');
|
||||
try stream.write(tree.slice(i));
|
||||
}
|
||||
},
|
||||
.Int => |int| {
|
||||
if (int.sign) |s| {
|
||||
try stream.write(tree.slice(s));
|
||||
try stream.writeByte(' ');
|
||||
}
|
||||
if (int.int) |i| {
|
||||
try stream.writeByte(' ');
|
||||
try stream.write(tree.slice(i));
|
||||
}
|
||||
},
|
||||
.Long => |long| {
|
||||
if (long.sign) |s| {
|
||||
try stream.write(tree.slice(s));
|
||||
try stream.writeByte(' ');
|
||||
}
|
||||
try stream.write(tree.slice(long.long));
|
||||
if (long.longlong) |l| {
|
||||
try stream.writeByte(' ');
|
||||
try stream.write(tree.slice(l));
|
||||
}
|
||||
if (long.int) |i| {
|
||||
try stream.writeByte(' ');
|
||||
try stream.write(tree.slice(i));
|
||||
}
|
||||
},
|
||||
.Float => |float| {
|
||||
try stream.write(tree.slice(float.float));
|
||||
if (float.complex) |c| {
|
||||
try stream.writeByte(' ');
|
||||
try stream.write(tree.slice(c));
|
||||
}
|
||||
},
|
||||
.Double => |double| {
|
||||
if (double.long) |l| {
|
||||
try stream.write(tree.slice(l));
|
||||
try stream.writeByte(' ');
|
||||
}
|
||||
try stream.write(tree.slice(double.double));
|
||||
if (double.complex) |c| {
|
||||
try stream.writeByte(' ');
|
||||
try stream.write(tree.slice(c));
|
||||
}
|
||||
},
|
||||
.Bool => |index| try stream.write(tree.slice(index)),
|
||||
.Typedef => |typedef| try stream.write(tree.slice(typedef.sym)),
|
||||
else => try stream.print("TODO print {}", self.spec),
|
||||
}
|
||||
}
|
||||
} = .None,
|
||||
};
|
||||
|
||||
pub const EnumType = struct {
|
||||
tok: TokenIndex,
|
||||
name: ?TokenIndex,
|
||||
body: ?struct {
|
||||
lbrace: TokenIndex,
|
||||
|
||||
/// always EnumField
|
||||
fields: FieldList,
|
||||
rbrace: TokenIndex,
|
||||
},
|
||||
|
||||
pub const FieldList = Root.DeclList;
|
||||
};
|
||||
|
||||
pub const EnumField = struct {
|
||||
base: Node = Node{ .id = .EnumField },
|
||||
name: TokenIndex,
|
||||
value: ?*Node,
|
||||
};
|
||||
|
||||
pub const RecordType = struct {
|
||||
tok: TokenIndex,
|
||||
kind: enum {
|
||||
Struct,
|
||||
Union,
|
||||
},
|
||||
name: ?TokenIndex,
|
||||
body: ?struct {
|
||||
lbrace: TokenIndex,
|
||||
|
||||
/// RecordField or StaticAssert
|
||||
fields: FieldList,
|
||||
rbrace: TokenIndex,
|
||||
},
|
||||
|
||||
pub const FieldList = Root.DeclList;
|
||||
};
|
||||
|
||||
pub const RecordField = struct {
|
||||
base: Node = Node{ .id = .RecordField },
|
||||
type_spec: TypeSpec,
|
||||
declarators: DeclaratorList,
|
||||
semicolon: TokenIndex,
|
||||
|
||||
pub const DeclaratorList = Root.DeclList;
|
||||
};
|
||||
|
||||
pub const RecordDeclarator = struct {
|
||||
base: Node = Node{ .id = .RecordDeclarator },
|
||||
declarator: ?*Declarator,
|
||||
bit_field_expr: ?*Expr,
|
||||
};
|
||||
|
||||
pub const TypeQual = struct {
|
||||
@"const": ?TokenIndex = null,
|
||||
atomic: ?TokenIndex = null,
|
||||
@"volatile": ?TokenIndex = null,
|
||||
restrict: ?TokenIndex = null,
|
||||
};
|
||||
|
||||
pub const JumpStmt = struct {
|
||||
base: Node = Node{ .id = .JumpStmt },
|
||||
ltoken: TokenIndex,
|
||||
kind: union(enum) {
|
||||
Break,
|
||||
Continue,
|
||||
Return: ?*Node,
|
||||
Goto: TokenIndex,
|
||||
},
|
||||
semicolon: TokenIndex,
|
||||
};
|
||||
|
||||
pub const ExprStmt = struct {
|
||||
base: Node = Node{ .id = .ExprStmt },
|
||||
expr: ?*Expr,
|
||||
semicolon: TokenIndex,
|
||||
};
|
||||
|
||||
pub const LabeledStmt = struct {
|
||||
base: Node = Node{ .id = .LabeledStmt },
|
||||
kind: union(enum) {
|
||||
Label: TokenIndex,
|
||||
Case: TokenIndex,
|
||||
Default: TokenIndex,
|
||||
},
|
||||
stmt: *Node,
|
||||
};
|
||||
|
||||
pub const CompoundStmt = struct {
|
||||
base: Node = Node{ .id = .CompoundStmt },
|
||||
lbrace: TokenIndex,
|
||||
statements: StmtList,
|
||||
rbrace: TokenIndex,
|
||||
|
||||
pub const StmtList = Root.DeclList;
|
||||
};
|
||||
|
||||
pub const IfStmt = struct {
|
||||
base: Node = Node{ .id = .IfStmt },
|
||||
@"if": TokenIndex,
|
||||
cond: *Node,
|
||||
body: *Node,
|
||||
@"else": ?struct {
|
||||
tok: TokenIndex,
|
||||
body: *Node,
|
||||
},
|
||||
};
|
||||
|
||||
pub const SwitchStmt = struct {
|
||||
base: Node = Node{ .id = .SwitchStmt },
|
||||
@"switch": TokenIndex,
|
||||
expr: *Expr,
|
||||
rparen: TokenIndex,
|
||||
stmt: *Node,
|
||||
};
|
||||
|
||||
pub const WhileStmt = struct {
|
||||
base: Node = Node{ .id = .WhileStmt },
|
||||
@"while": TokenIndex,
|
||||
cond: *Expr,
|
||||
rparen: TokenIndex,
|
||||
body: *Node,
|
||||
};
|
||||
|
||||
pub const DoStmt = struct {
|
||||
base: Node = Node{ .id = .DoStmt },
|
||||
do: TokenIndex,
|
||||
body: *Node,
|
||||
@"while": TokenIndex,
|
||||
cond: *Expr,
|
||||
semicolon: TokenIndex,
|
||||
};
|
||||
|
||||
pub const ForStmt = struct {
|
||||
base: Node = Node{ .id = .ForStmt },
|
||||
@"for": TokenIndex,
|
||||
init: ?*Node,
|
||||
cond: ?*Expr,
|
||||
semicolon: TokenIndex,
|
||||
incr: ?*Expr,
|
||||
rparen: TokenIndex,
|
||||
body: *Node,
|
||||
};
|
||||
|
||||
pub const StaticAssert = struct {
|
||||
base: Node = Node{ .id = .StaticAssert },
|
||||
assert: TokenIndex,
|
||||
expr: *Node,
|
||||
semicolon: TokenIndex,
|
||||
};
|
||||
|
||||
pub const Declarator = struct {
|
||||
base: Node = Node{ .id = .Declarator },
|
||||
pointer: ?*Pointer,
|
||||
prefix: union(enum) {
|
||||
None,
|
||||
Identifer: TokenIndex,
|
||||
Complex: struct {
|
||||
lparen: TokenIndex,
|
||||
inner: *Node,
|
||||
rparen: TokenIndex,
|
||||
},
|
||||
},
|
||||
suffix: union(enum) {
|
||||
None,
|
||||
Fn: struct {
|
||||
lparen: TokenIndex,
|
||||
params: Params,
|
||||
rparen: TokenIndex,
|
||||
},
|
||||
Array: Arrays,
|
||||
},
|
||||
|
||||
pub const Arrays = ArrayList(*Array);
|
||||
pub const Params = ArrayList(*Param);
|
||||
};
|
||||
|
||||
pub const Array = struct {
|
||||
lbracket: TokenIndex,
|
||||
inner: union(enum) {
|
||||
Inferred,
|
||||
Unspecified: TokenIndex,
|
||||
Variable: struct {
|
||||
asterisk: ?TokenIndex,
|
||||
static: ?TokenIndex,
|
||||
qual: TypeQual,
|
||||
expr: *Expr,
|
||||
},
|
||||
},
|
||||
rbracket: TokenIndex,
|
||||
};
|
||||
|
||||
pub const Pointer = struct {
|
||||
base: Node = Node{ .id = .Pointer },
|
||||
asterisk: TokenIndex,
|
||||
qual: TypeQual,
|
||||
pointer: ?*Pointer,
|
||||
};
|
||||
|
||||
pub const Param = struct {
|
||||
kind: union(enum) {
|
||||
Variable,
|
||||
Old: TokenIndex,
|
||||
Normal: struct {
|
||||
decl_spec: *DeclSpec,
|
||||
declarator: *Node,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
pub const FnDecl = struct {
|
||||
base: Node = Node{ .id = .FnDecl },
|
||||
decl_spec: DeclSpec,
|
||||
declarator: *Declarator,
|
||||
old_decls: OldDeclList,
|
||||
body: ?*CompoundStmt,
|
||||
|
||||
pub const OldDeclList = ArrayList(*Node);
|
||||
};
|
||||
|
||||
pub const Typedef = struct {
|
||||
base: Node = Node{ .id = .Typedef },
|
||||
decl_spec: DeclSpec,
|
||||
declarators: DeclaratorList,
|
||||
semicolon: TokenIndex,
|
||||
|
||||
pub const DeclaratorList = Root.DeclList;
|
||||
};
|
||||
|
||||
pub const VarDecl = struct {
|
||||
base: Node = Node{ .id = .VarDecl },
|
||||
decl_spec: DeclSpec,
|
||||
initializers: Initializers,
|
||||
semicolon: TokenIndex,
|
||||
|
||||
pub const Initializers = Root.DeclList;
|
||||
};
|
||||
|
||||
pub const Initialized = struct {
|
||||
base: Node = Node{ .id = Initialized },
|
||||
declarator: *Declarator,
|
||||
eq: TokenIndex,
|
||||
init: Initializer,
|
||||
};
|
||||
|
||||
pub const Initializer = union(enum) {
|
||||
list: struct {
|
||||
initializers: List,
|
||||
rbrace: TokenIndex,
|
||||
},
|
||||
expr: *Expr,
|
||||
|
||||
pub const List = ArrayList(*Initializer);
|
||||
};
|
||||
|
||||
pub const Macro = struct {
|
||||
base: Node = Node{ .id = Macro },
|
||||
kind: union(enum) {
|
||||
Undef: []const u8,
|
||||
Fn: struct {
|
||||
params: []const []const u8,
|
||||
expr: *Expr,
|
||||
},
|
||||
Expr: *Expr,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
pub const Expr = struct {
|
||||
id: Id,
|
||||
ty: *Type,
|
||||
value: union(enum) {
|
||||
None,
|
||||
},
|
||||
|
||||
pub const Id = enum {
|
||||
Infix,
|
||||
Literal,
|
||||
};
|
||||
|
||||
pub const Infix = struct {
|
||||
base: Expr = Expr{ .id = .Infix },
|
||||
lhs: *Expr,
|
||||
op_token: TokenIndex,
|
||||
rhs: *Expr,
|
||||
};
|
||||
};
|
||||
-1434
@@ -1,1434 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2015-2021 Zig Contributors
|
||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
||||
// The MIT license requires this copyright notice to be included in all copies
|
||||
// and substantial portions of the software.
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ast = std.c.ast;
|
||||
const Node = ast.Node;
|
||||
const Type = ast.Type;
|
||||
const Tree = ast.Tree;
|
||||
const TokenIndex = ast.TokenIndex;
|
||||
const Token = std.c.Token;
|
||||
const TokenIterator = ast.Tree.TokenList.Iterator;
|
||||
|
||||
pub const Error = error{ParseError} || Allocator.Error;
|
||||
|
||||
pub const Options = struct {
|
||||
// /// Keep simple macros unexpanded and add the definitions to the ast
|
||||
// retain_macros: bool = false,
|
||||
/// Warning or error
|
||||
warn_as_err: union(enum) {
|
||||
/// All warnings are warnings
|
||||
None,
|
||||
|
||||
/// Some warnings are errors
|
||||
Some: []std.meta.Tag(ast.Error),
|
||||
|
||||
/// All warnings are errors
|
||||
All,
|
||||
} = .All,
|
||||
};
|
||||
|
||||
/// Result should be freed with tree.deinit() when there are
|
||||
/// no more references to any of the tokens or nodes.
|
||||
pub fn parse(allocator: *Allocator, source: []const u8, options: Options) !*Tree {
|
||||
const tree = blk: {
|
||||
// This block looks unnecessary, but is a "foot-shield" to prevent the SegmentedLists
|
||||
// from being initialized with a pointer to this `arena`, which is created on
|
||||
// the stack. Following code should instead refer to `&tree.arena_allocator`, a
|
||||
// pointer to data which lives safely on the heap and will outlive `parse`.
|
||||
var arena = std.heap.ArenaAllocator.init(allocator);
|
||||
errdefer arena.deinit();
|
||||
const tree = try arena.allocator.create(ast.Tree);
|
||||
tree.* = .{
|
||||
.root_node = undefined,
|
||||
.arena_allocator = arena,
|
||||
.tokens = undefined,
|
||||
.sources = undefined,
|
||||
};
|
||||
break :blk tree;
|
||||
};
|
||||
errdefer tree.deinit();
|
||||
const arena = &tree.arena_allocator.allocator;
|
||||
|
||||
tree.tokens = ast.Tree.TokenList.init(arena);
|
||||
tree.sources = ast.Tree.SourceList.init(arena);
|
||||
|
||||
var tokenizer = std.zig.Tokenizer.init(source);
|
||||
while (true) {
|
||||
const tree_token = try tree.tokens.addOne();
|
||||
tree_token.* = tokenizer.next();
|
||||
if (tree_token.id == .Eof) break;
|
||||
}
|
||||
// TODO preprocess here
|
||||
var it = tree.tokens.iterator(0);
|
||||
|
||||
while (true) {
|
||||
const tok = it.peek().?.id;
|
||||
switch (id) {
|
||||
.LineComment,
|
||||
.MultiLineComment,
|
||||
=> {
|
||||
_ = it.next();
|
||||
},
|
||||
else => break,
|
||||
}
|
||||
}
|
||||
|
||||
var parse_arena = std.heap.ArenaAllocator.init(allocator);
|
||||
defer parse_arena.deinit();
|
||||
|
||||
var parser = Parser{
|
||||
.scopes = Parser.SymbolList.init(allocator),
|
||||
.arena = &parse_arena.allocator,
|
||||
.it = &it,
|
||||
.tree = tree,
|
||||
.options = options,
|
||||
};
|
||||
defer parser.symbols.deinit();
|
||||
|
||||
tree.root_node = try parser.root();
|
||||
return tree;
|
||||
}
|
||||
|
||||
const Parser = struct {
|
||||
arena: *Allocator,
|
||||
it: *TokenIterator,
|
||||
tree: *Tree,
|
||||
|
||||
arena: *Allocator,
|
||||
scopes: ScopeList,
|
||||
options: Options,
|
||||
|
||||
const ScopeList = std.SegmentedLists(Scope);
|
||||
const SymbolList = std.SegmentedLists(Symbol);
|
||||
|
||||
const Scope = struct {
|
||||
kind: ScopeKind,
|
||||
syms: SymbolList,
|
||||
};
|
||||
|
||||
const Symbol = struct {
|
||||
name: []const u8,
|
||||
ty: *Type,
|
||||
};
|
||||
|
||||
const ScopeKind = enum {
|
||||
Block,
|
||||
Loop,
|
||||
Root,
|
||||
Switch,
|
||||
};
|
||||
|
||||
fn pushScope(parser: *Parser, kind: ScopeKind) !void {
|
||||
const new = try parser.scopes.addOne();
|
||||
new.* = .{
|
||||
.kind = kind,
|
||||
.syms = SymbolList.init(parser.arena),
|
||||
};
|
||||
}
|
||||
|
||||
fn popScope(parser: *Parser, len: usize) void {
|
||||
_ = parser.scopes.pop();
|
||||
}
|
||||
|
||||
fn getSymbol(parser: *Parser, tok: TokenIndex) ?*Symbol {
|
||||
const name = parser.tree.tokenSlice(tok);
|
||||
var scope_it = parser.scopes.iterator(parser.scopes.len);
|
||||
while (scope_it.prev()) |scope| {
|
||||
var sym_it = scope.syms.iterator(scope.syms.len);
|
||||
while (sym_it.prev()) |sym| {
|
||||
if (mem.eql(u8, sym.name, name)) {
|
||||
return sym;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
fn declareSymbol(parser: *Parser, type_spec: Node.TypeSpec, dr: *Node.Declarator) Error!void {
|
||||
return; // TODO
|
||||
}
|
||||
|
||||
/// Root <- ExternalDeclaration* eof
|
||||
fn root(parser: *Parser) Allocator.Error!*Node.Root {
|
||||
try parser.pushScope(.Root);
|
||||
defer parser.popScope();
|
||||
const node = try parser.arena.create(Node.Root);
|
||||
node.* = .{
|
||||
.decls = Node.Root.DeclList.init(parser.arena),
|
||||
.eof = undefined,
|
||||
};
|
||||
while (parser.externalDeclarations() catch |e| switch (e) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.ParseError => return node,
|
||||
}) |decl| {
|
||||
try node.decls.push(decl);
|
||||
}
|
||||
node.eof = parser.eatToken(.Eof) orelse return node;
|
||||
return node;
|
||||
}
|
||||
|
||||
/// ExternalDeclaration
|
||||
/// <- DeclSpec Declarator OldStyleDecl* CompoundStmt
|
||||
/// / Declaration
|
||||
/// OldStyleDecl <- DeclSpec Declarator (COMMA Declarator)* SEMICOLON
|
||||
fn externalDeclarations(parser: *Parser) !?*Node {
|
||||
return parser.declarationExtra(false);
|
||||
}
|
||||
|
||||
/// Declaration
|
||||
/// <- DeclSpec DeclInit SEMICOLON
|
||||
/// / StaticAssert
|
||||
/// DeclInit <- Declarator (EQUAL Initializer)? (COMMA Declarator (EQUAL Initializer)?)*
|
||||
fn declaration(parser: *Parser) !?*Node {
|
||||
return parser.declarationExtra(true);
|
||||
}
|
||||
|
||||
fn declarationExtra(parser: *Parser, local: bool) !?*Node {
|
||||
if (try parser.staticAssert()) |decl| return decl;
|
||||
const begin = parser.it.index + 1;
|
||||
var ds = Node.DeclSpec{};
|
||||
const got_ds = try parser.declSpec(&ds);
|
||||
if (local and !got_ds) {
|
||||
// not a declaration
|
||||
return null;
|
||||
}
|
||||
switch (ds.storage_class) {
|
||||
.Auto, .Register => |tok| return parser.err(.{
|
||||
.InvalidStorageClass = .{ .token = tok },
|
||||
}),
|
||||
.Typedef => {
|
||||
const node = try parser.arena.create(Node.Typedef);
|
||||
node.* = .{
|
||||
.decl_spec = ds,
|
||||
.declarators = Node.Typedef.DeclaratorList.init(parser.arena),
|
||||
.semicolon = undefined,
|
||||
};
|
||||
while (true) {
|
||||
const dr = @fieldParentPtr(Node.Declarator, "base", (try parser.declarator(.Must)) orelse return parser.err(.{
|
||||
.ExpectedDeclarator = .{ .token = parser.it.index },
|
||||
}));
|
||||
try parser.declareSymbol(ds.type_spec, dr);
|
||||
try node.declarators.push(&dr.base);
|
||||
if (parser.eatToken(.Comma)) |_| {} else break;
|
||||
}
|
||||
return &node.base;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
var first_dr = try parser.declarator(.Must);
|
||||
if (first_dr != null and declaratorIsFunction(first_dr.?)) {
|
||||
// TODO typedeffed fn proto-only
|
||||
const dr = @fieldParentPtr(Node.Declarator, "base", first_dr.?);
|
||||
try parser.declareSymbol(ds.type_spec, dr);
|
||||
var old_decls = Node.FnDecl.OldDeclList.init(parser.arena);
|
||||
const body = if (parser.eatToken(.Semicolon)) |_|
|
||||
null
|
||||
else blk: {
|
||||
if (local) {
|
||||
// TODO nested function warning
|
||||
}
|
||||
// TODO first_dr.is_old
|
||||
// while (true) {
|
||||
// var old_ds = Node.DeclSpec{};
|
||||
// if (!(try parser.declSpec(&old_ds))) {
|
||||
// // not old decl
|
||||
// break;
|
||||
// }
|
||||
// var old_dr = (try parser.declarator(.Must));
|
||||
// // if (old_dr == null)
|
||||
// // try parser.err(.{
|
||||
// // .NoParamName = .{ .token = parser.it.index },
|
||||
// // });
|
||||
// // try old_decls.push(decl);
|
||||
// }
|
||||
const body_node = (try parser.compoundStmt()) orelse return parser.err(.{
|
||||
.ExpectedFnBody = .{ .token = parser.it.index },
|
||||
});
|
||||
break :blk @fieldParentPtr(Node.CompoundStmt, "base", body_node);
|
||||
};
|
||||
|
||||
const node = try parser.arena.create(Node.FnDecl);
|
||||
node.* = .{
|
||||
.decl_spec = ds,
|
||||
.declarator = dr,
|
||||
.old_decls = old_decls,
|
||||
.body = body,
|
||||
};
|
||||
return &node.base;
|
||||
} else {
|
||||
switch (ds.fn_spec) {
|
||||
.Inline, .Noreturn => |tok| return parser.err(.{
|
||||
.FnSpecOnNonFn = .{ .token = tok },
|
||||
}),
|
||||
else => {},
|
||||
}
|
||||
// TODO threadlocal without static or extern on local variable
|
||||
const node = try parser.arena.create(Node.VarDecl);
|
||||
node.* = .{
|
||||
.decl_spec = ds,
|
||||
.initializers = Node.VarDecl.Initializers.init(parser.arena),
|
||||
.semicolon = undefined,
|
||||
};
|
||||
if (first_dr == null) {
|
||||
node.semicolon = try parser.expectToken(.Semicolon);
|
||||
const ok = switch (ds.type_spec.spec) {
|
||||
.Enum => |e| e.name != null,
|
||||
.Record => |r| r.name != null,
|
||||
else => false,
|
||||
};
|
||||
const q = ds.type_spec.qual;
|
||||
if (!ok)
|
||||
try parser.warn(.{
|
||||
.NothingDeclared = .{ .token = begin },
|
||||
})
|
||||
else if (q.@"const" orelse q.atomic orelse q.@"volatile" orelse q.restrict) |tok|
|
||||
try parser.warn(.{
|
||||
.QualifierIgnored = .{ .token = tok },
|
||||
});
|
||||
return &node.base;
|
||||
}
|
||||
var dr = @fieldParentPtr(Node.Declarator, "base", first_dr.?);
|
||||
while (true) {
|
||||
try parser.declareSymbol(ds.type_spec, dr);
|
||||
if (parser.eatToken(.Equal)) |tok| {
|
||||
try node.initializers.push((try parser.initializer(dr)) orelse return parser.err(.{
|
||||
.ExpectedInitializer = .{ .token = parser.it.index },
|
||||
}));
|
||||
} else try node.initializers.push(&dr.base);
|
||||
if (parser.eatToken(.Comma) != null) break;
|
||||
dr = @fieldParentPtr(Node.Declarator, "base", (try parser.declarator(.Must)) orelse return parser.err(.{
|
||||
.ExpectedDeclarator = .{ .token = parser.it.index },
|
||||
}));
|
||||
}
|
||||
node.semicolon = try parser.expectToken(.Semicolon);
|
||||
return &node.base;
|
||||
}
|
||||
}
|
||||
|
||||
fn declaratorIsFunction(node: *Node) bool {
|
||||
if (node.id != .Declarator) return false;
|
||||
assert(node.id == .Declarator);
|
||||
const dr = @fieldParentPtr(Node.Declarator, "base", node);
|
||||
if (dr.suffix != .Fn) return false;
|
||||
switch (dr.prefix) {
|
||||
.None, .Identifer => return true,
|
||||
.Complex => |inner| {
|
||||
var inner_node = inner.inner;
|
||||
while (true) {
|
||||
if (inner_node.id != .Declarator) return false;
|
||||
assert(inner_node.id == .Declarator);
|
||||
const inner_dr = @fieldParentPtr(Node.Declarator, "base", inner_node);
|
||||
if (inner_dr.pointer != null) return false;
|
||||
switch (inner_dr.prefix) {
|
||||
.None, .Identifer => return true,
|
||||
.Complex => |c| inner_node = c.inner,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// StaticAssert <- Keyword_static_assert LPAREN ConstExpr COMMA STRINGLITERAL RPAREN SEMICOLON
|
||||
fn staticAssert(parser: *Parser) !?*Node {
|
||||
const tok = parser.eatToken(.Keyword_static_assert) orelse return null;
|
||||
_ = try parser.expectToken(.LParen);
|
||||
const const_expr = (try parser.constExpr()) orelse parser.err(.{
|
||||
.ExpectedExpr = .{ .token = parser.it.index },
|
||||
});
|
||||
_ = try parser.expectToken(.Comma);
|
||||
const str = try parser.expectToken(.StringLiteral);
|
||||
_ = try parser.expectToken(.RParen);
|
||||
const node = try parser.arena.create(Node.StaticAssert);
|
||||
node.* = .{
|
||||
.assert = tok,
|
||||
.expr = const_expr,
|
||||
.semicolon = try parser.expectToken(.Semicolon),
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
/// DeclSpec <- (StorageClassSpec / TypeSpec / FnSpec / AlignSpec)*
|
||||
/// returns true if any tokens were consumed
|
||||
fn declSpec(parser: *Parser, ds: *Node.DeclSpec) !bool {
|
||||
var got = false;
|
||||
while ((try parser.storageClassSpec(ds)) or (try parser.typeSpec(&ds.type_spec)) or (try parser.fnSpec(ds)) or (try parser.alignSpec(ds))) {
|
||||
got = true;
|
||||
}
|
||||
return got;
|
||||
}
|
||||
|
||||
/// StorageClassSpec
|
||||
/// <- Keyword_typedef / Keyword_extern / Keyword_static / Keyword_thread_local / Keyword_auto / Keyword_register
|
||||
fn storageClassSpec(parser: *Parser, ds: *Node.DeclSpec) !bool {
|
||||
blk: {
|
||||
if (parser.eatToken(.Keyword_typedef)) |tok| {
|
||||
if (ds.storage_class != .None or ds.thread_local != null)
|
||||
break :blk;
|
||||
ds.storage_class = .{ .Typedef = tok };
|
||||
} else if (parser.eatToken(.Keyword_extern)) |tok| {
|
||||
if (ds.storage_class != .None)
|
||||
break :blk;
|
||||
ds.storage_class = .{ .Extern = tok };
|
||||
} else if (parser.eatToken(.Keyword_static)) |tok| {
|
||||
if (ds.storage_class != .None)
|
||||
break :blk;
|
||||
ds.storage_class = .{ .Static = tok };
|
||||
} else if (parser.eatToken(.Keyword_thread_local)) |tok| {
|
||||
switch (ds.storage_class) {
|
||||
.None, .Extern, .Static => {},
|
||||
else => break :blk,
|
||||
}
|
||||
ds.thread_local = tok;
|
||||
} else if (parser.eatToken(.Keyword_auto)) |tok| {
|
||||
if (ds.storage_class != .None or ds.thread_local != null)
|
||||
break :blk;
|
||||
ds.storage_class = .{ .Auto = tok };
|
||||
} else if (parser.eatToken(.Keyword_register)) |tok| {
|
||||
if (ds.storage_class != .None or ds.thread_local != null)
|
||||
break :blk;
|
||||
ds.storage_class = .{ .Register = tok };
|
||||
} else return false;
|
||||
return true;
|
||||
}
|
||||
try parser.warn(.{
|
||||
.DuplicateSpecifier = .{ .token = parser.it.index },
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/// TypeSpec
|
||||
/// <- Keyword_void / Keyword_char / Keyword_short / Keyword_int / Keyword_long / Keyword_float / Keyword_double
|
||||
/// / Keyword_signed / Keyword_unsigned / Keyword_bool / Keyword_complex / Keyword_imaginary /
|
||||
/// / Keyword_atomic LPAREN TypeName RPAREN
|
||||
/// / EnumSpec
|
||||
/// / RecordSpec
|
||||
/// / IDENTIFIER // typedef name
|
||||
/// / TypeQual
|
||||
fn typeSpec(parser: *Parser, type_spec: *Node.TypeSpec) !bool {
|
||||
blk: {
|
||||
if (parser.eatToken(.Keyword_void)) |tok| {
|
||||
if (type_spec.spec != .None)
|
||||
break :blk;
|
||||
type_spec.spec = .{ .Void = tok };
|
||||
} else if (parser.eatToken(.Keyword_char)) |tok| {
|
||||
switch (type_spec.spec) {
|
||||
.None => {
|
||||
type_spec.spec = .{
|
||||
.Char = .{
|
||||
.char = tok,
|
||||
},
|
||||
};
|
||||
},
|
||||
.Int => |int| {
|
||||
if (int.int != null)
|
||||
break :blk;
|
||||
type_spec.spec = .{
|
||||
.Char = .{
|
||||
.char = tok,
|
||||
.sign = int.sign,
|
||||
},
|
||||
};
|
||||
},
|
||||
else => break :blk,
|
||||
}
|
||||
} else if (parser.eatToken(.Keyword_short)) |tok| {
|
||||
switch (type_spec.spec) {
|
||||
.None => {
|
||||
type_spec.spec = .{
|
||||
.Short = .{
|
||||
.short = tok,
|
||||
},
|
||||
};
|
||||
},
|
||||
.Int => |int| {
|
||||
if (int.int != null)
|
||||
break :blk;
|
||||
type_spec.spec = .{
|
||||
.Short = .{
|
||||
.short = tok,
|
||||
.sign = int.sign,
|
||||
},
|
||||
};
|
||||
},
|
||||
else => break :blk,
|
||||
}
|
||||
} else if (parser.eatToken(.Keyword_long)) |tok| {
|
||||
switch (type_spec.spec) {
|
||||
.None => {
|
||||
type_spec.spec = .{
|
||||
.Long = .{
|
||||
.long = tok,
|
||||
},
|
||||
};
|
||||
},
|
||||
.Int => |int| {
|
||||
type_spec.spec = .{
|
||||
.Long = .{
|
||||
.long = tok,
|
||||
.sign = int.sign,
|
||||
.int = int.int,
|
||||
},
|
||||
};
|
||||
},
|
||||
.Long => |*long| {
|
||||
if (long.longlong != null)
|
||||
break :blk;
|
||||
long.longlong = tok;
|
||||
},
|
||||
.Double => |*double| {
|
||||
if (double.long != null)
|
||||
break :blk;
|
||||
double.long = tok;
|
||||
},
|
||||
else => break :blk,
|
||||
}
|
||||
} else if (parser.eatToken(.Keyword_int)) |tok| {
|
||||
switch (type_spec.spec) {
|
||||
.None => {
|
||||
type_spec.spec = .{
|
||||
.Int = .{
|
||||
.int = tok,
|
||||
},
|
||||
};
|
||||
},
|
||||
.Short => |*short| {
|
||||
if (short.int != null)
|
||||
break :blk;
|
||||
short.int = tok;
|
||||
},
|
||||
.Int => |*int| {
|
||||
if (int.int != null)
|
||||
break :blk;
|
||||
int.int = tok;
|
||||
},
|
||||
.Long => |*long| {
|
||||
if (long.int != null)
|
||||
break :blk;
|
||||
long.int = tok;
|
||||
},
|
||||
else => break :blk,
|
||||
}
|
||||
} else if (parser.eatToken(.Keyword_signed) orelse parser.eatToken(.Keyword_unsigned)) |tok| {
|
||||
switch (type_spec.spec) {
|
||||
.None => {
|
||||
type_spec.spec = .{
|
||||
.Int = .{
|
||||
.sign = tok,
|
||||
},
|
||||
};
|
||||
},
|
||||
.Char => |*char| {
|
||||
if (char.sign != null)
|
||||
break :blk;
|
||||
char.sign = tok;
|
||||
},
|
||||
.Short => |*short| {
|
||||
if (short.sign != null)
|
||||
break :blk;
|
||||
short.sign = tok;
|
||||
},
|
||||
.Int => |*int| {
|
||||
if (int.sign != null)
|
||||
break :blk;
|
||||
int.sign = tok;
|
||||
},
|
||||
.Long => |*long| {
|
||||
if (long.sign != null)
|
||||
break :blk;
|
||||
long.sign = tok;
|
||||
},
|
||||
else => break :blk,
|
||||
}
|
||||
} else if (parser.eatToken(.Keyword_float)) |tok| {
|
||||
if (type_spec.spec != .None)
|
||||
break :blk;
|
||||
type_spec.spec = .{
|
||||
.Float = .{
|
||||
.float = tok,
|
||||
},
|
||||
};
|
||||
} else if (parser.eatToken(.Keyword_double)) |tok| {
|
||||
if (type_spec.spec != .None)
|
||||
break :blk;
|
||||
type_spec.spec = .{
|
||||
.Double = .{
|
||||
.double = tok,
|
||||
},
|
||||
};
|
||||
} else if (parser.eatToken(.Keyword_complex)) |tok| {
|
||||
switch (type_spec.spec) {
|
||||
.None => {
|
||||
type_spec.spec = .{
|
||||
.Double = .{
|
||||
.complex = tok,
|
||||
.double = null,
|
||||
},
|
||||
};
|
||||
},
|
||||
.Float => |*float| {
|
||||
if (float.complex != null)
|
||||
break :blk;
|
||||
float.complex = tok;
|
||||
},
|
||||
.Double => |*double| {
|
||||
if (double.complex != null)
|
||||
break :blk;
|
||||
double.complex = tok;
|
||||
},
|
||||
else => break :blk,
|
||||
}
|
||||
} else if (parser.eatToken(.Keyword_bool)) |tok| {
|
||||
if (type_spec.spec != .None)
|
||||
break :blk;
|
||||
type_spec.spec = .{ .Bool = tok };
|
||||
} else if (parser.eatToken(.Keyword_atomic)) |tok| {
|
||||
// might be _Atomic qualifier
|
||||
if (parser.eatToken(.LParen)) |_| {
|
||||
if (type_spec.spec != .None)
|
||||
break :blk;
|
||||
const name = (try parser.typeName()) orelse return parser.err(.{
|
||||
.ExpectedTypeName = .{ .token = parser.it.index },
|
||||
});
|
||||
type_spec.spec.Atomic = .{
|
||||
.atomic = tok,
|
||||
.typename = name,
|
||||
.rparen = try parser.expectToken(.RParen),
|
||||
};
|
||||
} else {
|
||||
parser.putBackToken(tok);
|
||||
}
|
||||
} else if (parser.eatToken(.Keyword_enum)) |tok| {
|
||||
if (type_spec.spec != .None)
|
||||
break :blk;
|
||||
type_spec.spec.Enum = try parser.enumSpec(tok);
|
||||
} else if (parser.eatToken(.Keyword_union) orelse parser.eatToken(.Keyword_struct)) |tok| {
|
||||
if (type_spec.spec != .None)
|
||||
break :blk;
|
||||
type_spec.spec.Record = try parser.recordSpec(tok);
|
||||
} else if (parser.eatToken(.Identifier)) |tok| {
|
||||
const ty = parser.getSymbol(tok) orelse {
|
||||
parser.putBackToken(tok);
|
||||
return false;
|
||||
};
|
||||
switch (ty.id) {
|
||||
.Enum => |e| inner: {
|
||||
if (e.name) |some|
|
||||
if (!parser.tree.tokenEql(some, tok))
|
||||
break :inner;
|
||||
return parser.err(.{
|
||||
.MustUseKwToRefer = .{ .kw = e.tok, .name = tok },
|
||||
});
|
||||
},
|
||||
.Record => |r| inner: {
|
||||
if (r.name) |some|
|
||||
if (!parser.tree.tokenEql(some, tok))
|
||||
break :inner;
|
||||
return parser.err(.{
|
||||
.MustUseKwToRefer = .{
|
||||
.kw = r.tok,
|
||||
.name = tok,
|
||||
},
|
||||
});
|
||||
},
|
||||
.Typedef => {
|
||||
type_spec.spec = .{
|
||||
.Typedef = .{
|
||||
.sym = tok,
|
||||
.sym_type = ty,
|
||||
},
|
||||
};
|
||||
return true;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
parser.putBackToken(tok);
|
||||
return false;
|
||||
}
|
||||
return parser.typeQual(&type_spec.qual);
|
||||
}
|
||||
return parser.err(.{
|
||||
.InvalidTypeSpecifier = .{
|
||||
.token = parser.it.index,
|
||||
.type_spec = type_spec,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/// TypeQual <- Keyword_const / Keyword_restrict / Keyword_volatile / Keyword_atomic
|
||||
fn typeQual(parser: *Parser, qual: *Node.TypeQual) !bool {
|
||||
blk: {
|
||||
if (parser.eatToken(.Keyword_const)) |tok| {
|
||||
if (qual.@"const" != null)
|
||||
break :blk;
|
||||
qual.@"const" = tok;
|
||||
} else if (parser.eatToken(.Keyword_restrict)) |tok| {
|
||||
if (qual.atomic != null)
|
||||
break :blk;
|
||||
qual.atomic = tok;
|
||||
} else if (parser.eatToken(.Keyword_volatile)) |tok| {
|
||||
if (qual.@"volatile" != null)
|
||||
break :blk;
|
||||
qual.@"volatile" = tok;
|
||||
} else if (parser.eatToken(.Keyword_atomic)) |tok| {
|
||||
if (qual.atomic != null)
|
||||
break :blk;
|
||||
qual.atomic = tok;
|
||||
} else return false;
|
||||
return true;
|
||||
}
|
||||
try parser.warn(.{
|
||||
.DuplicateQualifier = .{ .token = parser.it.index },
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/// FnSpec <- Keyword_inline / Keyword_noreturn
|
||||
fn fnSpec(parser: *Parser, ds: *Node.DeclSpec) !bool {
|
||||
blk: {
|
||||
if (parser.eatToken(.Keyword_inline)) |tok| {
|
||||
if (ds.fn_spec != .None)
|
||||
break :blk;
|
||||
ds.fn_spec = .{ .Inline = tok };
|
||||
} else if (parser.eatToken(.Keyword_noreturn)) |tok| {
|
||||
if (ds.fn_spec != .None)
|
||||
break :blk;
|
||||
ds.fn_spec = .{ .Noreturn = tok };
|
||||
} else return false;
|
||||
return true;
|
||||
}
|
||||
try parser.warn(.{
|
||||
.DuplicateSpecifier = .{ .token = parser.it.index },
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/// AlignSpec <- Keyword_alignas LPAREN (TypeName / ConstExpr) RPAREN
|
||||
fn alignSpec(parser: *Parser, ds: *Node.DeclSpec) !bool {
|
||||
if (parser.eatToken(.Keyword_alignas)) |tok| {
|
||||
_ = try parser.expectToken(.LParen);
|
||||
const node = (try parser.typeName()) orelse (try parser.constExpr()) orelse parser.err(.{
|
||||
.ExpectedExpr = .{ .token = parser.it.index },
|
||||
});
|
||||
if (ds.align_spec != null) {
|
||||
try parser.warn(.{
|
||||
.DuplicateSpecifier = .{ .token = parser.it.index },
|
||||
});
|
||||
}
|
||||
ds.align_spec = .{
|
||||
.alignas = tok,
|
||||
.expr = node,
|
||||
.rparen = try parser.expectToken(.RParen),
|
||||
};
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// EnumSpec <- Keyword_enum IDENTIFIER? (LBRACE EnumField RBRACE)?
|
||||
fn enumSpec(parser: *Parser, tok: TokenIndex) !*Node.EnumType {
|
||||
const node = try parser.arena.create(Node.EnumType);
|
||||
const name = parser.eatToken(.Identifier);
|
||||
node.* = .{
|
||||
.tok = tok,
|
||||
.name = name,
|
||||
.body = null,
|
||||
};
|
||||
const ty = try parser.arena.create(Type);
|
||||
ty.* = .{
|
||||
.id = .{
|
||||
.Enum = node,
|
||||
},
|
||||
};
|
||||
if (name) |some|
|
||||
try parser.symbols.append(.{
|
||||
.name = parser.tree.tokenSlice(some),
|
||||
.ty = ty,
|
||||
});
|
||||
if (parser.eatToken(.LBrace)) |lbrace| {
|
||||
var fields = Node.EnumType.FieldList.init(parser.arena);
|
||||
try fields.push((try parser.enumField()) orelse return parser.err(.{
|
||||
.ExpectedEnumField = .{ .token = parser.it.index },
|
||||
}));
|
||||
while (parser.eatToken(.Comma)) |_| {
|
||||
try fields.push((try parser.enumField()) orelse break);
|
||||
}
|
||||
node.body = .{
|
||||
.lbrace = lbrace,
|
||||
.fields = fields,
|
||||
.rbrace = try parser.expectToken(.RBrace),
|
||||
};
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/// EnumField <- IDENTIFIER (EQUAL ConstExpr)? (COMMA EnumField) COMMA?
|
||||
fn enumField(parser: *Parser) !?*Node {
|
||||
const name = parser.eatToken(.Identifier) orelse return null;
|
||||
const node = try parser.arena.create(Node.EnumField);
|
||||
node.* = .{
|
||||
.name = name,
|
||||
.value = null,
|
||||
};
|
||||
if (parser.eatToken(.Equal)) |eq| {
|
||||
node.value = (try parser.constExpr()) orelse parser.err(.{
|
||||
.ExpectedExpr = .{ .token = parser.it.index },
|
||||
});
|
||||
}
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
/// RecordSpec <- (Keyword_struct / Keyword_union) IDENTIFIER? (LBRACE RecordField+ RBRACE)?
|
||||
fn recordSpec(parser: *Parser, tok: TokenIndex) !*Node.RecordType {
|
||||
const node = try parser.arena.create(Node.RecordType);
|
||||
const name = parser.eatToken(.Identifier);
|
||||
const is_struct = parser.tree.tokenSlice(tok)[0] == 's';
|
||||
node.* = .{
|
||||
.tok = tok,
|
||||
.kind = if (is_struct) .Struct else .Union,
|
||||
.name = name,
|
||||
.body = null,
|
||||
};
|
||||
const ty = try parser.arena.create(Type);
|
||||
ty.* = .{
|
||||
.id = .{
|
||||
.Record = node,
|
||||
},
|
||||
};
|
||||
if (name) |some|
|
||||
try parser.symbols.append(.{
|
||||
.name = parser.tree.tokenSlice(some),
|
||||
.ty = ty,
|
||||
});
|
||||
if (parser.eatToken(.LBrace)) |lbrace| {
|
||||
try parser.pushScope(.Block);
|
||||
defer parser.popScope();
|
||||
var fields = Node.RecordType.FieldList.init(parser.arena);
|
||||
while (true) {
|
||||
if (parser.eatToken(.RBrace)) |rbrace| {
|
||||
node.body = .{
|
||||
.lbrace = lbrace,
|
||||
.fields = fields,
|
||||
.rbrace = rbrace,
|
||||
};
|
||||
break;
|
||||
}
|
||||
try fields.push(try parser.recordField());
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/// RecordField
|
||||
/// <- TypeSpec* (RecordDeclarator (COMMA RecordDeclarator))? SEMICOLON
|
||||
/// \ StaticAssert
|
||||
fn recordField(parser: *Parser) Error!*Node {
|
||||
if (try parser.staticAssert()) |decl| return decl;
|
||||
var got = false;
|
||||
var type_spec = Node.TypeSpec{};
|
||||
while (try parser.typeSpec(&type_spec)) got = true;
|
||||
if (!got)
|
||||
return parser.err(.{
|
||||
.ExpectedType = .{ .token = parser.it.index },
|
||||
});
|
||||
const node = try parser.arena.create(Node.RecordField);
|
||||
node.* = .{
|
||||
.type_spec = type_spec,
|
||||
.declarators = Node.RecordField.DeclaratorList.init(parser.arena),
|
||||
.semicolon = undefined,
|
||||
};
|
||||
while (true) {
|
||||
const rdr = try parser.recordDeclarator();
|
||||
try parser.declareSymbol(type_spec, rdr.declarator);
|
||||
try node.declarators.push(&rdr.base);
|
||||
if (parser.eatToken(.Comma)) |_| {} else break;
|
||||
}
|
||||
|
||||
node.semicolon = try parser.expectToken(.Semicolon);
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
/// TypeName <- TypeSpec* AbstractDeclarator?
|
||||
fn typeName(parser: *Parser) Error!?*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// RecordDeclarator <- Declarator? (COLON ConstExpr)?
|
||||
fn recordDeclarator(parser: *Parser) Error!*Node.RecordDeclarator {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// Pointer <- ASTERISK TypeQual* Pointer?
|
||||
fn pointer(parser: *Parser) Error!?*Node.Pointer {
|
||||
const asterisk = parser.eatToken(.Asterisk) orelse return null;
|
||||
const node = try parser.arena.create(Node.Pointer);
|
||||
node.* = .{
|
||||
.asterisk = asterisk,
|
||||
.qual = .{},
|
||||
.pointer = null,
|
||||
};
|
||||
while (try parser.typeQual(&node.qual)) {}
|
||||
node.pointer = try parser.pointer();
|
||||
return node;
|
||||
}
|
||||
|
||||
const Named = enum {
|
||||
Must,
|
||||
Allowed,
|
||||
Forbidden,
|
||||
};
|
||||
|
||||
/// Declarator <- Pointer? DeclaratorSuffix
|
||||
/// DeclaratorPrefix
|
||||
/// <- IDENTIFIER // if named != .Forbidden
|
||||
/// / LPAREN Declarator RPAREN
|
||||
/// / (none) // if named != .Must
|
||||
/// DeclaratorSuffix
|
||||
/// <- DeclaratorPrefix (LBRACKET ArrayDeclarator? RBRACKET)*
|
||||
/// / DeclaratorPrefix LPAREN (ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)?)? RPAREN
|
||||
fn declarator(parser: *Parser, named: Named) Error!?*Node {
|
||||
const ptr = try parser.pointer();
|
||||
var node: *Node.Declarator = undefined;
|
||||
var inner_fn = false;
|
||||
|
||||
// TODO sizof(int (int))
|
||||
// prefix
|
||||
if (parser.eatToken(.LParen)) |lparen| {
|
||||
const inner = (try parser.declarator(named)) orelse return parser.err(.{
|
||||
.ExpectedDeclarator = .{ .token = lparen + 1 },
|
||||
});
|
||||
inner_fn = declaratorIsFunction(inner);
|
||||
node = try parser.arena.create(Node.Declarator);
|
||||
node.* = .{
|
||||
.pointer = ptr,
|
||||
.prefix = .{
|
||||
.Complex = .{
|
||||
.lparen = lparen,
|
||||
.inner = inner,
|
||||
.rparen = try parser.expectToken(.RParen),
|
||||
},
|
||||
},
|
||||
.suffix = .None,
|
||||
};
|
||||
} else if (named != .Forbidden) {
|
||||
if (parser.eatToken(.Identifier)) |tok| {
|
||||
node = try parser.arena.create(Node.Declarator);
|
||||
node.* = .{
|
||||
.pointer = ptr,
|
||||
.prefix = .{ .Identifer = tok },
|
||||
.suffix = .None,
|
||||
};
|
||||
} else if (named == .Must) {
|
||||
return parser.err(.{
|
||||
.ExpectedToken = .{ .token = parser.it.index, .expected_id = .Identifier },
|
||||
});
|
||||
} else {
|
||||
if (ptr) |some|
|
||||
return &some.base;
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
node = try parser.arena.create(Node.Declarator);
|
||||
node.* = .{
|
||||
.pointer = ptr,
|
||||
.prefix = .None,
|
||||
.suffix = .None,
|
||||
};
|
||||
}
|
||||
// suffix
|
||||
if (parser.eatToken(.LParen)) |lparen| {
|
||||
if (inner_fn)
|
||||
return parser.err(.{
|
||||
.InvalidDeclarator = .{ .token = lparen },
|
||||
});
|
||||
node.suffix = .{
|
||||
.Fn = .{
|
||||
.lparen = lparen,
|
||||
.params = Node.Declarator.Params.init(parser.arena),
|
||||
.rparen = undefined,
|
||||
},
|
||||
};
|
||||
try parser.paramDecl(node);
|
||||
node.suffix.Fn.rparen = try parser.expectToken(.RParen);
|
||||
} else if (parser.eatToken(.LBracket)) |tok| {
|
||||
if (inner_fn)
|
||||
return parser.err(.{
|
||||
.InvalidDeclarator = .{ .token = tok },
|
||||
});
|
||||
node.suffix = .{ .Array = Node.Declarator.Arrays.init(parser.arena) };
|
||||
var lbrace = tok;
|
||||
while (true) {
|
||||
try node.suffix.Array.push(try parser.arrayDeclarator(lbrace));
|
||||
if (parser.eatToken(.LBracket)) |t| lbrace = t else break;
|
||||
}
|
||||
}
|
||||
if (parser.eatToken(.LParen) orelse parser.eatToken(.LBracket)) |tok|
|
||||
return parser.err(.{
|
||||
.InvalidDeclarator = .{ .token = tok },
|
||||
});
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
/// ArrayDeclarator
|
||||
/// <- ASTERISK
|
||||
/// / Keyword_static TypeQual* AssignmentExpr
|
||||
/// / TypeQual+ (ASTERISK / Keyword_static AssignmentExpr)
|
||||
/// / TypeQual+ AssignmentExpr?
|
||||
/// / AssignmentExpr
|
||||
fn arrayDeclarator(parser: *Parser, lbracket: TokenIndex) !*Node.Array {
|
||||
const arr = try parser.arena.create(Node.Array);
|
||||
arr.* = .{
|
||||
.lbracket = lbracket,
|
||||
.inner = .Inferred,
|
||||
.rbracket = undefined,
|
||||
};
|
||||
if (parser.eatToken(.Asterisk)) |tok| {
|
||||
arr.inner = .{ .Unspecified = tok };
|
||||
} else {
|
||||
// TODO
|
||||
}
|
||||
arr.rbracket = try parser.expectToken(.RBracket);
|
||||
return arr;
|
||||
}
|
||||
|
||||
/// Params <- ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)?
|
||||
/// ParamDecl <- DeclSpec (Declarator / AbstractDeclarator)
|
||||
fn paramDecl(parser: *Parser, dr: *Node.Declarator) !void {
|
||||
var old_style = false;
|
||||
while (true) {
|
||||
var ds = Node.DeclSpec{};
|
||||
if (try parser.declSpec(&ds)) {
|
||||
//TODO
|
||||
// TODO try parser.declareSymbol(ds.type_spec, dr);
|
||||
} else if (parser.eatToken(.Identifier)) |tok| {
|
||||
old_style = true;
|
||||
} else if (parser.eatToken(.Ellipsis)) |tok| {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Expr <- AssignmentExpr (COMMA Expr)*
|
||||
fn expr(parser: *Parser) Error!?*Expr {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// AssignmentExpr
|
||||
/// <- ConditionalExpr // TODO recursive?
|
||||
/// / UnaryExpr (EQUAL / ASTERISKEQUAL / SLASHEQUAL / PERCENTEQUAL / PLUSEQUAL / MINUSEQUA /
|
||||
/// / ANGLEBRACKETANGLEBRACKETLEFTEQUAL / ANGLEBRACKETANGLEBRACKETRIGHTEQUAL /
|
||||
/// / AMPERSANDEQUAL / CARETEQUAL / PIPEEQUAL) AssignmentExpr
|
||||
fn assignmentExpr(parser: *Parser) !?*Expr {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// ConstExpr <- ConditionalExpr
|
||||
fn constExpr(parser: *Parser) Error!?*Expr {
|
||||
const start = parser.it.index;
|
||||
const expression = try parser.conditionalExpr();
|
||||
if (expression != null and expression.?.value == .None)
|
||||
return parser.err(.{
|
||||
.ConsExpr = start,
|
||||
});
|
||||
return expression;
|
||||
}
|
||||
|
||||
/// ConditionalExpr <- LogicalOrExpr (QUESTIONMARK Expr COLON ConditionalExpr)?
|
||||
fn conditionalExpr(parser: *Parser) Error!?*Expr {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// LogicalOrExpr <- LogicalAndExpr (PIPEPIPE LogicalOrExpr)*
|
||||
fn logicalOrExpr(parser: *Parser) !*Node {
|
||||
const lhs = (try parser.logicalAndExpr()) orelse return null;
|
||||
}
|
||||
|
||||
/// LogicalAndExpr <- BinOrExpr (AMPERSANDAMPERSAND LogicalAndExpr)*
|
||||
fn logicalAndExpr(parser: *Parser) !*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// BinOrExpr <- BinXorExpr (PIPE BinOrExpr)*
|
||||
fn binOrExpr(parser: *Parser) !*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// BinXorExpr <- BinAndExpr (CARET BinXorExpr)*
|
||||
fn binXorExpr(parser: *Parser) !*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// BinAndExpr <- EqualityExpr (AMPERSAND BinAndExpr)*
|
||||
fn binAndExpr(parser: *Parser) !*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// EqualityExpr <- ComparisionExpr ((EQUALEQUAL / BANGEQUAL) EqualityExpr)*
|
||||
fn equalityExpr(parser: *Parser) !*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// ComparisionExpr <- ShiftExpr (ANGLEBRACKETLEFT / ANGLEBRACKETLEFTEQUAL /ANGLEBRACKETRIGHT / ANGLEBRACKETRIGHTEQUAL) ComparisionExpr)*
|
||||
fn comparisionExpr(parser: *Parser) !*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// ShiftExpr <- AdditiveExpr (ANGLEBRACKETANGLEBRACKETLEFT / ANGLEBRACKETANGLEBRACKETRIGHT) ShiftExpr)*
|
||||
fn shiftExpr(parser: *Parser) !*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// AdditiveExpr <- MultiplicativeExpr (PLUS / MINUS) AdditiveExpr)*
|
||||
fn additiveExpr(parser: *Parser) !*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// MultiplicativeExpr <- UnaryExpr (ASTERISK / SLASH / PERCENT) MultiplicativeExpr)*
|
||||
fn multiplicativeExpr(parser: *Parser) !*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// UnaryExpr
|
||||
/// <- LPAREN TypeName RPAREN UnaryExpr
|
||||
/// / Keyword_sizeof LAPERN TypeName RPAREN
|
||||
/// / Keyword_sizeof UnaryExpr
|
||||
/// / Keyword_alignof LAPERN TypeName RPAREN
|
||||
/// / (AMPERSAND / ASTERISK / PLUS / PLUSPLUS / MINUS / MINUSMINUS / TILDE / BANG) UnaryExpr
|
||||
/// / PrimaryExpr PostFixExpr*
|
||||
fn unaryExpr(parser: *Parser) !*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// PrimaryExpr
|
||||
/// <- IDENTIFIER
|
||||
/// / INTEGERLITERAL / FLOATLITERAL / STRINGLITERAL / CHARLITERAL
|
||||
/// / LPAREN Expr RPAREN
|
||||
/// / Keyword_generic LPAREN AssignmentExpr (COMMA Generic)+ RPAREN
|
||||
fn primaryExpr(parser: *Parser) !*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// Generic
|
||||
/// <- TypeName COLON AssignmentExpr
|
||||
/// / Keyword_default COLON AssignmentExpr
|
||||
fn generic(parser: *Parser) !*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// PostFixExpr
|
||||
/// <- LPAREN TypeName RPAREN LBRACE Initializers RBRACE
|
||||
/// / LBRACKET Expr RBRACKET
|
||||
/// / LPAREN (AssignmentExpr (COMMA AssignmentExpr)*)? RPAREN
|
||||
/// / (PERIOD / ARROW) IDENTIFIER
|
||||
/// / (PLUSPLUS / MINUSMINUS)
|
||||
fn postFixExpr(parser: *Parser) !*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// Initializers <- ((Designator+ EQUAL)? Initializer COMMA)* (Designator+ EQUAL)? Initializer COMMA?
|
||||
fn initializers(parser: *Parser) !*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// Initializer
|
||||
/// <- LBRACE Initializers RBRACE
|
||||
/// / AssignmentExpr
|
||||
fn initializer(parser: *Parser, dr: *Node.Declarator) Error!?*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// Designator
|
||||
/// <- LBRACKET ConstExpr RBRACKET
|
||||
/// / PERIOD IDENTIFIER
|
||||
fn designator(parser: *Parser) !*Node {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
/// CompoundStmt <- LBRACE (Declaration / Stmt)* RBRACE
|
||||
fn compoundStmt(parser: *Parser) Error!?*Node {
|
||||
const lbrace = parser.eatToken(.LBrace) orelse return null;
|
||||
try parser.pushScope(.Block);
|
||||
defer parser.popScope();
|
||||
const body_node = try parser.arena.create(Node.CompoundStmt);
|
||||
body_node.* = .{
|
||||
.lbrace = lbrace,
|
||||
.statements = Node.CompoundStmt.StmtList.init(parser.arena),
|
||||
.rbrace = undefined,
|
||||
};
|
||||
while (true) {
|
||||
if (parser.eatToken(.RBRACE)) |rbrace| {
|
||||
body_node.rbrace = rbrace;
|
||||
break;
|
||||
}
|
||||
try body_node.statements.push((try parser.declaration()) orelse (try parser.stmt()));
|
||||
}
|
||||
return &body_node.base;
|
||||
}
|
||||
|
||||
/// Stmt
|
||||
/// <- CompoundStmt
|
||||
/// / Keyword_if LPAREN Expr RPAREN Stmt (Keyword_ELSE Stmt)?
|
||||
/// / Keyword_switch LPAREN Expr RPAREN Stmt
|
||||
/// / Keyword_while LPAREN Expr RPAREN Stmt
|
||||
/// / Keyword_do statement Keyword_while LPAREN Expr RPAREN SEMICOLON
|
||||
/// / Keyword_for LPAREN (Declaration / ExprStmt) ExprStmt Expr? RPAREN Stmt
|
||||
/// / Keyword_default COLON Stmt
|
||||
/// / Keyword_case ConstExpr COLON Stmt
|
||||
/// / Keyword_goto IDENTIFIER SEMICOLON
|
||||
/// / Keyword_continue SEMICOLON
|
||||
/// / Keyword_break SEMICOLON
|
||||
/// / Keyword_return Expr? SEMICOLON
|
||||
/// / IDENTIFIER COLON Stmt
|
||||
/// / ExprStmt
|
||||
fn stmt(parser: *Parser) Error!*Node {
|
||||
if (try parser.compoundStmt()) |node| return node;
|
||||
if (parser.eatToken(.Keyword_if)) |tok| {
|
||||
const node = try parser.arena.create(Node.IfStmt);
|
||||
_ = try parser.expectToken(.LParen);
|
||||
node.* = .{
|
||||
.@"if" = tok,
|
||||
.cond = (try parser.expr()) orelse return parser.err(.{
|
||||
.ExpectedExpr = .{ .token = parser.it.index },
|
||||
}),
|
||||
.body = undefined,
|
||||
.@"else" = null,
|
||||
};
|
||||
_ = try parser.expectToken(.RParen);
|
||||
node.body = try parser.stmt();
|
||||
if (parser.eatToken(.Keyword_else)) |else_tok| {
|
||||
node.@"else" = .{
|
||||
.tok = else_tok,
|
||||
.body = try parser.stmt(),
|
||||
};
|
||||
}
|
||||
return &node.base;
|
||||
}
|
||||
if (parser.eatToken(.Keyword_while)) |tok| {
|
||||
try parser.pushScope(.Loop);
|
||||
defer parser.popScope();
|
||||
_ = try parser.expectToken(.LParen);
|
||||
const cond = (try parser.expr()) orelse return parser.err(.{
|
||||
.ExpectedExpr = .{ .token = parser.it.index },
|
||||
});
|
||||
const rparen = try parser.expectToken(.RParen);
|
||||
const node = try parser.arena.create(Node.WhileStmt);
|
||||
node.* = .{
|
||||
.@"while" = tok,
|
||||
.cond = cond,
|
||||
.rparen = rparen,
|
||||
.body = try parser.stmt(),
|
||||
.semicolon = try parser.expectToken(.Semicolon),
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
if (parser.eatToken(.Keyword_do)) |tok| {
|
||||
try parser.pushScope(.Loop);
|
||||
defer parser.popScope();
|
||||
const body = try parser.stmt();
|
||||
_ = try parser.expectToken(.LParen);
|
||||
const cond = (try parser.expr()) orelse return parser.err(.{
|
||||
.ExpectedExpr = .{ .token = parser.it.index },
|
||||
});
|
||||
_ = try parser.expectToken(.RParen);
|
||||
const node = try parser.arena.create(Node.DoStmt);
|
||||
node.* = .{
|
||||
.do = tok,
|
||||
.body = body,
|
||||
.cond = cond,
|
||||
.@"while" = @"while",
|
||||
.semicolon = try parser.expectToken(.Semicolon),
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
if (parser.eatToken(.Keyword_for)) |tok| {
|
||||
try parser.pushScope(.Loop);
|
||||
defer parser.popScope();
|
||||
_ = try parser.expectToken(.LParen);
|
||||
const init = if (try parser.declaration()) |decl| blk: {
|
||||
// TODO disallow storage class other than auto and register
|
||||
break :blk decl;
|
||||
} else try parser.exprStmt();
|
||||
const cond = try parser.expr();
|
||||
const semicolon = try parser.expectToken(.Semicolon);
|
||||
const incr = try parser.expr();
|
||||
const rparen = try parser.expectToken(.RParen);
|
||||
const node = try parser.arena.create(Node.ForStmt);
|
||||
node.* = .{
|
||||
.@"for" = tok,
|
||||
.init = init,
|
||||
.cond = cond,
|
||||
.semicolon = semicolon,
|
||||
.incr = incr,
|
||||
.rparen = rparen,
|
||||
.body = try parser.stmt(),
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
if (parser.eatToken(.Keyword_switch)) |tok| {
|
||||
try parser.pushScope(.Switch);
|
||||
defer parser.popScope();
|
||||
_ = try parser.expectToken(.LParen);
|
||||
const switch_expr = try parser.exprStmt();
|
||||
const rparen = try parser.expectToken(.RParen);
|
||||
const node = try parser.arena.create(Node.SwitchStmt);
|
||||
node.* = .{
|
||||
.@"switch" = tok,
|
||||
.expr = switch_expr,
|
||||
.rparen = rparen,
|
||||
.body = try parser.stmt(),
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
if (parser.eatToken(.Keyword_default)) |tok| {
|
||||
_ = try parser.expectToken(.Colon);
|
||||
const node = try parser.arena.create(Node.LabeledStmt);
|
||||
node.* = .{
|
||||
.kind = .{ .Default = tok },
|
||||
.stmt = try parser.stmt(),
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
if (parser.eatToken(.Keyword_case)) |tok| {
|
||||
_ = try parser.expectToken(.Colon);
|
||||
const node = try parser.arena.create(Node.LabeledStmt);
|
||||
node.* = .{
|
||||
.kind = .{ .Case = tok },
|
||||
.stmt = try parser.stmt(),
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
if (parser.eatToken(.Keyword_goto)) |tok| {
|
||||
const node = try parser.arena.create(Node.JumpStmt);
|
||||
node.* = .{
|
||||
.ltoken = tok,
|
||||
.kind = .{ .Goto = tok },
|
||||
.semicolon = try parser.expectToken(.Semicolon),
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
if (parser.eatToken(.Keyword_continue)) |tok| {
|
||||
const node = try parser.arena.create(Node.JumpStmt);
|
||||
node.* = .{
|
||||
.ltoken = tok,
|
||||
.kind = .Continue,
|
||||
.semicolon = try parser.expectToken(.Semicolon),
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
if (parser.eatToken(.Keyword_break)) |tok| {
|
||||
const node = try parser.arena.create(Node.JumpStmt);
|
||||
node.* = .{
|
||||
.ltoken = tok,
|
||||
.kind = .Break,
|
||||
.semicolon = try parser.expectToken(.Semicolon),
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
if (parser.eatToken(.Keyword_return)) |tok| {
|
||||
const node = try parser.arena.create(Node.JumpStmt);
|
||||
node.* = .{
|
||||
.ltoken = tok,
|
||||
.kind = .{ .Return = try parser.expr() },
|
||||
.semicolon = try parser.expectToken(.Semicolon),
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
if (parser.eatToken(.Identifier)) |tok| {
|
||||
if (parser.eatToken(.Colon)) |_| {
|
||||
const node = try parser.arena.create(Node.LabeledStmt);
|
||||
node.* = .{
|
||||
.kind = .{ .Label = tok },
|
||||
.stmt = try parser.stmt(),
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
parser.putBackToken(tok);
|
||||
}
|
||||
return parser.exprStmt();
|
||||
}
|
||||
|
||||
/// ExprStmt <- Expr? SEMICOLON
|
||||
fn exprStmt(parser: *Parser) !*Node {
|
||||
const node = try parser.arena.create(Node.ExprStmt);
|
||||
node.* = .{
|
||||
.expr = try parser.expr(),
|
||||
.semicolon = try parser.expectToken(.Semicolon),
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
fn eatToken(parser: *Parser, id: std.meta.Tag(Token.Id)) ?TokenIndex {
|
||||
while (true) {
|
||||
switch ((parser.it.next() orelse return null).id) {
|
||||
.LineComment, .MultiLineComment, .Nl => continue,
|
||||
else => |next_id| if (next_id == id) {
|
||||
return parser.it.index;
|
||||
} else {
|
||||
_ = parser.it.prev();
|
||||
return null;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expectToken(parser: *Parser, id: std.meta.Tag(Token.Id)) Error!TokenIndex {
|
||||
while (true) {
|
||||
switch ((parser.it.next() orelse return error.ParseError).id) {
|
||||
.LineComment, .MultiLineComment, .Nl => continue,
|
||||
else => |next_id| if (next_id != id) {
|
||||
return parser.err(.{
|
||||
.ExpectedToken = .{ .token = parser.it.index, .expected_id = id },
|
||||
});
|
||||
} else {
|
||||
return parser.it.index;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn putBackToken(parser: *Parser, putting_back: TokenIndex) void {
|
||||
while (true) {
|
||||
const prev_tok = parser.it.next() orelse return;
|
||||
switch (prev_tok.id) {
|
||||
.LineComment, .MultiLineComment, .Nl => continue,
|
||||
else => {
|
||||
assert(parser.it.list.at(putting_back) == prev_tok);
|
||||
return;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn err(parser: *Parser, msg: ast.Error) Error {
|
||||
try parser.tree.msgs.push(.{
|
||||
.kind = .Error,
|
||||
.inner = msg,
|
||||
});
|
||||
return error.ParseError;
|
||||
}
|
||||
|
||||
fn warn(parser: *Parser, msg: ast.Error) Error!void {
|
||||
const is_warning = switch (parser.options.warn_as_err) {
|
||||
.None => true,
|
||||
.Some => |list| for (list) |item| (if (item == msg) break false) else true,
|
||||
.All => false,
|
||||
};
|
||||
try parser.tree.msgs.push(.{
|
||||
.kind = if (is_warning) .Warning else .Error,
|
||||
.inner = msg,
|
||||
});
|
||||
if (!is_warning) return error.ParseError;
|
||||
}
|
||||
|
||||
fn note(parser: *Parser, msg: ast.Error) Error!void {
|
||||
try parser.tree.msgs.push(.{
|
||||
.kind = .Note,
|
||||
.inner = msg,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -662,14 +662,12 @@ test "lengths overflow" {
|
||||
// malformed final dynamic block, tries to write 321 code lengths (MAXCODES is 316)
|
||||
// f dy hlit hdist hclen 16 17 18 0 (18) x138 (18) x138 (18) x39 (16) x6
|
||||
// 1 10 11101 11101 0000 010 010 010 010 (11) 1111111 (11) 1111111 (11) 0011100 (01) 11
|
||||
const stream = [_]u8{
|
||||
0b11101101, 0b00011101, 0b00100100, 0b11101001, 0b11111111, 0b11111111, 0b00111001, 0b00001110
|
||||
};
|
||||
const stream = [_]u8{ 0b11101101, 0b00011101, 0b00100100, 0b11101001, 0b11111111, 0b11111111, 0b00111001, 0b00001110 };
|
||||
|
||||
const reader = std.io.fixedBufferStream(&stream).reader();
|
||||
var window: [0x8000]u8 = undefined;
|
||||
var inflate = inflateStream(reader, &window);
|
||||
|
||||
var buf: [1]u8 = undefined;
|
||||
std.testing.expectError(error.InvalidLength, inflate.read(&buf));
|
||||
std.testing.expectError(error.InvalidLength, inflate.read(&buf));
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ pub const dh = struct {
|
||||
pub const ecc = struct {
|
||||
pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519;
|
||||
pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519;
|
||||
pub const P256 = @import("crypto/pcurves/p256.zig").P256;
|
||||
pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
const std = @import("std");
|
||||
const builtin = std.builtin;
|
||||
const crypto = std.crypto;
|
||||
const debug = std.debug;
|
||||
const mem = std.mem;
|
||||
const meta = std.meta;
|
||||
|
||||
const NonCanonicalError = crypto.errors.NonCanonicalError;
|
||||
const NotSquareError = crypto.errors.NotSquareError;
|
||||
|
||||
/// Parameters to create a finite field type.
|
||||
pub const FieldParams = struct {
|
||||
fiat: type,
|
||||
field_order: comptime_int,
|
||||
field_bits: comptime_int,
|
||||
saturated_bits: comptime_int,
|
||||
encoded_length: comptime_int,
|
||||
};
|
||||
|
||||
/// A field element, internally stored in Montgomery domain.
|
||||
pub fn Field(comptime params: FieldParams) type {
|
||||
const fiat = params.fiat;
|
||||
const Limbs = fiat.Limbs;
|
||||
|
||||
return struct {
|
||||
const Fe = @This();
|
||||
|
||||
limbs: Limbs,
|
||||
|
||||
/// Field size.
|
||||
pub const field_order = params.field_order;
|
||||
|
||||
/// Number of bits to represent the set of all elements.
|
||||
pub const field_bits = params.field_bits;
|
||||
|
||||
/// Number of bits that can be saturated without overflowing.
|
||||
pub const saturated_bits = params.saturated_bits;
|
||||
|
||||
/// Number of bytes required to encode an element.
|
||||
pub const encoded_length = params.encoded_length;
|
||||
|
||||
/// Zero.
|
||||
pub const zero: Fe = Fe{ .limbs = mem.zeroes(Limbs) };
|
||||
|
||||
/// One.
|
||||
pub const one = comptime one: {
|
||||
var fe: Fe = undefined;
|
||||
fiat.setOne(&fe.limbs);
|
||||
break :one fe;
|
||||
};
|
||||
|
||||
/// Reject non-canonical encodings of an element.
|
||||
pub fn rejectNonCanonical(s_: [encoded_length]u8, endian: builtin.Endian) NonCanonicalError!void {
|
||||
var s = if (endian == .Little) s_ else orderSwap(s_);
|
||||
const field_order_s = comptime fos: {
|
||||
var fos: [encoded_length]u8 = undefined;
|
||||
mem.writeIntLittle(std.meta.Int(.unsigned, encoded_length * 8), &fos, field_order);
|
||||
break :fos fos;
|
||||
};
|
||||
if (crypto.utils.timingSafeCompare(u8, &s, &field_order_s, .Little) != .lt) {
|
||||
return error.NonCanonical;
|
||||
}
|
||||
}
|
||||
|
||||
/// Swap the endianness of an encoded element.
|
||||
pub fn orderSwap(s: [encoded_length]u8) [encoded_length]u8 {
|
||||
var t = s;
|
||||
for (s) |x, i| t[t.len - 1 - i] = x;
|
||||
return t;
|
||||
}
|
||||
|
||||
/// Unpack a field element.
|
||||
pub fn fromBytes(s_: [encoded_length]u8, endian: builtin.Endian) NonCanonicalError!Fe {
|
||||
var s = if (endian == .Little) s_ else orderSwap(s_);
|
||||
try rejectNonCanonical(s, .Little);
|
||||
var limbs_z: Limbs = undefined;
|
||||
fiat.fromBytes(&limbs_z, s);
|
||||
var limbs: Limbs = undefined;
|
||||
fiat.toMontgomery(&limbs, limbs_z);
|
||||
return Fe{ .limbs = limbs };
|
||||
}
|
||||
|
||||
/// Pack a field element.
|
||||
pub fn toBytes(fe: Fe, endian: builtin.Endian) [encoded_length]u8 {
|
||||
var limbs_z: Limbs = undefined;
|
||||
fiat.fromMontgomery(&limbs_z, fe.limbs);
|
||||
var s: [encoded_length]u8 = undefined;
|
||||
fiat.toBytes(&s, limbs_z);
|
||||
return if (endian == .Little) s else orderSwap(s);
|
||||
}
|
||||
|
||||
/// Element as an integer.
|
||||
pub const IntRepr = meta.Int(.unsigned, params.field_bits);
|
||||
|
||||
/// Create a field element from an integer.
|
||||
pub fn fromInt(comptime x: IntRepr) NonCanonicalError!Fe {
|
||||
var s: [encoded_length]u8 = undefined;
|
||||
mem.writeIntLittle(IntRepr, &s, x);
|
||||
return fromBytes(s, .Little);
|
||||
}
|
||||
|
||||
/// Return the field element as an integer.
|
||||
pub fn toInt(fe: Fe) IntRepr {
|
||||
const s = fe.toBytes(.Little);
|
||||
return mem.readIntLittle(IntRepr, &s);
|
||||
}
|
||||
|
||||
/// Return true if the field element is zero.
|
||||
pub fn isZero(fe: Fe) bool {
|
||||
var z: @TypeOf(fe.limbs[0]) = undefined;
|
||||
fiat.nonzero(&z, fe.limbs);
|
||||
return z == 0;
|
||||
}
|
||||
|
||||
/// Return true if both field elements are equivalent.
|
||||
pub fn equivalent(a: Fe, b: Fe) bool {
|
||||
return a.sub(b).isZero();
|
||||
}
|
||||
|
||||
/// Return true if the element is odd.
|
||||
pub fn isOdd(fe: Fe) bool {
|
||||
const s = fe.toBytes(.Little);
|
||||
return @truncate(u1, s[0]) != 0;
|
||||
}
|
||||
|
||||
/// Conditonally replace a field element with `a` if `c` is positive.
|
||||
pub fn cMov(fe: *Fe, a: Fe, c: u1) void {
|
||||
fiat.selectznz(&fe.limbs, c, fe.limbs, a.limbs);
|
||||
}
|
||||
|
||||
/// Add field elements.
|
||||
pub fn add(a: Fe, b: Fe) Fe {
|
||||
var fe: Fe = undefined;
|
||||
fiat.add(&fe.limbs, a.limbs, b.limbs);
|
||||
return fe;
|
||||
}
|
||||
|
||||
/// Subtract field elements.
|
||||
pub fn sub(a: Fe, b: Fe) Fe {
|
||||
var fe: Fe = undefined;
|
||||
fiat.sub(&fe.limbs, a.limbs, b.limbs);
|
||||
return fe;
|
||||
}
|
||||
|
||||
/// Double a field element.
|
||||
pub fn dbl(a: Fe) Fe {
|
||||
var fe: Fe = undefined;
|
||||
fiat.add(&fe.limbs, a.limbs, a.limbs);
|
||||
return fe;
|
||||
}
|
||||
|
||||
/// Multiply field elements.
|
||||
pub fn mul(a: Fe, b: Fe) Fe {
|
||||
var fe: Fe = undefined;
|
||||
fiat.mul(&fe.limbs, a.limbs, b.limbs);
|
||||
return fe;
|
||||
}
|
||||
|
||||
/// Square a field element.
|
||||
pub fn sq(a: Fe) Fe {
|
||||
var fe: Fe = undefined;
|
||||
fiat.square(&fe.limbs, a.limbs);
|
||||
return fe;
|
||||
}
|
||||
|
||||
/// Square a field element n times.
|
||||
fn sqn(a: Fe, comptime n: comptime_int) Fe {
|
||||
var i: usize = 0;
|
||||
var fe = a;
|
||||
while (i < n) : (i += 1) {
|
||||
fe = fe.sq();
|
||||
}
|
||||
return fe;
|
||||
}
|
||||
|
||||
/// Compute a^n.
|
||||
pub fn pow(a: Fe, comptime T: type, comptime n: T) Fe {
|
||||
var fe = one;
|
||||
var x: T = n;
|
||||
var t = a;
|
||||
while (true) {
|
||||
if (@truncate(u1, x) != 0) fe = fe.mul(t);
|
||||
x >>= 1;
|
||||
if (x == 0) break;
|
||||
t = t.sq();
|
||||
}
|
||||
return fe;
|
||||
}
|
||||
|
||||
/// Negate a field element.
|
||||
pub fn neg(a: Fe) Fe {
|
||||
var fe: Fe = undefined;
|
||||
fiat.opp(&fe.limbs, a.limbs);
|
||||
return fe;
|
||||
}
|
||||
|
||||
/// Return the inverse of a field element, or 0 if a=0.
|
||||
// Field inversion from https://eprint.iacr.org/2021/549.pdf
|
||||
pub fn invert(a: Fe) Fe {
|
||||
const iterations = (49 * field_bits + 57) / 17;
|
||||
const Word = @TypeOf(a.limbs[0]);
|
||||
const XLimbs = [a.limbs.len + 1]Word;
|
||||
|
||||
var d: Word = 1;
|
||||
var f: XLimbs = undefined;
|
||||
fiat.msat(&f);
|
||||
|
||||
var g: XLimbs = undefined;
|
||||
fiat.fromMontgomery(g[0..a.limbs.len], a.limbs);
|
||||
g[g.len - 1] = 0;
|
||||
|
||||
var r: Limbs = undefined;
|
||||
fiat.setOne(&r);
|
||||
var v = mem.zeroes(Limbs);
|
||||
|
||||
var precomp: Limbs = undefined;
|
||||
fiat.divstepPrecomp(&precomp);
|
||||
|
||||
var out1: Word = undefined;
|
||||
var out2: XLimbs = undefined;
|
||||
var out3: XLimbs = undefined;
|
||||
var out4: Limbs = undefined;
|
||||
var out5: Limbs = undefined;
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < iterations - iterations % 2) : (i += 2) {
|
||||
fiat.divstep(&out1, &out2, &out3, &out4, &out5, d, f, g, v, r);
|
||||
fiat.divstep(&d, &f, &g, &v, &r, out1, out2, out3, out4, out5);
|
||||
}
|
||||
if (iterations % 2 != 0) {
|
||||
fiat.divstep(&out1, &out2, &out3, &out4, &out5, d, f, g, v, r);
|
||||
mem.copy(Word, &v, &out4);
|
||||
mem.copy(Word, &f, &out2);
|
||||
}
|
||||
var v_opp: Limbs = undefined;
|
||||
fiat.opp(&v_opp, v);
|
||||
fiat.selectznz(&v, @truncate(u1, f[f.len - 1] >> (meta.bitCount(Word) - 1)), v, v_opp);
|
||||
var fe: Fe = undefined;
|
||||
fiat.mul(&fe.limbs, v, precomp);
|
||||
return fe;
|
||||
}
|
||||
|
||||
/// Return true if the field element is a square.
|
||||
pub fn isSquare(x2: Fe) bool {
|
||||
if (field_order == 115792089210356248762697446949407573530086143415290314195533631308867097853951) {
|
||||
const t110 = x2.mul(x2.sq()).sq();
|
||||
const t111 = x2.mul(t110);
|
||||
const t111111 = t111.mul(x2.mul(t110).sqn(3));
|
||||
const x15 = t111111.sqn(6).mul(t111111).sqn(3).mul(t111);
|
||||
const x16 = x15.sq().mul(x2);
|
||||
const x53 = x16.sqn(16).mul(x16).sqn(15);
|
||||
const x47 = x15.mul(x53);
|
||||
const ls = x47.mul(((x53.sqn(17).mul(x2)).sqn(143).mul(x47)).sqn(47)).sq().mul(x2);
|
||||
return ls.equivalent(Fe.one);
|
||||
} else {
|
||||
const ls = x2.pow(std.meta.Int(.unsigned, field_bits), (field_order - 1) / 2); // Legendre symbol
|
||||
return ls.equivalent(Fe.one);
|
||||
}
|
||||
}
|
||||
|
||||
// x=x2^((field_order+1)/4) w/ field order=3 (mod 4).
|
||||
fn uncheckedSqrt(x2: Fe) Fe {
|
||||
comptime debug.assert(field_order % 4 == 3);
|
||||
if (field_order == 115792089210356248762697446949407573530086143415290314195533631308867097853951) {
|
||||
const t11 = x2.mul(x2.sq());
|
||||
const t1111 = t11.mul(t11.sqn(2));
|
||||
const t11111111 = t1111.mul(t1111.sqn(4));
|
||||
const x16 = t11111111.sqn(8).mul(t11111111);
|
||||
return x16.sqn(16).mul(x16).sqn(32).mul(x2).sqn(96).mul(x2).sqn(94);
|
||||
} else {
|
||||
return x2.pow(std.meta.Int(.unsigned, field_bits), (field_order + 1) / 4);
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the square root of `x2`, returning `error.NotSquare` if `x2` was not a square.
|
||||
pub fn sqrt(x2: Fe) NotSquareError!Fe {
|
||||
const x = x2.uncheckedSqrt();
|
||||
if (x.sq().equivalent(x2)) {
|
||||
return x;
|
||||
}
|
||||
return error.NotSquare;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,412 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2015-2021 Zig Contributors
|
||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
||||
// The MIT license requires this copyright notice to be included in all copies
|
||||
// and substantial portions of the software.
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = std.builtin;
|
||||
const crypto = std.crypto;
|
||||
const mem = std.mem;
|
||||
const meta = std.meta;
|
||||
|
||||
const EncodingError = crypto.errors.EncodingError;
|
||||
const IdentityElementError = crypto.errors.IdentityElementError;
|
||||
const NonCanonicalError = crypto.errors.NonCanonicalError;
|
||||
const NotSquareError = crypto.errors.NotSquareError;
|
||||
|
||||
/// Group operations over P256.
|
||||
pub const P256 = struct {
|
||||
/// The underlying prime field.
|
||||
pub const Fe = @import("p256/field.zig").Fe;
|
||||
/// Field arithmetic mod the order of the main subgroup.
|
||||
pub const scalar = @import("p256/scalar.zig");
|
||||
|
||||
x: Fe,
|
||||
y: Fe,
|
||||
z: Fe = Fe.one,
|
||||
|
||||
is_base: bool = false,
|
||||
|
||||
/// The P256 base point.
|
||||
pub const basePoint = P256{
|
||||
.x = try Fe.fromInt(48439561293906451759052585252797914202762949526041747995844080717082404635286),
|
||||
.y = try Fe.fromInt(36134250956749795798585127919587881956611106672985015071877198253568414405109),
|
||||
.z = Fe.one,
|
||||
.is_base = true,
|
||||
};
|
||||
|
||||
/// The P256 neutral element.
|
||||
pub const identityElement = P256{ .x = Fe.zero, .y = Fe.one, .z = Fe.zero };
|
||||
|
||||
pub const B = try Fe.fromInt(41058363725152142129326129780047268409114441015993725554835256314039467401291);
|
||||
|
||||
/// Reject the neutral element.
|
||||
pub fn rejectIdentity(p: P256) IdentityElementError!void {
|
||||
if (p.x.isZero()) {
|
||||
return error.IdentityElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a point from affine coordinates after checking that they match the curve equation.
|
||||
pub fn fromAffineCoordinates(x: Fe, y: Fe) EncodingError!P256 {
|
||||
const x3AxB = x.sq().mul(x).sub(x).sub(x).sub(x).add(B);
|
||||
const yy = y.sq();
|
||||
if (!x3AxB.equivalent(yy)) {
|
||||
return error.InvalidEncoding;
|
||||
}
|
||||
const p: P256 = .{ .x = x, .y = y, .z = Fe.one };
|
||||
return p;
|
||||
}
|
||||
|
||||
/// Create a point from serialized affine coordinates.
|
||||
pub fn fromSerializedAffineCoordinates(xs: [32]u8, ys: [32]u8, endian: builtin.Endian) (NonCanonicalError || EncodingError)!P256 {
|
||||
const x = try Fe.fromBytes(xs, endian);
|
||||
const y = try Fe.fromBytes(ys, endian);
|
||||
return fromAffineCoordinates(x, y);
|
||||
}
|
||||
|
||||
/// Recover the Y coordinate from the X coordinate.
|
||||
pub fn recoverY(x: Fe, is_odd: bool) NotSquareError!Fe {
|
||||
const x3AxB = x.sq().mul(x).sub(x).sub(x).sub(x).add(B);
|
||||
var y = try x3AxB.sqrt();
|
||||
const yn = y.neg();
|
||||
y.cMov(yn, @boolToInt(is_odd) ^ @boolToInt(y.isOdd()));
|
||||
return y;
|
||||
}
|
||||
|
||||
/// Deserialize a SEC1-encoded point.
|
||||
pub fn fromSec1(s: []const u8) (EncodingError || NotSquareError || NonCanonicalError)!P256 {
|
||||
if (s.len < 1) return error.InvalidEncoding;
|
||||
const encoding_type = s[0];
|
||||
const encoded = s[1..];
|
||||
switch (encoding_type) {
|
||||
0 => {
|
||||
if (encoded.len != 0) return error.InvalidEncoding;
|
||||
return P256.identityElement;
|
||||
},
|
||||
2, 3 => {
|
||||
if (encoded.len != 32) return error.InvalidEncoding;
|
||||
const x = try Fe.fromBytes(encoded[0..32].*, .Big);
|
||||
const y_is_odd = (encoding_type == 3);
|
||||
const y = try recoverY(x, y_is_odd);
|
||||
return P256{ .x = x, .y = y };
|
||||
},
|
||||
4 => {
|
||||
if (encoded.len != 64) return error.InvalidEncoding;
|
||||
const x = try Fe.fromBytes(encoded[0..32].*, .Big);
|
||||
const y = try Fe.fromBytes(encoded[32..64].*, .Big);
|
||||
return P256.fromAffineCoordinates(x, y);
|
||||
},
|
||||
else => return error.InvalidEncoding,
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize a point using the compressed SEC-1 format.
|
||||
pub fn toCompressedSec1(p: P256) [33]u8 {
|
||||
var out: [33]u8 = undefined;
|
||||
const xy = p.affineCoordinates();
|
||||
out[0] = if (xy.y.isOdd()) 3 else 2;
|
||||
mem.copy(u8, out[1..], &xy.x.toBytes(.Big));
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Serialize a point using the uncompressed SEC-1 format.
|
||||
pub fn toUncompressedSec1(p: P256) [65]u8 {
|
||||
var out: [65]u8 = undefined;
|
||||
out[0] = 4;
|
||||
const xy = p.affineCoordinates();
|
||||
mem.copy(u8, out[1..33], &xy.x.toBytes(.Big));
|
||||
mem.copy(u8, out[33..65], &xy.y.toBytes(.Big));
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Return a random point.
|
||||
pub fn random() P256 {
|
||||
const n = scalar.random(.Little);
|
||||
return basePoint.mul(n, .Little) catch unreachable;
|
||||
}
|
||||
|
||||
/// Flip the sign of the X coordinate.
|
||||
pub fn neg(p: P256) P256 {
|
||||
return .{ .x = p.x, .y = p.y.neg(), .z = p.z };
|
||||
}
|
||||
|
||||
/// Double a P256 point.
|
||||
// Algorithm 6 from https://eprint.iacr.org/2015/1060.pdf
|
||||
pub fn dbl(p: P256) P256 {
|
||||
var t0 = p.x.sq();
|
||||
var t1 = p.y.sq();
|
||||
var t2 = p.z.sq();
|
||||
var t3 = p.x.mul(p.y);
|
||||
t3 = t3.dbl();
|
||||
var Z3 = p.x.mul(p.z);
|
||||
Z3 = Z3.add(Z3);
|
||||
var Y3 = B.mul(t2);
|
||||
Y3 = Y3.sub(Z3);
|
||||
var X3 = Y3.dbl();
|
||||
Y3 = X3.add(Y3);
|
||||
X3 = t1.sub(Y3);
|
||||
Y3 = t1.add(Y3);
|
||||
Y3 = X3.mul(Y3);
|
||||
X3 = X3.mul(t3);
|
||||
t3 = t2.dbl();
|
||||
t2 = t2.add(t3);
|
||||
Z3 = B.mul(Z3);
|
||||
Z3 = Z3.sub(t2);
|
||||
Z3 = Z3.sub(t0);
|
||||
t3 = Z3.dbl();
|
||||
Z3 = Z3.add(t3);
|
||||
t3 = t0.dbl();
|
||||
t0 = t3.add(t0);
|
||||
t0 = t0.sub(t2);
|
||||
t0 = t0.mul(Z3);
|
||||
Y3 = Y3.add(t0);
|
||||
t0 = p.y.mul(p.z);
|
||||
t0 = t0.dbl();
|
||||
Z3 = t0.mul(Z3);
|
||||
X3 = X3.sub(Z3);
|
||||
Z3 = t0.mul(t1);
|
||||
Z3 = Z3.dbl().dbl();
|
||||
return .{
|
||||
.x = X3,
|
||||
.y = Y3,
|
||||
.z = Z3,
|
||||
};
|
||||
}
|
||||
|
||||
/// Add P256 points, the second being specified using affine coordinates.
|
||||
// Algorithm 5 from https://eprint.iacr.org/2015/1060.pdf
|
||||
pub fn addMixed(p: P256, q: struct { x: Fe, y: Fe }) P256 {
|
||||
var t0 = p.x.mul(q.x);
|
||||
var t1 = p.y.mul(q.y);
|
||||
var t3 = q.x.add(q.y);
|
||||
var t4 = p.x.add(p.y);
|
||||
t3 = t3.mul(t4);
|
||||
t4 = t0.add(t1);
|
||||
t3 = t3.sub(t4);
|
||||
t4 = q.y.mul(p.z);
|
||||
t4 = t4.add(p.y);
|
||||
var Y3 = q.x.mul(p.z);
|
||||
Y3 = Y3.add(p.x);
|
||||
var Z3 = B.mul(p.z);
|
||||
var X3 = Y3.sub(Z3);
|
||||
Z3 = X3.dbl();
|
||||
X3 = X3.add(Z3);
|
||||
Z3 = t1.sub(X3);
|
||||
X3 = t1.dbl();
|
||||
Y3 = B.mul(Y3);
|
||||
t1 = p.z.add(p.z);
|
||||
var t2 = t1.add(p.z);
|
||||
Y3 = Y3.sub(t2);
|
||||
Y3 = Y3.sub(t0);
|
||||
t1 = Y3.dbl();
|
||||
Y3 = t1.add(Y3);
|
||||
t1 = t0.dbl();
|
||||
t0 = t1.add(t0);
|
||||
t0 = t0.sub(t2);
|
||||
t1 = t4.mul(Y3);
|
||||
t2 = t0.mul(Y3);
|
||||
Y3 = X3.mul(Z3);
|
||||
Y3 = Y3.add(t2);
|
||||
X3 = t3.mul(X3);
|
||||
X3 = X3.sub(t1);
|
||||
Z3 = t4.mul(Z3);
|
||||
t1 = t3.mul(t0);
|
||||
Z3 = Z3.add(t1);
|
||||
return .{
|
||||
.x = X3,
|
||||
.y = Y3,
|
||||
.z = Z3,
|
||||
};
|
||||
}
|
||||
|
||||
// Add P256 points.
|
||||
// Algorithm 4 from https://eprint.iacr.org/2015/1060.pdf
|
||||
pub fn add(p: P256, q: P256) P256 {
|
||||
var t0 = p.x.mul(q.x);
|
||||
var t1 = p.y.mul(q.y);
|
||||
var t2 = p.z.mul(q.z);
|
||||
var t3 = p.x.add(p.y);
|
||||
var t4 = q.x.add(q.y);
|
||||
t3 = t3.mul(t4);
|
||||
t4 = t0.add(t1);
|
||||
t3 = t3.sub(t4);
|
||||
t4 = p.y.add(p.z);
|
||||
var X3 = q.y.add(q.z);
|
||||
t4 = t4.mul(X3);
|
||||
X3 = t1.add(t2);
|
||||
t4 = t4.sub(X3);
|
||||
X3 = p.x.add(p.z);
|
||||
var Y3 = q.x.add(q.z);
|
||||
X3 = X3.mul(Y3);
|
||||
Y3 = t0.add(t2);
|
||||
Y3 = X3.sub(Y3);
|
||||
var Z3 = B.mul(t2);
|
||||
X3 = Y3.sub(Z3);
|
||||
Z3 = X3.dbl();
|
||||
X3 = X3.add(Z3);
|
||||
Z3 = t1.sub(X3);
|
||||
X3 = t1.add(X3);
|
||||
Y3 = B.mul(Y3);
|
||||
t1 = t2.dbl();
|
||||
t2 = t1.add(t2);
|
||||
Y3 = Y3.sub(t2);
|
||||
Y3 = Y3.sub(t0);
|
||||
t1 = Y3.dbl();
|
||||
Y3 = t1.add(Y3);
|
||||
t1 = t0.dbl();
|
||||
t0 = t1.add(t0);
|
||||
t0 = t0.sub(t2);
|
||||
t1 = t4.mul(Y3);
|
||||
t2 = t0.mul(Y3);
|
||||
Y3 = X3.mul(Z3);
|
||||
Y3 = Y3.add(t2);
|
||||
X3 = t3.mul(X3);
|
||||
X3 = X3.sub(t1);
|
||||
Z3 = t4.mul(Z3);
|
||||
t1 = t3.mul(t0);
|
||||
Z3 = Z3.add(t1);
|
||||
return .{
|
||||
.x = X3,
|
||||
.y = Y3,
|
||||
.z = Z3,
|
||||
};
|
||||
}
|
||||
|
||||
// Subtract P256 points.
|
||||
pub fn sub(p: P256, q: P256) P256 {
|
||||
return p.add(q.neg());
|
||||
}
|
||||
|
||||
/// Return affine coordinates.
|
||||
pub fn affineCoordinates(p: P256) struct { x: Fe, y: Fe } {
|
||||
const zinv = p.z.invert();
|
||||
const ret = .{
|
||||
.x = p.x.mul(zinv),
|
||||
.y = p.y.mul(zinv),
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Return true if both coordinate sets represent the same point.
|
||||
pub fn equivalent(a: P256, b: P256) bool {
|
||||
if (a.sub(b).rejectIdentity()) {
|
||||
return false;
|
||||
} else |_| {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fn cMov(p: *P256, a: P256, c: u1) void {
|
||||
p.x.cMov(a.x, c);
|
||||
p.y.cMov(a.y, c);
|
||||
p.z.cMov(a.z, c);
|
||||
}
|
||||
|
||||
fn pcSelect(comptime n: usize, pc: [n]P256, b: u8) P256 {
|
||||
var t = P256.identityElement;
|
||||
comptime var i: u8 = 1;
|
||||
inline while (i < pc.len) : (i += 1) {
|
||||
t.cMov(pc[i], @truncate(u1, (@as(usize, b ^ i) -% 1) >> 8));
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
fn slide(s: [32]u8) [2 * 32 + 1]i8 {
|
||||
var e: [2 * 32 + 1]i8 = undefined;
|
||||
for (s) |x, i| {
|
||||
e[i * 2 + 0] = @as(i8, @truncate(u4, x));
|
||||
e[i * 2 + 1] = @as(i8, @truncate(u4, x >> 4));
|
||||
}
|
||||
// Now, e[0..63] is between 0 and 15, e[63] is between 0 and 7
|
||||
var carry: i8 = 0;
|
||||
for (e[0..64]) |*x| {
|
||||
x.* += carry;
|
||||
carry = (x.* + 8) >> 4;
|
||||
x.* -= carry * 16;
|
||||
std.debug.assert(x.* >= -8 and x.* <= 8);
|
||||
}
|
||||
e[64] = carry;
|
||||
// Now, e[*] is between -8 and 8, including e[64]
|
||||
std.debug.assert(carry >= -8 and carry <= 8);
|
||||
return e;
|
||||
}
|
||||
|
||||
fn pcMul(pc: [9]P256, s: [32]u8, comptime vartime: bool) IdentityElementError!P256 {
|
||||
std.debug.assert(vartime);
|
||||
const e = slide(s);
|
||||
var q = P256.identityElement;
|
||||
var pos = e.len - 1;
|
||||
while (true) : (pos -= 1) {
|
||||
const slot = e[pos];
|
||||
if (slot > 0) {
|
||||
q = q.add(pc[@intCast(usize, slot)]);
|
||||
} else if (slot < 0) {
|
||||
q = q.sub(pc[@intCast(usize, -slot)]);
|
||||
}
|
||||
if (pos == 0) break;
|
||||
q = q.dbl().dbl().dbl().dbl();
|
||||
}
|
||||
try q.rejectIdentity();
|
||||
return q;
|
||||
}
|
||||
|
||||
fn pcMul16(pc: [16]P256, s: [32]u8, comptime vartime: bool) IdentityElementError!P256 {
|
||||
var q = P256.identityElement;
|
||||
var pos: usize = 252;
|
||||
while (true) : (pos -= 4) {
|
||||
const slot = @truncate(u4, (s[pos >> 3] >> @truncate(u3, pos)));
|
||||
if (vartime) {
|
||||
if (slot != 0) {
|
||||
q = q.add(pc[slot]);
|
||||
}
|
||||
} else {
|
||||
q = q.add(pcSelect(16, pc, slot));
|
||||
}
|
||||
if (pos == 0) break;
|
||||
q = q.dbl().dbl().dbl().dbl();
|
||||
}
|
||||
try q.rejectIdentity();
|
||||
return q;
|
||||
}
|
||||
|
||||
fn precompute(p: P256, comptime count: usize) [1 + count]P256 {
|
||||
var pc: [1 + count]P256 = undefined;
|
||||
pc[0] = P256.identityElement;
|
||||
pc[1] = p;
|
||||
var i: usize = 2;
|
||||
while (i <= count) : (i += 1) {
|
||||
pc[i] = if (i % 2 == 0) pc[i / 2].dbl() else pc[i - 1].add(p);
|
||||
}
|
||||
return pc;
|
||||
}
|
||||
|
||||
/// Multiply an elliptic curve point by a scalar.
|
||||
/// Return error.IdentityElement if the result is the identity element.
|
||||
pub fn mul(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {
|
||||
const s = if (endian == .Little) s_ else Fe.orderSwap(s_);
|
||||
const pc = if (p.is_base) precompute(P256.basePoint, 15) else pc: {
|
||||
try p.rejectIdentity();
|
||||
const xpc = precompute(p, 15);
|
||||
break :pc xpc;
|
||||
};
|
||||
return pcMul16(pc, s, false);
|
||||
}
|
||||
|
||||
/// Multiply an elliptic curve point by a *PUBLIC* scalar *IN VARIABLE TIME*
|
||||
/// This can be used for signature verification.
|
||||
pub fn mulPublic(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {
|
||||
const s = if (endian == .Little) s_ else Fe.orderSwap(s_);
|
||||
const pc = if (p.is_base) precompute(P256.basePoint, 8) else pc: {
|
||||
try p.rejectIdentity();
|
||||
const xpc = precompute(p, 8);
|
||||
break :pc xpc;
|
||||
};
|
||||
return pcMul(pc, s, true);
|
||||
}
|
||||
};
|
||||
|
||||
test "p256" {
|
||||
_ = @import("tests.zig");
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2015-2021 Zig Contributors
|
||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
||||
// The MIT license requires this copyright notice to be included in all copies
|
||||
// and substantial portions of the software.
|
||||
|
||||
const std = @import("std");
|
||||
const common = @import("../common.zig");
|
||||
|
||||
const Field = common.Field;
|
||||
|
||||
pub const Fe = Field(.{
|
||||
.fiat = @import("p256_64.zig"),
|
||||
.field_order = 115792089210356248762697446949407573530086143415290314195533631308867097853951,
|
||||
.field_bits = 256,
|
||||
.saturated_bits = 255,
|
||||
.encoded_length = 32,
|
||||
});
|
||||
@@ -0,0 +1,1812 @@
|
||||
// Autogenerated: 'src/ExtractionOCaml/word_by_word_montgomery' --lang Zig --internal-static --public-function-case camelCase --private-function-case camelCase --no-prefix-fiat --package-name p256 '' 64 '2^256 - 2^224 + 2^192 + 2^96 - 1' mul square add sub opp from_montgomery to_montgomery nonzero selectznz to_bytes from_bytes one msat divstep divstep_precomp
|
||||
// curve description (via package name): p256
|
||||
// machine_wordsize = 64 (from "64")
|
||||
// requested operations: mul, square, add, sub, opp, from_montgomery, to_montgomery, nonzero, selectznz, to_bytes, from_bytes, one, msat, divstep, divstep_precomp
|
||||
// m = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff (from "2^256 - 2^224 + 2^192 + 2^96 - 1")
|
||||
//
|
||||
// NOTE: In addition to the bounds specified above each function, all
|
||||
// functions synthesized for this Montgomery arithmetic require the
|
||||
// input to be strictly less than the prime modulus (m), and also
|
||||
// require the input to be in the unique saturated representation.
|
||||
// All functions also ensure that these two properties are true of
|
||||
// return values.
|
||||
//
|
||||
// Computed values:
|
||||
// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192)
|
||||
// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248)
|
||||
// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in
|
||||
// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256
|
||||
|
||||
const std = @import("std");
|
||||
const cast = std.meta.cast;
|
||||
const mode = std.builtin.mode; // Checked arithmetic is disabled in non-debug modes to avoid side channels
|
||||
|
||||
pub const Limbs = [4]u64;
|
||||
|
||||
/// The function addcarryxU64 is an addition with carry.
|
||||
/// Postconditions:
|
||||
/// out1 = (arg1 + arg2 + arg3) mod 2^64
|
||||
/// out2 = ⌊(arg1 + arg2 + arg3) / 2^64⌋
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [0x0 ~> 0x1]
|
||||
/// arg2: [0x0 ~> 0xffffffffffffffff]
|
||||
/// arg3: [0x0 ~> 0xffffffffffffffff]
|
||||
/// Output Bounds:
|
||||
/// out1: [0x0 ~> 0xffffffffffffffff]
|
||||
/// out2: [0x0 ~> 0x1]
|
||||
fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
var t: u64 = undefined;
|
||||
const carry1 = @addWithOverflow(u64, arg2, arg3, &t);
|
||||
const carry2 = @addWithOverflow(u64, t, arg1, out1);
|
||||
out2.* = @boolToInt(carry1) | @boolToInt(carry2);
|
||||
}
|
||||
|
||||
/// The function subborrowxU64 is a subtraction with borrow.
|
||||
/// Postconditions:
|
||||
/// out1 = (-arg1 + arg2 + -arg3) mod 2^64
|
||||
/// out2 = -⌊(-arg1 + arg2 + -arg3) / 2^64⌋
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [0x0 ~> 0x1]
|
||||
/// arg2: [0x0 ~> 0xffffffffffffffff]
|
||||
/// arg3: [0x0 ~> 0xffffffffffffffff]
|
||||
/// Output Bounds:
|
||||
/// out1: [0x0 ~> 0xffffffffffffffff]
|
||||
/// out2: [0x0 ~> 0x1]
|
||||
fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
var t: u64 = undefined;
|
||||
const carry1 = @subWithOverflow(u64, arg2, arg3, &t);
|
||||
const carry2 = @subWithOverflow(u64, t, arg1, out1);
|
||||
out2.* = @boolToInt(carry1) | @boolToInt(carry2);
|
||||
}
|
||||
|
||||
/// The function mulxU64 is a multiplication, returning the full double-width result.
|
||||
/// Postconditions:
|
||||
/// out1 = (arg1 * arg2) mod 2^64
|
||||
/// out2 = ⌊arg1 * arg2 / 2^64⌋
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [0x0 ~> 0xffffffffffffffff]
|
||||
/// arg2: [0x0 ~> 0xffffffffffffffff]
|
||||
/// Output Bounds:
|
||||
/// out1: [0x0 ~> 0xffffffffffffffff]
|
||||
/// out2: [0x0 ~> 0xffffffffffffffff]
|
||||
fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) callconv(.Inline) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const x = @as(u128, arg1) * @as(u128, arg2);
|
||||
out1.* = @truncate(u64, x);
|
||||
out2.* = @truncate(u64, x >> 64);
|
||||
}
|
||||
|
||||
/// The function cmovznzU64 is a single-word conditional move.
|
||||
/// Postconditions:
|
||||
/// out1 = (if arg1 = 0 then arg2 else arg3)
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [0x0 ~> 0x1]
|
||||
/// arg2: [0x0 ~> 0xffffffffffffffff]
|
||||
/// arg3: [0x0 ~> 0xffffffffffffffff]
|
||||
/// Output Bounds:
|
||||
/// out1: [0x0 ~> 0xffffffffffffffff]
|
||||
fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const mask = 0 -% @as(u64, arg1);
|
||||
out1.* = (mask & arg3) | ((~mask) & arg2);
|
||||
}
|
||||
|
||||
/// The function mul multiplies two field elements in the Montgomery domain.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// 0 ≤ eval arg2 < m
|
||||
/// Postconditions:
|
||||
/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn mul(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const x1 = (arg1[1]);
|
||||
const x2 = (arg1[2]);
|
||||
const x3 = (arg1[3]);
|
||||
const x4 = (arg1[0]);
|
||||
var x5: u64 = undefined;
|
||||
var x6: u64 = undefined;
|
||||
mulxU64(&x5, &x6, x4, (arg2[3]));
|
||||
var x7: u64 = undefined;
|
||||
var x8: u64 = undefined;
|
||||
mulxU64(&x7, &x8, x4, (arg2[2]));
|
||||
var x9: u64 = undefined;
|
||||
var x10: u64 = undefined;
|
||||
mulxU64(&x9, &x10, x4, (arg2[1]));
|
||||
var x11: u64 = undefined;
|
||||
var x12: u64 = undefined;
|
||||
mulxU64(&x11, &x12, x4, (arg2[0]));
|
||||
var x13: u64 = undefined;
|
||||
var x14: u1 = undefined;
|
||||
addcarryxU64(&x13, &x14, 0x0, x12, x9);
|
||||
var x15: u64 = undefined;
|
||||
var x16: u1 = undefined;
|
||||
addcarryxU64(&x15, &x16, x14, x10, x7);
|
||||
var x17: u64 = undefined;
|
||||
var x18: u1 = undefined;
|
||||
addcarryxU64(&x17, &x18, x16, x8, x5);
|
||||
const x19 = (cast(u64, x18) + x6);
|
||||
var x20: u64 = undefined;
|
||||
var x21: u64 = undefined;
|
||||
mulxU64(&x20, &x21, x11, 0xffffffff00000001);
|
||||
var x22: u64 = undefined;
|
||||
var x23: u64 = undefined;
|
||||
mulxU64(&x22, &x23, x11, 0xffffffff);
|
||||
var x24: u64 = undefined;
|
||||
var x25: u64 = undefined;
|
||||
mulxU64(&x24, &x25, x11, 0xffffffffffffffff);
|
||||
var x26: u64 = undefined;
|
||||
var x27: u1 = undefined;
|
||||
addcarryxU64(&x26, &x27, 0x0, x25, x22);
|
||||
const x28 = (cast(u64, x27) + x23);
|
||||
var x29: u64 = undefined;
|
||||
var x30: u1 = undefined;
|
||||
addcarryxU64(&x29, &x30, 0x0, x11, x24);
|
||||
var x31: u64 = undefined;
|
||||
var x32: u1 = undefined;
|
||||
addcarryxU64(&x31, &x32, x30, x13, x26);
|
||||
var x33: u64 = undefined;
|
||||
var x34: u1 = undefined;
|
||||
addcarryxU64(&x33, &x34, x32, x15, x28);
|
||||
var x35: u64 = undefined;
|
||||
var x36: u1 = undefined;
|
||||
addcarryxU64(&x35, &x36, x34, x17, x20);
|
||||
var x37: u64 = undefined;
|
||||
var x38: u1 = undefined;
|
||||
addcarryxU64(&x37, &x38, x36, x19, x21);
|
||||
var x39: u64 = undefined;
|
||||
var x40: u64 = undefined;
|
||||
mulxU64(&x39, &x40, x1, (arg2[3]));
|
||||
var x41: u64 = undefined;
|
||||
var x42: u64 = undefined;
|
||||
mulxU64(&x41, &x42, x1, (arg2[2]));
|
||||
var x43: u64 = undefined;
|
||||
var x44: u64 = undefined;
|
||||
mulxU64(&x43, &x44, x1, (arg2[1]));
|
||||
var x45: u64 = undefined;
|
||||
var x46: u64 = undefined;
|
||||
mulxU64(&x45, &x46, x1, (arg2[0]));
|
||||
var x47: u64 = undefined;
|
||||
var x48: u1 = undefined;
|
||||
addcarryxU64(&x47, &x48, 0x0, x46, x43);
|
||||
var x49: u64 = undefined;
|
||||
var x50: u1 = undefined;
|
||||
addcarryxU64(&x49, &x50, x48, x44, x41);
|
||||
var x51: u64 = undefined;
|
||||
var x52: u1 = undefined;
|
||||
addcarryxU64(&x51, &x52, x50, x42, x39);
|
||||
const x53 = (cast(u64, x52) + x40);
|
||||
var x54: u64 = undefined;
|
||||
var x55: u1 = undefined;
|
||||
addcarryxU64(&x54, &x55, 0x0, x31, x45);
|
||||
var x56: u64 = undefined;
|
||||
var x57: u1 = undefined;
|
||||
addcarryxU64(&x56, &x57, x55, x33, x47);
|
||||
var x58: u64 = undefined;
|
||||
var x59: u1 = undefined;
|
||||
addcarryxU64(&x58, &x59, x57, x35, x49);
|
||||
var x60: u64 = undefined;
|
||||
var x61: u1 = undefined;
|
||||
addcarryxU64(&x60, &x61, x59, x37, x51);
|
||||
var x62: u64 = undefined;
|
||||
var x63: u1 = undefined;
|
||||
addcarryxU64(&x62, &x63, x61, cast(u64, x38), x53);
|
||||
var x64: u64 = undefined;
|
||||
var x65: u64 = undefined;
|
||||
mulxU64(&x64, &x65, x54, 0xffffffff00000001);
|
||||
var x66: u64 = undefined;
|
||||
var x67: u64 = undefined;
|
||||
mulxU64(&x66, &x67, x54, 0xffffffff);
|
||||
var x68: u64 = undefined;
|
||||
var x69: u64 = undefined;
|
||||
mulxU64(&x68, &x69, x54, 0xffffffffffffffff);
|
||||
var x70: u64 = undefined;
|
||||
var x71: u1 = undefined;
|
||||
addcarryxU64(&x70, &x71, 0x0, x69, x66);
|
||||
const x72 = (cast(u64, x71) + x67);
|
||||
var x73: u64 = undefined;
|
||||
var x74: u1 = undefined;
|
||||
addcarryxU64(&x73, &x74, 0x0, x54, x68);
|
||||
var x75: u64 = undefined;
|
||||
var x76: u1 = undefined;
|
||||
addcarryxU64(&x75, &x76, x74, x56, x70);
|
||||
var x77: u64 = undefined;
|
||||
var x78: u1 = undefined;
|
||||
addcarryxU64(&x77, &x78, x76, x58, x72);
|
||||
var x79: u64 = undefined;
|
||||
var x80: u1 = undefined;
|
||||
addcarryxU64(&x79, &x80, x78, x60, x64);
|
||||
var x81: u64 = undefined;
|
||||
var x82: u1 = undefined;
|
||||
addcarryxU64(&x81, &x82, x80, x62, x65);
|
||||
const x83 = (cast(u64, x82) + cast(u64, x63));
|
||||
var x84: u64 = undefined;
|
||||
var x85: u64 = undefined;
|
||||
mulxU64(&x84, &x85, x2, (arg2[3]));
|
||||
var x86: u64 = undefined;
|
||||
var x87: u64 = undefined;
|
||||
mulxU64(&x86, &x87, x2, (arg2[2]));
|
||||
var x88: u64 = undefined;
|
||||
var x89: u64 = undefined;
|
||||
mulxU64(&x88, &x89, x2, (arg2[1]));
|
||||
var x90: u64 = undefined;
|
||||
var x91: u64 = undefined;
|
||||
mulxU64(&x90, &x91, x2, (arg2[0]));
|
||||
var x92: u64 = undefined;
|
||||
var x93: u1 = undefined;
|
||||
addcarryxU64(&x92, &x93, 0x0, x91, x88);
|
||||
var x94: u64 = undefined;
|
||||
var x95: u1 = undefined;
|
||||
addcarryxU64(&x94, &x95, x93, x89, x86);
|
||||
var x96: u64 = undefined;
|
||||
var x97: u1 = undefined;
|
||||
addcarryxU64(&x96, &x97, x95, x87, x84);
|
||||
const x98 = (cast(u64, x97) + x85);
|
||||
var x99: u64 = undefined;
|
||||
var x100: u1 = undefined;
|
||||
addcarryxU64(&x99, &x100, 0x0, x75, x90);
|
||||
var x101: u64 = undefined;
|
||||
var x102: u1 = undefined;
|
||||
addcarryxU64(&x101, &x102, x100, x77, x92);
|
||||
var x103: u64 = undefined;
|
||||
var x104: u1 = undefined;
|
||||
addcarryxU64(&x103, &x104, x102, x79, x94);
|
||||
var x105: u64 = undefined;
|
||||
var x106: u1 = undefined;
|
||||
addcarryxU64(&x105, &x106, x104, x81, x96);
|
||||
var x107: u64 = undefined;
|
||||
var x108: u1 = undefined;
|
||||
addcarryxU64(&x107, &x108, x106, x83, x98);
|
||||
var x109: u64 = undefined;
|
||||
var x110: u64 = undefined;
|
||||
mulxU64(&x109, &x110, x99, 0xffffffff00000001);
|
||||
var x111: u64 = undefined;
|
||||
var x112: u64 = undefined;
|
||||
mulxU64(&x111, &x112, x99, 0xffffffff);
|
||||
var x113: u64 = undefined;
|
||||
var x114: u64 = undefined;
|
||||
mulxU64(&x113, &x114, x99, 0xffffffffffffffff);
|
||||
var x115: u64 = undefined;
|
||||
var x116: u1 = undefined;
|
||||
addcarryxU64(&x115, &x116, 0x0, x114, x111);
|
||||
const x117 = (cast(u64, x116) + x112);
|
||||
var x118: u64 = undefined;
|
||||
var x119: u1 = undefined;
|
||||
addcarryxU64(&x118, &x119, 0x0, x99, x113);
|
||||
var x120: u64 = undefined;
|
||||
var x121: u1 = undefined;
|
||||
addcarryxU64(&x120, &x121, x119, x101, x115);
|
||||
var x122: u64 = undefined;
|
||||
var x123: u1 = undefined;
|
||||
addcarryxU64(&x122, &x123, x121, x103, x117);
|
||||
var x124: u64 = undefined;
|
||||
var x125: u1 = undefined;
|
||||
addcarryxU64(&x124, &x125, x123, x105, x109);
|
||||
var x126: u64 = undefined;
|
||||
var x127: u1 = undefined;
|
||||
addcarryxU64(&x126, &x127, x125, x107, x110);
|
||||
const x128 = (cast(u64, x127) + cast(u64, x108));
|
||||
var x129: u64 = undefined;
|
||||
var x130: u64 = undefined;
|
||||
mulxU64(&x129, &x130, x3, (arg2[3]));
|
||||
var x131: u64 = undefined;
|
||||
var x132: u64 = undefined;
|
||||
mulxU64(&x131, &x132, x3, (arg2[2]));
|
||||
var x133: u64 = undefined;
|
||||
var x134: u64 = undefined;
|
||||
mulxU64(&x133, &x134, x3, (arg2[1]));
|
||||
var x135: u64 = undefined;
|
||||
var x136: u64 = undefined;
|
||||
mulxU64(&x135, &x136, x3, (arg2[0]));
|
||||
var x137: u64 = undefined;
|
||||
var x138: u1 = undefined;
|
||||
addcarryxU64(&x137, &x138, 0x0, x136, x133);
|
||||
var x139: u64 = undefined;
|
||||
var x140: u1 = undefined;
|
||||
addcarryxU64(&x139, &x140, x138, x134, x131);
|
||||
var x141: u64 = undefined;
|
||||
var x142: u1 = undefined;
|
||||
addcarryxU64(&x141, &x142, x140, x132, x129);
|
||||
const x143 = (cast(u64, x142) + x130);
|
||||
var x144: u64 = undefined;
|
||||
var x145: u1 = undefined;
|
||||
addcarryxU64(&x144, &x145, 0x0, x120, x135);
|
||||
var x146: u64 = undefined;
|
||||
var x147: u1 = undefined;
|
||||
addcarryxU64(&x146, &x147, x145, x122, x137);
|
||||
var x148: u64 = undefined;
|
||||
var x149: u1 = undefined;
|
||||
addcarryxU64(&x148, &x149, x147, x124, x139);
|
||||
var x150: u64 = undefined;
|
||||
var x151: u1 = undefined;
|
||||
addcarryxU64(&x150, &x151, x149, x126, x141);
|
||||
var x152: u64 = undefined;
|
||||
var x153: u1 = undefined;
|
||||
addcarryxU64(&x152, &x153, x151, x128, x143);
|
||||
var x154: u64 = undefined;
|
||||
var x155: u64 = undefined;
|
||||
mulxU64(&x154, &x155, x144, 0xffffffff00000001);
|
||||
var x156: u64 = undefined;
|
||||
var x157: u64 = undefined;
|
||||
mulxU64(&x156, &x157, x144, 0xffffffff);
|
||||
var x158: u64 = undefined;
|
||||
var x159: u64 = undefined;
|
||||
mulxU64(&x158, &x159, x144, 0xffffffffffffffff);
|
||||
var x160: u64 = undefined;
|
||||
var x161: u1 = undefined;
|
||||
addcarryxU64(&x160, &x161, 0x0, x159, x156);
|
||||
const x162 = (cast(u64, x161) + x157);
|
||||
var x163: u64 = undefined;
|
||||
var x164: u1 = undefined;
|
||||
addcarryxU64(&x163, &x164, 0x0, x144, x158);
|
||||
var x165: u64 = undefined;
|
||||
var x166: u1 = undefined;
|
||||
addcarryxU64(&x165, &x166, x164, x146, x160);
|
||||
var x167: u64 = undefined;
|
||||
var x168: u1 = undefined;
|
||||
addcarryxU64(&x167, &x168, x166, x148, x162);
|
||||
var x169: u64 = undefined;
|
||||
var x170: u1 = undefined;
|
||||
addcarryxU64(&x169, &x170, x168, x150, x154);
|
||||
var x171: u64 = undefined;
|
||||
var x172: u1 = undefined;
|
||||
addcarryxU64(&x171, &x172, x170, x152, x155);
|
||||
const x173 = (cast(u64, x172) + cast(u64, x153));
|
||||
var x174: u64 = undefined;
|
||||
var x175: u1 = undefined;
|
||||
subborrowxU64(&x174, &x175, 0x0, x165, 0xffffffffffffffff);
|
||||
var x176: u64 = undefined;
|
||||
var x177: u1 = undefined;
|
||||
subborrowxU64(&x176, &x177, x175, x167, 0xffffffff);
|
||||
var x178: u64 = undefined;
|
||||
var x179: u1 = undefined;
|
||||
subborrowxU64(&x178, &x179, x177, x169, cast(u64, 0x0));
|
||||
var x180: u64 = undefined;
|
||||
var x181: u1 = undefined;
|
||||
subborrowxU64(&x180, &x181, x179, x171, 0xffffffff00000001);
|
||||
var x182: u64 = undefined;
|
||||
var x183: u1 = undefined;
|
||||
subborrowxU64(&x182, &x183, x181, x173, cast(u64, 0x0));
|
||||
var x184: u64 = undefined;
|
||||
cmovznzU64(&x184, x183, x174, x165);
|
||||
var x185: u64 = undefined;
|
||||
cmovznzU64(&x185, x183, x176, x167);
|
||||
var x186: u64 = undefined;
|
||||
cmovznzU64(&x186, x183, x178, x169);
|
||||
var x187: u64 = undefined;
|
||||
cmovznzU64(&x187, x183, x180, x171);
|
||||
out1[0] = x184;
|
||||
out1[1] = x185;
|
||||
out1[2] = x186;
|
||||
out1[3] = x187;
|
||||
}
|
||||
|
||||
/// The function square squares a field element in the Montgomery domain.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// Postconditions:
|
||||
/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn square(out1: *[4]u64, arg1: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const x1 = (arg1[1]);
|
||||
const x2 = (arg1[2]);
|
||||
const x3 = (arg1[3]);
|
||||
const x4 = (arg1[0]);
|
||||
var x5: u64 = undefined;
|
||||
var x6: u64 = undefined;
|
||||
mulxU64(&x5, &x6, x4, (arg1[3]));
|
||||
var x7: u64 = undefined;
|
||||
var x8: u64 = undefined;
|
||||
mulxU64(&x7, &x8, x4, (arg1[2]));
|
||||
var x9: u64 = undefined;
|
||||
var x10: u64 = undefined;
|
||||
mulxU64(&x9, &x10, x4, (arg1[1]));
|
||||
var x11: u64 = undefined;
|
||||
var x12: u64 = undefined;
|
||||
mulxU64(&x11, &x12, x4, (arg1[0]));
|
||||
var x13: u64 = undefined;
|
||||
var x14: u1 = undefined;
|
||||
addcarryxU64(&x13, &x14, 0x0, x12, x9);
|
||||
var x15: u64 = undefined;
|
||||
var x16: u1 = undefined;
|
||||
addcarryxU64(&x15, &x16, x14, x10, x7);
|
||||
var x17: u64 = undefined;
|
||||
var x18: u1 = undefined;
|
||||
addcarryxU64(&x17, &x18, x16, x8, x5);
|
||||
const x19 = (cast(u64, x18) + x6);
|
||||
var x20: u64 = undefined;
|
||||
var x21: u64 = undefined;
|
||||
mulxU64(&x20, &x21, x11, 0xffffffff00000001);
|
||||
var x22: u64 = undefined;
|
||||
var x23: u64 = undefined;
|
||||
mulxU64(&x22, &x23, x11, 0xffffffff);
|
||||
var x24: u64 = undefined;
|
||||
var x25: u64 = undefined;
|
||||
mulxU64(&x24, &x25, x11, 0xffffffffffffffff);
|
||||
var x26: u64 = undefined;
|
||||
var x27: u1 = undefined;
|
||||
addcarryxU64(&x26, &x27, 0x0, x25, x22);
|
||||
const x28 = (cast(u64, x27) + x23);
|
||||
var x29: u64 = undefined;
|
||||
var x30: u1 = undefined;
|
||||
addcarryxU64(&x29, &x30, 0x0, x11, x24);
|
||||
var x31: u64 = undefined;
|
||||
var x32: u1 = undefined;
|
||||
addcarryxU64(&x31, &x32, x30, x13, x26);
|
||||
var x33: u64 = undefined;
|
||||
var x34: u1 = undefined;
|
||||
addcarryxU64(&x33, &x34, x32, x15, x28);
|
||||
var x35: u64 = undefined;
|
||||
var x36: u1 = undefined;
|
||||
addcarryxU64(&x35, &x36, x34, x17, x20);
|
||||
var x37: u64 = undefined;
|
||||
var x38: u1 = undefined;
|
||||
addcarryxU64(&x37, &x38, x36, x19, x21);
|
||||
var x39: u64 = undefined;
|
||||
var x40: u64 = undefined;
|
||||
mulxU64(&x39, &x40, x1, (arg1[3]));
|
||||
var x41: u64 = undefined;
|
||||
var x42: u64 = undefined;
|
||||
mulxU64(&x41, &x42, x1, (arg1[2]));
|
||||
var x43: u64 = undefined;
|
||||
var x44: u64 = undefined;
|
||||
mulxU64(&x43, &x44, x1, (arg1[1]));
|
||||
var x45: u64 = undefined;
|
||||
var x46: u64 = undefined;
|
||||
mulxU64(&x45, &x46, x1, (arg1[0]));
|
||||
var x47: u64 = undefined;
|
||||
var x48: u1 = undefined;
|
||||
addcarryxU64(&x47, &x48, 0x0, x46, x43);
|
||||
var x49: u64 = undefined;
|
||||
var x50: u1 = undefined;
|
||||
addcarryxU64(&x49, &x50, x48, x44, x41);
|
||||
var x51: u64 = undefined;
|
||||
var x52: u1 = undefined;
|
||||
addcarryxU64(&x51, &x52, x50, x42, x39);
|
||||
const x53 = (cast(u64, x52) + x40);
|
||||
var x54: u64 = undefined;
|
||||
var x55: u1 = undefined;
|
||||
addcarryxU64(&x54, &x55, 0x0, x31, x45);
|
||||
var x56: u64 = undefined;
|
||||
var x57: u1 = undefined;
|
||||
addcarryxU64(&x56, &x57, x55, x33, x47);
|
||||
var x58: u64 = undefined;
|
||||
var x59: u1 = undefined;
|
||||
addcarryxU64(&x58, &x59, x57, x35, x49);
|
||||
var x60: u64 = undefined;
|
||||
var x61: u1 = undefined;
|
||||
addcarryxU64(&x60, &x61, x59, x37, x51);
|
||||
var x62: u64 = undefined;
|
||||
var x63: u1 = undefined;
|
||||
addcarryxU64(&x62, &x63, x61, cast(u64, x38), x53);
|
||||
var x64: u64 = undefined;
|
||||
var x65: u64 = undefined;
|
||||
mulxU64(&x64, &x65, x54, 0xffffffff00000001);
|
||||
var x66: u64 = undefined;
|
||||
var x67: u64 = undefined;
|
||||
mulxU64(&x66, &x67, x54, 0xffffffff);
|
||||
var x68: u64 = undefined;
|
||||
var x69: u64 = undefined;
|
||||
mulxU64(&x68, &x69, x54, 0xffffffffffffffff);
|
||||
var x70: u64 = undefined;
|
||||
var x71: u1 = undefined;
|
||||
addcarryxU64(&x70, &x71, 0x0, x69, x66);
|
||||
const x72 = (cast(u64, x71) + x67);
|
||||
var x73: u64 = undefined;
|
||||
var x74: u1 = undefined;
|
||||
addcarryxU64(&x73, &x74, 0x0, x54, x68);
|
||||
var x75: u64 = undefined;
|
||||
var x76: u1 = undefined;
|
||||
addcarryxU64(&x75, &x76, x74, x56, x70);
|
||||
var x77: u64 = undefined;
|
||||
var x78: u1 = undefined;
|
||||
addcarryxU64(&x77, &x78, x76, x58, x72);
|
||||
var x79: u64 = undefined;
|
||||
var x80: u1 = undefined;
|
||||
addcarryxU64(&x79, &x80, x78, x60, x64);
|
||||
var x81: u64 = undefined;
|
||||
var x82: u1 = undefined;
|
||||
addcarryxU64(&x81, &x82, x80, x62, x65);
|
||||
const x83 = (cast(u64, x82) + cast(u64, x63));
|
||||
var x84: u64 = undefined;
|
||||
var x85: u64 = undefined;
|
||||
mulxU64(&x84, &x85, x2, (arg1[3]));
|
||||
var x86: u64 = undefined;
|
||||
var x87: u64 = undefined;
|
||||
mulxU64(&x86, &x87, x2, (arg1[2]));
|
||||
var x88: u64 = undefined;
|
||||
var x89: u64 = undefined;
|
||||
mulxU64(&x88, &x89, x2, (arg1[1]));
|
||||
var x90: u64 = undefined;
|
||||
var x91: u64 = undefined;
|
||||
mulxU64(&x90, &x91, x2, (arg1[0]));
|
||||
var x92: u64 = undefined;
|
||||
var x93: u1 = undefined;
|
||||
addcarryxU64(&x92, &x93, 0x0, x91, x88);
|
||||
var x94: u64 = undefined;
|
||||
var x95: u1 = undefined;
|
||||
addcarryxU64(&x94, &x95, x93, x89, x86);
|
||||
var x96: u64 = undefined;
|
||||
var x97: u1 = undefined;
|
||||
addcarryxU64(&x96, &x97, x95, x87, x84);
|
||||
const x98 = (cast(u64, x97) + x85);
|
||||
var x99: u64 = undefined;
|
||||
var x100: u1 = undefined;
|
||||
addcarryxU64(&x99, &x100, 0x0, x75, x90);
|
||||
var x101: u64 = undefined;
|
||||
var x102: u1 = undefined;
|
||||
addcarryxU64(&x101, &x102, x100, x77, x92);
|
||||
var x103: u64 = undefined;
|
||||
var x104: u1 = undefined;
|
||||
addcarryxU64(&x103, &x104, x102, x79, x94);
|
||||
var x105: u64 = undefined;
|
||||
var x106: u1 = undefined;
|
||||
addcarryxU64(&x105, &x106, x104, x81, x96);
|
||||
var x107: u64 = undefined;
|
||||
var x108: u1 = undefined;
|
||||
addcarryxU64(&x107, &x108, x106, x83, x98);
|
||||
var x109: u64 = undefined;
|
||||
var x110: u64 = undefined;
|
||||
mulxU64(&x109, &x110, x99, 0xffffffff00000001);
|
||||
var x111: u64 = undefined;
|
||||
var x112: u64 = undefined;
|
||||
mulxU64(&x111, &x112, x99, 0xffffffff);
|
||||
var x113: u64 = undefined;
|
||||
var x114: u64 = undefined;
|
||||
mulxU64(&x113, &x114, x99, 0xffffffffffffffff);
|
||||
var x115: u64 = undefined;
|
||||
var x116: u1 = undefined;
|
||||
addcarryxU64(&x115, &x116, 0x0, x114, x111);
|
||||
const x117 = (cast(u64, x116) + x112);
|
||||
var x118: u64 = undefined;
|
||||
var x119: u1 = undefined;
|
||||
addcarryxU64(&x118, &x119, 0x0, x99, x113);
|
||||
var x120: u64 = undefined;
|
||||
var x121: u1 = undefined;
|
||||
addcarryxU64(&x120, &x121, x119, x101, x115);
|
||||
var x122: u64 = undefined;
|
||||
var x123: u1 = undefined;
|
||||
addcarryxU64(&x122, &x123, x121, x103, x117);
|
||||
var x124: u64 = undefined;
|
||||
var x125: u1 = undefined;
|
||||
addcarryxU64(&x124, &x125, x123, x105, x109);
|
||||
var x126: u64 = undefined;
|
||||
var x127: u1 = undefined;
|
||||
addcarryxU64(&x126, &x127, x125, x107, x110);
|
||||
const x128 = (cast(u64, x127) + cast(u64, x108));
|
||||
var x129: u64 = undefined;
|
||||
var x130: u64 = undefined;
|
||||
mulxU64(&x129, &x130, x3, (arg1[3]));
|
||||
var x131: u64 = undefined;
|
||||
var x132: u64 = undefined;
|
||||
mulxU64(&x131, &x132, x3, (arg1[2]));
|
||||
var x133: u64 = undefined;
|
||||
var x134: u64 = undefined;
|
||||
mulxU64(&x133, &x134, x3, (arg1[1]));
|
||||
var x135: u64 = undefined;
|
||||
var x136: u64 = undefined;
|
||||
mulxU64(&x135, &x136, x3, (arg1[0]));
|
||||
var x137: u64 = undefined;
|
||||
var x138: u1 = undefined;
|
||||
addcarryxU64(&x137, &x138, 0x0, x136, x133);
|
||||
var x139: u64 = undefined;
|
||||
var x140: u1 = undefined;
|
||||
addcarryxU64(&x139, &x140, x138, x134, x131);
|
||||
var x141: u64 = undefined;
|
||||
var x142: u1 = undefined;
|
||||
addcarryxU64(&x141, &x142, x140, x132, x129);
|
||||
const x143 = (cast(u64, x142) + x130);
|
||||
var x144: u64 = undefined;
|
||||
var x145: u1 = undefined;
|
||||
addcarryxU64(&x144, &x145, 0x0, x120, x135);
|
||||
var x146: u64 = undefined;
|
||||
var x147: u1 = undefined;
|
||||
addcarryxU64(&x146, &x147, x145, x122, x137);
|
||||
var x148: u64 = undefined;
|
||||
var x149: u1 = undefined;
|
||||
addcarryxU64(&x148, &x149, x147, x124, x139);
|
||||
var x150: u64 = undefined;
|
||||
var x151: u1 = undefined;
|
||||
addcarryxU64(&x150, &x151, x149, x126, x141);
|
||||
var x152: u64 = undefined;
|
||||
var x153: u1 = undefined;
|
||||
addcarryxU64(&x152, &x153, x151, x128, x143);
|
||||
var x154: u64 = undefined;
|
||||
var x155: u64 = undefined;
|
||||
mulxU64(&x154, &x155, x144, 0xffffffff00000001);
|
||||
var x156: u64 = undefined;
|
||||
var x157: u64 = undefined;
|
||||
mulxU64(&x156, &x157, x144, 0xffffffff);
|
||||
var x158: u64 = undefined;
|
||||
var x159: u64 = undefined;
|
||||
mulxU64(&x158, &x159, x144, 0xffffffffffffffff);
|
||||
var x160: u64 = undefined;
|
||||
var x161: u1 = undefined;
|
||||
addcarryxU64(&x160, &x161, 0x0, x159, x156);
|
||||
const x162 = (cast(u64, x161) + x157);
|
||||
var x163: u64 = undefined;
|
||||
var x164: u1 = undefined;
|
||||
addcarryxU64(&x163, &x164, 0x0, x144, x158);
|
||||
var x165: u64 = undefined;
|
||||
var x166: u1 = undefined;
|
||||
addcarryxU64(&x165, &x166, x164, x146, x160);
|
||||
var x167: u64 = undefined;
|
||||
var x168: u1 = undefined;
|
||||
addcarryxU64(&x167, &x168, x166, x148, x162);
|
||||
var x169: u64 = undefined;
|
||||
var x170: u1 = undefined;
|
||||
addcarryxU64(&x169, &x170, x168, x150, x154);
|
||||
var x171: u64 = undefined;
|
||||
var x172: u1 = undefined;
|
||||
addcarryxU64(&x171, &x172, x170, x152, x155);
|
||||
const x173 = (cast(u64, x172) + cast(u64, x153));
|
||||
var x174: u64 = undefined;
|
||||
var x175: u1 = undefined;
|
||||
subborrowxU64(&x174, &x175, 0x0, x165, 0xffffffffffffffff);
|
||||
var x176: u64 = undefined;
|
||||
var x177: u1 = undefined;
|
||||
subborrowxU64(&x176, &x177, x175, x167, 0xffffffff);
|
||||
var x178: u64 = undefined;
|
||||
var x179: u1 = undefined;
|
||||
subborrowxU64(&x178, &x179, x177, x169, cast(u64, 0x0));
|
||||
var x180: u64 = undefined;
|
||||
var x181: u1 = undefined;
|
||||
subborrowxU64(&x180, &x181, x179, x171, 0xffffffff00000001);
|
||||
var x182: u64 = undefined;
|
||||
var x183: u1 = undefined;
|
||||
subborrowxU64(&x182, &x183, x181, x173, cast(u64, 0x0));
|
||||
var x184: u64 = undefined;
|
||||
cmovznzU64(&x184, x183, x174, x165);
|
||||
var x185: u64 = undefined;
|
||||
cmovznzU64(&x185, x183, x176, x167);
|
||||
var x186: u64 = undefined;
|
||||
cmovznzU64(&x186, x183, x178, x169);
|
||||
var x187: u64 = undefined;
|
||||
cmovznzU64(&x187, x183, x180, x171);
|
||||
out1[0] = x184;
|
||||
out1[1] = x185;
|
||||
out1[2] = x186;
|
||||
out1[3] = x187;
|
||||
}
|
||||
|
||||
/// The function add adds two field elements in the Montgomery domain.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// 0 ≤ eval arg2 < m
|
||||
/// Postconditions:
|
||||
/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
var x1: u64 = undefined;
|
||||
var x2: u1 = undefined;
|
||||
addcarryxU64(&x1, &x2, 0x0, (arg1[0]), (arg2[0]));
|
||||
var x3: u64 = undefined;
|
||||
var x4: u1 = undefined;
|
||||
addcarryxU64(&x3, &x4, x2, (arg1[1]), (arg2[1]));
|
||||
var x5: u64 = undefined;
|
||||
var x6: u1 = undefined;
|
||||
addcarryxU64(&x5, &x6, x4, (arg1[2]), (arg2[2]));
|
||||
var x7: u64 = undefined;
|
||||
var x8: u1 = undefined;
|
||||
addcarryxU64(&x7, &x8, x6, (arg1[3]), (arg2[3]));
|
||||
var x9: u64 = undefined;
|
||||
var x10: u1 = undefined;
|
||||
subborrowxU64(&x9, &x10, 0x0, x1, 0xffffffffffffffff);
|
||||
var x11: u64 = undefined;
|
||||
var x12: u1 = undefined;
|
||||
subborrowxU64(&x11, &x12, x10, x3, 0xffffffff);
|
||||
var x13: u64 = undefined;
|
||||
var x14: u1 = undefined;
|
||||
subborrowxU64(&x13, &x14, x12, x5, cast(u64, 0x0));
|
||||
var x15: u64 = undefined;
|
||||
var x16: u1 = undefined;
|
||||
subborrowxU64(&x15, &x16, x14, x7, 0xffffffff00000001);
|
||||
var x17: u64 = undefined;
|
||||
var x18: u1 = undefined;
|
||||
subborrowxU64(&x17, &x18, x16, cast(u64, x8), cast(u64, 0x0));
|
||||
var x19: u64 = undefined;
|
||||
cmovznzU64(&x19, x18, x9, x1);
|
||||
var x20: u64 = undefined;
|
||||
cmovznzU64(&x20, x18, x11, x3);
|
||||
var x21: u64 = undefined;
|
||||
cmovznzU64(&x21, x18, x13, x5);
|
||||
var x22: u64 = undefined;
|
||||
cmovznzU64(&x22, x18, x15, x7);
|
||||
out1[0] = x19;
|
||||
out1[1] = x20;
|
||||
out1[2] = x21;
|
||||
out1[3] = x22;
|
||||
}
|
||||
|
||||
/// The function sub subtracts two field elements in the Montgomery domain.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// 0 ≤ eval arg2 < m
|
||||
/// Postconditions:
|
||||
/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn sub(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
var x1: u64 = undefined;
|
||||
var x2: u1 = undefined;
|
||||
subborrowxU64(&x1, &x2, 0x0, (arg1[0]), (arg2[0]));
|
||||
var x3: u64 = undefined;
|
||||
var x4: u1 = undefined;
|
||||
subborrowxU64(&x3, &x4, x2, (arg1[1]), (arg2[1]));
|
||||
var x5: u64 = undefined;
|
||||
var x6: u1 = undefined;
|
||||
subborrowxU64(&x5, &x6, x4, (arg1[2]), (arg2[2]));
|
||||
var x7: u64 = undefined;
|
||||
var x8: u1 = undefined;
|
||||
subborrowxU64(&x7, &x8, x6, (arg1[3]), (arg2[3]));
|
||||
var x9: u64 = undefined;
|
||||
cmovznzU64(&x9, x8, cast(u64, 0x0), 0xffffffffffffffff);
|
||||
var x10: u64 = undefined;
|
||||
var x11: u1 = undefined;
|
||||
addcarryxU64(&x10, &x11, 0x0, x1, x9);
|
||||
var x12: u64 = undefined;
|
||||
var x13: u1 = undefined;
|
||||
addcarryxU64(&x12, &x13, x11, x3, (x9 & 0xffffffff));
|
||||
var x14: u64 = undefined;
|
||||
var x15: u1 = undefined;
|
||||
addcarryxU64(&x14, &x15, x13, x5, cast(u64, 0x0));
|
||||
var x16: u64 = undefined;
|
||||
var x17: u1 = undefined;
|
||||
addcarryxU64(&x16, &x17, x15, x7, (x9 & 0xffffffff00000001));
|
||||
out1[0] = x10;
|
||||
out1[1] = x12;
|
||||
out1[2] = x14;
|
||||
out1[3] = x16;
|
||||
}
|
||||
|
||||
/// The function opp negates a field element in the Montgomery domain.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// Postconditions:
|
||||
/// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn opp(out1: *[4]u64, arg1: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
var x1: u64 = undefined;
|
||||
var x2: u1 = undefined;
|
||||
subborrowxU64(&x1, &x2, 0x0, cast(u64, 0x0), (arg1[0]));
|
||||
var x3: u64 = undefined;
|
||||
var x4: u1 = undefined;
|
||||
subborrowxU64(&x3, &x4, x2, cast(u64, 0x0), (arg1[1]));
|
||||
var x5: u64 = undefined;
|
||||
var x6: u1 = undefined;
|
||||
subborrowxU64(&x5, &x6, x4, cast(u64, 0x0), (arg1[2]));
|
||||
var x7: u64 = undefined;
|
||||
var x8: u1 = undefined;
|
||||
subborrowxU64(&x7, &x8, x6, cast(u64, 0x0), (arg1[3]));
|
||||
var x9: u64 = undefined;
|
||||
cmovznzU64(&x9, x8, cast(u64, 0x0), 0xffffffffffffffff);
|
||||
var x10: u64 = undefined;
|
||||
var x11: u1 = undefined;
|
||||
addcarryxU64(&x10, &x11, 0x0, x1, x9);
|
||||
var x12: u64 = undefined;
|
||||
var x13: u1 = undefined;
|
||||
addcarryxU64(&x12, &x13, x11, x3, (x9 & 0xffffffff));
|
||||
var x14: u64 = undefined;
|
||||
var x15: u1 = undefined;
|
||||
addcarryxU64(&x14, &x15, x13, x5, cast(u64, 0x0));
|
||||
var x16: u64 = undefined;
|
||||
var x17: u1 = undefined;
|
||||
addcarryxU64(&x16, &x17, x15, x7, (x9 & 0xffffffff00000001));
|
||||
out1[0] = x10;
|
||||
out1[1] = x12;
|
||||
out1[2] = x14;
|
||||
out1[3] = x16;
|
||||
}
|
||||
|
||||
/// The function fromMontgomery translates a field element out of the Montgomery domain.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// Postconditions:
|
||||
/// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn fromMontgomery(out1: *[4]u64, arg1: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const x1 = (arg1[0]);
|
||||
var x2: u64 = undefined;
|
||||
var x3: u64 = undefined;
|
||||
mulxU64(&x2, &x3, x1, 0xffffffff00000001);
|
||||
var x4: u64 = undefined;
|
||||
var x5: u64 = undefined;
|
||||
mulxU64(&x4, &x5, x1, 0xffffffff);
|
||||
var x6: u64 = undefined;
|
||||
var x7: u64 = undefined;
|
||||
mulxU64(&x6, &x7, x1, 0xffffffffffffffff);
|
||||
var x8: u64 = undefined;
|
||||
var x9: u1 = undefined;
|
||||
addcarryxU64(&x8, &x9, 0x0, x7, x4);
|
||||
var x10: u64 = undefined;
|
||||
var x11: u1 = undefined;
|
||||
addcarryxU64(&x10, &x11, 0x0, x1, x6);
|
||||
var x12: u64 = undefined;
|
||||
var x13: u1 = undefined;
|
||||
addcarryxU64(&x12, &x13, x11, cast(u64, 0x0), x8);
|
||||
var x14: u64 = undefined;
|
||||
var x15: u1 = undefined;
|
||||
addcarryxU64(&x14, &x15, 0x0, x12, (arg1[1]));
|
||||
var x16: u64 = undefined;
|
||||
var x17: u64 = undefined;
|
||||
mulxU64(&x16, &x17, x14, 0xffffffff00000001);
|
||||
var x18: u64 = undefined;
|
||||
var x19: u64 = undefined;
|
||||
mulxU64(&x18, &x19, x14, 0xffffffff);
|
||||
var x20: u64 = undefined;
|
||||
var x21: u64 = undefined;
|
||||
mulxU64(&x20, &x21, x14, 0xffffffffffffffff);
|
||||
var x22: u64 = undefined;
|
||||
var x23: u1 = undefined;
|
||||
addcarryxU64(&x22, &x23, 0x0, x21, x18);
|
||||
var x24: u64 = undefined;
|
||||
var x25: u1 = undefined;
|
||||
addcarryxU64(&x24, &x25, 0x0, x14, x20);
|
||||
var x26: u64 = undefined;
|
||||
var x27: u1 = undefined;
|
||||
addcarryxU64(&x26, &x27, x25, (cast(u64, x15) + (cast(u64, x13) + (cast(u64, x9) + x5))), x22);
|
||||
var x28: u64 = undefined;
|
||||
var x29: u1 = undefined;
|
||||
addcarryxU64(&x28, &x29, x27, x2, (cast(u64, x23) + x19));
|
||||
var x30: u64 = undefined;
|
||||
var x31: u1 = undefined;
|
||||
addcarryxU64(&x30, &x31, x29, x3, x16);
|
||||
var x32: u64 = undefined;
|
||||
var x33: u1 = undefined;
|
||||
addcarryxU64(&x32, &x33, 0x0, x26, (arg1[2]));
|
||||
var x34: u64 = undefined;
|
||||
var x35: u1 = undefined;
|
||||
addcarryxU64(&x34, &x35, x33, x28, cast(u64, 0x0));
|
||||
var x36: u64 = undefined;
|
||||
var x37: u1 = undefined;
|
||||
addcarryxU64(&x36, &x37, x35, x30, cast(u64, 0x0));
|
||||
var x38: u64 = undefined;
|
||||
var x39: u64 = undefined;
|
||||
mulxU64(&x38, &x39, x32, 0xffffffff00000001);
|
||||
var x40: u64 = undefined;
|
||||
var x41: u64 = undefined;
|
||||
mulxU64(&x40, &x41, x32, 0xffffffff);
|
||||
var x42: u64 = undefined;
|
||||
var x43: u64 = undefined;
|
||||
mulxU64(&x42, &x43, x32, 0xffffffffffffffff);
|
||||
var x44: u64 = undefined;
|
||||
var x45: u1 = undefined;
|
||||
addcarryxU64(&x44, &x45, 0x0, x43, x40);
|
||||
var x46: u64 = undefined;
|
||||
var x47: u1 = undefined;
|
||||
addcarryxU64(&x46, &x47, 0x0, x32, x42);
|
||||
var x48: u64 = undefined;
|
||||
var x49: u1 = undefined;
|
||||
addcarryxU64(&x48, &x49, x47, x34, x44);
|
||||
var x50: u64 = undefined;
|
||||
var x51: u1 = undefined;
|
||||
addcarryxU64(&x50, &x51, x49, x36, (cast(u64, x45) + x41));
|
||||
var x52: u64 = undefined;
|
||||
var x53: u1 = undefined;
|
||||
addcarryxU64(&x52, &x53, x51, (cast(u64, x37) + (cast(u64, x31) + x17)), x38);
|
||||
var x54: u64 = undefined;
|
||||
var x55: u1 = undefined;
|
||||
addcarryxU64(&x54, &x55, 0x0, x48, (arg1[3]));
|
||||
var x56: u64 = undefined;
|
||||
var x57: u1 = undefined;
|
||||
addcarryxU64(&x56, &x57, x55, x50, cast(u64, 0x0));
|
||||
var x58: u64 = undefined;
|
||||
var x59: u1 = undefined;
|
||||
addcarryxU64(&x58, &x59, x57, x52, cast(u64, 0x0));
|
||||
var x60: u64 = undefined;
|
||||
var x61: u64 = undefined;
|
||||
mulxU64(&x60, &x61, x54, 0xffffffff00000001);
|
||||
var x62: u64 = undefined;
|
||||
var x63: u64 = undefined;
|
||||
mulxU64(&x62, &x63, x54, 0xffffffff);
|
||||
var x64: u64 = undefined;
|
||||
var x65: u64 = undefined;
|
||||
mulxU64(&x64, &x65, x54, 0xffffffffffffffff);
|
||||
var x66: u64 = undefined;
|
||||
var x67: u1 = undefined;
|
||||
addcarryxU64(&x66, &x67, 0x0, x65, x62);
|
||||
var x68: u64 = undefined;
|
||||
var x69: u1 = undefined;
|
||||
addcarryxU64(&x68, &x69, 0x0, x54, x64);
|
||||
var x70: u64 = undefined;
|
||||
var x71: u1 = undefined;
|
||||
addcarryxU64(&x70, &x71, x69, x56, x66);
|
||||
var x72: u64 = undefined;
|
||||
var x73: u1 = undefined;
|
||||
addcarryxU64(&x72, &x73, x71, x58, (cast(u64, x67) + x63));
|
||||
var x74: u64 = undefined;
|
||||
var x75: u1 = undefined;
|
||||
addcarryxU64(&x74, &x75, x73, (cast(u64, x59) + (cast(u64, x53) + x39)), x60);
|
||||
const x76 = (cast(u64, x75) + x61);
|
||||
var x77: u64 = undefined;
|
||||
var x78: u1 = undefined;
|
||||
subborrowxU64(&x77, &x78, 0x0, x70, 0xffffffffffffffff);
|
||||
var x79: u64 = undefined;
|
||||
var x80: u1 = undefined;
|
||||
subborrowxU64(&x79, &x80, x78, x72, 0xffffffff);
|
||||
var x81: u64 = undefined;
|
||||
var x82: u1 = undefined;
|
||||
subborrowxU64(&x81, &x82, x80, x74, cast(u64, 0x0));
|
||||
var x83: u64 = undefined;
|
||||
var x84: u1 = undefined;
|
||||
subborrowxU64(&x83, &x84, x82, x76, 0xffffffff00000001);
|
||||
var x85: u64 = undefined;
|
||||
var x86: u1 = undefined;
|
||||
subborrowxU64(&x85, &x86, x84, cast(u64, 0x0), cast(u64, 0x0));
|
||||
var x87: u64 = undefined;
|
||||
cmovznzU64(&x87, x86, x77, x70);
|
||||
var x88: u64 = undefined;
|
||||
cmovznzU64(&x88, x86, x79, x72);
|
||||
var x89: u64 = undefined;
|
||||
cmovznzU64(&x89, x86, x81, x74);
|
||||
var x90: u64 = undefined;
|
||||
cmovznzU64(&x90, x86, x83, x76);
|
||||
out1[0] = x87;
|
||||
out1[1] = x88;
|
||||
out1[2] = x89;
|
||||
out1[3] = x90;
|
||||
}
|
||||
|
||||
/// The function toMontgomery translates a field element into the Montgomery domain.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// Postconditions:
|
||||
/// eval (from_montgomery out1) mod m = eval arg1 mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn toMontgomery(out1: *[4]u64, arg1: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const x1 = (arg1[1]);
|
||||
const x2 = (arg1[2]);
|
||||
const x3 = (arg1[3]);
|
||||
const x4 = (arg1[0]);
|
||||
var x5: u64 = undefined;
|
||||
var x6: u64 = undefined;
|
||||
mulxU64(&x5, &x6, x4, 0x4fffffffd);
|
||||
var x7: u64 = undefined;
|
||||
var x8: u64 = undefined;
|
||||
mulxU64(&x7, &x8, x4, 0xfffffffffffffffe);
|
||||
var x9: u64 = undefined;
|
||||
var x10: u64 = undefined;
|
||||
mulxU64(&x9, &x10, x4, 0xfffffffbffffffff);
|
||||
var x11: u64 = undefined;
|
||||
var x12: u64 = undefined;
|
||||
mulxU64(&x11, &x12, x4, 0x3);
|
||||
var x13: u64 = undefined;
|
||||
var x14: u1 = undefined;
|
||||
addcarryxU64(&x13, &x14, 0x0, x12, x9);
|
||||
var x15: u64 = undefined;
|
||||
var x16: u1 = undefined;
|
||||
addcarryxU64(&x15, &x16, x14, x10, x7);
|
||||
var x17: u64 = undefined;
|
||||
var x18: u1 = undefined;
|
||||
addcarryxU64(&x17, &x18, x16, x8, x5);
|
||||
var x19: u64 = undefined;
|
||||
var x20: u64 = undefined;
|
||||
mulxU64(&x19, &x20, x11, 0xffffffff00000001);
|
||||
var x21: u64 = undefined;
|
||||
var x22: u64 = undefined;
|
||||
mulxU64(&x21, &x22, x11, 0xffffffff);
|
||||
var x23: u64 = undefined;
|
||||
var x24: u64 = undefined;
|
||||
mulxU64(&x23, &x24, x11, 0xffffffffffffffff);
|
||||
var x25: u64 = undefined;
|
||||
var x26: u1 = undefined;
|
||||
addcarryxU64(&x25, &x26, 0x0, x24, x21);
|
||||
var x27: u64 = undefined;
|
||||
var x28: u1 = undefined;
|
||||
addcarryxU64(&x27, &x28, 0x0, x11, x23);
|
||||
var x29: u64 = undefined;
|
||||
var x30: u1 = undefined;
|
||||
addcarryxU64(&x29, &x30, x28, x13, x25);
|
||||
var x31: u64 = undefined;
|
||||
var x32: u1 = undefined;
|
||||
addcarryxU64(&x31, &x32, x30, x15, (cast(u64, x26) + x22));
|
||||
var x33: u64 = undefined;
|
||||
var x34: u1 = undefined;
|
||||
addcarryxU64(&x33, &x34, x32, x17, x19);
|
||||
var x35: u64 = undefined;
|
||||
var x36: u1 = undefined;
|
||||
addcarryxU64(&x35, &x36, x34, (cast(u64, x18) + x6), x20);
|
||||
var x37: u64 = undefined;
|
||||
var x38: u64 = undefined;
|
||||
mulxU64(&x37, &x38, x1, 0x4fffffffd);
|
||||
var x39: u64 = undefined;
|
||||
var x40: u64 = undefined;
|
||||
mulxU64(&x39, &x40, x1, 0xfffffffffffffffe);
|
||||
var x41: u64 = undefined;
|
||||
var x42: u64 = undefined;
|
||||
mulxU64(&x41, &x42, x1, 0xfffffffbffffffff);
|
||||
var x43: u64 = undefined;
|
||||
var x44: u64 = undefined;
|
||||
mulxU64(&x43, &x44, x1, 0x3);
|
||||
var x45: u64 = undefined;
|
||||
var x46: u1 = undefined;
|
||||
addcarryxU64(&x45, &x46, 0x0, x44, x41);
|
||||
var x47: u64 = undefined;
|
||||
var x48: u1 = undefined;
|
||||
addcarryxU64(&x47, &x48, x46, x42, x39);
|
||||
var x49: u64 = undefined;
|
||||
var x50: u1 = undefined;
|
||||
addcarryxU64(&x49, &x50, x48, x40, x37);
|
||||
var x51: u64 = undefined;
|
||||
var x52: u1 = undefined;
|
||||
addcarryxU64(&x51, &x52, 0x0, x29, x43);
|
||||
var x53: u64 = undefined;
|
||||
var x54: u1 = undefined;
|
||||
addcarryxU64(&x53, &x54, x52, x31, x45);
|
||||
var x55: u64 = undefined;
|
||||
var x56: u1 = undefined;
|
||||
addcarryxU64(&x55, &x56, x54, x33, x47);
|
||||
var x57: u64 = undefined;
|
||||
var x58: u1 = undefined;
|
||||
addcarryxU64(&x57, &x58, x56, x35, x49);
|
||||
var x59: u64 = undefined;
|
||||
var x60: u64 = undefined;
|
||||
mulxU64(&x59, &x60, x51, 0xffffffff00000001);
|
||||
var x61: u64 = undefined;
|
||||
var x62: u64 = undefined;
|
||||
mulxU64(&x61, &x62, x51, 0xffffffff);
|
||||
var x63: u64 = undefined;
|
||||
var x64: u64 = undefined;
|
||||
mulxU64(&x63, &x64, x51, 0xffffffffffffffff);
|
||||
var x65: u64 = undefined;
|
||||
var x66: u1 = undefined;
|
||||
addcarryxU64(&x65, &x66, 0x0, x64, x61);
|
||||
var x67: u64 = undefined;
|
||||
var x68: u1 = undefined;
|
||||
addcarryxU64(&x67, &x68, 0x0, x51, x63);
|
||||
var x69: u64 = undefined;
|
||||
var x70: u1 = undefined;
|
||||
addcarryxU64(&x69, &x70, x68, x53, x65);
|
||||
var x71: u64 = undefined;
|
||||
var x72: u1 = undefined;
|
||||
addcarryxU64(&x71, &x72, x70, x55, (cast(u64, x66) + x62));
|
||||
var x73: u64 = undefined;
|
||||
var x74: u1 = undefined;
|
||||
addcarryxU64(&x73, &x74, x72, x57, x59);
|
||||
var x75: u64 = undefined;
|
||||
var x76: u1 = undefined;
|
||||
addcarryxU64(&x75, &x76, x74, ((cast(u64, x58) + cast(u64, x36)) + (cast(u64, x50) + x38)), x60);
|
||||
var x77: u64 = undefined;
|
||||
var x78: u64 = undefined;
|
||||
mulxU64(&x77, &x78, x2, 0x4fffffffd);
|
||||
var x79: u64 = undefined;
|
||||
var x80: u64 = undefined;
|
||||
mulxU64(&x79, &x80, x2, 0xfffffffffffffffe);
|
||||
var x81: u64 = undefined;
|
||||
var x82: u64 = undefined;
|
||||
mulxU64(&x81, &x82, x2, 0xfffffffbffffffff);
|
||||
var x83: u64 = undefined;
|
||||
var x84: u64 = undefined;
|
||||
mulxU64(&x83, &x84, x2, 0x3);
|
||||
var x85: u64 = undefined;
|
||||
var x86: u1 = undefined;
|
||||
addcarryxU64(&x85, &x86, 0x0, x84, x81);
|
||||
var x87: u64 = undefined;
|
||||
var x88: u1 = undefined;
|
||||
addcarryxU64(&x87, &x88, x86, x82, x79);
|
||||
var x89: u64 = undefined;
|
||||
var x90: u1 = undefined;
|
||||
addcarryxU64(&x89, &x90, x88, x80, x77);
|
||||
var x91: u64 = undefined;
|
||||
var x92: u1 = undefined;
|
||||
addcarryxU64(&x91, &x92, 0x0, x69, x83);
|
||||
var x93: u64 = undefined;
|
||||
var x94: u1 = undefined;
|
||||
addcarryxU64(&x93, &x94, x92, x71, x85);
|
||||
var x95: u64 = undefined;
|
||||
var x96: u1 = undefined;
|
||||
addcarryxU64(&x95, &x96, x94, x73, x87);
|
||||
var x97: u64 = undefined;
|
||||
var x98: u1 = undefined;
|
||||
addcarryxU64(&x97, &x98, x96, x75, x89);
|
||||
var x99: u64 = undefined;
|
||||
var x100: u64 = undefined;
|
||||
mulxU64(&x99, &x100, x91, 0xffffffff00000001);
|
||||
var x101: u64 = undefined;
|
||||
var x102: u64 = undefined;
|
||||
mulxU64(&x101, &x102, x91, 0xffffffff);
|
||||
var x103: u64 = undefined;
|
||||
var x104: u64 = undefined;
|
||||
mulxU64(&x103, &x104, x91, 0xffffffffffffffff);
|
||||
var x105: u64 = undefined;
|
||||
var x106: u1 = undefined;
|
||||
addcarryxU64(&x105, &x106, 0x0, x104, x101);
|
||||
var x107: u64 = undefined;
|
||||
var x108: u1 = undefined;
|
||||
addcarryxU64(&x107, &x108, 0x0, x91, x103);
|
||||
var x109: u64 = undefined;
|
||||
var x110: u1 = undefined;
|
||||
addcarryxU64(&x109, &x110, x108, x93, x105);
|
||||
var x111: u64 = undefined;
|
||||
var x112: u1 = undefined;
|
||||
addcarryxU64(&x111, &x112, x110, x95, (cast(u64, x106) + x102));
|
||||
var x113: u64 = undefined;
|
||||
var x114: u1 = undefined;
|
||||
addcarryxU64(&x113, &x114, x112, x97, x99);
|
||||
var x115: u64 = undefined;
|
||||
var x116: u1 = undefined;
|
||||
addcarryxU64(&x115, &x116, x114, ((cast(u64, x98) + cast(u64, x76)) + (cast(u64, x90) + x78)), x100);
|
||||
var x117: u64 = undefined;
|
||||
var x118: u64 = undefined;
|
||||
mulxU64(&x117, &x118, x3, 0x4fffffffd);
|
||||
var x119: u64 = undefined;
|
||||
var x120: u64 = undefined;
|
||||
mulxU64(&x119, &x120, x3, 0xfffffffffffffffe);
|
||||
var x121: u64 = undefined;
|
||||
var x122: u64 = undefined;
|
||||
mulxU64(&x121, &x122, x3, 0xfffffffbffffffff);
|
||||
var x123: u64 = undefined;
|
||||
var x124: u64 = undefined;
|
||||
mulxU64(&x123, &x124, x3, 0x3);
|
||||
var x125: u64 = undefined;
|
||||
var x126: u1 = undefined;
|
||||
addcarryxU64(&x125, &x126, 0x0, x124, x121);
|
||||
var x127: u64 = undefined;
|
||||
var x128: u1 = undefined;
|
||||
addcarryxU64(&x127, &x128, x126, x122, x119);
|
||||
var x129: u64 = undefined;
|
||||
var x130: u1 = undefined;
|
||||
addcarryxU64(&x129, &x130, x128, x120, x117);
|
||||
var x131: u64 = undefined;
|
||||
var x132: u1 = undefined;
|
||||
addcarryxU64(&x131, &x132, 0x0, x109, x123);
|
||||
var x133: u64 = undefined;
|
||||
var x134: u1 = undefined;
|
||||
addcarryxU64(&x133, &x134, x132, x111, x125);
|
||||
var x135: u64 = undefined;
|
||||
var x136: u1 = undefined;
|
||||
addcarryxU64(&x135, &x136, x134, x113, x127);
|
||||
var x137: u64 = undefined;
|
||||
var x138: u1 = undefined;
|
||||
addcarryxU64(&x137, &x138, x136, x115, x129);
|
||||
var x139: u64 = undefined;
|
||||
var x140: u64 = undefined;
|
||||
mulxU64(&x139, &x140, x131, 0xffffffff00000001);
|
||||
var x141: u64 = undefined;
|
||||
var x142: u64 = undefined;
|
||||
mulxU64(&x141, &x142, x131, 0xffffffff);
|
||||
var x143: u64 = undefined;
|
||||
var x144: u64 = undefined;
|
||||
mulxU64(&x143, &x144, x131, 0xffffffffffffffff);
|
||||
var x145: u64 = undefined;
|
||||
var x146: u1 = undefined;
|
||||
addcarryxU64(&x145, &x146, 0x0, x144, x141);
|
||||
var x147: u64 = undefined;
|
||||
var x148: u1 = undefined;
|
||||
addcarryxU64(&x147, &x148, 0x0, x131, x143);
|
||||
var x149: u64 = undefined;
|
||||
var x150: u1 = undefined;
|
||||
addcarryxU64(&x149, &x150, x148, x133, x145);
|
||||
var x151: u64 = undefined;
|
||||
var x152: u1 = undefined;
|
||||
addcarryxU64(&x151, &x152, x150, x135, (cast(u64, x146) + x142));
|
||||
var x153: u64 = undefined;
|
||||
var x154: u1 = undefined;
|
||||
addcarryxU64(&x153, &x154, x152, x137, x139);
|
||||
var x155: u64 = undefined;
|
||||
var x156: u1 = undefined;
|
||||
addcarryxU64(&x155, &x156, x154, ((cast(u64, x138) + cast(u64, x116)) + (cast(u64, x130) + x118)), x140);
|
||||
var x157: u64 = undefined;
|
||||
var x158: u1 = undefined;
|
||||
subborrowxU64(&x157, &x158, 0x0, x149, 0xffffffffffffffff);
|
||||
var x159: u64 = undefined;
|
||||
var x160: u1 = undefined;
|
||||
subborrowxU64(&x159, &x160, x158, x151, 0xffffffff);
|
||||
var x161: u64 = undefined;
|
||||
var x162: u1 = undefined;
|
||||
subborrowxU64(&x161, &x162, x160, x153, cast(u64, 0x0));
|
||||
var x163: u64 = undefined;
|
||||
var x164: u1 = undefined;
|
||||
subborrowxU64(&x163, &x164, x162, x155, 0xffffffff00000001);
|
||||
var x165: u64 = undefined;
|
||||
var x166: u1 = undefined;
|
||||
subborrowxU64(&x165, &x166, x164, cast(u64, x156), cast(u64, 0x0));
|
||||
var x167: u64 = undefined;
|
||||
cmovznzU64(&x167, x166, x157, x149);
|
||||
var x168: u64 = undefined;
|
||||
cmovznzU64(&x168, x166, x159, x151);
|
||||
var x169: u64 = undefined;
|
||||
cmovznzU64(&x169, x166, x161, x153);
|
||||
var x170: u64 = undefined;
|
||||
cmovznzU64(&x170, x166, x163, x155);
|
||||
out1[0] = x167;
|
||||
out1[1] = x168;
|
||||
out1[2] = x169;
|
||||
out1[3] = x170;
|
||||
}
|
||||
|
||||
/// The function nonzero outputs a single non-zero word if the input is non-zero and zero otherwise.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// Postconditions:
|
||||
/// out1 = 0 ↔ eval (from_montgomery arg1) mod m = 0
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [0x0 ~> 0xffffffffffffffff]
|
||||
pub fn nonzero(out1: *u64, arg1: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const x1 = ((arg1[0]) | ((arg1[1]) | ((arg1[2]) | (arg1[3]))));
|
||||
out1.* = x1;
|
||||
}
|
||||
|
||||
/// The function selectznz is a multi-limb conditional select.
|
||||
/// Postconditions:
|
||||
/// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3)
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [0x0 ~> 0x1]
|
||||
/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
var x1: u64 = undefined;
|
||||
cmovznzU64(&x1, arg1, (arg2[0]), (arg3[0]));
|
||||
var x2: u64 = undefined;
|
||||
cmovznzU64(&x2, arg1, (arg2[1]), (arg3[1]));
|
||||
var x3: u64 = undefined;
|
||||
cmovznzU64(&x3, arg1, (arg2[2]), (arg3[2]));
|
||||
var x4: u64 = undefined;
|
||||
cmovznzU64(&x4, arg1, (arg2[3]), (arg3[3]));
|
||||
out1[0] = x1;
|
||||
out1[1] = x2;
|
||||
out1[2] = x3;
|
||||
out1[3] = x4;
|
||||
}
|
||||
|
||||
/// The function toBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// Postconditions:
|
||||
/// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..31]
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]]
|
||||
pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const x1 = (arg1[3]);
|
||||
const x2 = (arg1[2]);
|
||||
const x3 = (arg1[1]);
|
||||
const x4 = (arg1[0]);
|
||||
const x5 = cast(u8, (x4 & cast(u64, 0xff)));
|
||||
const x6 = (x4 >> 8);
|
||||
const x7 = cast(u8, (x6 & cast(u64, 0xff)));
|
||||
const x8 = (x6 >> 8);
|
||||
const x9 = cast(u8, (x8 & cast(u64, 0xff)));
|
||||
const x10 = (x8 >> 8);
|
||||
const x11 = cast(u8, (x10 & cast(u64, 0xff)));
|
||||
const x12 = (x10 >> 8);
|
||||
const x13 = cast(u8, (x12 & cast(u64, 0xff)));
|
||||
const x14 = (x12 >> 8);
|
||||
const x15 = cast(u8, (x14 & cast(u64, 0xff)));
|
||||
const x16 = (x14 >> 8);
|
||||
const x17 = cast(u8, (x16 & cast(u64, 0xff)));
|
||||
const x18 = cast(u8, (x16 >> 8));
|
||||
const x19 = cast(u8, (x3 & cast(u64, 0xff)));
|
||||
const x20 = (x3 >> 8);
|
||||
const x21 = cast(u8, (x20 & cast(u64, 0xff)));
|
||||
const x22 = (x20 >> 8);
|
||||
const x23 = cast(u8, (x22 & cast(u64, 0xff)));
|
||||
const x24 = (x22 >> 8);
|
||||
const x25 = cast(u8, (x24 & cast(u64, 0xff)));
|
||||
const x26 = (x24 >> 8);
|
||||
const x27 = cast(u8, (x26 & cast(u64, 0xff)));
|
||||
const x28 = (x26 >> 8);
|
||||
const x29 = cast(u8, (x28 & cast(u64, 0xff)));
|
||||
const x30 = (x28 >> 8);
|
||||
const x31 = cast(u8, (x30 & cast(u64, 0xff)));
|
||||
const x32 = cast(u8, (x30 >> 8));
|
||||
const x33 = cast(u8, (x2 & cast(u64, 0xff)));
|
||||
const x34 = (x2 >> 8);
|
||||
const x35 = cast(u8, (x34 & cast(u64, 0xff)));
|
||||
const x36 = (x34 >> 8);
|
||||
const x37 = cast(u8, (x36 & cast(u64, 0xff)));
|
||||
const x38 = (x36 >> 8);
|
||||
const x39 = cast(u8, (x38 & cast(u64, 0xff)));
|
||||
const x40 = (x38 >> 8);
|
||||
const x41 = cast(u8, (x40 & cast(u64, 0xff)));
|
||||
const x42 = (x40 >> 8);
|
||||
const x43 = cast(u8, (x42 & cast(u64, 0xff)));
|
||||
const x44 = (x42 >> 8);
|
||||
const x45 = cast(u8, (x44 & cast(u64, 0xff)));
|
||||
const x46 = cast(u8, (x44 >> 8));
|
||||
const x47 = cast(u8, (x1 & cast(u64, 0xff)));
|
||||
const x48 = (x1 >> 8);
|
||||
const x49 = cast(u8, (x48 & cast(u64, 0xff)));
|
||||
const x50 = (x48 >> 8);
|
||||
const x51 = cast(u8, (x50 & cast(u64, 0xff)));
|
||||
const x52 = (x50 >> 8);
|
||||
const x53 = cast(u8, (x52 & cast(u64, 0xff)));
|
||||
const x54 = (x52 >> 8);
|
||||
const x55 = cast(u8, (x54 & cast(u64, 0xff)));
|
||||
const x56 = (x54 >> 8);
|
||||
const x57 = cast(u8, (x56 & cast(u64, 0xff)));
|
||||
const x58 = (x56 >> 8);
|
||||
const x59 = cast(u8, (x58 & cast(u64, 0xff)));
|
||||
const x60 = cast(u8, (x58 >> 8));
|
||||
out1[0] = x5;
|
||||
out1[1] = x7;
|
||||
out1[2] = x9;
|
||||
out1[3] = x11;
|
||||
out1[4] = x13;
|
||||
out1[5] = x15;
|
||||
out1[6] = x17;
|
||||
out1[7] = x18;
|
||||
out1[8] = x19;
|
||||
out1[9] = x21;
|
||||
out1[10] = x23;
|
||||
out1[11] = x25;
|
||||
out1[12] = x27;
|
||||
out1[13] = x29;
|
||||
out1[14] = x31;
|
||||
out1[15] = x32;
|
||||
out1[16] = x33;
|
||||
out1[17] = x35;
|
||||
out1[18] = x37;
|
||||
out1[19] = x39;
|
||||
out1[20] = x41;
|
||||
out1[21] = x43;
|
||||
out1[22] = x45;
|
||||
out1[23] = x46;
|
||||
out1[24] = x47;
|
||||
out1[25] = x49;
|
||||
out1[26] = x51;
|
||||
out1[27] = x53;
|
||||
out1[28] = x55;
|
||||
out1[29] = x57;
|
||||
out1[30] = x59;
|
||||
out1[31] = x60;
|
||||
}
|
||||
|
||||
/// The function fromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ bytes_eval arg1 < m
|
||||
/// Postconditions:
|
||||
/// eval out1 mod m = bytes_eval arg1 mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const x1 = (cast(u64, (arg1[31])) << 56);
|
||||
const x2 = (cast(u64, (arg1[30])) << 48);
|
||||
const x3 = (cast(u64, (arg1[29])) << 40);
|
||||
const x4 = (cast(u64, (arg1[28])) << 32);
|
||||
const x5 = (cast(u64, (arg1[27])) << 24);
|
||||
const x6 = (cast(u64, (arg1[26])) << 16);
|
||||
const x7 = (cast(u64, (arg1[25])) << 8);
|
||||
const x8 = (arg1[24]);
|
||||
const x9 = (cast(u64, (arg1[23])) << 56);
|
||||
const x10 = (cast(u64, (arg1[22])) << 48);
|
||||
const x11 = (cast(u64, (arg1[21])) << 40);
|
||||
const x12 = (cast(u64, (arg1[20])) << 32);
|
||||
const x13 = (cast(u64, (arg1[19])) << 24);
|
||||
const x14 = (cast(u64, (arg1[18])) << 16);
|
||||
const x15 = (cast(u64, (arg1[17])) << 8);
|
||||
const x16 = (arg1[16]);
|
||||
const x17 = (cast(u64, (arg1[15])) << 56);
|
||||
const x18 = (cast(u64, (arg1[14])) << 48);
|
||||
const x19 = (cast(u64, (arg1[13])) << 40);
|
||||
const x20 = (cast(u64, (arg1[12])) << 32);
|
||||
const x21 = (cast(u64, (arg1[11])) << 24);
|
||||
const x22 = (cast(u64, (arg1[10])) << 16);
|
||||
const x23 = (cast(u64, (arg1[9])) << 8);
|
||||
const x24 = (arg1[8]);
|
||||
const x25 = (cast(u64, (arg1[7])) << 56);
|
||||
const x26 = (cast(u64, (arg1[6])) << 48);
|
||||
const x27 = (cast(u64, (arg1[5])) << 40);
|
||||
const x28 = (cast(u64, (arg1[4])) << 32);
|
||||
const x29 = (cast(u64, (arg1[3])) << 24);
|
||||
const x30 = (cast(u64, (arg1[2])) << 16);
|
||||
const x31 = (cast(u64, (arg1[1])) << 8);
|
||||
const x32 = (arg1[0]);
|
||||
const x33 = (x31 + cast(u64, x32));
|
||||
const x34 = (x30 + x33);
|
||||
const x35 = (x29 + x34);
|
||||
const x36 = (x28 + x35);
|
||||
const x37 = (x27 + x36);
|
||||
const x38 = (x26 + x37);
|
||||
const x39 = (x25 + x38);
|
||||
const x40 = (x23 + cast(u64, x24));
|
||||
const x41 = (x22 + x40);
|
||||
const x42 = (x21 + x41);
|
||||
const x43 = (x20 + x42);
|
||||
const x44 = (x19 + x43);
|
||||
const x45 = (x18 + x44);
|
||||
const x46 = (x17 + x45);
|
||||
const x47 = (x15 + cast(u64, x16));
|
||||
const x48 = (x14 + x47);
|
||||
const x49 = (x13 + x48);
|
||||
const x50 = (x12 + x49);
|
||||
const x51 = (x11 + x50);
|
||||
const x52 = (x10 + x51);
|
||||
const x53 = (x9 + x52);
|
||||
const x54 = (x7 + cast(u64, x8));
|
||||
const x55 = (x6 + x54);
|
||||
const x56 = (x5 + x55);
|
||||
const x57 = (x4 + x56);
|
||||
const x58 = (x3 + x57);
|
||||
const x59 = (x2 + x58);
|
||||
const x60 = (x1 + x59);
|
||||
out1[0] = x39;
|
||||
out1[1] = x46;
|
||||
out1[2] = x53;
|
||||
out1[3] = x60;
|
||||
}
|
||||
|
||||
/// The function setOne returns the field element one in the Montgomery domain.
|
||||
/// Postconditions:
|
||||
/// eval (from_montgomery out1) mod m = 1 mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn setOne(out1: *[4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
out1[0] = cast(u64, 0x1);
|
||||
out1[1] = 0xffffffff00000000;
|
||||
out1[2] = 0xffffffffffffffff;
|
||||
out1[3] = 0xfffffffe;
|
||||
}
|
||||
|
||||
/// The function msat returns the saturated representation of the prime modulus.
|
||||
/// Postconditions:
|
||||
/// twos_complement_eval out1 = m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn msat(out1: *[5]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
out1[0] = 0xffffffffffffffff;
|
||||
out1[1] = 0xffffffff;
|
||||
out1[2] = cast(u64, 0x0);
|
||||
out1[3] = 0xffffffff00000001;
|
||||
out1[4] = cast(u64, 0x0);
|
||||
}
|
||||
|
||||
/// The function divstep computes a divstep.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg4 < m
|
||||
/// 0 ≤ eval arg5 < m
|
||||
/// Postconditions:
|
||||
/// out1 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then 1 - arg1 else 1 + arg1)
|
||||
/// twos_complement_eval out2 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then twos_complement_eval arg3 else twos_complement_eval arg2)
|
||||
/// twos_complement_eval out3 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then ⌊(twos_complement_eval arg3 - twos_complement_eval arg2) / 2⌋ else ⌊(twos_complement_eval arg3 + (twos_complement_eval arg3 mod 2) * twos_complement_eval arg2) / 2⌋)
|
||||
/// eval (from_montgomery out4) mod m = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then (2 * eval (from_montgomery arg5)) mod m else (2 * eval (from_montgomery arg4)) mod m)
|
||||
/// eval (from_montgomery out5) mod m = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then (eval (from_montgomery arg4) - eval (from_montgomery arg4)) mod m else (eval (from_montgomery arg5) + (twos_complement_eval arg3 mod 2) * eval (from_montgomery arg4)) mod m)
|
||||
/// 0 ≤ eval out5 < m
|
||||
/// 0 ≤ eval out5 < m
|
||||
/// 0 ≤ eval out2 < m
|
||||
/// 0 ≤ eval out3 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [0x0 ~> 0xffffffffffffffff]
|
||||
/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// arg4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// arg5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [0x0 ~> 0xffffffffffffffff]
|
||||
/// out2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// out3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// out4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// out5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[4]u64, arg1: u64, arg2: [5]u64, arg3: [5]u64, arg4: [4]u64, arg5: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
var x1: u64 = undefined;
|
||||
var x2: u1 = undefined;
|
||||
addcarryxU64(&x1, &x2, 0x0, (~arg1), cast(u64, 0x1));
|
||||
const x3 = (cast(u1, (x1 >> 63)) & cast(u1, ((arg3[0]) & cast(u64, 0x1))));
|
||||
var x4: u64 = undefined;
|
||||
var x5: u1 = undefined;
|
||||
addcarryxU64(&x4, &x5, 0x0, (~arg1), cast(u64, 0x1));
|
||||
var x6: u64 = undefined;
|
||||
cmovznzU64(&x6, x3, arg1, x4);
|
||||
var x7: u64 = undefined;
|
||||
cmovznzU64(&x7, x3, (arg2[0]), (arg3[0]));
|
||||
var x8: u64 = undefined;
|
||||
cmovznzU64(&x8, x3, (arg2[1]), (arg3[1]));
|
||||
var x9: u64 = undefined;
|
||||
cmovznzU64(&x9, x3, (arg2[2]), (arg3[2]));
|
||||
var x10: u64 = undefined;
|
||||
cmovznzU64(&x10, x3, (arg2[3]), (arg3[3]));
|
||||
var x11: u64 = undefined;
|
||||
cmovznzU64(&x11, x3, (arg2[4]), (arg3[4]));
|
||||
var x12: u64 = undefined;
|
||||
var x13: u1 = undefined;
|
||||
addcarryxU64(&x12, &x13, 0x0, cast(u64, 0x1), (~(arg2[0])));
|
||||
var x14: u64 = undefined;
|
||||
var x15: u1 = undefined;
|
||||
addcarryxU64(&x14, &x15, x13, cast(u64, 0x0), (~(arg2[1])));
|
||||
var x16: u64 = undefined;
|
||||
var x17: u1 = undefined;
|
||||
addcarryxU64(&x16, &x17, x15, cast(u64, 0x0), (~(arg2[2])));
|
||||
var x18: u64 = undefined;
|
||||
var x19: u1 = undefined;
|
||||
addcarryxU64(&x18, &x19, x17, cast(u64, 0x0), (~(arg2[3])));
|
||||
var x20: u64 = undefined;
|
||||
var x21: u1 = undefined;
|
||||
addcarryxU64(&x20, &x21, x19, cast(u64, 0x0), (~(arg2[4])));
|
||||
var x22: u64 = undefined;
|
||||
cmovznzU64(&x22, x3, (arg3[0]), x12);
|
||||
var x23: u64 = undefined;
|
||||
cmovznzU64(&x23, x3, (arg3[1]), x14);
|
||||
var x24: u64 = undefined;
|
||||
cmovznzU64(&x24, x3, (arg3[2]), x16);
|
||||
var x25: u64 = undefined;
|
||||
cmovznzU64(&x25, x3, (arg3[3]), x18);
|
||||
var x26: u64 = undefined;
|
||||
cmovznzU64(&x26, x3, (arg3[4]), x20);
|
||||
var x27: u64 = undefined;
|
||||
cmovznzU64(&x27, x3, (arg4[0]), (arg5[0]));
|
||||
var x28: u64 = undefined;
|
||||
cmovznzU64(&x28, x3, (arg4[1]), (arg5[1]));
|
||||
var x29: u64 = undefined;
|
||||
cmovznzU64(&x29, x3, (arg4[2]), (arg5[2]));
|
||||
var x30: u64 = undefined;
|
||||
cmovznzU64(&x30, x3, (arg4[3]), (arg5[3]));
|
||||
var x31: u64 = undefined;
|
||||
var x32: u1 = undefined;
|
||||
addcarryxU64(&x31, &x32, 0x0, x27, x27);
|
||||
var x33: u64 = undefined;
|
||||
var x34: u1 = undefined;
|
||||
addcarryxU64(&x33, &x34, x32, x28, x28);
|
||||
var x35: u64 = undefined;
|
||||
var x36: u1 = undefined;
|
||||
addcarryxU64(&x35, &x36, x34, x29, x29);
|
||||
var x37: u64 = undefined;
|
||||
var x38: u1 = undefined;
|
||||
addcarryxU64(&x37, &x38, x36, x30, x30);
|
||||
var x39: u64 = undefined;
|
||||
var x40: u1 = undefined;
|
||||
subborrowxU64(&x39, &x40, 0x0, x31, 0xffffffffffffffff);
|
||||
var x41: u64 = undefined;
|
||||
var x42: u1 = undefined;
|
||||
subborrowxU64(&x41, &x42, x40, x33, 0xffffffff);
|
||||
var x43: u64 = undefined;
|
||||
var x44: u1 = undefined;
|
||||
subborrowxU64(&x43, &x44, x42, x35, cast(u64, 0x0));
|
||||
var x45: u64 = undefined;
|
||||
var x46: u1 = undefined;
|
||||
subborrowxU64(&x45, &x46, x44, x37, 0xffffffff00000001);
|
||||
var x47: u64 = undefined;
|
||||
var x48: u1 = undefined;
|
||||
subborrowxU64(&x47, &x48, x46, cast(u64, x38), cast(u64, 0x0));
|
||||
const x49 = (arg4[3]);
|
||||
const x50 = (arg4[2]);
|
||||
const x51 = (arg4[1]);
|
||||
const x52 = (arg4[0]);
|
||||
var x53: u64 = undefined;
|
||||
var x54: u1 = undefined;
|
||||
subborrowxU64(&x53, &x54, 0x0, cast(u64, 0x0), x52);
|
||||
var x55: u64 = undefined;
|
||||
var x56: u1 = undefined;
|
||||
subborrowxU64(&x55, &x56, x54, cast(u64, 0x0), x51);
|
||||
var x57: u64 = undefined;
|
||||
var x58: u1 = undefined;
|
||||
subborrowxU64(&x57, &x58, x56, cast(u64, 0x0), x50);
|
||||
var x59: u64 = undefined;
|
||||
var x60: u1 = undefined;
|
||||
subborrowxU64(&x59, &x60, x58, cast(u64, 0x0), x49);
|
||||
var x61: u64 = undefined;
|
||||
cmovznzU64(&x61, x60, cast(u64, 0x0), 0xffffffffffffffff);
|
||||
var x62: u64 = undefined;
|
||||
var x63: u1 = undefined;
|
||||
addcarryxU64(&x62, &x63, 0x0, x53, x61);
|
||||
var x64: u64 = undefined;
|
||||
var x65: u1 = undefined;
|
||||
addcarryxU64(&x64, &x65, x63, x55, (x61 & 0xffffffff));
|
||||
var x66: u64 = undefined;
|
||||
var x67: u1 = undefined;
|
||||
addcarryxU64(&x66, &x67, x65, x57, cast(u64, 0x0));
|
||||
var x68: u64 = undefined;
|
||||
var x69: u1 = undefined;
|
||||
addcarryxU64(&x68, &x69, x67, x59, (x61 & 0xffffffff00000001));
|
||||
var x70: u64 = undefined;
|
||||
cmovznzU64(&x70, x3, (arg5[0]), x62);
|
||||
var x71: u64 = undefined;
|
||||
cmovznzU64(&x71, x3, (arg5[1]), x64);
|
||||
var x72: u64 = undefined;
|
||||
cmovznzU64(&x72, x3, (arg5[2]), x66);
|
||||
var x73: u64 = undefined;
|
||||
cmovznzU64(&x73, x3, (arg5[3]), x68);
|
||||
const x74 = cast(u1, (x22 & cast(u64, 0x1)));
|
||||
var x75: u64 = undefined;
|
||||
cmovznzU64(&x75, x74, cast(u64, 0x0), x7);
|
||||
var x76: u64 = undefined;
|
||||
cmovznzU64(&x76, x74, cast(u64, 0x0), x8);
|
||||
var x77: u64 = undefined;
|
||||
cmovznzU64(&x77, x74, cast(u64, 0x0), x9);
|
||||
var x78: u64 = undefined;
|
||||
cmovznzU64(&x78, x74, cast(u64, 0x0), x10);
|
||||
var x79: u64 = undefined;
|
||||
cmovznzU64(&x79, x74, cast(u64, 0x0), x11);
|
||||
var x80: u64 = undefined;
|
||||
var x81: u1 = undefined;
|
||||
addcarryxU64(&x80, &x81, 0x0, x22, x75);
|
||||
var x82: u64 = undefined;
|
||||
var x83: u1 = undefined;
|
||||
addcarryxU64(&x82, &x83, x81, x23, x76);
|
||||
var x84: u64 = undefined;
|
||||
var x85: u1 = undefined;
|
||||
addcarryxU64(&x84, &x85, x83, x24, x77);
|
||||
var x86: u64 = undefined;
|
||||
var x87: u1 = undefined;
|
||||
addcarryxU64(&x86, &x87, x85, x25, x78);
|
||||
var x88: u64 = undefined;
|
||||
var x89: u1 = undefined;
|
||||
addcarryxU64(&x88, &x89, x87, x26, x79);
|
||||
var x90: u64 = undefined;
|
||||
cmovznzU64(&x90, x74, cast(u64, 0x0), x27);
|
||||
var x91: u64 = undefined;
|
||||
cmovznzU64(&x91, x74, cast(u64, 0x0), x28);
|
||||
var x92: u64 = undefined;
|
||||
cmovznzU64(&x92, x74, cast(u64, 0x0), x29);
|
||||
var x93: u64 = undefined;
|
||||
cmovznzU64(&x93, x74, cast(u64, 0x0), x30);
|
||||
var x94: u64 = undefined;
|
||||
var x95: u1 = undefined;
|
||||
addcarryxU64(&x94, &x95, 0x0, x70, x90);
|
||||
var x96: u64 = undefined;
|
||||
var x97: u1 = undefined;
|
||||
addcarryxU64(&x96, &x97, x95, x71, x91);
|
||||
var x98: u64 = undefined;
|
||||
var x99: u1 = undefined;
|
||||
addcarryxU64(&x98, &x99, x97, x72, x92);
|
||||
var x100: u64 = undefined;
|
||||
var x101: u1 = undefined;
|
||||
addcarryxU64(&x100, &x101, x99, x73, x93);
|
||||
var x102: u64 = undefined;
|
||||
var x103: u1 = undefined;
|
||||
subborrowxU64(&x102, &x103, 0x0, x94, 0xffffffffffffffff);
|
||||
var x104: u64 = undefined;
|
||||
var x105: u1 = undefined;
|
||||
subborrowxU64(&x104, &x105, x103, x96, 0xffffffff);
|
||||
var x106: u64 = undefined;
|
||||
var x107: u1 = undefined;
|
||||
subborrowxU64(&x106, &x107, x105, x98, cast(u64, 0x0));
|
||||
var x108: u64 = undefined;
|
||||
var x109: u1 = undefined;
|
||||
subborrowxU64(&x108, &x109, x107, x100, 0xffffffff00000001);
|
||||
var x110: u64 = undefined;
|
||||
var x111: u1 = undefined;
|
||||
subborrowxU64(&x110, &x111, x109, cast(u64, x101), cast(u64, 0x0));
|
||||
var x112: u64 = undefined;
|
||||
var x113: u1 = undefined;
|
||||
addcarryxU64(&x112, &x113, 0x0, x6, cast(u64, 0x1));
|
||||
const x114 = ((x80 >> 1) | ((x82 << 63) & 0xffffffffffffffff));
|
||||
const x115 = ((x82 >> 1) | ((x84 << 63) & 0xffffffffffffffff));
|
||||
const x116 = ((x84 >> 1) | ((x86 << 63) & 0xffffffffffffffff));
|
||||
const x117 = ((x86 >> 1) | ((x88 << 63) & 0xffffffffffffffff));
|
||||
const x118 = ((x88 & 0x8000000000000000) | (x88 >> 1));
|
||||
var x119: u64 = undefined;
|
||||
cmovznzU64(&x119, x48, x39, x31);
|
||||
var x120: u64 = undefined;
|
||||
cmovznzU64(&x120, x48, x41, x33);
|
||||
var x121: u64 = undefined;
|
||||
cmovznzU64(&x121, x48, x43, x35);
|
||||
var x122: u64 = undefined;
|
||||
cmovznzU64(&x122, x48, x45, x37);
|
||||
var x123: u64 = undefined;
|
||||
cmovznzU64(&x123, x111, x102, x94);
|
||||
var x124: u64 = undefined;
|
||||
cmovznzU64(&x124, x111, x104, x96);
|
||||
var x125: u64 = undefined;
|
||||
cmovznzU64(&x125, x111, x106, x98);
|
||||
var x126: u64 = undefined;
|
||||
cmovznzU64(&x126, x111, x108, x100);
|
||||
out1.* = x112;
|
||||
out2[0] = x7;
|
||||
out2[1] = x8;
|
||||
out2[2] = x9;
|
||||
out2[3] = x10;
|
||||
out2[4] = x11;
|
||||
out3[0] = x114;
|
||||
out3[1] = x115;
|
||||
out3[2] = x116;
|
||||
out3[3] = x117;
|
||||
out3[4] = x118;
|
||||
out4[0] = x119;
|
||||
out4[1] = x120;
|
||||
out4[2] = x121;
|
||||
out4[3] = x122;
|
||||
out5[0] = x123;
|
||||
out5[1] = x124;
|
||||
out5[2] = x125;
|
||||
out5[3] = x126;
|
||||
}
|
||||
|
||||
/// The function divstepPrecomp returns the precomputed value for Bernstein-Yang-inversion (in montgomery form).
|
||||
/// Postconditions:
|
||||
/// eval (from_montgomery out1) = ⌊(m - 1) / 2⌋^(if (log2 m) + 1 < 46 then ⌊(49 * ((log2 m) + 1) + 80) / 17⌋ else ⌊(49 * ((log2 m) + 1) + 57) / 17⌋)
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn divstepPrecomp(out1: *[4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
out1[0] = 0x67ffffffb8000000;
|
||||
out1[1] = 0xc000000038000000;
|
||||
out1[2] = 0xd80000007fffffff;
|
||||
out1[3] = 0x2fffffffffffffff;
|
||||
}
|
||||
@@ -0,0 +1,2016 @@
|
||||
// Autogenerated: './src/ExtractionOCaml/word_by_word_montgomery' --lang Zig --internal-static --public-function-case camelCase --private-function-case camelCase --no-prefix-fiat --package-name p256-scalar '' 64 115792089210356248762697446949407573529996955224135760342422259061068512044369
|
||||
// curve description (via package name): p256-scalar
|
||||
// machine_wordsize = 64 (from "64")
|
||||
// requested operations: (all)
|
||||
// m = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 (from "115792089210356248762697446949407573529996955224135760342422259061068512044369")
|
||||
//
|
||||
// NOTE: In addition to the bounds specified above each function, all
|
||||
// functions synthesized for this Montgomery arithmetic require the
|
||||
// input to be strictly less than the prime modulus (m), and also
|
||||
// require the input to be in the unique saturated representation.
|
||||
// All functions also ensure that these two properties are true of
|
||||
// return values.
|
||||
//
|
||||
// Computed values:
|
||||
// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192)
|
||||
// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248)
|
||||
// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in
|
||||
// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256
|
||||
|
||||
const std = @import("std");
|
||||
const cast = std.meta.cast;
|
||||
const mode = std.builtin.mode; // Checked arithmetic is disabled in non-debug modes to avoid side channels
|
||||
|
||||
pub const Limbs = [4]u64;
|
||||
|
||||
/// The function addcarryxU64 is an addition with carry.
|
||||
/// Postconditions:
|
||||
/// out1 = (arg1 + arg2 + arg3) mod 2^64
|
||||
/// out2 = ⌊(arg1 + arg2 + arg3) / 2^64⌋
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [0x0 ~> 0x1]
|
||||
/// arg2: [0x0 ~> 0xffffffffffffffff]
|
||||
/// arg3: [0x0 ~> 0xffffffffffffffff]
|
||||
/// Output Bounds:
|
||||
/// out1: [0x0 ~> 0xffffffffffffffff]
|
||||
/// out2: [0x0 ~> 0x1]
|
||||
fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
var t: u64 = undefined;
|
||||
const carry1 = @addWithOverflow(u64, arg2, arg3, &t);
|
||||
const carry2 = @addWithOverflow(u64, t, arg1, out1);
|
||||
out2.* = @boolToInt(carry1) | @boolToInt(carry2);
|
||||
}
|
||||
|
||||
/// The function subborrowxU64 is a subtraction with borrow.
|
||||
/// Postconditions:
|
||||
/// out1 = (-arg1 + arg2 + -arg3) mod 2^64
|
||||
/// out2 = -⌊(-arg1 + arg2 + -arg3) / 2^64⌋
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [0x0 ~> 0x1]
|
||||
/// arg2: [0x0 ~> 0xffffffffffffffff]
|
||||
/// arg3: [0x0 ~> 0xffffffffffffffff]
|
||||
/// Output Bounds:
|
||||
/// out1: [0x0 ~> 0xffffffffffffffff]
|
||||
/// out2: [0x0 ~> 0x1]
|
||||
fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
var t: u64 = undefined;
|
||||
const carry1 = @subWithOverflow(u64, arg2, arg3, &t);
|
||||
const carry2 = @subWithOverflow(u64, t, arg1, out1);
|
||||
out2.* = @boolToInt(carry1) | @boolToInt(carry2);
|
||||
}
|
||||
|
||||
/// The function mulxU64 is a multiplication, returning the full double-width result.
|
||||
/// Postconditions:
|
||||
/// out1 = (arg1 * arg2) mod 2^64
|
||||
/// out2 = ⌊arg1 * arg2 / 2^64⌋
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [0x0 ~> 0xffffffffffffffff]
|
||||
/// arg2: [0x0 ~> 0xffffffffffffffff]
|
||||
/// Output Bounds:
|
||||
/// out1: [0x0 ~> 0xffffffffffffffff]
|
||||
/// out2: [0x0 ~> 0xffffffffffffffff]
|
||||
fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) callconv(.Inline) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const x = @as(u128, arg1) * @as(u128, arg2);
|
||||
out1.* = @truncate(u64, x);
|
||||
out2.* = @truncate(u64, x >> 64);
|
||||
}
|
||||
|
||||
/// The function cmovznzU64 is a single-word conditional move.
|
||||
/// Postconditions:
|
||||
/// out1 = (if arg1 = 0 then arg2 else arg3)
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [0x0 ~> 0x1]
|
||||
/// arg2: [0x0 ~> 0xffffffffffffffff]
|
||||
/// arg3: [0x0 ~> 0xffffffffffffffff]
|
||||
/// Output Bounds:
|
||||
/// out1: [0x0 ~> 0xffffffffffffffff]
|
||||
fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const mask = 0 -% @as(u64, arg1);
|
||||
out1.* = (mask & arg3) | ((~mask) & arg2);
|
||||
}
|
||||
|
||||
/// The function mul multiplies two field elements in the Montgomery domain.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// 0 ≤ eval arg2 < m
|
||||
/// Postconditions:
|
||||
/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn mul(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const x1 = (arg1[1]);
|
||||
const x2 = (arg1[2]);
|
||||
const x3 = (arg1[3]);
|
||||
const x4 = (arg1[0]);
|
||||
var x5: u64 = undefined;
|
||||
var x6: u64 = undefined;
|
||||
mulxU64(&x5, &x6, x4, (arg2[3]));
|
||||
var x7: u64 = undefined;
|
||||
var x8: u64 = undefined;
|
||||
mulxU64(&x7, &x8, x4, (arg2[2]));
|
||||
var x9: u64 = undefined;
|
||||
var x10: u64 = undefined;
|
||||
mulxU64(&x9, &x10, x4, (arg2[1]));
|
||||
var x11: u64 = undefined;
|
||||
var x12: u64 = undefined;
|
||||
mulxU64(&x11, &x12, x4, (arg2[0]));
|
||||
var x13: u64 = undefined;
|
||||
var x14: u1 = undefined;
|
||||
addcarryxU64(&x13, &x14, 0x0, x12, x9);
|
||||
var x15: u64 = undefined;
|
||||
var x16: u1 = undefined;
|
||||
addcarryxU64(&x15, &x16, x14, x10, x7);
|
||||
var x17: u64 = undefined;
|
||||
var x18: u1 = undefined;
|
||||
addcarryxU64(&x17, &x18, x16, x8, x5);
|
||||
const x19 = (cast(u64, x18) + x6);
|
||||
var x20: u64 = undefined;
|
||||
var x21: u64 = undefined;
|
||||
mulxU64(&x20, &x21, x11, 0xccd1c8aaee00bc4f);
|
||||
var x22: u64 = undefined;
|
||||
var x23: u64 = undefined;
|
||||
mulxU64(&x22, &x23, x20, 0xffffffff00000000);
|
||||
var x24: u64 = undefined;
|
||||
var x25: u64 = undefined;
|
||||
mulxU64(&x24, &x25, x20, 0xffffffffffffffff);
|
||||
var x26: u64 = undefined;
|
||||
var x27: u64 = undefined;
|
||||
mulxU64(&x26, &x27, x20, 0xbce6faada7179e84);
|
||||
var x28: u64 = undefined;
|
||||
var x29: u64 = undefined;
|
||||
mulxU64(&x28, &x29, x20, 0xf3b9cac2fc632551);
|
||||
var x30: u64 = undefined;
|
||||
var x31: u1 = undefined;
|
||||
addcarryxU64(&x30, &x31, 0x0, x29, x26);
|
||||
var x32: u64 = undefined;
|
||||
var x33: u1 = undefined;
|
||||
addcarryxU64(&x32, &x33, x31, x27, x24);
|
||||
var x34: u64 = undefined;
|
||||
var x35: u1 = undefined;
|
||||
addcarryxU64(&x34, &x35, x33, x25, x22);
|
||||
const x36 = (cast(u64, x35) + x23);
|
||||
var x37: u64 = undefined;
|
||||
var x38: u1 = undefined;
|
||||
addcarryxU64(&x37, &x38, 0x0, x11, x28);
|
||||
var x39: u64 = undefined;
|
||||
var x40: u1 = undefined;
|
||||
addcarryxU64(&x39, &x40, x38, x13, x30);
|
||||
var x41: u64 = undefined;
|
||||
var x42: u1 = undefined;
|
||||
addcarryxU64(&x41, &x42, x40, x15, x32);
|
||||
var x43: u64 = undefined;
|
||||
var x44: u1 = undefined;
|
||||
addcarryxU64(&x43, &x44, x42, x17, x34);
|
||||
var x45: u64 = undefined;
|
||||
var x46: u1 = undefined;
|
||||
addcarryxU64(&x45, &x46, x44, x19, x36);
|
||||
var x47: u64 = undefined;
|
||||
var x48: u64 = undefined;
|
||||
mulxU64(&x47, &x48, x1, (arg2[3]));
|
||||
var x49: u64 = undefined;
|
||||
var x50: u64 = undefined;
|
||||
mulxU64(&x49, &x50, x1, (arg2[2]));
|
||||
var x51: u64 = undefined;
|
||||
var x52: u64 = undefined;
|
||||
mulxU64(&x51, &x52, x1, (arg2[1]));
|
||||
var x53: u64 = undefined;
|
||||
var x54: u64 = undefined;
|
||||
mulxU64(&x53, &x54, x1, (arg2[0]));
|
||||
var x55: u64 = undefined;
|
||||
var x56: u1 = undefined;
|
||||
addcarryxU64(&x55, &x56, 0x0, x54, x51);
|
||||
var x57: u64 = undefined;
|
||||
var x58: u1 = undefined;
|
||||
addcarryxU64(&x57, &x58, x56, x52, x49);
|
||||
var x59: u64 = undefined;
|
||||
var x60: u1 = undefined;
|
||||
addcarryxU64(&x59, &x60, x58, x50, x47);
|
||||
const x61 = (cast(u64, x60) + x48);
|
||||
var x62: u64 = undefined;
|
||||
var x63: u1 = undefined;
|
||||
addcarryxU64(&x62, &x63, 0x0, x39, x53);
|
||||
var x64: u64 = undefined;
|
||||
var x65: u1 = undefined;
|
||||
addcarryxU64(&x64, &x65, x63, x41, x55);
|
||||
var x66: u64 = undefined;
|
||||
var x67: u1 = undefined;
|
||||
addcarryxU64(&x66, &x67, x65, x43, x57);
|
||||
var x68: u64 = undefined;
|
||||
var x69: u1 = undefined;
|
||||
addcarryxU64(&x68, &x69, x67, x45, x59);
|
||||
var x70: u64 = undefined;
|
||||
var x71: u1 = undefined;
|
||||
addcarryxU64(&x70, &x71, x69, cast(u64, x46), x61);
|
||||
var x72: u64 = undefined;
|
||||
var x73: u64 = undefined;
|
||||
mulxU64(&x72, &x73, x62, 0xccd1c8aaee00bc4f);
|
||||
var x74: u64 = undefined;
|
||||
var x75: u64 = undefined;
|
||||
mulxU64(&x74, &x75, x72, 0xffffffff00000000);
|
||||
var x76: u64 = undefined;
|
||||
var x77: u64 = undefined;
|
||||
mulxU64(&x76, &x77, x72, 0xffffffffffffffff);
|
||||
var x78: u64 = undefined;
|
||||
var x79: u64 = undefined;
|
||||
mulxU64(&x78, &x79, x72, 0xbce6faada7179e84);
|
||||
var x80: u64 = undefined;
|
||||
var x81: u64 = undefined;
|
||||
mulxU64(&x80, &x81, x72, 0xf3b9cac2fc632551);
|
||||
var x82: u64 = undefined;
|
||||
var x83: u1 = undefined;
|
||||
addcarryxU64(&x82, &x83, 0x0, x81, x78);
|
||||
var x84: u64 = undefined;
|
||||
var x85: u1 = undefined;
|
||||
addcarryxU64(&x84, &x85, x83, x79, x76);
|
||||
var x86: u64 = undefined;
|
||||
var x87: u1 = undefined;
|
||||
addcarryxU64(&x86, &x87, x85, x77, x74);
|
||||
const x88 = (cast(u64, x87) + x75);
|
||||
var x89: u64 = undefined;
|
||||
var x90: u1 = undefined;
|
||||
addcarryxU64(&x89, &x90, 0x0, x62, x80);
|
||||
var x91: u64 = undefined;
|
||||
var x92: u1 = undefined;
|
||||
addcarryxU64(&x91, &x92, x90, x64, x82);
|
||||
var x93: u64 = undefined;
|
||||
var x94: u1 = undefined;
|
||||
addcarryxU64(&x93, &x94, x92, x66, x84);
|
||||
var x95: u64 = undefined;
|
||||
var x96: u1 = undefined;
|
||||
addcarryxU64(&x95, &x96, x94, x68, x86);
|
||||
var x97: u64 = undefined;
|
||||
var x98: u1 = undefined;
|
||||
addcarryxU64(&x97, &x98, x96, x70, x88);
|
||||
const x99 = (cast(u64, x98) + cast(u64, x71));
|
||||
var x100: u64 = undefined;
|
||||
var x101: u64 = undefined;
|
||||
mulxU64(&x100, &x101, x2, (arg2[3]));
|
||||
var x102: u64 = undefined;
|
||||
var x103: u64 = undefined;
|
||||
mulxU64(&x102, &x103, x2, (arg2[2]));
|
||||
var x104: u64 = undefined;
|
||||
var x105: u64 = undefined;
|
||||
mulxU64(&x104, &x105, x2, (arg2[1]));
|
||||
var x106: u64 = undefined;
|
||||
var x107: u64 = undefined;
|
||||
mulxU64(&x106, &x107, x2, (arg2[0]));
|
||||
var x108: u64 = undefined;
|
||||
var x109: u1 = undefined;
|
||||
addcarryxU64(&x108, &x109, 0x0, x107, x104);
|
||||
var x110: u64 = undefined;
|
||||
var x111: u1 = undefined;
|
||||
addcarryxU64(&x110, &x111, x109, x105, x102);
|
||||
var x112: u64 = undefined;
|
||||
var x113: u1 = undefined;
|
||||
addcarryxU64(&x112, &x113, x111, x103, x100);
|
||||
const x114 = (cast(u64, x113) + x101);
|
||||
var x115: u64 = undefined;
|
||||
var x116: u1 = undefined;
|
||||
addcarryxU64(&x115, &x116, 0x0, x91, x106);
|
||||
var x117: u64 = undefined;
|
||||
var x118: u1 = undefined;
|
||||
addcarryxU64(&x117, &x118, x116, x93, x108);
|
||||
var x119: u64 = undefined;
|
||||
var x120: u1 = undefined;
|
||||
addcarryxU64(&x119, &x120, x118, x95, x110);
|
||||
var x121: u64 = undefined;
|
||||
var x122: u1 = undefined;
|
||||
addcarryxU64(&x121, &x122, x120, x97, x112);
|
||||
var x123: u64 = undefined;
|
||||
var x124: u1 = undefined;
|
||||
addcarryxU64(&x123, &x124, x122, x99, x114);
|
||||
var x125: u64 = undefined;
|
||||
var x126: u64 = undefined;
|
||||
mulxU64(&x125, &x126, x115, 0xccd1c8aaee00bc4f);
|
||||
var x127: u64 = undefined;
|
||||
var x128: u64 = undefined;
|
||||
mulxU64(&x127, &x128, x125, 0xffffffff00000000);
|
||||
var x129: u64 = undefined;
|
||||
var x130: u64 = undefined;
|
||||
mulxU64(&x129, &x130, x125, 0xffffffffffffffff);
|
||||
var x131: u64 = undefined;
|
||||
var x132: u64 = undefined;
|
||||
mulxU64(&x131, &x132, x125, 0xbce6faada7179e84);
|
||||
var x133: u64 = undefined;
|
||||
var x134: u64 = undefined;
|
||||
mulxU64(&x133, &x134, x125, 0xf3b9cac2fc632551);
|
||||
var x135: u64 = undefined;
|
||||
var x136: u1 = undefined;
|
||||
addcarryxU64(&x135, &x136, 0x0, x134, x131);
|
||||
var x137: u64 = undefined;
|
||||
var x138: u1 = undefined;
|
||||
addcarryxU64(&x137, &x138, x136, x132, x129);
|
||||
var x139: u64 = undefined;
|
||||
var x140: u1 = undefined;
|
||||
addcarryxU64(&x139, &x140, x138, x130, x127);
|
||||
const x141 = (cast(u64, x140) + x128);
|
||||
var x142: u64 = undefined;
|
||||
var x143: u1 = undefined;
|
||||
addcarryxU64(&x142, &x143, 0x0, x115, x133);
|
||||
var x144: u64 = undefined;
|
||||
var x145: u1 = undefined;
|
||||
addcarryxU64(&x144, &x145, x143, x117, x135);
|
||||
var x146: u64 = undefined;
|
||||
var x147: u1 = undefined;
|
||||
addcarryxU64(&x146, &x147, x145, x119, x137);
|
||||
var x148: u64 = undefined;
|
||||
var x149: u1 = undefined;
|
||||
addcarryxU64(&x148, &x149, x147, x121, x139);
|
||||
var x150: u64 = undefined;
|
||||
var x151: u1 = undefined;
|
||||
addcarryxU64(&x150, &x151, x149, x123, x141);
|
||||
const x152 = (cast(u64, x151) + cast(u64, x124));
|
||||
var x153: u64 = undefined;
|
||||
var x154: u64 = undefined;
|
||||
mulxU64(&x153, &x154, x3, (arg2[3]));
|
||||
var x155: u64 = undefined;
|
||||
var x156: u64 = undefined;
|
||||
mulxU64(&x155, &x156, x3, (arg2[2]));
|
||||
var x157: u64 = undefined;
|
||||
var x158: u64 = undefined;
|
||||
mulxU64(&x157, &x158, x3, (arg2[1]));
|
||||
var x159: u64 = undefined;
|
||||
var x160: u64 = undefined;
|
||||
mulxU64(&x159, &x160, x3, (arg2[0]));
|
||||
var x161: u64 = undefined;
|
||||
var x162: u1 = undefined;
|
||||
addcarryxU64(&x161, &x162, 0x0, x160, x157);
|
||||
var x163: u64 = undefined;
|
||||
var x164: u1 = undefined;
|
||||
addcarryxU64(&x163, &x164, x162, x158, x155);
|
||||
var x165: u64 = undefined;
|
||||
var x166: u1 = undefined;
|
||||
addcarryxU64(&x165, &x166, x164, x156, x153);
|
||||
const x167 = (cast(u64, x166) + x154);
|
||||
var x168: u64 = undefined;
|
||||
var x169: u1 = undefined;
|
||||
addcarryxU64(&x168, &x169, 0x0, x144, x159);
|
||||
var x170: u64 = undefined;
|
||||
var x171: u1 = undefined;
|
||||
addcarryxU64(&x170, &x171, x169, x146, x161);
|
||||
var x172: u64 = undefined;
|
||||
var x173: u1 = undefined;
|
||||
addcarryxU64(&x172, &x173, x171, x148, x163);
|
||||
var x174: u64 = undefined;
|
||||
var x175: u1 = undefined;
|
||||
addcarryxU64(&x174, &x175, x173, x150, x165);
|
||||
var x176: u64 = undefined;
|
||||
var x177: u1 = undefined;
|
||||
addcarryxU64(&x176, &x177, x175, x152, x167);
|
||||
var x178: u64 = undefined;
|
||||
var x179: u64 = undefined;
|
||||
mulxU64(&x178, &x179, x168, 0xccd1c8aaee00bc4f);
|
||||
var x180: u64 = undefined;
|
||||
var x181: u64 = undefined;
|
||||
mulxU64(&x180, &x181, x178, 0xffffffff00000000);
|
||||
var x182: u64 = undefined;
|
||||
var x183: u64 = undefined;
|
||||
mulxU64(&x182, &x183, x178, 0xffffffffffffffff);
|
||||
var x184: u64 = undefined;
|
||||
var x185: u64 = undefined;
|
||||
mulxU64(&x184, &x185, x178, 0xbce6faada7179e84);
|
||||
var x186: u64 = undefined;
|
||||
var x187: u64 = undefined;
|
||||
mulxU64(&x186, &x187, x178, 0xf3b9cac2fc632551);
|
||||
var x188: u64 = undefined;
|
||||
var x189: u1 = undefined;
|
||||
addcarryxU64(&x188, &x189, 0x0, x187, x184);
|
||||
var x190: u64 = undefined;
|
||||
var x191: u1 = undefined;
|
||||
addcarryxU64(&x190, &x191, x189, x185, x182);
|
||||
var x192: u64 = undefined;
|
||||
var x193: u1 = undefined;
|
||||
addcarryxU64(&x192, &x193, x191, x183, x180);
|
||||
const x194 = (cast(u64, x193) + x181);
|
||||
var x195: u64 = undefined;
|
||||
var x196: u1 = undefined;
|
||||
addcarryxU64(&x195, &x196, 0x0, x168, x186);
|
||||
var x197: u64 = undefined;
|
||||
var x198: u1 = undefined;
|
||||
addcarryxU64(&x197, &x198, x196, x170, x188);
|
||||
var x199: u64 = undefined;
|
||||
var x200: u1 = undefined;
|
||||
addcarryxU64(&x199, &x200, x198, x172, x190);
|
||||
var x201: u64 = undefined;
|
||||
var x202: u1 = undefined;
|
||||
addcarryxU64(&x201, &x202, x200, x174, x192);
|
||||
var x203: u64 = undefined;
|
||||
var x204: u1 = undefined;
|
||||
addcarryxU64(&x203, &x204, x202, x176, x194);
|
||||
const x205 = (cast(u64, x204) + cast(u64, x177));
|
||||
var x206: u64 = undefined;
|
||||
var x207: u1 = undefined;
|
||||
subborrowxU64(&x206, &x207, 0x0, x197, 0xf3b9cac2fc632551);
|
||||
var x208: u64 = undefined;
|
||||
var x209: u1 = undefined;
|
||||
subborrowxU64(&x208, &x209, x207, x199, 0xbce6faada7179e84);
|
||||
var x210: u64 = undefined;
|
||||
var x211: u1 = undefined;
|
||||
subborrowxU64(&x210, &x211, x209, x201, 0xffffffffffffffff);
|
||||
var x212: u64 = undefined;
|
||||
var x213: u1 = undefined;
|
||||
subborrowxU64(&x212, &x213, x211, x203, 0xffffffff00000000);
|
||||
var x214: u64 = undefined;
|
||||
var x215: u1 = undefined;
|
||||
subborrowxU64(&x214, &x215, x213, x205, cast(u64, 0x0));
|
||||
var x216: u64 = undefined;
|
||||
cmovznzU64(&x216, x215, x206, x197);
|
||||
var x217: u64 = undefined;
|
||||
cmovznzU64(&x217, x215, x208, x199);
|
||||
var x218: u64 = undefined;
|
||||
cmovznzU64(&x218, x215, x210, x201);
|
||||
var x219: u64 = undefined;
|
||||
cmovznzU64(&x219, x215, x212, x203);
|
||||
out1[0] = x216;
|
||||
out1[1] = x217;
|
||||
out1[2] = x218;
|
||||
out1[3] = x219;
|
||||
}
|
||||
|
||||
/// The function square squares a field element in the Montgomery domain.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// Postconditions:
|
||||
/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn square(out1: *[4]u64, arg1: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const x1 = (arg1[1]);
|
||||
const x2 = (arg1[2]);
|
||||
const x3 = (arg1[3]);
|
||||
const x4 = (arg1[0]);
|
||||
var x5: u64 = undefined;
|
||||
var x6: u64 = undefined;
|
||||
mulxU64(&x5, &x6, x4, (arg1[3]));
|
||||
var x7: u64 = undefined;
|
||||
var x8: u64 = undefined;
|
||||
mulxU64(&x7, &x8, x4, (arg1[2]));
|
||||
var x9: u64 = undefined;
|
||||
var x10: u64 = undefined;
|
||||
mulxU64(&x9, &x10, x4, (arg1[1]));
|
||||
var x11: u64 = undefined;
|
||||
var x12: u64 = undefined;
|
||||
mulxU64(&x11, &x12, x4, (arg1[0]));
|
||||
var x13: u64 = undefined;
|
||||
var x14: u1 = undefined;
|
||||
addcarryxU64(&x13, &x14, 0x0, x12, x9);
|
||||
var x15: u64 = undefined;
|
||||
var x16: u1 = undefined;
|
||||
addcarryxU64(&x15, &x16, x14, x10, x7);
|
||||
var x17: u64 = undefined;
|
||||
var x18: u1 = undefined;
|
||||
addcarryxU64(&x17, &x18, x16, x8, x5);
|
||||
const x19 = (cast(u64, x18) + x6);
|
||||
var x20: u64 = undefined;
|
||||
var x21: u64 = undefined;
|
||||
mulxU64(&x20, &x21, x11, 0xccd1c8aaee00bc4f);
|
||||
var x22: u64 = undefined;
|
||||
var x23: u64 = undefined;
|
||||
mulxU64(&x22, &x23, x20, 0xffffffff00000000);
|
||||
var x24: u64 = undefined;
|
||||
var x25: u64 = undefined;
|
||||
mulxU64(&x24, &x25, x20, 0xffffffffffffffff);
|
||||
var x26: u64 = undefined;
|
||||
var x27: u64 = undefined;
|
||||
mulxU64(&x26, &x27, x20, 0xbce6faada7179e84);
|
||||
var x28: u64 = undefined;
|
||||
var x29: u64 = undefined;
|
||||
mulxU64(&x28, &x29, x20, 0xf3b9cac2fc632551);
|
||||
var x30: u64 = undefined;
|
||||
var x31: u1 = undefined;
|
||||
addcarryxU64(&x30, &x31, 0x0, x29, x26);
|
||||
var x32: u64 = undefined;
|
||||
var x33: u1 = undefined;
|
||||
addcarryxU64(&x32, &x33, x31, x27, x24);
|
||||
var x34: u64 = undefined;
|
||||
var x35: u1 = undefined;
|
||||
addcarryxU64(&x34, &x35, x33, x25, x22);
|
||||
const x36 = (cast(u64, x35) + x23);
|
||||
var x37: u64 = undefined;
|
||||
var x38: u1 = undefined;
|
||||
addcarryxU64(&x37, &x38, 0x0, x11, x28);
|
||||
var x39: u64 = undefined;
|
||||
var x40: u1 = undefined;
|
||||
addcarryxU64(&x39, &x40, x38, x13, x30);
|
||||
var x41: u64 = undefined;
|
||||
var x42: u1 = undefined;
|
||||
addcarryxU64(&x41, &x42, x40, x15, x32);
|
||||
var x43: u64 = undefined;
|
||||
var x44: u1 = undefined;
|
||||
addcarryxU64(&x43, &x44, x42, x17, x34);
|
||||
var x45: u64 = undefined;
|
||||
var x46: u1 = undefined;
|
||||
addcarryxU64(&x45, &x46, x44, x19, x36);
|
||||
var x47: u64 = undefined;
|
||||
var x48: u64 = undefined;
|
||||
mulxU64(&x47, &x48, x1, (arg1[3]));
|
||||
var x49: u64 = undefined;
|
||||
var x50: u64 = undefined;
|
||||
mulxU64(&x49, &x50, x1, (arg1[2]));
|
||||
var x51: u64 = undefined;
|
||||
var x52: u64 = undefined;
|
||||
mulxU64(&x51, &x52, x1, (arg1[1]));
|
||||
var x53: u64 = undefined;
|
||||
var x54: u64 = undefined;
|
||||
mulxU64(&x53, &x54, x1, (arg1[0]));
|
||||
var x55: u64 = undefined;
|
||||
var x56: u1 = undefined;
|
||||
addcarryxU64(&x55, &x56, 0x0, x54, x51);
|
||||
var x57: u64 = undefined;
|
||||
var x58: u1 = undefined;
|
||||
addcarryxU64(&x57, &x58, x56, x52, x49);
|
||||
var x59: u64 = undefined;
|
||||
var x60: u1 = undefined;
|
||||
addcarryxU64(&x59, &x60, x58, x50, x47);
|
||||
const x61 = (cast(u64, x60) + x48);
|
||||
var x62: u64 = undefined;
|
||||
var x63: u1 = undefined;
|
||||
addcarryxU64(&x62, &x63, 0x0, x39, x53);
|
||||
var x64: u64 = undefined;
|
||||
var x65: u1 = undefined;
|
||||
addcarryxU64(&x64, &x65, x63, x41, x55);
|
||||
var x66: u64 = undefined;
|
||||
var x67: u1 = undefined;
|
||||
addcarryxU64(&x66, &x67, x65, x43, x57);
|
||||
var x68: u64 = undefined;
|
||||
var x69: u1 = undefined;
|
||||
addcarryxU64(&x68, &x69, x67, x45, x59);
|
||||
var x70: u64 = undefined;
|
||||
var x71: u1 = undefined;
|
||||
addcarryxU64(&x70, &x71, x69, cast(u64, x46), x61);
|
||||
var x72: u64 = undefined;
|
||||
var x73: u64 = undefined;
|
||||
mulxU64(&x72, &x73, x62, 0xccd1c8aaee00bc4f);
|
||||
var x74: u64 = undefined;
|
||||
var x75: u64 = undefined;
|
||||
mulxU64(&x74, &x75, x72, 0xffffffff00000000);
|
||||
var x76: u64 = undefined;
|
||||
var x77: u64 = undefined;
|
||||
mulxU64(&x76, &x77, x72, 0xffffffffffffffff);
|
||||
var x78: u64 = undefined;
|
||||
var x79: u64 = undefined;
|
||||
mulxU64(&x78, &x79, x72, 0xbce6faada7179e84);
|
||||
var x80: u64 = undefined;
|
||||
var x81: u64 = undefined;
|
||||
mulxU64(&x80, &x81, x72, 0xf3b9cac2fc632551);
|
||||
var x82: u64 = undefined;
|
||||
var x83: u1 = undefined;
|
||||
addcarryxU64(&x82, &x83, 0x0, x81, x78);
|
||||
var x84: u64 = undefined;
|
||||
var x85: u1 = undefined;
|
||||
addcarryxU64(&x84, &x85, x83, x79, x76);
|
||||
var x86: u64 = undefined;
|
||||
var x87: u1 = undefined;
|
||||
addcarryxU64(&x86, &x87, x85, x77, x74);
|
||||
const x88 = (cast(u64, x87) + x75);
|
||||
var x89: u64 = undefined;
|
||||
var x90: u1 = undefined;
|
||||
addcarryxU64(&x89, &x90, 0x0, x62, x80);
|
||||
var x91: u64 = undefined;
|
||||
var x92: u1 = undefined;
|
||||
addcarryxU64(&x91, &x92, x90, x64, x82);
|
||||
var x93: u64 = undefined;
|
||||
var x94: u1 = undefined;
|
||||
addcarryxU64(&x93, &x94, x92, x66, x84);
|
||||
var x95: u64 = undefined;
|
||||
var x96: u1 = undefined;
|
||||
addcarryxU64(&x95, &x96, x94, x68, x86);
|
||||
var x97: u64 = undefined;
|
||||
var x98: u1 = undefined;
|
||||
addcarryxU64(&x97, &x98, x96, x70, x88);
|
||||
const x99 = (cast(u64, x98) + cast(u64, x71));
|
||||
var x100: u64 = undefined;
|
||||
var x101: u64 = undefined;
|
||||
mulxU64(&x100, &x101, x2, (arg1[3]));
|
||||
var x102: u64 = undefined;
|
||||
var x103: u64 = undefined;
|
||||
mulxU64(&x102, &x103, x2, (arg1[2]));
|
||||
var x104: u64 = undefined;
|
||||
var x105: u64 = undefined;
|
||||
mulxU64(&x104, &x105, x2, (arg1[1]));
|
||||
var x106: u64 = undefined;
|
||||
var x107: u64 = undefined;
|
||||
mulxU64(&x106, &x107, x2, (arg1[0]));
|
||||
var x108: u64 = undefined;
|
||||
var x109: u1 = undefined;
|
||||
addcarryxU64(&x108, &x109, 0x0, x107, x104);
|
||||
var x110: u64 = undefined;
|
||||
var x111: u1 = undefined;
|
||||
addcarryxU64(&x110, &x111, x109, x105, x102);
|
||||
var x112: u64 = undefined;
|
||||
var x113: u1 = undefined;
|
||||
addcarryxU64(&x112, &x113, x111, x103, x100);
|
||||
const x114 = (cast(u64, x113) + x101);
|
||||
var x115: u64 = undefined;
|
||||
var x116: u1 = undefined;
|
||||
addcarryxU64(&x115, &x116, 0x0, x91, x106);
|
||||
var x117: u64 = undefined;
|
||||
var x118: u1 = undefined;
|
||||
addcarryxU64(&x117, &x118, x116, x93, x108);
|
||||
var x119: u64 = undefined;
|
||||
var x120: u1 = undefined;
|
||||
addcarryxU64(&x119, &x120, x118, x95, x110);
|
||||
var x121: u64 = undefined;
|
||||
var x122: u1 = undefined;
|
||||
addcarryxU64(&x121, &x122, x120, x97, x112);
|
||||
var x123: u64 = undefined;
|
||||
var x124: u1 = undefined;
|
||||
addcarryxU64(&x123, &x124, x122, x99, x114);
|
||||
var x125: u64 = undefined;
|
||||
var x126: u64 = undefined;
|
||||
mulxU64(&x125, &x126, x115, 0xccd1c8aaee00bc4f);
|
||||
var x127: u64 = undefined;
|
||||
var x128: u64 = undefined;
|
||||
mulxU64(&x127, &x128, x125, 0xffffffff00000000);
|
||||
var x129: u64 = undefined;
|
||||
var x130: u64 = undefined;
|
||||
mulxU64(&x129, &x130, x125, 0xffffffffffffffff);
|
||||
var x131: u64 = undefined;
|
||||
var x132: u64 = undefined;
|
||||
mulxU64(&x131, &x132, x125, 0xbce6faada7179e84);
|
||||
var x133: u64 = undefined;
|
||||
var x134: u64 = undefined;
|
||||
mulxU64(&x133, &x134, x125, 0xf3b9cac2fc632551);
|
||||
var x135: u64 = undefined;
|
||||
var x136: u1 = undefined;
|
||||
addcarryxU64(&x135, &x136, 0x0, x134, x131);
|
||||
var x137: u64 = undefined;
|
||||
var x138: u1 = undefined;
|
||||
addcarryxU64(&x137, &x138, x136, x132, x129);
|
||||
var x139: u64 = undefined;
|
||||
var x140: u1 = undefined;
|
||||
addcarryxU64(&x139, &x140, x138, x130, x127);
|
||||
const x141 = (cast(u64, x140) + x128);
|
||||
var x142: u64 = undefined;
|
||||
var x143: u1 = undefined;
|
||||
addcarryxU64(&x142, &x143, 0x0, x115, x133);
|
||||
var x144: u64 = undefined;
|
||||
var x145: u1 = undefined;
|
||||
addcarryxU64(&x144, &x145, x143, x117, x135);
|
||||
var x146: u64 = undefined;
|
||||
var x147: u1 = undefined;
|
||||
addcarryxU64(&x146, &x147, x145, x119, x137);
|
||||
var x148: u64 = undefined;
|
||||
var x149: u1 = undefined;
|
||||
addcarryxU64(&x148, &x149, x147, x121, x139);
|
||||
var x150: u64 = undefined;
|
||||
var x151: u1 = undefined;
|
||||
addcarryxU64(&x150, &x151, x149, x123, x141);
|
||||
const x152 = (cast(u64, x151) + cast(u64, x124));
|
||||
var x153: u64 = undefined;
|
||||
var x154: u64 = undefined;
|
||||
mulxU64(&x153, &x154, x3, (arg1[3]));
|
||||
var x155: u64 = undefined;
|
||||
var x156: u64 = undefined;
|
||||
mulxU64(&x155, &x156, x3, (arg1[2]));
|
||||
var x157: u64 = undefined;
|
||||
var x158: u64 = undefined;
|
||||
mulxU64(&x157, &x158, x3, (arg1[1]));
|
||||
var x159: u64 = undefined;
|
||||
var x160: u64 = undefined;
|
||||
mulxU64(&x159, &x160, x3, (arg1[0]));
|
||||
var x161: u64 = undefined;
|
||||
var x162: u1 = undefined;
|
||||
addcarryxU64(&x161, &x162, 0x0, x160, x157);
|
||||
var x163: u64 = undefined;
|
||||
var x164: u1 = undefined;
|
||||
addcarryxU64(&x163, &x164, x162, x158, x155);
|
||||
var x165: u64 = undefined;
|
||||
var x166: u1 = undefined;
|
||||
addcarryxU64(&x165, &x166, x164, x156, x153);
|
||||
const x167 = (cast(u64, x166) + x154);
|
||||
var x168: u64 = undefined;
|
||||
var x169: u1 = undefined;
|
||||
addcarryxU64(&x168, &x169, 0x0, x144, x159);
|
||||
var x170: u64 = undefined;
|
||||
var x171: u1 = undefined;
|
||||
addcarryxU64(&x170, &x171, x169, x146, x161);
|
||||
var x172: u64 = undefined;
|
||||
var x173: u1 = undefined;
|
||||
addcarryxU64(&x172, &x173, x171, x148, x163);
|
||||
var x174: u64 = undefined;
|
||||
var x175: u1 = undefined;
|
||||
addcarryxU64(&x174, &x175, x173, x150, x165);
|
||||
var x176: u64 = undefined;
|
||||
var x177: u1 = undefined;
|
||||
addcarryxU64(&x176, &x177, x175, x152, x167);
|
||||
var x178: u64 = undefined;
|
||||
var x179: u64 = undefined;
|
||||
mulxU64(&x178, &x179, x168, 0xccd1c8aaee00bc4f);
|
||||
var x180: u64 = undefined;
|
||||
var x181: u64 = undefined;
|
||||
mulxU64(&x180, &x181, x178, 0xffffffff00000000);
|
||||
var x182: u64 = undefined;
|
||||
var x183: u64 = undefined;
|
||||
mulxU64(&x182, &x183, x178, 0xffffffffffffffff);
|
||||
var x184: u64 = undefined;
|
||||
var x185: u64 = undefined;
|
||||
mulxU64(&x184, &x185, x178, 0xbce6faada7179e84);
|
||||
var x186: u64 = undefined;
|
||||
var x187: u64 = undefined;
|
||||
mulxU64(&x186, &x187, x178, 0xf3b9cac2fc632551);
|
||||
var x188: u64 = undefined;
|
||||
var x189: u1 = undefined;
|
||||
addcarryxU64(&x188, &x189, 0x0, x187, x184);
|
||||
var x190: u64 = undefined;
|
||||
var x191: u1 = undefined;
|
||||
addcarryxU64(&x190, &x191, x189, x185, x182);
|
||||
var x192: u64 = undefined;
|
||||
var x193: u1 = undefined;
|
||||
addcarryxU64(&x192, &x193, x191, x183, x180);
|
||||
const x194 = (cast(u64, x193) + x181);
|
||||
var x195: u64 = undefined;
|
||||
var x196: u1 = undefined;
|
||||
addcarryxU64(&x195, &x196, 0x0, x168, x186);
|
||||
var x197: u64 = undefined;
|
||||
var x198: u1 = undefined;
|
||||
addcarryxU64(&x197, &x198, x196, x170, x188);
|
||||
var x199: u64 = undefined;
|
||||
var x200: u1 = undefined;
|
||||
addcarryxU64(&x199, &x200, x198, x172, x190);
|
||||
var x201: u64 = undefined;
|
||||
var x202: u1 = undefined;
|
||||
addcarryxU64(&x201, &x202, x200, x174, x192);
|
||||
var x203: u64 = undefined;
|
||||
var x204: u1 = undefined;
|
||||
addcarryxU64(&x203, &x204, x202, x176, x194);
|
||||
const x205 = (cast(u64, x204) + cast(u64, x177));
|
||||
var x206: u64 = undefined;
|
||||
var x207: u1 = undefined;
|
||||
subborrowxU64(&x206, &x207, 0x0, x197, 0xf3b9cac2fc632551);
|
||||
var x208: u64 = undefined;
|
||||
var x209: u1 = undefined;
|
||||
subborrowxU64(&x208, &x209, x207, x199, 0xbce6faada7179e84);
|
||||
var x210: u64 = undefined;
|
||||
var x211: u1 = undefined;
|
||||
subborrowxU64(&x210, &x211, x209, x201, 0xffffffffffffffff);
|
||||
var x212: u64 = undefined;
|
||||
var x213: u1 = undefined;
|
||||
subborrowxU64(&x212, &x213, x211, x203, 0xffffffff00000000);
|
||||
var x214: u64 = undefined;
|
||||
var x215: u1 = undefined;
|
||||
subborrowxU64(&x214, &x215, x213, x205, cast(u64, 0x0));
|
||||
var x216: u64 = undefined;
|
||||
cmovznzU64(&x216, x215, x206, x197);
|
||||
var x217: u64 = undefined;
|
||||
cmovznzU64(&x217, x215, x208, x199);
|
||||
var x218: u64 = undefined;
|
||||
cmovznzU64(&x218, x215, x210, x201);
|
||||
var x219: u64 = undefined;
|
||||
cmovznzU64(&x219, x215, x212, x203);
|
||||
out1[0] = x216;
|
||||
out1[1] = x217;
|
||||
out1[2] = x218;
|
||||
out1[3] = x219;
|
||||
}
|
||||
|
||||
/// The function add adds two field elements in the Montgomery domain.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// 0 ≤ eval arg2 < m
|
||||
/// Postconditions:
|
||||
/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
var x1: u64 = undefined;
|
||||
var x2: u1 = undefined;
|
||||
addcarryxU64(&x1, &x2, 0x0, (arg1[0]), (arg2[0]));
|
||||
var x3: u64 = undefined;
|
||||
var x4: u1 = undefined;
|
||||
addcarryxU64(&x3, &x4, x2, (arg1[1]), (arg2[1]));
|
||||
var x5: u64 = undefined;
|
||||
var x6: u1 = undefined;
|
||||
addcarryxU64(&x5, &x6, x4, (arg1[2]), (arg2[2]));
|
||||
var x7: u64 = undefined;
|
||||
var x8: u1 = undefined;
|
||||
addcarryxU64(&x7, &x8, x6, (arg1[3]), (arg2[3]));
|
||||
var x9: u64 = undefined;
|
||||
var x10: u1 = undefined;
|
||||
subborrowxU64(&x9, &x10, 0x0, x1, 0xf3b9cac2fc632551);
|
||||
var x11: u64 = undefined;
|
||||
var x12: u1 = undefined;
|
||||
subborrowxU64(&x11, &x12, x10, x3, 0xbce6faada7179e84);
|
||||
var x13: u64 = undefined;
|
||||
var x14: u1 = undefined;
|
||||
subborrowxU64(&x13, &x14, x12, x5, 0xffffffffffffffff);
|
||||
var x15: u64 = undefined;
|
||||
var x16: u1 = undefined;
|
||||
subborrowxU64(&x15, &x16, x14, x7, 0xffffffff00000000);
|
||||
var x17: u64 = undefined;
|
||||
var x18: u1 = undefined;
|
||||
subborrowxU64(&x17, &x18, x16, cast(u64, x8), cast(u64, 0x0));
|
||||
var x19: u64 = undefined;
|
||||
cmovznzU64(&x19, x18, x9, x1);
|
||||
var x20: u64 = undefined;
|
||||
cmovznzU64(&x20, x18, x11, x3);
|
||||
var x21: u64 = undefined;
|
||||
cmovznzU64(&x21, x18, x13, x5);
|
||||
var x22: u64 = undefined;
|
||||
cmovznzU64(&x22, x18, x15, x7);
|
||||
out1[0] = x19;
|
||||
out1[1] = x20;
|
||||
out1[2] = x21;
|
||||
out1[3] = x22;
|
||||
}
|
||||
|
||||
/// The function sub subtracts two field elements in the Montgomery domain.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// 0 ≤ eval arg2 < m
|
||||
/// Postconditions:
|
||||
/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn sub(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
var x1: u64 = undefined;
|
||||
var x2: u1 = undefined;
|
||||
subborrowxU64(&x1, &x2, 0x0, (arg1[0]), (arg2[0]));
|
||||
var x3: u64 = undefined;
|
||||
var x4: u1 = undefined;
|
||||
subborrowxU64(&x3, &x4, x2, (arg1[1]), (arg2[1]));
|
||||
var x5: u64 = undefined;
|
||||
var x6: u1 = undefined;
|
||||
subborrowxU64(&x5, &x6, x4, (arg1[2]), (arg2[2]));
|
||||
var x7: u64 = undefined;
|
||||
var x8: u1 = undefined;
|
||||
subborrowxU64(&x7, &x8, x6, (arg1[3]), (arg2[3]));
|
||||
var x9: u64 = undefined;
|
||||
cmovznzU64(&x9, x8, cast(u64, 0x0), 0xffffffffffffffff);
|
||||
var x10: u64 = undefined;
|
||||
var x11: u1 = undefined;
|
||||
addcarryxU64(&x10, &x11, 0x0, x1, (x9 & 0xf3b9cac2fc632551));
|
||||
var x12: u64 = undefined;
|
||||
var x13: u1 = undefined;
|
||||
addcarryxU64(&x12, &x13, x11, x3, (x9 & 0xbce6faada7179e84));
|
||||
var x14: u64 = undefined;
|
||||
var x15: u1 = undefined;
|
||||
addcarryxU64(&x14, &x15, x13, x5, x9);
|
||||
var x16: u64 = undefined;
|
||||
var x17: u1 = undefined;
|
||||
addcarryxU64(&x16, &x17, x15, x7, (x9 & 0xffffffff00000000));
|
||||
out1[0] = x10;
|
||||
out1[1] = x12;
|
||||
out1[2] = x14;
|
||||
out1[3] = x16;
|
||||
}
|
||||
|
||||
/// The function opp negates a field element in the Montgomery domain.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// Postconditions:
|
||||
/// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn opp(out1: *[4]u64, arg1: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
var x1: u64 = undefined;
|
||||
var x2: u1 = undefined;
|
||||
subborrowxU64(&x1, &x2, 0x0, cast(u64, 0x0), (arg1[0]));
|
||||
var x3: u64 = undefined;
|
||||
var x4: u1 = undefined;
|
||||
subborrowxU64(&x3, &x4, x2, cast(u64, 0x0), (arg1[1]));
|
||||
var x5: u64 = undefined;
|
||||
var x6: u1 = undefined;
|
||||
subborrowxU64(&x5, &x6, x4, cast(u64, 0x0), (arg1[2]));
|
||||
var x7: u64 = undefined;
|
||||
var x8: u1 = undefined;
|
||||
subborrowxU64(&x7, &x8, x6, cast(u64, 0x0), (arg1[3]));
|
||||
var x9: u64 = undefined;
|
||||
cmovznzU64(&x9, x8, cast(u64, 0x0), 0xffffffffffffffff);
|
||||
var x10: u64 = undefined;
|
||||
var x11: u1 = undefined;
|
||||
addcarryxU64(&x10, &x11, 0x0, x1, (x9 & 0xf3b9cac2fc632551));
|
||||
var x12: u64 = undefined;
|
||||
var x13: u1 = undefined;
|
||||
addcarryxU64(&x12, &x13, x11, x3, (x9 & 0xbce6faada7179e84));
|
||||
var x14: u64 = undefined;
|
||||
var x15: u1 = undefined;
|
||||
addcarryxU64(&x14, &x15, x13, x5, x9);
|
||||
var x16: u64 = undefined;
|
||||
var x17: u1 = undefined;
|
||||
addcarryxU64(&x16, &x17, x15, x7, (x9 & 0xffffffff00000000));
|
||||
out1[0] = x10;
|
||||
out1[1] = x12;
|
||||
out1[2] = x14;
|
||||
out1[3] = x16;
|
||||
}
|
||||
|
||||
/// The function fromMontgomery translates a field element out of the Montgomery domain.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// Postconditions:
|
||||
/// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn fromMontgomery(out1: *[4]u64, arg1: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const x1 = (arg1[0]);
|
||||
var x2: u64 = undefined;
|
||||
var x3: u64 = undefined;
|
||||
mulxU64(&x2, &x3, x1, 0xccd1c8aaee00bc4f);
|
||||
var x4: u64 = undefined;
|
||||
var x5: u64 = undefined;
|
||||
mulxU64(&x4, &x5, x2, 0xffffffff00000000);
|
||||
var x6: u64 = undefined;
|
||||
var x7: u64 = undefined;
|
||||
mulxU64(&x6, &x7, x2, 0xffffffffffffffff);
|
||||
var x8: u64 = undefined;
|
||||
var x9: u64 = undefined;
|
||||
mulxU64(&x8, &x9, x2, 0xbce6faada7179e84);
|
||||
var x10: u64 = undefined;
|
||||
var x11: u64 = undefined;
|
||||
mulxU64(&x10, &x11, x2, 0xf3b9cac2fc632551);
|
||||
var x12: u64 = undefined;
|
||||
var x13: u1 = undefined;
|
||||
addcarryxU64(&x12, &x13, 0x0, x11, x8);
|
||||
var x14: u64 = undefined;
|
||||
var x15: u1 = undefined;
|
||||
addcarryxU64(&x14, &x15, x13, x9, x6);
|
||||
var x16: u64 = undefined;
|
||||
var x17: u1 = undefined;
|
||||
addcarryxU64(&x16, &x17, x15, x7, x4);
|
||||
var x18: u64 = undefined;
|
||||
var x19: u1 = undefined;
|
||||
addcarryxU64(&x18, &x19, 0x0, x1, x10);
|
||||
var x20: u64 = undefined;
|
||||
var x21: u1 = undefined;
|
||||
addcarryxU64(&x20, &x21, x19, cast(u64, 0x0), x12);
|
||||
var x22: u64 = undefined;
|
||||
var x23: u1 = undefined;
|
||||
addcarryxU64(&x22, &x23, x21, cast(u64, 0x0), x14);
|
||||
var x24: u64 = undefined;
|
||||
var x25: u1 = undefined;
|
||||
addcarryxU64(&x24, &x25, x23, cast(u64, 0x0), x16);
|
||||
var x26: u64 = undefined;
|
||||
var x27: u1 = undefined;
|
||||
addcarryxU64(&x26, &x27, 0x0, x20, (arg1[1]));
|
||||
var x28: u64 = undefined;
|
||||
var x29: u1 = undefined;
|
||||
addcarryxU64(&x28, &x29, x27, x22, cast(u64, 0x0));
|
||||
var x30: u64 = undefined;
|
||||
var x31: u1 = undefined;
|
||||
addcarryxU64(&x30, &x31, x29, x24, cast(u64, 0x0));
|
||||
var x32: u64 = undefined;
|
||||
var x33: u64 = undefined;
|
||||
mulxU64(&x32, &x33, x26, 0xccd1c8aaee00bc4f);
|
||||
var x34: u64 = undefined;
|
||||
var x35: u64 = undefined;
|
||||
mulxU64(&x34, &x35, x32, 0xffffffff00000000);
|
||||
var x36: u64 = undefined;
|
||||
var x37: u64 = undefined;
|
||||
mulxU64(&x36, &x37, x32, 0xffffffffffffffff);
|
||||
var x38: u64 = undefined;
|
||||
var x39: u64 = undefined;
|
||||
mulxU64(&x38, &x39, x32, 0xbce6faada7179e84);
|
||||
var x40: u64 = undefined;
|
||||
var x41: u64 = undefined;
|
||||
mulxU64(&x40, &x41, x32, 0xf3b9cac2fc632551);
|
||||
var x42: u64 = undefined;
|
||||
var x43: u1 = undefined;
|
||||
addcarryxU64(&x42, &x43, 0x0, x41, x38);
|
||||
var x44: u64 = undefined;
|
||||
var x45: u1 = undefined;
|
||||
addcarryxU64(&x44, &x45, x43, x39, x36);
|
||||
var x46: u64 = undefined;
|
||||
var x47: u1 = undefined;
|
||||
addcarryxU64(&x46, &x47, x45, x37, x34);
|
||||
var x48: u64 = undefined;
|
||||
var x49: u1 = undefined;
|
||||
addcarryxU64(&x48, &x49, 0x0, x26, x40);
|
||||
var x50: u64 = undefined;
|
||||
var x51: u1 = undefined;
|
||||
addcarryxU64(&x50, &x51, x49, x28, x42);
|
||||
var x52: u64 = undefined;
|
||||
var x53: u1 = undefined;
|
||||
addcarryxU64(&x52, &x53, x51, x30, x44);
|
||||
var x54: u64 = undefined;
|
||||
var x55: u1 = undefined;
|
||||
addcarryxU64(&x54, &x55, x53, (cast(u64, x31) + (cast(u64, x25) + (cast(u64, x17) + x5))), x46);
|
||||
var x56: u64 = undefined;
|
||||
var x57: u1 = undefined;
|
||||
addcarryxU64(&x56, &x57, 0x0, x50, (arg1[2]));
|
||||
var x58: u64 = undefined;
|
||||
var x59: u1 = undefined;
|
||||
addcarryxU64(&x58, &x59, x57, x52, cast(u64, 0x0));
|
||||
var x60: u64 = undefined;
|
||||
var x61: u1 = undefined;
|
||||
addcarryxU64(&x60, &x61, x59, x54, cast(u64, 0x0));
|
||||
var x62: u64 = undefined;
|
||||
var x63: u64 = undefined;
|
||||
mulxU64(&x62, &x63, x56, 0xccd1c8aaee00bc4f);
|
||||
var x64: u64 = undefined;
|
||||
var x65: u64 = undefined;
|
||||
mulxU64(&x64, &x65, x62, 0xffffffff00000000);
|
||||
var x66: u64 = undefined;
|
||||
var x67: u64 = undefined;
|
||||
mulxU64(&x66, &x67, x62, 0xffffffffffffffff);
|
||||
var x68: u64 = undefined;
|
||||
var x69: u64 = undefined;
|
||||
mulxU64(&x68, &x69, x62, 0xbce6faada7179e84);
|
||||
var x70: u64 = undefined;
|
||||
var x71: u64 = undefined;
|
||||
mulxU64(&x70, &x71, x62, 0xf3b9cac2fc632551);
|
||||
var x72: u64 = undefined;
|
||||
var x73: u1 = undefined;
|
||||
addcarryxU64(&x72, &x73, 0x0, x71, x68);
|
||||
var x74: u64 = undefined;
|
||||
var x75: u1 = undefined;
|
||||
addcarryxU64(&x74, &x75, x73, x69, x66);
|
||||
var x76: u64 = undefined;
|
||||
var x77: u1 = undefined;
|
||||
addcarryxU64(&x76, &x77, x75, x67, x64);
|
||||
var x78: u64 = undefined;
|
||||
var x79: u1 = undefined;
|
||||
addcarryxU64(&x78, &x79, 0x0, x56, x70);
|
||||
var x80: u64 = undefined;
|
||||
var x81: u1 = undefined;
|
||||
addcarryxU64(&x80, &x81, x79, x58, x72);
|
||||
var x82: u64 = undefined;
|
||||
var x83: u1 = undefined;
|
||||
addcarryxU64(&x82, &x83, x81, x60, x74);
|
||||
var x84: u64 = undefined;
|
||||
var x85: u1 = undefined;
|
||||
addcarryxU64(&x84, &x85, x83, (cast(u64, x61) + (cast(u64, x55) + (cast(u64, x47) + x35))), x76);
|
||||
var x86: u64 = undefined;
|
||||
var x87: u1 = undefined;
|
||||
addcarryxU64(&x86, &x87, 0x0, x80, (arg1[3]));
|
||||
var x88: u64 = undefined;
|
||||
var x89: u1 = undefined;
|
||||
addcarryxU64(&x88, &x89, x87, x82, cast(u64, 0x0));
|
||||
var x90: u64 = undefined;
|
||||
var x91: u1 = undefined;
|
||||
addcarryxU64(&x90, &x91, x89, x84, cast(u64, 0x0));
|
||||
var x92: u64 = undefined;
|
||||
var x93: u64 = undefined;
|
||||
mulxU64(&x92, &x93, x86, 0xccd1c8aaee00bc4f);
|
||||
var x94: u64 = undefined;
|
||||
var x95: u64 = undefined;
|
||||
mulxU64(&x94, &x95, x92, 0xffffffff00000000);
|
||||
var x96: u64 = undefined;
|
||||
var x97: u64 = undefined;
|
||||
mulxU64(&x96, &x97, x92, 0xffffffffffffffff);
|
||||
var x98: u64 = undefined;
|
||||
var x99: u64 = undefined;
|
||||
mulxU64(&x98, &x99, x92, 0xbce6faada7179e84);
|
||||
var x100: u64 = undefined;
|
||||
var x101: u64 = undefined;
|
||||
mulxU64(&x100, &x101, x92, 0xf3b9cac2fc632551);
|
||||
var x102: u64 = undefined;
|
||||
var x103: u1 = undefined;
|
||||
addcarryxU64(&x102, &x103, 0x0, x101, x98);
|
||||
var x104: u64 = undefined;
|
||||
var x105: u1 = undefined;
|
||||
addcarryxU64(&x104, &x105, x103, x99, x96);
|
||||
var x106: u64 = undefined;
|
||||
var x107: u1 = undefined;
|
||||
addcarryxU64(&x106, &x107, x105, x97, x94);
|
||||
var x108: u64 = undefined;
|
||||
var x109: u1 = undefined;
|
||||
addcarryxU64(&x108, &x109, 0x0, x86, x100);
|
||||
var x110: u64 = undefined;
|
||||
var x111: u1 = undefined;
|
||||
addcarryxU64(&x110, &x111, x109, x88, x102);
|
||||
var x112: u64 = undefined;
|
||||
var x113: u1 = undefined;
|
||||
addcarryxU64(&x112, &x113, x111, x90, x104);
|
||||
var x114: u64 = undefined;
|
||||
var x115: u1 = undefined;
|
||||
addcarryxU64(&x114, &x115, x113, (cast(u64, x91) + (cast(u64, x85) + (cast(u64, x77) + x65))), x106);
|
||||
const x116 = (cast(u64, x115) + (cast(u64, x107) + x95));
|
||||
var x117: u64 = undefined;
|
||||
var x118: u1 = undefined;
|
||||
subborrowxU64(&x117, &x118, 0x0, x110, 0xf3b9cac2fc632551);
|
||||
var x119: u64 = undefined;
|
||||
var x120: u1 = undefined;
|
||||
subborrowxU64(&x119, &x120, x118, x112, 0xbce6faada7179e84);
|
||||
var x121: u64 = undefined;
|
||||
var x122: u1 = undefined;
|
||||
subborrowxU64(&x121, &x122, x120, x114, 0xffffffffffffffff);
|
||||
var x123: u64 = undefined;
|
||||
var x124: u1 = undefined;
|
||||
subborrowxU64(&x123, &x124, x122, x116, 0xffffffff00000000);
|
||||
var x125: u64 = undefined;
|
||||
var x126: u1 = undefined;
|
||||
subborrowxU64(&x125, &x126, x124, cast(u64, 0x0), cast(u64, 0x0));
|
||||
var x127: u64 = undefined;
|
||||
cmovznzU64(&x127, x126, x117, x110);
|
||||
var x128: u64 = undefined;
|
||||
cmovznzU64(&x128, x126, x119, x112);
|
||||
var x129: u64 = undefined;
|
||||
cmovznzU64(&x129, x126, x121, x114);
|
||||
var x130: u64 = undefined;
|
||||
cmovznzU64(&x130, x126, x123, x116);
|
||||
out1[0] = x127;
|
||||
out1[1] = x128;
|
||||
out1[2] = x129;
|
||||
out1[3] = x130;
|
||||
}
|
||||
|
||||
/// The function toMontgomery translates a field element into the Montgomery domain.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// Postconditions:
|
||||
/// eval (from_montgomery out1) mod m = eval arg1 mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn toMontgomery(out1: *[4]u64, arg1: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const x1 = (arg1[1]);
|
||||
const x2 = (arg1[2]);
|
||||
const x3 = (arg1[3]);
|
||||
const x4 = (arg1[0]);
|
||||
var x5: u64 = undefined;
|
||||
var x6: u64 = undefined;
|
||||
mulxU64(&x5, &x6, x4, 0x66e12d94f3d95620);
|
||||
var x7: u64 = undefined;
|
||||
var x8: u64 = undefined;
|
||||
mulxU64(&x7, &x8, x4, 0x2845b2392b6bec59);
|
||||
var x9: u64 = undefined;
|
||||
var x10: u64 = undefined;
|
||||
mulxU64(&x9, &x10, x4, 0x4699799c49bd6fa6);
|
||||
var x11: u64 = undefined;
|
||||
var x12: u64 = undefined;
|
||||
mulxU64(&x11, &x12, x4, 0x83244c95be79eea2);
|
||||
var x13: u64 = undefined;
|
||||
var x14: u1 = undefined;
|
||||
addcarryxU64(&x13, &x14, 0x0, x12, x9);
|
||||
var x15: u64 = undefined;
|
||||
var x16: u1 = undefined;
|
||||
addcarryxU64(&x15, &x16, x14, x10, x7);
|
||||
var x17: u64 = undefined;
|
||||
var x18: u1 = undefined;
|
||||
addcarryxU64(&x17, &x18, x16, x8, x5);
|
||||
var x19: u64 = undefined;
|
||||
var x20: u64 = undefined;
|
||||
mulxU64(&x19, &x20, x11, 0xccd1c8aaee00bc4f);
|
||||
var x21: u64 = undefined;
|
||||
var x22: u64 = undefined;
|
||||
mulxU64(&x21, &x22, x19, 0xffffffff00000000);
|
||||
var x23: u64 = undefined;
|
||||
var x24: u64 = undefined;
|
||||
mulxU64(&x23, &x24, x19, 0xffffffffffffffff);
|
||||
var x25: u64 = undefined;
|
||||
var x26: u64 = undefined;
|
||||
mulxU64(&x25, &x26, x19, 0xbce6faada7179e84);
|
||||
var x27: u64 = undefined;
|
||||
var x28: u64 = undefined;
|
||||
mulxU64(&x27, &x28, x19, 0xf3b9cac2fc632551);
|
||||
var x29: u64 = undefined;
|
||||
var x30: u1 = undefined;
|
||||
addcarryxU64(&x29, &x30, 0x0, x28, x25);
|
||||
var x31: u64 = undefined;
|
||||
var x32: u1 = undefined;
|
||||
addcarryxU64(&x31, &x32, x30, x26, x23);
|
||||
var x33: u64 = undefined;
|
||||
var x34: u1 = undefined;
|
||||
addcarryxU64(&x33, &x34, x32, x24, x21);
|
||||
var x35: u64 = undefined;
|
||||
var x36: u1 = undefined;
|
||||
addcarryxU64(&x35, &x36, 0x0, x11, x27);
|
||||
var x37: u64 = undefined;
|
||||
var x38: u1 = undefined;
|
||||
addcarryxU64(&x37, &x38, x36, x13, x29);
|
||||
var x39: u64 = undefined;
|
||||
var x40: u1 = undefined;
|
||||
addcarryxU64(&x39, &x40, x38, x15, x31);
|
||||
var x41: u64 = undefined;
|
||||
var x42: u1 = undefined;
|
||||
addcarryxU64(&x41, &x42, x40, x17, x33);
|
||||
var x43: u64 = undefined;
|
||||
var x44: u1 = undefined;
|
||||
addcarryxU64(&x43, &x44, x42, (cast(u64, x18) + x6), (cast(u64, x34) + x22));
|
||||
var x45: u64 = undefined;
|
||||
var x46: u64 = undefined;
|
||||
mulxU64(&x45, &x46, x1, 0x66e12d94f3d95620);
|
||||
var x47: u64 = undefined;
|
||||
var x48: u64 = undefined;
|
||||
mulxU64(&x47, &x48, x1, 0x2845b2392b6bec59);
|
||||
var x49: u64 = undefined;
|
||||
var x50: u64 = undefined;
|
||||
mulxU64(&x49, &x50, x1, 0x4699799c49bd6fa6);
|
||||
var x51: u64 = undefined;
|
||||
var x52: u64 = undefined;
|
||||
mulxU64(&x51, &x52, x1, 0x83244c95be79eea2);
|
||||
var x53: u64 = undefined;
|
||||
var x54: u1 = undefined;
|
||||
addcarryxU64(&x53, &x54, 0x0, x52, x49);
|
||||
var x55: u64 = undefined;
|
||||
var x56: u1 = undefined;
|
||||
addcarryxU64(&x55, &x56, x54, x50, x47);
|
||||
var x57: u64 = undefined;
|
||||
var x58: u1 = undefined;
|
||||
addcarryxU64(&x57, &x58, x56, x48, x45);
|
||||
var x59: u64 = undefined;
|
||||
var x60: u1 = undefined;
|
||||
addcarryxU64(&x59, &x60, 0x0, x37, x51);
|
||||
var x61: u64 = undefined;
|
||||
var x62: u1 = undefined;
|
||||
addcarryxU64(&x61, &x62, x60, x39, x53);
|
||||
var x63: u64 = undefined;
|
||||
var x64: u1 = undefined;
|
||||
addcarryxU64(&x63, &x64, x62, x41, x55);
|
||||
var x65: u64 = undefined;
|
||||
var x66: u1 = undefined;
|
||||
addcarryxU64(&x65, &x66, x64, x43, x57);
|
||||
var x67: u64 = undefined;
|
||||
var x68: u64 = undefined;
|
||||
mulxU64(&x67, &x68, x59, 0xccd1c8aaee00bc4f);
|
||||
var x69: u64 = undefined;
|
||||
var x70: u64 = undefined;
|
||||
mulxU64(&x69, &x70, x67, 0xffffffff00000000);
|
||||
var x71: u64 = undefined;
|
||||
var x72: u64 = undefined;
|
||||
mulxU64(&x71, &x72, x67, 0xffffffffffffffff);
|
||||
var x73: u64 = undefined;
|
||||
var x74: u64 = undefined;
|
||||
mulxU64(&x73, &x74, x67, 0xbce6faada7179e84);
|
||||
var x75: u64 = undefined;
|
||||
var x76: u64 = undefined;
|
||||
mulxU64(&x75, &x76, x67, 0xf3b9cac2fc632551);
|
||||
var x77: u64 = undefined;
|
||||
var x78: u1 = undefined;
|
||||
addcarryxU64(&x77, &x78, 0x0, x76, x73);
|
||||
var x79: u64 = undefined;
|
||||
var x80: u1 = undefined;
|
||||
addcarryxU64(&x79, &x80, x78, x74, x71);
|
||||
var x81: u64 = undefined;
|
||||
var x82: u1 = undefined;
|
||||
addcarryxU64(&x81, &x82, x80, x72, x69);
|
||||
var x83: u64 = undefined;
|
||||
var x84: u1 = undefined;
|
||||
addcarryxU64(&x83, &x84, 0x0, x59, x75);
|
||||
var x85: u64 = undefined;
|
||||
var x86: u1 = undefined;
|
||||
addcarryxU64(&x85, &x86, x84, x61, x77);
|
||||
var x87: u64 = undefined;
|
||||
var x88: u1 = undefined;
|
||||
addcarryxU64(&x87, &x88, x86, x63, x79);
|
||||
var x89: u64 = undefined;
|
||||
var x90: u1 = undefined;
|
||||
addcarryxU64(&x89, &x90, x88, x65, x81);
|
||||
var x91: u64 = undefined;
|
||||
var x92: u1 = undefined;
|
||||
addcarryxU64(&x91, &x92, x90, ((cast(u64, x66) + cast(u64, x44)) + (cast(u64, x58) + x46)), (cast(u64, x82) + x70));
|
||||
var x93: u64 = undefined;
|
||||
var x94: u64 = undefined;
|
||||
mulxU64(&x93, &x94, x2, 0x66e12d94f3d95620);
|
||||
var x95: u64 = undefined;
|
||||
var x96: u64 = undefined;
|
||||
mulxU64(&x95, &x96, x2, 0x2845b2392b6bec59);
|
||||
var x97: u64 = undefined;
|
||||
var x98: u64 = undefined;
|
||||
mulxU64(&x97, &x98, x2, 0x4699799c49bd6fa6);
|
||||
var x99: u64 = undefined;
|
||||
var x100: u64 = undefined;
|
||||
mulxU64(&x99, &x100, x2, 0x83244c95be79eea2);
|
||||
var x101: u64 = undefined;
|
||||
var x102: u1 = undefined;
|
||||
addcarryxU64(&x101, &x102, 0x0, x100, x97);
|
||||
var x103: u64 = undefined;
|
||||
var x104: u1 = undefined;
|
||||
addcarryxU64(&x103, &x104, x102, x98, x95);
|
||||
var x105: u64 = undefined;
|
||||
var x106: u1 = undefined;
|
||||
addcarryxU64(&x105, &x106, x104, x96, x93);
|
||||
var x107: u64 = undefined;
|
||||
var x108: u1 = undefined;
|
||||
addcarryxU64(&x107, &x108, 0x0, x85, x99);
|
||||
var x109: u64 = undefined;
|
||||
var x110: u1 = undefined;
|
||||
addcarryxU64(&x109, &x110, x108, x87, x101);
|
||||
var x111: u64 = undefined;
|
||||
var x112: u1 = undefined;
|
||||
addcarryxU64(&x111, &x112, x110, x89, x103);
|
||||
var x113: u64 = undefined;
|
||||
var x114: u1 = undefined;
|
||||
addcarryxU64(&x113, &x114, x112, x91, x105);
|
||||
var x115: u64 = undefined;
|
||||
var x116: u64 = undefined;
|
||||
mulxU64(&x115, &x116, x107, 0xccd1c8aaee00bc4f);
|
||||
var x117: u64 = undefined;
|
||||
var x118: u64 = undefined;
|
||||
mulxU64(&x117, &x118, x115, 0xffffffff00000000);
|
||||
var x119: u64 = undefined;
|
||||
var x120: u64 = undefined;
|
||||
mulxU64(&x119, &x120, x115, 0xffffffffffffffff);
|
||||
var x121: u64 = undefined;
|
||||
var x122: u64 = undefined;
|
||||
mulxU64(&x121, &x122, x115, 0xbce6faada7179e84);
|
||||
var x123: u64 = undefined;
|
||||
var x124: u64 = undefined;
|
||||
mulxU64(&x123, &x124, x115, 0xf3b9cac2fc632551);
|
||||
var x125: u64 = undefined;
|
||||
var x126: u1 = undefined;
|
||||
addcarryxU64(&x125, &x126, 0x0, x124, x121);
|
||||
var x127: u64 = undefined;
|
||||
var x128: u1 = undefined;
|
||||
addcarryxU64(&x127, &x128, x126, x122, x119);
|
||||
var x129: u64 = undefined;
|
||||
var x130: u1 = undefined;
|
||||
addcarryxU64(&x129, &x130, x128, x120, x117);
|
||||
var x131: u64 = undefined;
|
||||
var x132: u1 = undefined;
|
||||
addcarryxU64(&x131, &x132, 0x0, x107, x123);
|
||||
var x133: u64 = undefined;
|
||||
var x134: u1 = undefined;
|
||||
addcarryxU64(&x133, &x134, x132, x109, x125);
|
||||
var x135: u64 = undefined;
|
||||
var x136: u1 = undefined;
|
||||
addcarryxU64(&x135, &x136, x134, x111, x127);
|
||||
var x137: u64 = undefined;
|
||||
var x138: u1 = undefined;
|
||||
addcarryxU64(&x137, &x138, x136, x113, x129);
|
||||
var x139: u64 = undefined;
|
||||
var x140: u1 = undefined;
|
||||
addcarryxU64(&x139, &x140, x138, ((cast(u64, x114) + cast(u64, x92)) + (cast(u64, x106) + x94)), (cast(u64, x130) + x118));
|
||||
var x141: u64 = undefined;
|
||||
var x142: u64 = undefined;
|
||||
mulxU64(&x141, &x142, x3, 0x66e12d94f3d95620);
|
||||
var x143: u64 = undefined;
|
||||
var x144: u64 = undefined;
|
||||
mulxU64(&x143, &x144, x3, 0x2845b2392b6bec59);
|
||||
var x145: u64 = undefined;
|
||||
var x146: u64 = undefined;
|
||||
mulxU64(&x145, &x146, x3, 0x4699799c49bd6fa6);
|
||||
var x147: u64 = undefined;
|
||||
var x148: u64 = undefined;
|
||||
mulxU64(&x147, &x148, x3, 0x83244c95be79eea2);
|
||||
var x149: u64 = undefined;
|
||||
var x150: u1 = undefined;
|
||||
addcarryxU64(&x149, &x150, 0x0, x148, x145);
|
||||
var x151: u64 = undefined;
|
||||
var x152: u1 = undefined;
|
||||
addcarryxU64(&x151, &x152, x150, x146, x143);
|
||||
var x153: u64 = undefined;
|
||||
var x154: u1 = undefined;
|
||||
addcarryxU64(&x153, &x154, x152, x144, x141);
|
||||
var x155: u64 = undefined;
|
||||
var x156: u1 = undefined;
|
||||
addcarryxU64(&x155, &x156, 0x0, x133, x147);
|
||||
var x157: u64 = undefined;
|
||||
var x158: u1 = undefined;
|
||||
addcarryxU64(&x157, &x158, x156, x135, x149);
|
||||
var x159: u64 = undefined;
|
||||
var x160: u1 = undefined;
|
||||
addcarryxU64(&x159, &x160, x158, x137, x151);
|
||||
var x161: u64 = undefined;
|
||||
var x162: u1 = undefined;
|
||||
addcarryxU64(&x161, &x162, x160, x139, x153);
|
||||
var x163: u64 = undefined;
|
||||
var x164: u64 = undefined;
|
||||
mulxU64(&x163, &x164, x155, 0xccd1c8aaee00bc4f);
|
||||
var x165: u64 = undefined;
|
||||
var x166: u64 = undefined;
|
||||
mulxU64(&x165, &x166, x163, 0xffffffff00000000);
|
||||
var x167: u64 = undefined;
|
||||
var x168: u64 = undefined;
|
||||
mulxU64(&x167, &x168, x163, 0xffffffffffffffff);
|
||||
var x169: u64 = undefined;
|
||||
var x170: u64 = undefined;
|
||||
mulxU64(&x169, &x170, x163, 0xbce6faada7179e84);
|
||||
var x171: u64 = undefined;
|
||||
var x172: u64 = undefined;
|
||||
mulxU64(&x171, &x172, x163, 0xf3b9cac2fc632551);
|
||||
var x173: u64 = undefined;
|
||||
var x174: u1 = undefined;
|
||||
addcarryxU64(&x173, &x174, 0x0, x172, x169);
|
||||
var x175: u64 = undefined;
|
||||
var x176: u1 = undefined;
|
||||
addcarryxU64(&x175, &x176, x174, x170, x167);
|
||||
var x177: u64 = undefined;
|
||||
var x178: u1 = undefined;
|
||||
addcarryxU64(&x177, &x178, x176, x168, x165);
|
||||
var x179: u64 = undefined;
|
||||
var x180: u1 = undefined;
|
||||
addcarryxU64(&x179, &x180, 0x0, x155, x171);
|
||||
var x181: u64 = undefined;
|
||||
var x182: u1 = undefined;
|
||||
addcarryxU64(&x181, &x182, x180, x157, x173);
|
||||
var x183: u64 = undefined;
|
||||
var x184: u1 = undefined;
|
||||
addcarryxU64(&x183, &x184, x182, x159, x175);
|
||||
var x185: u64 = undefined;
|
||||
var x186: u1 = undefined;
|
||||
addcarryxU64(&x185, &x186, x184, x161, x177);
|
||||
var x187: u64 = undefined;
|
||||
var x188: u1 = undefined;
|
||||
addcarryxU64(&x187, &x188, x186, ((cast(u64, x162) + cast(u64, x140)) + (cast(u64, x154) + x142)), (cast(u64, x178) + x166));
|
||||
var x189: u64 = undefined;
|
||||
var x190: u1 = undefined;
|
||||
subborrowxU64(&x189, &x190, 0x0, x181, 0xf3b9cac2fc632551);
|
||||
var x191: u64 = undefined;
|
||||
var x192: u1 = undefined;
|
||||
subborrowxU64(&x191, &x192, x190, x183, 0xbce6faada7179e84);
|
||||
var x193: u64 = undefined;
|
||||
var x194: u1 = undefined;
|
||||
subborrowxU64(&x193, &x194, x192, x185, 0xffffffffffffffff);
|
||||
var x195: u64 = undefined;
|
||||
var x196: u1 = undefined;
|
||||
subborrowxU64(&x195, &x196, x194, x187, 0xffffffff00000000);
|
||||
var x197: u64 = undefined;
|
||||
var x198: u1 = undefined;
|
||||
subborrowxU64(&x197, &x198, x196, cast(u64, x188), cast(u64, 0x0));
|
||||
var x199: u64 = undefined;
|
||||
cmovznzU64(&x199, x198, x189, x181);
|
||||
var x200: u64 = undefined;
|
||||
cmovznzU64(&x200, x198, x191, x183);
|
||||
var x201: u64 = undefined;
|
||||
cmovznzU64(&x201, x198, x193, x185);
|
||||
var x202: u64 = undefined;
|
||||
cmovznzU64(&x202, x198, x195, x187);
|
||||
out1[0] = x199;
|
||||
out1[1] = x200;
|
||||
out1[2] = x201;
|
||||
out1[3] = x202;
|
||||
}
|
||||
|
||||
/// The function nonzero outputs a single non-zero word if the input is non-zero and zero otherwise.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// Postconditions:
|
||||
/// out1 = 0 ↔ eval (from_montgomery arg1) mod m = 0
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [0x0 ~> 0xffffffffffffffff]
|
||||
pub fn nonzero(out1: *u64, arg1: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const x1 = ((arg1[0]) | ((arg1[1]) | ((arg1[2]) | (arg1[3]))));
|
||||
out1.* = x1;
|
||||
}
|
||||
|
||||
/// The function selectznz is a multi-limb conditional select.
|
||||
/// Postconditions:
|
||||
/// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3)
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [0x0 ~> 0x1]
|
||||
/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
var x1: u64 = undefined;
|
||||
cmovznzU64(&x1, arg1, (arg2[0]), (arg3[0]));
|
||||
var x2: u64 = undefined;
|
||||
cmovznzU64(&x2, arg1, (arg2[1]), (arg3[1]));
|
||||
var x3: u64 = undefined;
|
||||
cmovznzU64(&x3, arg1, (arg2[2]), (arg3[2]));
|
||||
var x4: u64 = undefined;
|
||||
cmovznzU64(&x4, arg1, (arg2[3]), (arg3[3]));
|
||||
out1[0] = x1;
|
||||
out1[1] = x2;
|
||||
out1[2] = x3;
|
||||
out1[3] = x4;
|
||||
}
|
||||
|
||||
/// The function toBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg1 < m
|
||||
/// Postconditions:
|
||||
/// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..31]
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]]
|
||||
pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const x1 = (arg1[3]);
|
||||
const x2 = (arg1[2]);
|
||||
const x3 = (arg1[1]);
|
||||
const x4 = (arg1[0]);
|
||||
const x5 = cast(u8, (x4 & cast(u64, 0xff)));
|
||||
const x6 = (x4 >> 8);
|
||||
const x7 = cast(u8, (x6 & cast(u64, 0xff)));
|
||||
const x8 = (x6 >> 8);
|
||||
const x9 = cast(u8, (x8 & cast(u64, 0xff)));
|
||||
const x10 = (x8 >> 8);
|
||||
const x11 = cast(u8, (x10 & cast(u64, 0xff)));
|
||||
const x12 = (x10 >> 8);
|
||||
const x13 = cast(u8, (x12 & cast(u64, 0xff)));
|
||||
const x14 = (x12 >> 8);
|
||||
const x15 = cast(u8, (x14 & cast(u64, 0xff)));
|
||||
const x16 = (x14 >> 8);
|
||||
const x17 = cast(u8, (x16 & cast(u64, 0xff)));
|
||||
const x18 = cast(u8, (x16 >> 8));
|
||||
const x19 = cast(u8, (x3 & cast(u64, 0xff)));
|
||||
const x20 = (x3 >> 8);
|
||||
const x21 = cast(u8, (x20 & cast(u64, 0xff)));
|
||||
const x22 = (x20 >> 8);
|
||||
const x23 = cast(u8, (x22 & cast(u64, 0xff)));
|
||||
const x24 = (x22 >> 8);
|
||||
const x25 = cast(u8, (x24 & cast(u64, 0xff)));
|
||||
const x26 = (x24 >> 8);
|
||||
const x27 = cast(u8, (x26 & cast(u64, 0xff)));
|
||||
const x28 = (x26 >> 8);
|
||||
const x29 = cast(u8, (x28 & cast(u64, 0xff)));
|
||||
const x30 = (x28 >> 8);
|
||||
const x31 = cast(u8, (x30 & cast(u64, 0xff)));
|
||||
const x32 = cast(u8, (x30 >> 8));
|
||||
const x33 = cast(u8, (x2 & cast(u64, 0xff)));
|
||||
const x34 = (x2 >> 8);
|
||||
const x35 = cast(u8, (x34 & cast(u64, 0xff)));
|
||||
const x36 = (x34 >> 8);
|
||||
const x37 = cast(u8, (x36 & cast(u64, 0xff)));
|
||||
const x38 = (x36 >> 8);
|
||||
const x39 = cast(u8, (x38 & cast(u64, 0xff)));
|
||||
const x40 = (x38 >> 8);
|
||||
const x41 = cast(u8, (x40 & cast(u64, 0xff)));
|
||||
const x42 = (x40 >> 8);
|
||||
const x43 = cast(u8, (x42 & cast(u64, 0xff)));
|
||||
const x44 = (x42 >> 8);
|
||||
const x45 = cast(u8, (x44 & cast(u64, 0xff)));
|
||||
const x46 = cast(u8, (x44 >> 8));
|
||||
const x47 = cast(u8, (x1 & cast(u64, 0xff)));
|
||||
const x48 = (x1 >> 8);
|
||||
const x49 = cast(u8, (x48 & cast(u64, 0xff)));
|
||||
const x50 = (x48 >> 8);
|
||||
const x51 = cast(u8, (x50 & cast(u64, 0xff)));
|
||||
const x52 = (x50 >> 8);
|
||||
const x53 = cast(u8, (x52 & cast(u64, 0xff)));
|
||||
const x54 = (x52 >> 8);
|
||||
const x55 = cast(u8, (x54 & cast(u64, 0xff)));
|
||||
const x56 = (x54 >> 8);
|
||||
const x57 = cast(u8, (x56 & cast(u64, 0xff)));
|
||||
const x58 = (x56 >> 8);
|
||||
const x59 = cast(u8, (x58 & cast(u64, 0xff)));
|
||||
const x60 = cast(u8, (x58 >> 8));
|
||||
out1[0] = x5;
|
||||
out1[1] = x7;
|
||||
out1[2] = x9;
|
||||
out1[3] = x11;
|
||||
out1[4] = x13;
|
||||
out1[5] = x15;
|
||||
out1[6] = x17;
|
||||
out1[7] = x18;
|
||||
out1[8] = x19;
|
||||
out1[9] = x21;
|
||||
out1[10] = x23;
|
||||
out1[11] = x25;
|
||||
out1[12] = x27;
|
||||
out1[13] = x29;
|
||||
out1[14] = x31;
|
||||
out1[15] = x32;
|
||||
out1[16] = x33;
|
||||
out1[17] = x35;
|
||||
out1[18] = x37;
|
||||
out1[19] = x39;
|
||||
out1[20] = x41;
|
||||
out1[21] = x43;
|
||||
out1[22] = x45;
|
||||
out1[23] = x46;
|
||||
out1[24] = x47;
|
||||
out1[25] = x49;
|
||||
out1[26] = x51;
|
||||
out1[27] = x53;
|
||||
out1[28] = x55;
|
||||
out1[29] = x57;
|
||||
out1[30] = x59;
|
||||
out1[31] = x60;
|
||||
}
|
||||
|
||||
/// The function fromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ bytes_eval arg1 < m
|
||||
/// Postconditions:
|
||||
/// eval out1 mod m = bytes_eval arg1 mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
const x1 = (cast(u64, (arg1[31])) << 56);
|
||||
const x2 = (cast(u64, (arg1[30])) << 48);
|
||||
const x3 = (cast(u64, (arg1[29])) << 40);
|
||||
const x4 = (cast(u64, (arg1[28])) << 32);
|
||||
const x5 = (cast(u64, (arg1[27])) << 24);
|
||||
const x6 = (cast(u64, (arg1[26])) << 16);
|
||||
const x7 = (cast(u64, (arg1[25])) << 8);
|
||||
const x8 = (arg1[24]);
|
||||
const x9 = (cast(u64, (arg1[23])) << 56);
|
||||
const x10 = (cast(u64, (arg1[22])) << 48);
|
||||
const x11 = (cast(u64, (arg1[21])) << 40);
|
||||
const x12 = (cast(u64, (arg1[20])) << 32);
|
||||
const x13 = (cast(u64, (arg1[19])) << 24);
|
||||
const x14 = (cast(u64, (arg1[18])) << 16);
|
||||
const x15 = (cast(u64, (arg1[17])) << 8);
|
||||
const x16 = (arg1[16]);
|
||||
const x17 = (cast(u64, (arg1[15])) << 56);
|
||||
const x18 = (cast(u64, (arg1[14])) << 48);
|
||||
const x19 = (cast(u64, (arg1[13])) << 40);
|
||||
const x20 = (cast(u64, (arg1[12])) << 32);
|
||||
const x21 = (cast(u64, (arg1[11])) << 24);
|
||||
const x22 = (cast(u64, (arg1[10])) << 16);
|
||||
const x23 = (cast(u64, (arg1[9])) << 8);
|
||||
const x24 = (arg1[8]);
|
||||
const x25 = (cast(u64, (arg1[7])) << 56);
|
||||
const x26 = (cast(u64, (arg1[6])) << 48);
|
||||
const x27 = (cast(u64, (arg1[5])) << 40);
|
||||
const x28 = (cast(u64, (arg1[4])) << 32);
|
||||
const x29 = (cast(u64, (arg1[3])) << 24);
|
||||
const x30 = (cast(u64, (arg1[2])) << 16);
|
||||
const x31 = (cast(u64, (arg1[1])) << 8);
|
||||
const x32 = (arg1[0]);
|
||||
const x33 = (x31 + cast(u64, x32));
|
||||
const x34 = (x30 + x33);
|
||||
const x35 = (x29 + x34);
|
||||
const x36 = (x28 + x35);
|
||||
const x37 = (x27 + x36);
|
||||
const x38 = (x26 + x37);
|
||||
const x39 = (x25 + x38);
|
||||
const x40 = (x23 + cast(u64, x24));
|
||||
const x41 = (x22 + x40);
|
||||
const x42 = (x21 + x41);
|
||||
const x43 = (x20 + x42);
|
||||
const x44 = (x19 + x43);
|
||||
const x45 = (x18 + x44);
|
||||
const x46 = (x17 + x45);
|
||||
const x47 = (x15 + cast(u64, x16));
|
||||
const x48 = (x14 + x47);
|
||||
const x49 = (x13 + x48);
|
||||
const x50 = (x12 + x49);
|
||||
const x51 = (x11 + x50);
|
||||
const x52 = (x10 + x51);
|
||||
const x53 = (x9 + x52);
|
||||
const x54 = (x7 + cast(u64, x8));
|
||||
const x55 = (x6 + x54);
|
||||
const x56 = (x5 + x55);
|
||||
const x57 = (x4 + x56);
|
||||
const x58 = (x3 + x57);
|
||||
const x59 = (x2 + x58);
|
||||
const x60 = (x1 + x59);
|
||||
out1[0] = x39;
|
||||
out1[1] = x46;
|
||||
out1[2] = x53;
|
||||
out1[3] = x60;
|
||||
}
|
||||
|
||||
/// The function setOne returns the field element one in the Montgomery domain.
|
||||
/// Postconditions:
|
||||
/// eval (from_montgomery out1) mod m = 1 mod m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn setOne(out1: *[4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
out1[0] = 0xc46353d039cdaaf;
|
||||
out1[1] = 0x4319055258e8617b;
|
||||
out1[2] = cast(u64, 0x0);
|
||||
out1[3] = 0xffffffff;
|
||||
}
|
||||
|
||||
/// The function msat returns the saturated representation of the prime modulus.
|
||||
/// Postconditions:
|
||||
/// twos_complement_eval out1 = m
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn msat(out1: *[5]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
out1[0] = 0xf3b9cac2fc632551;
|
||||
out1[1] = 0xbce6faada7179e84;
|
||||
out1[2] = 0xffffffffffffffff;
|
||||
out1[3] = 0xffffffff00000000;
|
||||
out1[4] = cast(u64, 0x0);
|
||||
}
|
||||
|
||||
/// The function divstepPrecomp returns the precomputed value for Bernstein-Yang-inversion (in montgomery form).
|
||||
/// Postconditions:
|
||||
/// eval (from_montgomery out1) = ⌊(m - 1) / 2⌋^(if (log2 m) + 1 < 46 then ⌊(49 * ((log2 m) + 1) + 80) / 17⌋ else ⌊(49 * ((log2 m) + 1) + 57) / 17⌋)
|
||||
/// 0 ≤ eval out1 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// Output Bounds:
|
||||
/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn divstepPrecomp(out1: *[4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
out1[0] = 0xd739262fb7fcfbb5;
|
||||
out1[1] = 0x8ac6f75d20074414;
|
||||
out1[2] = 0xc67428bfb5e3c256;
|
||||
out1[3] = 0x444962f2eda7aedf;
|
||||
}
|
||||
|
||||
/// The function divstep computes a divstep.
|
||||
/// Preconditions:
|
||||
/// 0 ≤ eval arg4 < m
|
||||
/// 0 ≤ eval arg5 < m
|
||||
/// Postconditions:
|
||||
/// out1 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then 1 - arg1 else 1 + arg1)
|
||||
/// twos_complement_eval out2 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then twos_complement_eval arg3 else twos_complement_eval arg2)
|
||||
/// twos_complement_eval out3 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then ⌊(twos_complement_eval arg3 - twos_complement_eval arg2) / 2⌋ else ⌊(twos_complement_eval arg3 + (twos_complement_eval arg3 mod 2) * twos_complement_eval arg2) / 2⌋)
|
||||
/// eval (from_montgomery out4) mod m = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then (2 * eval (from_montgomery arg5)) mod m else (2 * eval (from_montgomery arg4)) mod m)
|
||||
/// eval (from_montgomery out5) mod m = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then (eval (from_montgomery arg4) - eval (from_montgomery arg4)) mod m else (eval (from_montgomery arg5) + (twos_complement_eval arg3 mod 2) * eval (from_montgomery arg4)) mod m)
|
||||
/// 0 ≤ eval out5 < m
|
||||
/// 0 ≤ eval out5 < m
|
||||
/// 0 ≤ eval out2 < m
|
||||
/// 0 ≤ eval out3 < m
|
||||
///
|
||||
/// Input Bounds:
|
||||
/// arg1: [0x0 ~> 0xffffffffffffffff]
|
||||
/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// arg4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// arg5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// Output Bounds:
|
||||
/// out1: [0x0 ~> 0xffffffffffffffff]
|
||||
/// out2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// out3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// out4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
/// out5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
|
||||
pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[4]u64, arg1: u64, arg2: [5]u64, arg3: [5]u64, arg4: [4]u64, arg5: [4]u64) void {
|
||||
@setRuntimeSafety(mode == .Debug);
|
||||
|
||||
var x1: u64 = undefined;
|
||||
var x2: u1 = undefined;
|
||||
addcarryxU64(&x1, &x2, 0x0, (~arg1), cast(u64, 0x1));
|
||||
const x3 = (cast(u1, (x1 >> 63)) & cast(u1, ((arg3[0]) & cast(u64, 0x1))));
|
||||
var x4: u64 = undefined;
|
||||
var x5: u1 = undefined;
|
||||
addcarryxU64(&x4, &x5, 0x0, (~arg1), cast(u64, 0x1));
|
||||
var x6: u64 = undefined;
|
||||
cmovznzU64(&x6, x3, arg1, x4);
|
||||
var x7: u64 = undefined;
|
||||
cmovznzU64(&x7, x3, (arg2[0]), (arg3[0]));
|
||||
var x8: u64 = undefined;
|
||||
cmovznzU64(&x8, x3, (arg2[1]), (arg3[1]));
|
||||
var x9: u64 = undefined;
|
||||
cmovznzU64(&x9, x3, (arg2[2]), (arg3[2]));
|
||||
var x10: u64 = undefined;
|
||||
cmovznzU64(&x10, x3, (arg2[3]), (arg3[3]));
|
||||
var x11: u64 = undefined;
|
||||
cmovznzU64(&x11, x3, (arg2[4]), (arg3[4]));
|
||||
var x12: u64 = undefined;
|
||||
var x13: u1 = undefined;
|
||||
addcarryxU64(&x12, &x13, 0x0, cast(u64, 0x1), (~(arg2[0])));
|
||||
var x14: u64 = undefined;
|
||||
var x15: u1 = undefined;
|
||||
addcarryxU64(&x14, &x15, x13, cast(u64, 0x0), (~(arg2[1])));
|
||||
var x16: u64 = undefined;
|
||||
var x17: u1 = undefined;
|
||||
addcarryxU64(&x16, &x17, x15, cast(u64, 0x0), (~(arg2[2])));
|
||||
var x18: u64 = undefined;
|
||||
var x19: u1 = undefined;
|
||||
addcarryxU64(&x18, &x19, x17, cast(u64, 0x0), (~(arg2[3])));
|
||||
var x20: u64 = undefined;
|
||||
var x21: u1 = undefined;
|
||||
addcarryxU64(&x20, &x21, x19, cast(u64, 0x0), (~(arg2[4])));
|
||||
var x22: u64 = undefined;
|
||||
cmovznzU64(&x22, x3, (arg3[0]), x12);
|
||||
var x23: u64 = undefined;
|
||||
cmovznzU64(&x23, x3, (arg3[1]), x14);
|
||||
var x24: u64 = undefined;
|
||||
cmovznzU64(&x24, x3, (arg3[2]), x16);
|
||||
var x25: u64 = undefined;
|
||||
cmovznzU64(&x25, x3, (arg3[3]), x18);
|
||||
var x26: u64 = undefined;
|
||||
cmovznzU64(&x26, x3, (arg3[4]), x20);
|
||||
var x27: u64 = undefined;
|
||||
cmovznzU64(&x27, x3, (arg4[0]), (arg5[0]));
|
||||
var x28: u64 = undefined;
|
||||
cmovznzU64(&x28, x3, (arg4[1]), (arg5[1]));
|
||||
var x29: u64 = undefined;
|
||||
cmovznzU64(&x29, x3, (arg4[2]), (arg5[2]));
|
||||
var x30: u64 = undefined;
|
||||
cmovznzU64(&x30, x3, (arg4[3]), (arg5[3]));
|
||||
var x31: u64 = undefined;
|
||||
var x32: u1 = undefined;
|
||||
addcarryxU64(&x31, &x32, 0x0, x27, x27);
|
||||
var x33: u64 = undefined;
|
||||
var x34: u1 = undefined;
|
||||
addcarryxU64(&x33, &x34, x32, x28, x28);
|
||||
var x35: u64 = undefined;
|
||||
var x36: u1 = undefined;
|
||||
addcarryxU64(&x35, &x36, x34, x29, x29);
|
||||
var x37: u64 = undefined;
|
||||
var x38: u1 = undefined;
|
||||
addcarryxU64(&x37, &x38, x36, x30, x30);
|
||||
var x39: u64 = undefined;
|
||||
var x40: u1 = undefined;
|
||||
subborrowxU64(&x39, &x40, 0x0, x31, 0xf3b9cac2fc632551);
|
||||
var x41: u64 = undefined;
|
||||
var x42: u1 = undefined;
|
||||
subborrowxU64(&x41, &x42, x40, x33, 0xbce6faada7179e84);
|
||||
var x43: u64 = undefined;
|
||||
var x44: u1 = undefined;
|
||||
subborrowxU64(&x43, &x44, x42, x35, 0xffffffffffffffff);
|
||||
var x45: u64 = undefined;
|
||||
var x46: u1 = undefined;
|
||||
subborrowxU64(&x45, &x46, x44, x37, 0xffffffff00000000);
|
||||
var x47: u64 = undefined;
|
||||
var x48: u1 = undefined;
|
||||
subborrowxU64(&x47, &x48, x46, cast(u64, x38), cast(u64, 0x0));
|
||||
const x49 = (arg4[3]);
|
||||
const x50 = (arg4[2]);
|
||||
const x51 = (arg4[1]);
|
||||
const x52 = (arg4[0]);
|
||||
var x53: u64 = undefined;
|
||||
var x54: u1 = undefined;
|
||||
subborrowxU64(&x53, &x54, 0x0, cast(u64, 0x0), x52);
|
||||
var x55: u64 = undefined;
|
||||
var x56: u1 = undefined;
|
||||
subborrowxU64(&x55, &x56, x54, cast(u64, 0x0), x51);
|
||||
var x57: u64 = undefined;
|
||||
var x58: u1 = undefined;
|
||||
subborrowxU64(&x57, &x58, x56, cast(u64, 0x0), x50);
|
||||
var x59: u64 = undefined;
|
||||
var x60: u1 = undefined;
|
||||
subborrowxU64(&x59, &x60, x58, cast(u64, 0x0), x49);
|
||||
var x61: u64 = undefined;
|
||||
cmovznzU64(&x61, x60, cast(u64, 0x0), 0xffffffffffffffff);
|
||||
var x62: u64 = undefined;
|
||||
var x63: u1 = undefined;
|
||||
addcarryxU64(&x62, &x63, 0x0, x53, (x61 & 0xf3b9cac2fc632551));
|
||||
var x64: u64 = undefined;
|
||||
var x65: u1 = undefined;
|
||||
addcarryxU64(&x64, &x65, x63, x55, (x61 & 0xbce6faada7179e84));
|
||||
var x66: u64 = undefined;
|
||||
var x67: u1 = undefined;
|
||||
addcarryxU64(&x66, &x67, x65, x57, x61);
|
||||
var x68: u64 = undefined;
|
||||
var x69: u1 = undefined;
|
||||
addcarryxU64(&x68, &x69, x67, x59, (x61 & 0xffffffff00000000));
|
||||
var x70: u64 = undefined;
|
||||
cmovznzU64(&x70, x3, (arg5[0]), x62);
|
||||
var x71: u64 = undefined;
|
||||
cmovznzU64(&x71, x3, (arg5[1]), x64);
|
||||
var x72: u64 = undefined;
|
||||
cmovznzU64(&x72, x3, (arg5[2]), x66);
|
||||
var x73: u64 = undefined;
|
||||
cmovznzU64(&x73, x3, (arg5[3]), x68);
|
||||
const x74 = cast(u1, (x22 & cast(u64, 0x1)));
|
||||
var x75: u64 = undefined;
|
||||
cmovznzU64(&x75, x74, cast(u64, 0x0), x7);
|
||||
var x76: u64 = undefined;
|
||||
cmovznzU64(&x76, x74, cast(u64, 0x0), x8);
|
||||
var x77: u64 = undefined;
|
||||
cmovznzU64(&x77, x74, cast(u64, 0x0), x9);
|
||||
var x78: u64 = undefined;
|
||||
cmovznzU64(&x78, x74, cast(u64, 0x0), x10);
|
||||
var x79: u64 = undefined;
|
||||
cmovznzU64(&x79, x74, cast(u64, 0x0), x11);
|
||||
var x80: u64 = undefined;
|
||||
var x81: u1 = undefined;
|
||||
addcarryxU64(&x80, &x81, 0x0, x22, x75);
|
||||
var x82: u64 = undefined;
|
||||
var x83: u1 = undefined;
|
||||
addcarryxU64(&x82, &x83, x81, x23, x76);
|
||||
var x84: u64 = undefined;
|
||||
var x85: u1 = undefined;
|
||||
addcarryxU64(&x84, &x85, x83, x24, x77);
|
||||
var x86: u64 = undefined;
|
||||
var x87: u1 = undefined;
|
||||
addcarryxU64(&x86, &x87, x85, x25, x78);
|
||||
var x88: u64 = undefined;
|
||||
var x89: u1 = undefined;
|
||||
addcarryxU64(&x88, &x89, x87, x26, x79);
|
||||
var x90: u64 = undefined;
|
||||
cmovznzU64(&x90, x74, cast(u64, 0x0), x27);
|
||||
var x91: u64 = undefined;
|
||||
cmovznzU64(&x91, x74, cast(u64, 0x0), x28);
|
||||
var x92: u64 = undefined;
|
||||
cmovznzU64(&x92, x74, cast(u64, 0x0), x29);
|
||||
var x93: u64 = undefined;
|
||||
cmovznzU64(&x93, x74, cast(u64, 0x0), x30);
|
||||
var x94: u64 = undefined;
|
||||
var x95: u1 = undefined;
|
||||
addcarryxU64(&x94, &x95, 0x0, x70, x90);
|
||||
var x96: u64 = undefined;
|
||||
var x97: u1 = undefined;
|
||||
addcarryxU64(&x96, &x97, x95, x71, x91);
|
||||
var x98: u64 = undefined;
|
||||
var x99: u1 = undefined;
|
||||
addcarryxU64(&x98, &x99, x97, x72, x92);
|
||||
var x100: u64 = undefined;
|
||||
var x101: u1 = undefined;
|
||||
addcarryxU64(&x100, &x101, x99, x73, x93);
|
||||
var x102: u64 = undefined;
|
||||
var x103: u1 = undefined;
|
||||
subborrowxU64(&x102, &x103, 0x0, x94, 0xf3b9cac2fc632551);
|
||||
var x104: u64 = undefined;
|
||||
var x105: u1 = undefined;
|
||||
subborrowxU64(&x104, &x105, x103, x96, 0xbce6faada7179e84);
|
||||
var x106: u64 = undefined;
|
||||
var x107: u1 = undefined;
|
||||
subborrowxU64(&x106, &x107, x105, x98, 0xffffffffffffffff);
|
||||
var x108: u64 = undefined;
|
||||
var x109: u1 = undefined;
|
||||
subborrowxU64(&x108, &x109, x107, x100, 0xffffffff00000000);
|
||||
var x110: u64 = undefined;
|
||||
var x111: u1 = undefined;
|
||||
subborrowxU64(&x110, &x111, x109, cast(u64, x101), cast(u64, 0x0));
|
||||
var x112: u64 = undefined;
|
||||
var x113: u1 = undefined;
|
||||
addcarryxU64(&x112, &x113, 0x0, x6, cast(u64, 0x1));
|
||||
const x114 = ((x80 >> 1) | ((x82 << 63) & 0xffffffffffffffff));
|
||||
const x115 = ((x82 >> 1) | ((x84 << 63) & 0xffffffffffffffff));
|
||||
const x116 = ((x84 >> 1) | ((x86 << 63) & 0xffffffffffffffff));
|
||||
const x117 = ((x86 >> 1) | ((x88 << 63) & 0xffffffffffffffff));
|
||||
const x118 = ((x88 & 0x8000000000000000) | (x88 >> 1));
|
||||
var x119: u64 = undefined;
|
||||
cmovznzU64(&x119, x48, x39, x31);
|
||||
var x120: u64 = undefined;
|
||||
cmovznzU64(&x120, x48, x41, x33);
|
||||
var x121: u64 = undefined;
|
||||
cmovznzU64(&x121, x48, x43, x35);
|
||||
var x122: u64 = undefined;
|
||||
cmovznzU64(&x122, x48, x45, x37);
|
||||
var x123: u64 = undefined;
|
||||
cmovznzU64(&x123, x111, x102, x94);
|
||||
var x124: u64 = undefined;
|
||||
cmovznzU64(&x124, x111, x104, x96);
|
||||
var x125: u64 = undefined;
|
||||
cmovznzU64(&x125, x111, x106, x98);
|
||||
var x126: u64 = undefined;
|
||||
cmovznzU64(&x126, x111, x108, x100);
|
||||
out1.* = x112;
|
||||
out2[0] = x7;
|
||||
out2[1] = x8;
|
||||
out2[2] = x9;
|
||||
out2[3] = x10;
|
||||
out2[4] = x11;
|
||||
out3[0] = x114;
|
||||
out3[1] = x115;
|
||||
out3[2] = x116;
|
||||
out3[3] = x117;
|
||||
out3[4] = x118;
|
||||
out4[0] = x119;
|
||||
out4[1] = x120;
|
||||
out4[2] = x121;
|
||||
out4[3] = x122;
|
||||
out5[0] = x123;
|
||||
out5[1] = x124;
|
||||
out5[2] = x125;
|
||||
out5[3] = x126;
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2015-2021 Zig Contributors
|
||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
||||
// The MIT license requires this copyright notice to be included in all copies
|
||||
// and substantial portions of the software.
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = std.builtin;
|
||||
const common = @import("../common.zig");
|
||||
const crypto = std.crypto;
|
||||
const debug = std.debug;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
|
||||
const Field = common.Field;
|
||||
|
||||
const NonCanonicalError = std.crypto.errors.NonCanonicalError;
|
||||
const NotSquareError = std.crypto.errors.NotSquareError;
|
||||
|
||||
/// Number of bytes required to encode a scalar.
|
||||
pub const encoded_length = 32;
|
||||
|
||||
/// A compressed scalar, in canonical form.
|
||||
pub const CompressedScalar = [encoded_length]u8;
|
||||
|
||||
const Fe = Field(.{
|
||||
.fiat = @import("p256_scalar_64.zig"),
|
||||
.field_order = 115792089210356248762697446949407573529996955224135760342422259061068512044369,
|
||||
.field_bits = 256,
|
||||
.saturated_bits = 255,
|
||||
.encoded_length = encoded_length,
|
||||
});
|
||||
|
||||
/// Reject a scalar whose encoding is not canonical.
|
||||
pub fn rejectNonCanonical(s: CompressedScalar, endian: builtin.Endian) NonCanonicalError!void {
|
||||
return Fe.rejectNonCanonical(s, endian);
|
||||
}
|
||||
|
||||
/// Reduce a 48-bytes scalar to the field size.
|
||||
pub fn reduce48(s: [48]u8, endian: builtin.Endian) CompressedScalar {
|
||||
return Scalar.fromBytes48(s, endian).toBytes(endian);
|
||||
}
|
||||
|
||||
/// Reduce a 64-bytes scalar to the field size.
|
||||
pub fn reduce64(s: [64]u8, endian: builtin.Endian) CompressedScalar {
|
||||
return ScalarDouble.fromBytes64(s, endian).toBytes(endian);
|
||||
}
|
||||
|
||||
/// Return a*b (mod L)
|
||||
pub fn mul(a: CompressedScalar, b: CompressedScalar, endian: builtin.Endian) NonCanonicalError!CompressedScalar {
|
||||
return (try Scalar.fromBytes(a, endian)).mul(try Scalar.fromBytes(b, endian)).toBytes(endian);
|
||||
}
|
||||
|
||||
/// Return a*b+c (mod L)
|
||||
pub fn mulAdd(a: CompressedScalar, b: CompressedScalar, c: CompressedScalar, endian: builtin.Endian) NonCanonicalError!CompressedScalar {
|
||||
return (try Scalar.fromBytes(a, endian)).mul(try Scalar.fromBytes(b, endian)).add(try Scalar.fromBytes(c, endian)).toBytes(endian);
|
||||
}
|
||||
|
||||
/// Return a+b (mod L)
|
||||
pub fn add(a: CompressedScalar, b: CompressedScalar, endian: builtin.Endian) NonCanonicalError!CompressedScalar {
|
||||
return (try Scalar.fromBytes(a, endian)).add(try Scalar.fromBytes(b, endian)).toBytes(endian);
|
||||
}
|
||||
|
||||
/// Return -s (mod L)
|
||||
pub fn neg(s: CompressedScalar, endian: builtin.Endian) NonCanonicalError!CompressedScalar {
|
||||
return (try Scalar.fromBytes(a, endian)).neg().toBytes(endian);
|
||||
}
|
||||
|
||||
/// Return (a-b) (mod L)
|
||||
pub fn sub(a: CompressedScalar, b: CompressedScalar, endian: builtin.Endian) NonCanonicalError!CompressedScalar {
|
||||
return (try Scalar.fromBytes(a, endian)).sub(try Scalar.fromBytes(b.endian)).toBytes(endian);
|
||||
}
|
||||
|
||||
/// Return a random scalar
|
||||
pub fn random(endian: builtin.Endian) CompressedScalar {
|
||||
return Scalar.random().toBytes(endian);
|
||||
}
|
||||
|
||||
/// A scalar in unpacked representation.
|
||||
pub const Scalar = struct {
|
||||
fe: Fe,
|
||||
|
||||
/// Zero.
|
||||
pub const zero = Scalar{ .fe = Fe.zero };
|
||||
|
||||
/// One.
|
||||
pub const one = Scalar{ .fe = Fe.one };
|
||||
|
||||
/// Unpack a serialized representation of a scalar.
|
||||
pub fn fromBytes(s: CompressedScalar, endian: builtin.Endian) NonCanonicalError!Scalar {
|
||||
return Scalar{ .fe = try Fe.fromBytes(s, endian) };
|
||||
}
|
||||
|
||||
/// Reduce a 384 bit input to the field size.
|
||||
pub fn fromBytes48(s: [48]u8, endian: builtin.Endian) Scalar {
|
||||
const t = ScalarDouble.fromBytes(384, s, endian);
|
||||
return t.reduce(384);
|
||||
}
|
||||
|
||||
/// Reduce a 512 bit input to the field size.
|
||||
pub fn fromBytes64(s: [64]u8, endian: builtin.Endian) Scalar {
|
||||
const t = ScalarDouble.fromBytes(512, s, endian);
|
||||
return t.reduce(512);
|
||||
}
|
||||
|
||||
/// Pack a scalar into bytes.
|
||||
pub fn toBytes(n: Scalar, endian: builtin.Endian) CompressedScalar {
|
||||
return n.fe.toBytes(endian);
|
||||
}
|
||||
|
||||
/// Return true if the scalar is zero..
|
||||
pub fn isZero(n: Scalar) bool {
|
||||
return n.fe.isZero();
|
||||
}
|
||||
|
||||
/// Return true if a and b are equivalent.
|
||||
pub fn equivalent(a: Scalar, b: Scalar) bool {
|
||||
return a.fe.equivalent(b.fe);
|
||||
}
|
||||
|
||||
/// Compute x+y (mod L)
|
||||
pub fn add(x: Scalar, y: Scalar) Scalar {
|
||||
return Scalar{ .fe = x.fe().add(y.fe) };
|
||||
}
|
||||
|
||||
/// Compute x-y (mod L)
|
||||
pub fn sub(x: Scalar, y: Scalar) Scalar {
|
||||
return Scalar{ .fe = x.fe().sub(y.fe) };
|
||||
}
|
||||
|
||||
/// Compute 2n (mod L)
|
||||
pub fn dbl(n: Scalar) Scalar {
|
||||
return Scalar{ .fe = n.fe.dbl() };
|
||||
}
|
||||
|
||||
/// Compute x*y (mod L)
|
||||
pub fn mul(x: Scalar, y: Scalar) Scalar {
|
||||
return Scalar{ .fe = x.fe().mul(y.fe) };
|
||||
}
|
||||
|
||||
/// Compute x^2 (mod L)
|
||||
pub fn sq(n: Scalar) Scalar {
|
||||
return Scalar{ .fe = n.fe.sq() };
|
||||
}
|
||||
|
||||
/// Compute x^n (mod L)
|
||||
pub fn pow(a: Scalar, comptime T: type, comptime n: T) Scalar {
|
||||
return Scalar{ .fe = a.fe.pow(n) };
|
||||
}
|
||||
|
||||
/// Compute -x (mod L)
|
||||
pub fn neg(n: Scalar) Scalar {
|
||||
return Scalar{ .fe = n.fe.neg() };
|
||||
}
|
||||
|
||||
/// Compute x^-1 (mod L)
|
||||
pub fn invert(n: Scalar) Scalar {
|
||||
return Scalar{ .fe = n.fe.invert() };
|
||||
}
|
||||
|
||||
/// Return true if n is a quadratic residue mod L.
|
||||
pub fn isSquare(n: Scalar) Scalar {
|
||||
return n.fe.isSquare();
|
||||
}
|
||||
|
||||
/// Return the square root of L, or NotSquare if there isn't any solutions.
|
||||
pub fn sqrt(n: Scalar) NotSquareError!Scalar {
|
||||
return Scalar{ .fe = try n.fe.sqrt() };
|
||||
}
|
||||
|
||||
/// Return a random scalar < L.
|
||||
pub fn random() Scalar {
|
||||
var s: [48]u8 = undefined;
|
||||
while (true) {
|
||||
crypto.random.bytes(&s);
|
||||
const n = Scalar.fromBytes48(s, .Little);
|
||||
if (!n.isZero()) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const ScalarDouble = struct {
|
||||
x1: Fe,
|
||||
x2: Fe,
|
||||
x3: Fe,
|
||||
|
||||
fn fromBytes(comptime bits: usize, s_: [bits / 8]u8, endian: builtin.Endian) ScalarDouble {
|
||||
debug.assert(bits > 0 and bits <= 512 and bits >= Fe.saturated_bits and bits <= Fe.saturated_bits * 3);
|
||||
|
||||
var s = s_;
|
||||
if (endian == .Big) {
|
||||
for (s_) |x, i| s[s.len - 1 - i] = x;
|
||||
}
|
||||
var t = ScalarDouble{ .x1 = undefined, .x2 = Fe.zero, .x3 = Fe.zero };
|
||||
{
|
||||
var b = [_]u8{0} ** encoded_length;
|
||||
const len = math.min(s.len, 24);
|
||||
mem.copy(u8, b[0..len], s[0..len]);
|
||||
t.x1 = Fe.fromBytes(b, .Little) catch unreachable;
|
||||
}
|
||||
if (s_.len >= 24) {
|
||||
var b = [_]u8{0} ** encoded_length;
|
||||
const len = math.min(s.len - 24, 24);
|
||||
mem.copy(u8, b[0..len], s[24..][0..len]);
|
||||
t.x2 = Fe.fromBytes(b, .Little) catch unreachable;
|
||||
}
|
||||
if (s_.len >= 48) {
|
||||
var b = [_]u8{0} ** encoded_length;
|
||||
const len = s.len - 48;
|
||||
mem.copy(u8, b[0..len], s[48..][0..len]);
|
||||
t.x3 = Fe.fromBytes(b, .Little) catch unreachable;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
fn reduce(expanded: ScalarDouble, comptime bits: usize) Scalar {
|
||||
debug.assert(bits > 0 and bits <= Fe.saturated_bits * 3 and bits <= 512);
|
||||
var fe = expanded.x1;
|
||||
if (bits >= 192) {
|
||||
const st1 = Fe.fromInt(1 << 192) catch unreachable;
|
||||
fe = fe.add(expanded.x2.mul(st1));
|
||||
if (bits >= 384) {
|
||||
const st2 = st1.sq();
|
||||
fe = fe.add(expanded.x3.mul(st2));
|
||||
}
|
||||
}
|
||||
return Scalar{ .fe = fe };
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2015-2021 Zig Contributors
|
||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
||||
// The MIT license requires this copyright notice to be included in all copies
|
||||
// and substantial portions of the software.
|
||||
|
||||
const std = @import("std");
|
||||
const fmt = std.fmt;
|
||||
const testing = std.testing;
|
||||
|
||||
const P256 = @import("p256.zig").P256;
|
||||
|
||||
test "p256 ECDH key exchange" {
|
||||
const dha = P256.scalar.random(.Little);
|
||||
const dhb = P256.scalar.random(.Little);
|
||||
const dhA = try P256.basePoint.mul(dha, .Little);
|
||||
const dhB = try P256.basePoint.mul(dhb, .Little);
|
||||
const shareda = try dhA.mul(dhb, .Little);
|
||||
const sharedb = try dhB.mul(dha, .Little);
|
||||
testing.expect(shareda.equivalent(sharedb));
|
||||
}
|
||||
|
||||
test "p256 point from affine coordinates" {
|
||||
const xh = "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296";
|
||||
const yh = "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5";
|
||||
var xs: [32]u8 = undefined;
|
||||
_ = try fmt.hexToBytes(&xs, xh);
|
||||
var ys: [32]u8 = undefined;
|
||||
_ = try fmt.hexToBytes(&ys, yh);
|
||||
var p = try P256.fromSerializedAffineCoordinates(xs, ys, .Big);
|
||||
testing.expect(p.equivalent(P256.basePoint));
|
||||
}
|
||||
|
||||
test "p256 test vectors" {
|
||||
const expected = [_][]const u8{
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
|
||||
"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978",
|
||||
"5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c",
|
||||
"e2534a3532d08fbba02dde659ee62bd0031fe2db785596ef509302446b030852",
|
||||
"51590b7a515140d2d784c85608668fdfef8c82fd1f5be52421554a0dc3d033ed",
|
||||
"b01a172a76a4602c92d3242cb897dde3024c740debb215b4c6b0aae93c2291a9",
|
||||
"8e533b6fa0bf7b4625bb30667c01fb607ef9f8b8a80fef5b300628703187b2a3",
|
||||
"62d9779dbee9b0534042742d3ab54cadc1d238980fce97dbb4dd9dc1db6fb393",
|
||||
"ea68d7b6fedf0b71878938d51d71f8729e0acb8c2c6df8b3d79e8a4b90949ee0",
|
||||
};
|
||||
var p = P256.identityElement;
|
||||
for (expected) |xh| {
|
||||
const x = p.affineCoordinates().x;
|
||||
p = p.add(P256.basePoint);
|
||||
var xs: [32]u8 = undefined;
|
||||
_ = try fmt.hexToBytes(&xs, xh);
|
||||
testing.expectEqualSlices(u8, &x.toBytes(.Big), &xs);
|
||||
}
|
||||
}
|
||||
|
||||
test "p256 test vectors - doubling" {
|
||||
const expected = [_][]const u8{
|
||||
"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
|
||||
"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978",
|
||||
"e2534a3532d08fbba02dde659ee62bd0031fe2db785596ef509302446b030852",
|
||||
"62d9779dbee9b0534042742d3ab54cadc1d238980fce97dbb4dd9dc1db6fb393",
|
||||
};
|
||||
var p = P256.basePoint;
|
||||
for (expected) |xh| {
|
||||
const x = p.affineCoordinates().x;
|
||||
p = p.dbl();
|
||||
var xs: [32]u8 = undefined;
|
||||
_ = try fmt.hexToBytes(&xs, xh);
|
||||
testing.expectEqualSlices(u8, &x.toBytes(.Big), &xs);
|
||||
}
|
||||
}
|
||||
|
||||
test "p256 compressed sec1 encoding/decoding" {
|
||||
const p = P256.random();
|
||||
const s = p.toCompressedSec1();
|
||||
const q = try P256.fromSec1(&s);
|
||||
testing.expect(p.equivalent(q));
|
||||
}
|
||||
|
||||
test "p256 uncompressed sec1 encoding/decoding" {
|
||||
const p = P256.random();
|
||||
const s = p.toUncompressedSec1();
|
||||
const q = try P256.fromSec1(&s);
|
||||
testing.expect(p.equivalent(q));
|
||||
}
|
||||
|
||||
test "p256 public key is the neutral element" {
|
||||
const n = P256.scalar.Scalar.zero.toBytes(.Little);
|
||||
const p = P256.random();
|
||||
testing.expectError(error.IdentityElement, p.mul(n, .Little));
|
||||
}
|
||||
|
||||
test "p256 public key is the neutral element (public verification)" {
|
||||
const n = P256.scalar.Scalar.zero.toBytes(.Little);
|
||||
const p = P256.random();
|
||||
testing.expectError(error.IdentityElement, p.mulPublic(n, .Little));
|
||||
}
|
||||
|
||||
test "p256 field element non-canonical encoding" {
|
||||
const s = [_]u8{0xff} ** 32;
|
||||
testing.expectError(error.NonCanonical, P256.Fe.fromBytes(s, .Little));
|
||||
}
|
||||
+159
@@ -696,6 +696,11 @@ fn formatFloatValue(
|
||||
error.NoSpaceLeft => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
} else if (comptime std.mem.eql(u8, fmt, "x")) {
|
||||
formatFloatHexadecimal(value, options, buf_stream.writer()) catch |err| switch (err) {
|
||||
error.NoSpaceLeft => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
} else {
|
||||
@compileError("Unsupported format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");
|
||||
}
|
||||
@@ -1023,6 +1028,112 @@ pub fn formatFloatScientific(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn formatFloatHexadecimal(
|
||||
value: anytype,
|
||||
options: FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
if (math.signbit(value)) {
|
||||
try writer.writeByte('-');
|
||||
}
|
||||
if (math.isNan(value)) {
|
||||
return writer.writeAll("nan");
|
||||
}
|
||||
if (math.isInf(value)) {
|
||||
return writer.writeAll("inf");
|
||||
}
|
||||
|
||||
const T = @TypeOf(value);
|
||||
const TU = std.meta.Int(.unsigned, std.meta.bitCount(T));
|
||||
|
||||
const mantissa_bits = math.floatMantissaBits(T);
|
||||
const exponent_bits = math.floatExponentBits(T);
|
||||
const mantissa_mask = (1 << mantissa_bits) - 1;
|
||||
const exponent_mask = (1 << exponent_bits) - 1;
|
||||
const exponent_bias = (1 << (exponent_bits - 1)) - 1;
|
||||
|
||||
const as_bits = @bitCast(TU, value);
|
||||
var mantissa = as_bits & mantissa_mask;
|
||||
var exponent: i32 = @truncate(u16, (as_bits >> mantissa_bits) & exponent_mask);
|
||||
|
||||
const is_denormal = exponent == 0 and mantissa != 0;
|
||||
const is_zero = exponent == 0 and mantissa == 0;
|
||||
|
||||
if (is_zero) {
|
||||
// Handle this case here to simplify the logic below.
|
||||
try writer.writeAll("0x0");
|
||||
if (options.precision) |precision| {
|
||||
if (precision > 0) {
|
||||
try writer.writeAll(".");
|
||||
try writer.writeByteNTimes('0', precision);
|
||||
}
|
||||
} else {
|
||||
try writer.writeAll(".0");
|
||||
}
|
||||
try writer.writeAll("p0");
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_denormal) {
|
||||
// Adjust the exponent for printing.
|
||||
exponent += 1;
|
||||
} else {
|
||||
// Add the implicit 1.
|
||||
mantissa |= 1 << mantissa_bits;
|
||||
}
|
||||
|
||||
// Fill in zeroes to round the mantissa width to a multiple of 4.
|
||||
if (T == f16) mantissa <<= 2 else if (T == f32) mantissa <<= 1;
|
||||
|
||||
const mantissa_digits = (mantissa_bits + 3) / 4;
|
||||
|
||||
if (options.precision) |precision| {
|
||||
// Round if needed.
|
||||
if (precision < mantissa_digits) {
|
||||
// We always have at least 4 extra bits.
|
||||
var extra_bits = (mantissa_digits - precision) * 4;
|
||||
// The result LSB is the Guard bit, we need two more (Round and
|
||||
// Sticky) to round the value.
|
||||
while (extra_bits > 2) {
|
||||
mantissa = (mantissa >> 1) | (mantissa & 1);
|
||||
extra_bits -= 1;
|
||||
}
|
||||
// Round to nearest, tie to even.
|
||||
mantissa |= @boolToInt(mantissa & 0b100 != 0);
|
||||
mantissa += 1;
|
||||
// Drop the excess bits.
|
||||
mantissa >>= 2;
|
||||
// Restore the alignment.
|
||||
mantissa <<= @intCast(math.Log2Int(TU), (mantissa_digits - precision) * 4);
|
||||
|
||||
const overflow = mantissa & (1 << 1 + mantissa_digits * 4) != 0;
|
||||
// Prefer a normalized result in case of overflow.
|
||||
if (overflow) {
|
||||
mantissa >>= 1;
|
||||
exponent += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// +1 for the decimal part.
|
||||
var buf: [1 + mantissa_digits]u8 = undefined;
|
||||
const N = formatIntBuf(&buf, mantissa, 16, false, .{ .fill = '0', .width = 1 + mantissa_digits });
|
||||
|
||||
try writer.writeAll("0x");
|
||||
try writer.writeByte(buf[0]);
|
||||
if (options.precision != @as(usize, 0))
|
||||
try writer.writeAll(".");
|
||||
const trimmed = mem.trimRight(u8, buf[1..], "0");
|
||||
try writer.writeAll(trimmed);
|
||||
// Add trailing zeros if explicitly requested.
|
||||
if (options.precision) |precision| if (precision > 0) {
|
||||
if (precision > trimmed.len)
|
||||
try writer.writeByteNTimes('0', precision - trimmed.len);
|
||||
};
|
||||
try writer.writeAll("p");
|
||||
try formatInt(exponent - exponent_bias, 10, false, .{}, writer);
|
||||
}
|
||||
|
||||
/// Print a float of the format x.yyyyy where the number of y is specified by the precision argument.
|
||||
/// By default floats are printed at full precision (no rounding).
|
||||
pub fn formatFloatDecimal(
|
||||
@@ -1917,6 +2028,54 @@ test "float.special" {
|
||||
try expectFmt("f64: -inf", "f64: {}", .{-math.inf_f64});
|
||||
}
|
||||
|
||||
test "float.hexadecimal.special" {
|
||||
try expectFmt("f64: nan", "f64: {x}", .{math.nan_f64});
|
||||
// negative nan is not defined by IEE 754,
|
||||
// and ARM thus normalizes it to positive nan
|
||||
if (builtin.arch != builtin.Arch.arm) {
|
||||
try expectFmt("f64: -nan", "f64: {x}", .{-math.nan_f64});
|
||||
}
|
||||
try expectFmt("f64: inf", "f64: {x}", .{math.inf_f64});
|
||||
try expectFmt("f64: -inf", "f64: {x}", .{-math.inf_f64});
|
||||
|
||||
try expectFmt("f64: 0x0.0p0", "f64: {x}", .{@as(f64, 0)});
|
||||
try expectFmt("f64: -0x0.0p0", "f64: {x}", .{-@as(f64, 0)});
|
||||
}
|
||||
|
||||
test "float.hexadecimal" {
|
||||
try expectFmt("f16: 0x1.554p-2", "f16: {x}", .{@as(f16, 1.0 / 3.0)});
|
||||
try expectFmt("f32: 0x1.555556p-2", "f32: {x}", .{@as(f32, 1.0 / 3.0)});
|
||||
try expectFmt("f64: 0x1.5555555555555p-2", "f64: {x}", .{@as(f64, 1.0 / 3.0)});
|
||||
try expectFmt("f128: 0x1.5555555555555555555555555555p-2", "f128: {x}", .{@as(f128, 1.0 / 3.0)});
|
||||
|
||||
try expectFmt("f16: 0x1.p-14", "f16: {x}", .{@as(f16, math.f16_min)});
|
||||
try expectFmt("f32: 0x1.p-126", "f32: {x}", .{@as(f32, math.f32_min)});
|
||||
try expectFmt("f64: 0x1.p-1022", "f64: {x}", .{@as(f64, math.f64_min)});
|
||||
try expectFmt("f128: 0x1.p-16382", "f128: {x}", .{@as(f128, math.f128_min)});
|
||||
|
||||
try expectFmt("f16: 0x0.004p-14", "f16: {x}", .{@as(f16, math.f16_true_min)});
|
||||
try expectFmt("f32: 0x0.000002p-126", "f32: {x}", .{@as(f32, math.f32_true_min)});
|
||||
try expectFmt("f64: 0x0.0000000000001p-1022", "f64: {x}", .{@as(f64, math.f64_true_min)});
|
||||
try expectFmt("f128: 0x0.0000000000000000000000000001p-16382", "f128: {x}", .{@as(f128, math.f128_true_min)});
|
||||
|
||||
try expectFmt("f16: 0x1.ffcp15", "f16: {x}", .{@as(f16, math.f16_max)});
|
||||
try expectFmt("f32: 0x1.fffffep127", "f32: {x}", .{@as(f32, math.f32_max)});
|
||||
try expectFmt("f64: 0x1.fffffffffffffp1023", "f64: {x}", .{@as(f64, math.f64_max)});
|
||||
try expectFmt("f128: 0x1.ffffffffffffffffffffffffffffp16383", "f128: {x}", .{@as(f128, math.f128_max)});
|
||||
}
|
||||
|
||||
test "float.hexadecimal.precision" {
|
||||
try expectFmt("f16: 0x1.5p-2", "f16: {x:.1}", .{@as(f16, 1.0 / 3.0)});
|
||||
try expectFmt("f32: 0x1.555p-2", "f32: {x:.3}", .{@as(f32, 1.0 / 3.0)});
|
||||
try expectFmt("f64: 0x1.55555p-2", "f64: {x:.5}", .{@as(f64, 1.0 / 3.0)});
|
||||
try expectFmt("f128: 0x1.5555555p-2", "f128: {x:.7}", .{@as(f128, 1.0 / 3.0)});
|
||||
|
||||
try expectFmt("f16: 0x1.00000p0", "f16: {x:.5}", .{@as(f16, 1.0)});
|
||||
try expectFmt("f32: 0x1.00000p0", "f32: {x:.5}", .{@as(f32, 1.0)});
|
||||
try expectFmt("f64: 0x1.00000p0", "f64: {x:.5}", .{@as(f64, 1.0)});
|
||||
try expectFmt("f128: 0x1.00000p0", "f128: {x:.5}", .{@as(f128, 1.0)});
|
||||
}
|
||||
|
||||
test "float.decimal" {
|
||||
try expectFmt("f64: 152314000000000000000000000000", "f64: {d}", .{@as(f64, 1.52314e+29)});
|
||||
try expectFmt("f32: 0", "f32: {d}", .{@as(f32, 0.0)});
|
||||
|
||||
@@ -20,6 +20,7 @@ pub fn copysign(comptime T: type, x: T, y: T) T {
|
||||
f16 => copysign16(x, y),
|
||||
f32 => copysign32(x, y),
|
||||
f64 => copysign64(x, y),
|
||||
f128 => copysign128(x, y),
|
||||
else => @compileError("copysign not implemented for " ++ @typeName(T)),
|
||||
};
|
||||
}
|
||||
@@ -51,10 +52,20 @@ fn copysign64(x: f64, y: f64) f64 {
|
||||
return @bitCast(f64, h1 | h2);
|
||||
}
|
||||
|
||||
fn copysign128(x: f128, y: f128) f128 {
|
||||
const ux = @bitCast(u128, x);
|
||||
const uy = @bitCast(u128, y);
|
||||
|
||||
const h1 = ux & (maxInt(u128) / 2);
|
||||
const h2 = uy & (@as(u128, 1) << 127);
|
||||
return @bitCast(f128, h1 | h2);
|
||||
}
|
||||
|
||||
test "math.copysign" {
|
||||
expect(copysign(f16, 1.0, 1.0) == copysign16(1.0, 1.0));
|
||||
expect(copysign(f32, 1.0, 1.0) == copysign32(1.0, 1.0));
|
||||
expect(copysign(f64, 1.0, 1.0) == copysign64(1.0, 1.0));
|
||||
expect(copysign(f128, 1.0, 1.0) == copysign128(1.0, 1.0));
|
||||
}
|
||||
|
||||
test "math.copysign16" {
|
||||
@@ -77,3 +88,10 @@ test "math.copysign64" {
|
||||
expect(copysign64(-5.0, -1.0) == -5.0);
|
||||
expect(copysign64(-5.0, 1.0) == 5.0);
|
||||
}
|
||||
|
||||
test "math.copysign128" {
|
||||
expect(copysign128(5.0, 1.0) == 5.0);
|
||||
expect(copysign128(5.0, -1.0) == -5.0);
|
||||
expect(copysign128(-5.0, -1.0) == -5.0);
|
||||
expect(copysign128(-5.0, 1.0) == 5.0);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@ pub fn isFinite(x: anytype) bool {
|
||||
const bits = @bitCast(u64, x);
|
||||
return bits & (maxInt(u64) >> 1) < (0x7FF << 52);
|
||||
},
|
||||
f128 => {
|
||||
const bits = @bitCast(u128, x);
|
||||
return bits & (maxInt(u128) >> 1) < (0x7FFF << 112);
|
||||
},
|
||||
else => {
|
||||
@compileError("isFinite not implemented for " ++ @typeName(T));
|
||||
},
|
||||
@@ -37,10 +41,24 @@ test "math.isFinite" {
|
||||
expect(isFinite(@as(f32, -0.0)));
|
||||
expect(isFinite(@as(f64, 0.0)));
|
||||
expect(isFinite(@as(f64, -0.0)));
|
||||
expect(isFinite(@as(f128, 0.0)));
|
||||
expect(isFinite(@as(f128, -0.0)));
|
||||
|
||||
expect(!isFinite(math.inf(f16)));
|
||||
expect(!isFinite(-math.inf(f16)));
|
||||
expect(!isFinite(math.inf(f32)));
|
||||
expect(!isFinite(-math.inf(f32)));
|
||||
expect(!isFinite(math.inf(f64)));
|
||||
expect(!isFinite(-math.inf(f64)));
|
||||
expect(!isFinite(math.inf(f128)));
|
||||
expect(!isFinite(-math.inf(f128)));
|
||||
|
||||
expect(!isFinite(math.nan(f16)));
|
||||
expect(!isFinite(-math.nan(f16)));
|
||||
expect(!isFinite(math.nan(f32)));
|
||||
expect(!isFinite(-math.nan(f32)));
|
||||
expect(!isFinite(math.nan(f64)));
|
||||
expect(!isFinite(-math.nan(f64)));
|
||||
expect(!isFinite(math.nan(f128)));
|
||||
expect(!isFinite(-math.nan(f128)));
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ pub fn signbit(x: anytype) bool {
|
||||
f16 => signbit16(x),
|
||||
f32 => signbit32(x),
|
||||
f64 => signbit64(x),
|
||||
f128 => signbit128(x),
|
||||
else => @compileError("signbit not implemented for " ++ @typeName(T)),
|
||||
};
|
||||
}
|
||||
@@ -33,10 +34,16 @@ fn signbit64(x: f64) bool {
|
||||
return bits >> 63 != 0;
|
||||
}
|
||||
|
||||
fn signbit128(x: f128) bool {
|
||||
const bits = @bitCast(u128, x);
|
||||
return bits >> 127 != 0;
|
||||
}
|
||||
|
||||
test "math.signbit" {
|
||||
expect(signbit(@as(f16, 4.0)) == signbit16(4.0));
|
||||
expect(signbit(@as(f32, 4.0)) == signbit32(4.0));
|
||||
expect(signbit(@as(f64, 4.0)) == signbit64(4.0));
|
||||
expect(signbit(@as(f128, 4.0)) == signbit128(4.0));
|
||||
}
|
||||
|
||||
test "math.signbit16" {
|
||||
@@ -53,3 +60,8 @@ test "math.signbit64" {
|
||||
expect(!signbit64(4.0));
|
||||
expect(signbit64(-3.0));
|
||||
}
|
||||
|
||||
test "math.signbit128" {
|
||||
expect(!signbit128(4.0));
|
||||
expect(signbit128(-3.0));
|
||||
}
|
||||
|
||||
@@ -832,6 +832,13 @@ pub const SO_RCVTIMEO = 0x1006;
|
||||
pub const SO_ERROR = 0x1007;
|
||||
pub const SO_TYPE = 0x1008;
|
||||
|
||||
pub const SO_NREAD = 0x1020;
|
||||
pub const SO_NKE = 0x1021;
|
||||
pub const SO_NOSIGPIPE = 0x1022;
|
||||
pub const SO_NOADDRERR = 0x1023;
|
||||
pub const SO_NWRITE = 0x1024;
|
||||
pub const SO_REUSESHAREUID = 0x1025;
|
||||
|
||||
fn wstatus(x: u32) u32 {
|
||||
return x & 0o177;
|
||||
}
|
||||
|
||||
+109
-39
@@ -5,11 +5,12 @@
|
||||
// and substantial portions of the software.
|
||||
const std = @import("../../std.zig");
|
||||
const maxInt = std.math.maxInt;
|
||||
const arch = std.Target.current.cpu.arch;
|
||||
const arch = @import("builtin").target.cpu.arch;
|
||||
usingnamespace @import("../bits.zig");
|
||||
|
||||
pub usingnamespace switch (arch) {
|
||||
.mips, .mipsel => @import("linux/errno-mips.zig"),
|
||||
.sparc, .sparcel, .sparcv9 => @import("linux/errno-sparc.zig"),
|
||||
else => @import("linux/errno-generic.zig"),
|
||||
};
|
||||
|
||||
@@ -31,6 +32,7 @@ pub usingnamespace @import("linux/prctl.zig");
|
||||
pub usingnamespace @import("linux/securebits.zig");
|
||||
|
||||
const is_mips = arch.isMIPS();
|
||||
const is_ppc = arch.isPPC();
|
||||
const is_ppc64 = arch.isPPC64();
|
||||
const is_sparc = arch.isSPARC();
|
||||
|
||||
@@ -247,40 +249,78 @@ else
|
||||
pub const SIG_SETMASK = 2;
|
||||
};
|
||||
|
||||
pub const SIGHUP = 1;
|
||||
pub const SIGINT = 2;
|
||||
pub const SIGQUIT = 3;
|
||||
pub const SIGILL = 4;
|
||||
pub const SIGTRAP = 5;
|
||||
pub const SIGABRT = 6;
|
||||
pub const SIGIOT = SIGABRT;
|
||||
pub const SIGBUS = 7;
|
||||
pub const SIGFPE = 8;
|
||||
pub const SIGKILL = 9;
|
||||
pub const SIGUSR1 = 10;
|
||||
pub const SIGSEGV = 11;
|
||||
pub const SIGUSR2 = 12;
|
||||
pub const SIGPIPE = 13;
|
||||
pub const SIGALRM = 14;
|
||||
pub const SIGTERM = 15;
|
||||
pub const SIGSTKFLT = 16;
|
||||
pub const SIGCHLD = 17;
|
||||
pub const SIGCONT = 18;
|
||||
pub const SIGSTOP = 19;
|
||||
pub const SIGTSTP = 20;
|
||||
pub const SIGTTIN = 21;
|
||||
pub const SIGTTOU = 22;
|
||||
pub const SIGURG = 23;
|
||||
pub const SIGXCPU = 24;
|
||||
pub const SIGXFSZ = 25;
|
||||
pub const SIGVTALRM = 26;
|
||||
pub const SIGPROF = 27;
|
||||
pub const SIGWINCH = 28;
|
||||
pub const SIGIO = 29;
|
||||
pub const SIGPOLL = 29;
|
||||
pub const SIGPWR = 30;
|
||||
pub const SIGSYS = 31;
|
||||
pub const SIGUNUSED = SIGSYS;
|
||||
pub usingnamespace if (is_sparc) struct {
|
||||
pub const SIGHUP = 1;
|
||||
pub const SIGINT = 2;
|
||||
pub const SIGQUIT = 3;
|
||||
pub const SIGILL = 4;
|
||||
pub const SIGTRAP = 5;
|
||||
pub const SIGABRT = 6;
|
||||
pub const SIGEMT = 7;
|
||||
pub const SIGFPE = 8;
|
||||
pub const SIGKILL = 9;
|
||||
pub const SIGBUS = 10;
|
||||
pub const SIGSEGV = 11;
|
||||
pub const SIGSYS = 12;
|
||||
pub const SIGPIPE = 13;
|
||||
pub const SIGALRM = 14;
|
||||
pub const SIGTERM = 15;
|
||||
pub const SIGURG = 16;
|
||||
pub const SIGSTOP = 17;
|
||||
pub const SIGTSTP = 18;
|
||||
pub const SIGCONT = 19;
|
||||
pub const SIGCHLD = 20;
|
||||
pub const SIGTTIN = 21;
|
||||
pub const SIGTTOU = 22;
|
||||
pub const SIGPOLL = 23;
|
||||
pub const SIGXCPU = 24;
|
||||
pub const SIGXFSZ = 25;
|
||||
pub const SIGVTALRM = 26;
|
||||
pub const SIGPROF = 27;
|
||||
pub const SIGWINCH = 28;
|
||||
pub const SIGLOST = 29;
|
||||
pub const SIGUSR1 = 30;
|
||||
pub const SIGUSR2 = 31;
|
||||
pub const SIGIOT = SIGABRT;
|
||||
pub const SIGCLD = SIGCHLD;
|
||||
pub const SIGPWR = SIGLOST;
|
||||
pub const SIGIO = SIGPOLL;
|
||||
} else struct {
|
||||
pub const SIGHUP = 1;
|
||||
pub const SIGINT = 2;
|
||||
pub const SIGQUIT = 3;
|
||||
pub const SIGILL = 4;
|
||||
pub const SIGTRAP = 5;
|
||||
pub const SIGABRT = 6;
|
||||
pub const SIGIOT = SIGABRT;
|
||||
pub const SIGBUS = 7;
|
||||
pub const SIGFPE = 8;
|
||||
pub const SIGKILL = 9;
|
||||
pub const SIGUSR1 = 10;
|
||||
pub const SIGSEGV = 11;
|
||||
pub const SIGUSR2 = 12;
|
||||
pub const SIGPIPE = 13;
|
||||
pub const SIGALRM = 14;
|
||||
pub const SIGTERM = 15;
|
||||
pub const SIGSTKFLT = 16;
|
||||
pub const SIGCHLD = 17;
|
||||
pub const SIGCONT = 18;
|
||||
pub const SIGSTOP = 19;
|
||||
pub const SIGTSTP = 20;
|
||||
pub const SIGTTIN = 21;
|
||||
pub const SIGTTOU = 22;
|
||||
pub const SIGURG = 23;
|
||||
pub const SIGXCPU = 24;
|
||||
pub const SIGXFSZ = 25;
|
||||
pub const SIGVTALRM = 26;
|
||||
pub const SIGPROF = 27;
|
||||
pub const SIGWINCH = 28;
|
||||
pub const SIGIO = 29;
|
||||
pub const SIGPOLL = 29;
|
||||
pub const SIGPWR = 30;
|
||||
pub const SIGSYS = 31;
|
||||
pub const SIGUNUSED = SIGSYS;
|
||||
};
|
||||
|
||||
pub const O_RDONLY = 0o0;
|
||||
pub const O_WRONLY = 0o1;
|
||||
@@ -419,7 +459,39 @@ pub const AF_QIPCRTR = PF_QIPCRTR;
|
||||
pub const AF_SMC = PF_SMC;
|
||||
pub const AF_MAX = PF_MAX;
|
||||
|
||||
pub usingnamespace if (!is_mips)
|
||||
pub usingnamespace if (is_mips)
|
||||
struct {}
|
||||
else if (is_ppc or is_ppc64)
|
||||
struct {
|
||||
pub const SO_DEBUG = 1;
|
||||
pub const SO_REUSEADDR = 2;
|
||||
pub const SO_TYPE = 3;
|
||||
pub const SO_ERROR = 4;
|
||||
pub const SO_DONTROUTE = 5;
|
||||
pub const SO_BROADCAST = 6;
|
||||
pub const SO_SNDBUF = 7;
|
||||
pub const SO_RCVBUF = 8;
|
||||
pub const SO_KEEPALIVE = 9;
|
||||
pub const SO_OOBINLINE = 10;
|
||||
pub const SO_NO_CHECK = 11;
|
||||
pub const SO_PRIORITY = 12;
|
||||
pub const SO_LINGER = 13;
|
||||
pub const SO_BSDCOMPAT = 14;
|
||||
pub const SO_REUSEPORT = 15;
|
||||
pub const SO_RCVLOWAT = 16;
|
||||
pub const SO_SNDLOWAT = 17;
|
||||
pub const SO_RCVTIMEO = 18;
|
||||
pub const SO_SNDTIMEO = 19;
|
||||
pub const SO_PASSCRED = 20;
|
||||
pub const SO_PEERCRED = 21;
|
||||
pub const SO_ACCEPTCONN = 30;
|
||||
pub const SO_PEERSEC = 31;
|
||||
pub const SO_SNDBUFFORCE = 32;
|
||||
pub const SO_RCVBUFFORCE = 33;
|
||||
pub const SO_PROTOCOL = 38;
|
||||
pub const SO_DOMAIN = 39;
|
||||
}
|
||||
else
|
||||
struct {
|
||||
pub const SO_DEBUG = 1;
|
||||
pub const SO_REUSEADDR = 2;
|
||||
@@ -448,9 +520,7 @@ pub usingnamespace if (!is_mips)
|
||||
pub const SO_RCVBUFFORCE = 33;
|
||||
pub const SO_PROTOCOL = 38;
|
||||
pub const SO_DOMAIN = 39;
|
||||
}
|
||||
else
|
||||
struct {};
|
||||
};
|
||||
|
||||
pub const SO_SECURITY_AUTHENTICATION = 22;
|
||||
pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
const std = @import("../../../std.zig");
|
||||
const linux = std.os.linux;
|
||||
const socklen_t = linux.socklen_t;
|
||||
const sockaddr = linux.sockaddr;
|
||||
const iovec = linux.iovec;
|
||||
const iovec_const = linux.iovec_const;
|
||||
const uid_t = linux.uid_t;
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
||||
// The MIT license requires this copyright notice to be included in all copies
|
||||
// and substantial portions of the software.
|
||||
|
||||
// These are MIPS ABI compatible.
|
||||
|
||||
pub const EPERM = 1;
|
||||
pub const ENOENT = 2;
|
||||
pub const ESRCH = 3;
|
||||
@@ -37,6 +40,7 @@ pub const EMLINK = 31;
|
||||
pub const EPIPE = 32;
|
||||
pub const EDOM = 33;
|
||||
pub const ERANGE = 34;
|
||||
|
||||
pub const ENOMSG = 35;
|
||||
pub const EIDRM = 36;
|
||||
pub const ECHRNG = 37;
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2015-2021 Zig Contributors
|
||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
||||
// The MIT license requires this copyright notice to be included in all copies
|
||||
// and substantial portions of the software.
|
||||
|
||||
// These match the SunOS error numbering scheme.
|
||||
|
||||
pub const EPERM = 1;
|
||||
pub const ENOENT = 2;
|
||||
pub const ESRCH = 3;
|
||||
pub const EINTR = 4;
|
||||
pub const EIO = 5;
|
||||
pub const ENXIO = 6;
|
||||
pub const E2BIG = 7;
|
||||
pub const ENOEXEC = 8;
|
||||
pub const EBADF = 9;
|
||||
pub const ECHILD = 10;
|
||||
pub const EAGAIN = 11;
|
||||
pub const ENOMEM = 12;
|
||||
pub const EACCES = 13;
|
||||
pub const EFAULT = 14;
|
||||
pub const ENOTBLK = 15;
|
||||
pub const EBUSY = 16;
|
||||
pub const EEXIST = 17;
|
||||
pub const EXDEV = 18;
|
||||
pub const ENODEV = 19;
|
||||
pub const ENOTDIR = 20;
|
||||
pub const EISDIR = 21;
|
||||
pub const EINVAL = 22;
|
||||
pub const ENFILE = 23;
|
||||
pub const EMFILE = 24;
|
||||
pub const ENOTTY = 25;
|
||||
pub const ETXTBSY = 26;
|
||||
pub const EFBIG = 27;
|
||||
pub const ENOSPC = 28;
|
||||
pub const ESPIPE = 29;
|
||||
pub const EROFS = 30;
|
||||
pub const EMLINK = 31;
|
||||
pub const EPIPE = 32;
|
||||
pub const EDOM = 33;
|
||||
pub const ERANGE = 34;
|
||||
|
||||
pub const EWOULDBLOCK = EAGAIN;
|
||||
pub const EINPROGRESS = 36;
|
||||
pub const EALREADY = 37;
|
||||
pub const ENOTSOCK = 38;
|
||||
pub const EDESTADDRREQ = 39;
|
||||
pub const EMSGSIZE = 40;
|
||||
pub const EPROTOTYPE = 41;
|
||||
pub const ENOPROTOOPT = 42;
|
||||
pub const EPROTONOSUPPORT = 43;
|
||||
pub const ESOCKTNOSUPPORT = 44;
|
||||
pub const EOPNOTSUPP = 45;
|
||||
pub const EPFNOSUPPORT = 46;
|
||||
pub const EAFNOSUPPORT = 47;
|
||||
pub const EADDRINUSE = 48;
|
||||
pub const EADDRNOTAVAIL = 49;
|
||||
pub const ENETDOWN = 50;
|
||||
pub const ENETUNREACH = 51;
|
||||
pub const ENETRESET = 52;
|
||||
pub const ECONNABORTED = 53;
|
||||
pub const ECONNRESET = 54;
|
||||
pub const ENOBUFS = 55;
|
||||
pub const EISCONN = 56;
|
||||
pub const ENOTCONN = 57;
|
||||
pub const ESHUTDOWN = 58;
|
||||
pub const ETOOMANYREFS = 59;
|
||||
pub const ETIMEDOUT = 60;
|
||||
pub const ECONNREFUSED = 61;
|
||||
pub const ELOOP = 62;
|
||||
pub const ENAMETOOLONG = 63;
|
||||
pub const EHOSTDOWN = 64;
|
||||
pub const EHOSTUNREACH = 65;
|
||||
pub const ENOTEMPTY = 66;
|
||||
pub const EPROCLIM = 67;
|
||||
pub const EUSERS = 68;
|
||||
pub const EDQUOT = 69;
|
||||
pub const ESTALE = 70;
|
||||
pub const EREMOTE = 71;
|
||||
pub const ENOSTR = 72;
|
||||
pub const ETIME = 73;
|
||||
pub const ENOSR = 74;
|
||||
pub const ENOMSG = 75;
|
||||
pub const EBADMSG = 76;
|
||||
pub const EIDRM = 77;
|
||||
pub const EDEADLK = 78;
|
||||
pub const ENOLCK = 79;
|
||||
pub const ENONET = 80;
|
||||
pub const ERREMOTE = 81;
|
||||
pub const ENOLINK = 82;
|
||||
pub const EADV = 83;
|
||||
pub const ESRMNT = 84;
|
||||
pub const ECOMM = 85;
|
||||
pub const EPROTO = 86;
|
||||
pub const EMULTIHOP = 87;
|
||||
pub const EDOTDOT = 88;
|
||||
pub const EREMCHG = 89;
|
||||
pub const ENOSYS = 90;
|
||||
pub const ESTRPIPE = 91;
|
||||
pub const EOVERFLOW = 92;
|
||||
pub const EBADFD = 93;
|
||||
pub const ECHRNG = 94;
|
||||
pub const EL2NSYNC = 95;
|
||||
pub const EL3HLT = 96;
|
||||
pub const EL3RST = 97;
|
||||
pub const ELNRNG = 98;
|
||||
pub const EUNATCH = 99;
|
||||
pub const ENOCSI = 100;
|
||||
pub const EL2HLT = 101;
|
||||
pub const EBADE = 102;
|
||||
pub const EBADR = 103;
|
||||
pub const EXFULL = 104;
|
||||
pub const ENOANO = 105;
|
||||
pub const EBADRQC = 106;
|
||||
pub const EBADSLT = 107;
|
||||
pub const EDEADLOCK = 108;
|
||||
pub const EBFONT = 109;
|
||||
pub const ELIBEXEC = 110;
|
||||
pub const ENODATA = 111;
|
||||
pub const ELIBBAD = 112;
|
||||
pub const ENOPKG = 113;
|
||||
pub const ELIBACC = 114;
|
||||
pub const ENOTUNIQ = 115;
|
||||
pub const ERESTART = 116;
|
||||
pub const EUCLEAN = 117;
|
||||
pub const ENOTNAM = 118;
|
||||
pub const ENAVAIL = 119;
|
||||
pub const EISNAM = 120;
|
||||
pub const EREMOTEIO = 121;
|
||||
pub const EILSEQ = 122;
|
||||
pub const ELIBMAX = 123;
|
||||
pub const ELIBSCN = 124;
|
||||
pub const ENOMEDIUM = 125;
|
||||
pub const EMEDIUMTYPE = 126;
|
||||
pub const ECANCELED = 127;
|
||||
pub const ENOKEY = 128;
|
||||
pub const EKEYEXPIRED = 129;
|
||||
pub const EKEYREVOKED = 130;
|
||||
pub const EKEYREJECTED = 131;
|
||||
pub const EOWNERDEAD = 132;
|
||||
pub const ENOTRECOVERABLE = 133;
|
||||
pub const ERFKILL = 134;
|
||||
pub const EHWPOISON = 135;
|
||||
@@ -376,6 +376,11 @@ pub const timespec = extern struct {
|
||||
tv_nsec: isize,
|
||||
};
|
||||
|
||||
pub const timeval = extern struct {
|
||||
tv_sec: time_t,
|
||||
tv_usec: i64,
|
||||
};
|
||||
|
||||
pub const Flock = extern struct {
|
||||
l_type: i16,
|
||||
l_whence: i16,
|
||||
|
||||
@@ -22,6 +22,11 @@ pub const timespec = extern struct {
|
||||
tv_nsec: c_long,
|
||||
};
|
||||
|
||||
pub const timeval = extern struct {
|
||||
tv_sec: c_long,
|
||||
tv_usec: c_long,
|
||||
};
|
||||
|
||||
pub const sig_atomic_t = c_int;
|
||||
|
||||
/// maximum signal number + 1
|
||||
|
||||
@@ -387,7 +387,7 @@ pub fn symlinkat(existing: [*:0]const u8, newfd: i32, newpath: [*:0]const u8) us
|
||||
}
|
||||
|
||||
pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: u64) usize {
|
||||
if (@hasField(SYS, "pread64")) {
|
||||
if (@hasField(SYS, "pread64") and usize_bits < 64) {
|
||||
const offset_halves = splitValue64(offset);
|
||||
if (require_aligned_register_pair) {
|
||||
return syscall6(
|
||||
@@ -410,8 +410,10 @@ pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: u64) usize {
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Some architectures (eg. 64bit SPARC) pread is called pread64.
|
||||
const S = if (!@hasField(SYS, "pread") and @hasField(SYS, "pread64")) .pread64 else .pread;
|
||||
return syscall4(
|
||||
.pread,
|
||||
S,
|
||||
@bitCast(usize, @as(isize, fd)),
|
||||
@ptrToInt(buf),
|
||||
count,
|
||||
@@ -451,7 +453,7 @@ pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
|
||||
}
|
||||
|
||||
pub fn ftruncate(fd: i32, length: u64) usize {
|
||||
if (@hasField(SYS, "ftruncate64")) {
|
||||
if (@hasField(SYS, "ftruncate64") and usize_bits < 64) {
|
||||
const length_halves = splitValue64(length);
|
||||
if (require_aligned_register_pair) {
|
||||
return syscall4(
|
||||
@@ -479,7 +481,7 @@ pub fn ftruncate(fd: i32, length: u64) usize {
|
||||
}
|
||||
|
||||
pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: u64) usize {
|
||||
if (@hasField(SYS, "pwrite64")) {
|
||||
if (@hasField(SYS, "pwrite64") and usize_bits < 64) {
|
||||
const offset_halves = splitValue64(offset);
|
||||
|
||||
if (require_aligned_register_pair) {
|
||||
@@ -503,8 +505,10 @@ pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: u64) usize {
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Some architectures (eg. 64bit SPARC) pwrite is called pwrite64.
|
||||
const S = if (!@hasField(SYS, "pwrite") and @hasField(SYS, "pwrite64")) .pwrite64 else .pwrite;
|
||||
return syscall4(
|
||||
.pwrite,
|
||||
S,
|
||||
@bitCast(usize, @as(isize, fd)),
|
||||
@ptrToInt(buf),
|
||||
count,
|
||||
|
||||
@@ -617,23 +617,24 @@ fn clone() callconv(.Naked) void {
|
||||
\\ # Shuffle the arguments
|
||||
\\ mov 217, %%g1
|
||||
\\ mov %%i2, %%o0
|
||||
\\ sub %%i1, 2047, %%o1
|
||||
\\ # Add some extra space for the initial frame
|
||||
\\ sub %%i1, 176 + 2047, %%o1
|
||||
\\ mov %%i4, %%o2
|
||||
\\ mov %%i5, %%o3
|
||||
\\ ldx [%%fp + 192 - 2*8 + 2047], %%o4
|
||||
\\ ldx [%%fp + 0x8af], %%o4
|
||||
\\ t 0x6d
|
||||
\\ bcs,pn %%xcc, 2f
|
||||
\\ nop
|
||||
\\ # sparc64 returns the child pid in o0 and a flag telling
|
||||
\\ # whether the process is the child in o1
|
||||
\\ # The child pid is returned in o0 while o1 tells if this
|
||||
\\ # process is # the child (=1) or the parent (=0).
|
||||
\\ brnz %%o1, 1f
|
||||
\\ nop
|
||||
\\ # This is the parent process, return the child pid
|
||||
\\ # Parent process, return the child pid
|
||||
\\ mov %%o0, %%i0
|
||||
\\ ret
|
||||
\\ restore
|
||||
\\1:
|
||||
\\ # This is the child process
|
||||
\\ # Child process, call func(arg)
|
||||
\\ mov %%g0, %%fp
|
||||
\\ call %%g2
|
||||
\\ mov %%g3, %%o0
|
||||
|
||||
@@ -1621,6 +1621,16 @@ pub const cpu = struct {
|
||||
.apple_a7,
|
||||
}),
|
||||
};
|
||||
pub const emag = CpuModel{
|
||||
.name = "emag",
|
||||
.llvm_name = null,
|
||||
.features = featureSet(&[_]Feature{
|
||||
.crc,
|
||||
.crypto,
|
||||
.perfmon,
|
||||
.v8a,
|
||||
}),
|
||||
};
|
||||
pub const exynos_m1 = CpuModel{
|
||||
.name = "exynos_m1",
|
||||
.llvm_name = null,
|
||||
@@ -1867,4 +1877,12 @@ pub const cpu = struct {
|
||||
.v8_2a,
|
||||
}),
|
||||
};
|
||||
pub const xgene1 = CpuModel{
|
||||
.name = "xgene1",
|
||||
.llvm_name = null,
|
||||
.features = featureSet(&[_]Feature{
|
||||
.perfmon,
|
||||
.v8a,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
+23
-1
@@ -1 +1,23 @@
|
||||
pub const os = @import("x/os/os.zig");
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2015-2021 Zig Contributors
|
||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
||||
// The MIT license requires this copyright notice to be included in all copies
|
||||
// and substantial portions of the software.
|
||||
|
||||
const std = @import("std.zig");
|
||||
|
||||
pub const os = struct {
|
||||
pub const Socket = @import("x/os/Socket.zig");
|
||||
pub usingnamespace @import("x/os/net.zig");
|
||||
};
|
||||
|
||||
pub const net = struct {
|
||||
pub const ip = @import("x/net/ip.zig");
|
||||
pub const tcp = @import("x/net/tcp.zig");
|
||||
};
|
||||
|
||||
test {
|
||||
inline for (.{ os, net }) |module| {
|
||||
std.testing.refAllDecls(module);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2015-2021 Zig Contributors
|
||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
||||
// The MIT license requires this copyright notice to be included in all copies
|
||||
// and substantial portions of the software.
|
||||
|
||||
const std = @import("../../std.zig");
|
||||
|
||||
const fmt = std.fmt;
|
||||
|
||||
const IPv4 = std.x.os.IPv4;
|
||||
const IPv6 = std.x.os.IPv6;
|
||||
const Socket = std.x.os.Socket;
|
||||
|
||||
/// A generic IP abstraction.
|
||||
const ip = @This();
|
||||
|
||||
/// A union of all eligible types of IP addresses.
|
||||
pub const Address = union(enum) {
|
||||
ipv4: IPv4.Address,
|
||||
ipv6: IPv6.Address,
|
||||
|
||||
/// Instantiate a new address with a IPv4 host and port.
|
||||
pub fn initIPv4(host: IPv4, port: u16) Address {
|
||||
return .{ .ipv4 = .{ .host = host, .port = port } };
|
||||
}
|
||||
|
||||
/// Instantiate a new address with a IPv6 host and port.
|
||||
pub fn initIPv6(host: IPv6, port: u16) Address {
|
||||
return .{ .ipv6 = .{ .host = host, .port = port } };
|
||||
}
|
||||
|
||||
/// Re-interpret a generic socket address into an IP address.
|
||||
pub fn from(address: Socket.Address) ip.Address {
|
||||
return switch (address) {
|
||||
.ipv4 => |ipv4_address| .{ .ipv4 = ipv4_address },
|
||||
.ipv6 => |ipv6_address| .{ .ipv6 = ipv6_address },
|
||||
};
|
||||
}
|
||||
|
||||
/// Re-interpret an IP address into a generic socket address.
|
||||
pub fn into(self: ip.Address) Socket.Address {
|
||||
return switch (self) {
|
||||
.ipv4 => |ipv4_address| .{ .ipv4 = ipv4_address },
|
||||
.ipv6 => |ipv6_address| .{ .ipv6 = ipv6_address },
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements the `std.fmt.format` API.
|
||||
pub fn format(
|
||||
self: ip.Address,
|
||||
comptime layout: []const u8,
|
||||
opts: fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
switch (self) {
|
||||
.ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
|
||||
.ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,352 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2015-2021 Zig Contributors
|
||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
||||
// The MIT license requires this copyright notice to be included in all copies
|
||||
// and substantial portions of the software.
|
||||
|
||||
const std = @import("../../std.zig");
|
||||
|
||||
const os = std.os;
|
||||
const ip = std.x.net.ip;
|
||||
|
||||
const fmt = std.fmt;
|
||||
const mem = std.mem;
|
||||
const builtin = std.builtin;
|
||||
const testing = std.testing;
|
||||
|
||||
const IPv4 = std.x.os.IPv4;
|
||||
const IPv6 = std.x.os.IPv6;
|
||||
const Socket = std.x.os.Socket;
|
||||
|
||||
/// A generic TCP socket abstraction.
|
||||
const tcp = @This();
|
||||
|
||||
/// A TCP client-address pair.
|
||||
pub const Connection = struct {
|
||||
client: tcp.Client,
|
||||
address: ip.Address,
|
||||
|
||||
/// Enclose a TCP client and address into a client-address pair.
|
||||
pub fn from(conn: Socket.Connection) tcp.Connection {
|
||||
return .{
|
||||
.client = tcp.Client.from(conn.socket),
|
||||
.address = ip.Address.from(conn.address),
|
||||
};
|
||||
}
|
||||
|
||||
/// Unravel a TCP client-address pair into a socket-address pair.
|
||||
pub fn into(self: tcp.Connection) Socket.Connection {
|
||||
return .{
|
||||
.socket = self.client.socket,
|
||||
.address = self.address.into(),
|
||||
};
|
||||
}
|
||||
|
||||
/// Closes the underlying client of the connection.
|
||||
pub fn deinit(self: tcp.Connection) void {
|
||||
self.client.deinit();
|
||||
}
|
||||
};
|
||||
|
||||
/// Possible domains that a TCP client/listener may operate over.
|
||||
pub const Domain = extern enum(u16) {
|
||||
ip = os.AF_INET,
|
||||
ipv6 = os.AF_INET6,
|
||||
};
|
||||
|
||||
/// A TCP client.
|
||||
pub const Client = struct {
|
||||
socket: Socket,
|
||||
|
||||
/// Opens a new client.
|
||||
pub fn init(domain: tcp.Domain, flags: u32) !Client {
|
||||
return Client{
|
||||
.socket = try Socket.init(
|
||||
@enumToInt(domain),
|
||||
os.SOCK_STREAM | flags,
|
||||
os.IPPROTO_TCP,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/// Enclose a TCP client over an existing socket.
|
||||
pub fn from(socket: Socket) Client {
|
||||
return Client{ .socket = socket };
|
||||
}
|
||||
|
||||
/// Closes the client.
|
||||
pub fn deinit(self: Client) void {
|
||||
self.socket.deinit();
|
||||
}
|
||||
|
||||
/// Shutdown either the read side, write side, or all sides of the client's underlying socket.
|
||||
pub fn shutdown(self: Client, how: os.ShutdownHow) !void {
|
||||
return self.socket.shutdown(how);
|
||||
}
|
||||
|
||||
/// Have the client attempt to the connect to an address.
|
||||
pub fn connect(self: Client, address: ip.Address) !void {
|
||||
return self.socket.connect(address.into());
|
||||
}
|
||||
|
||||
/// Read data from the socket into the buffer provided. It returns the
|
||||
/// number of bytes read into the buffer provided.
|
||||
pub fn read(self: Client, buf: []u8) !usize {
|
||||
return self.socket.read(buf);
|
||||
}
|
||||
|
||||
/// Read data from the socket into the buffer provided with a set of flags
|
||||
/// specified. It returns the number of bytes read into the buffer provided.
|
||||
pub fn recv(self: Client, buf: []u8, flags: u32) !usize {
|
||||
return self.socket.recv(buf, flags);
|
||||
}
|
||||
|
||||
/// Write a buffer of data provided to the socket. It returns the number
|
||||
/// of bytes that are written to the socket.
|
||||
pub fn write(self: Client, buf: []const u8) !usize {
|
||||
return self.socket.write(buf);
|
||||
}
|
||||
|
||||
/// Writes multiple I/O vectors to the socket. It returns the number
|
||||
/// of bytes that are written to the socket.
|
||||
pub fn writev(self: Client, buffers: []const os.iovec_const) !usize {
|
||||
return self.socket.writev(buffers);
|
||||
}
|
||||
|
||||
/// Write a buffer of data provided to the socket with a set of flags specified.
|
||||
/// It returns the number of bytes that are written to the socket.
|
||||
pub fn send(self: Client, buf: []const u8, flags: u32) !usize {
|
||||
return self.socket.send(buf, flags);
|
||||
}
|
||||
|
||||
/// Writes multiple I/O vectors with a prepended message header to the socket
|
||||
/// with a set of flags specified. It returns the number of bytes that are
|
||||
/// written to the socket.
|
||||
pub fn sendmsg(self: Client, msg: os.msghdr_const, flags: u32) !usize {
|
||||
return self.socket.sendmsg(msg, flags);
|
||||
}
|
||||
|
||||
/// Query and return the latest cached error on the client's underlying socket.
|
||||
pub fn getError(self: Client) !void {
|
||||
return self.socket.getError();
|
||||
}
|
||||
|
||||
/// Query the read buffer size of the client's underlying socket.
|
||||
pub fn getReadBufferSize(self: Client) !u32 {
|
||||
return self.socket.getReadBufferSize();
|
||||
}
|
||||
|
||||
/// Query the write buffer size of the client's underlying socket.
|
||||
pub fn getWriteBufferSize(self: Client) !u32 {
|
||||
return self.socket.getWriteBufferSize();
|
||||
}
|
||||
|
||||
/// Query the address that the client's socket is locally bounded to.
|
||||
pub fn getLocalAddress(self: Client) !ip.Address {
|
||||
return ip.Address.from(try self.socket.getLocalAddress());
|
||||
}
|
||||
|
||||
/// Disable Nagle's algorithm on a TCP socket. It returns `error.UnsupportedSocketOption` if
|
||||
/// the host does not support sockets disabling Nagle's algorithm.
|
||||
pub fn setNoDelay(self: Client, enabled: bool) !void {
|
||||
if (comptime @hasDecl(os, "TCP_NODELAY")) {
|
||||
const bytes = mem.asBytes(&@as(usize, @boolToInt(enabled)));
|
||||
return os.setsockopt(self.socket.fd, os.IPPROTO_TCP, os.TCP_NODELAY, bytes);
|
||||
}
|
||||
return error.UnsupportedSocketOption;
|
||||
}
|
||||
|
||||
/// Set the write buffer size of the socket.
|
||||
pub fn setWriteBufferSize(self: Client, size: u32) !void {
|
||||
return self.socket.setWriteBufferSize(size);
|
||||
}
|
||||
|
||||
/// Set the read buffer size of the socket.
|
||||
pub fn setReadBufferSize(self: Client, size: u32) !void {
|
||||
return self.socket.setReadBufferSize(size);
|
||||
}
|
||||
|
||||
/// Set a timeout on the socket that is to occur if no messages are successfully written
|
||||
/// to its bound destination after a specified number of milliseconds. A subsequent write
|
||||
/// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
|
||||
pub fn setWriteTimeout(self: Client, milliseconds: usize) !void {
|
||||
return self.socket.setWriteTimeout(milliseconds);
|
||||
}
|
||||
|
||||
/// Set a timeout on the socket that is to occur if no messages are successfully read
|
||||
/// from its bound destination after a specified number of milliseconds. A subsequent
|
||||
/// read from the socket will thereafter return `error.WouldBlock` should the timeout be
|
||||
/// exceeded.
|
||||
pub fn setReadTimeout(self: Client, milliseconds: usize) !void {
|
||||
return self.socket.setReadTimeout(milliseconds);
|
||||
}
|
||||
};
|
||||
|
||||
/// A TCP listener.
|
||||
pub const Listener = struct {
|
||||
socket: Socket,
|
||||
|
||||
/// Opens a new listener.
|
||||
pub fn init(domain: tcp.Domain, flags: u32) !Listener {
|
||||
return Listener{
|
||||
.socket = try Socket.init(
|
||||
@enumToInt(domain),
|
||||
os.SOCK_STREAM | flags,
|
||||
os.IPPROTO_TCP,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/// Closes the listener.
|
||||
pub fn deinit(self: Listener) void {
|
||||
self.socket.deinit();
|
||||
}
|
||||
|
||||
/// Shuts down the underlying listener's socket. The next subsequent call, or
|
||||
/// a current pending call to accept() after shutdown is called will return
|
||||
/// an error.
|
||||
pub fn shutdown(self: Listener) !void {
|
||||
return self.socket.shutdown(.recv);
|
||||
}
|
||||
|
||||
/// Binds the listener's socket to an address.
|
||||
pub fn bind(self: Listener, address: ip.Address) !void {
|
||||
return self.socket.bind(address.into());
|
||||
}
|
||||
|
||||
/// Start listening for incoming connections.
|
||||
pub fn listen(self: Listener, max_backlog_size: u31) !void {
|
||||
return self.socket.listen(max_backlog_size);
|
||||
}
|
||||
|
||||
/// Accept a pending incoming connection queued to the kernel backlog
|
||||
/// of the listener's socket.
|
||||
pub fn accept(self: Listener, flags: u32) !tcp.Connection {
|
||||
return tcp.Connection.from(try self.socket.accept(flags));
|
||||
}
|
||||
|
||||
/// Query and return the latest cached error on the listener's underlying socket.
|
||||
pub fn getError(self: Client) !void {
|
||||
return self.socket.getError();
|
||||
}
|
||||
|
||||
/// Query the address that the listener's socket is locally bounded to.
|
||||
pub fn getLocalAddress(self: Listener) !ip.Address {
|
||||
return ip.Address.from(try self.socket.getLocalAddress());
|
||||
}
|
||||
|
||||
/// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if
|
||||
/// the host does not support sockets listening the same address.
|
||||
pub fn setReuseAddress(self: Listener, enabled: bool) !void {
|
||||
return self.socket.setReuseAddress(enabled);
|
||||
}
|
||||
|
||||
/// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if
|
||||
/// the host does not supports sockets listening on the same port.
|
||||
pub fn setReusePort(self: Listener, enabled: bool) !void {
|
||||
return self.socket.setReusePort(enabled);
|
||||
}
|
||||
|
||||
/// Enables TCP Fast Open (RFC 7413) on a TCP socket. It returns `error.UnsupportedSocketOption` if the host does not
|
||||
/// support TCP Fast Open.
|
||||
pub fn setFastOpen(self: Listener, enabled: bool) !void {
|
||||
if (comptime @hasDecl(os, "TCP_FASTOPEN")) {
|
||||
return os.setsockopt(self.socket.fd, os.IPPROTO_TCP, os.TCP_FASTOPEN, mem.asBytes(&@as(usize, @boolToInt(enabled))));
|
||||
}
|
||||
return error.UnsupportedSocketOption;
|
||||
}
|
||||
|
||||
/// Enables TCP Quick ACK on a TCP socket to immediately send rather than delay ACKs when necessary. It returns
|
||||
/// `error.UnsupportedSocketOption` if the host does not support TCP Quick ACK.
|
||||
pub fn setQuickACK(self: Listener, enabled: bool) !void {
|
||||
if (comptime @hasDecl(os, "TCP_QUICKACK")) {
|
||||
return os.setsockopt(self.socket.fd, os.IPPROTO_TCP, os.TCP_QUICKACK, mem.asBytes(&@as(usize, @boolToInt(enabled))));
|
||||
}
|
||||
return error.UnsupportedSocketOption;
|
||||
}
|
||||
|
||||
/// Set a timeout on the listener that is to occur if no new incoming connections come in
|
||||
/// after a specified number of milliseconds. A subsequent accept call to the listener
|
||||
/// will thereafter return `error.WouldBlock` should the timeout be exceeded.
|
||||
pub fn setAcceptTimeout(self: Listener, milliseconds: usize) !void {
|
||||
return self.socket.setReadTimeout(milliseconds);
|
||||
}
|
||||
};
|
||||
|
||||
test "tcp: create client/listener pair" {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
|
||||
defer listener.deinit();
|
||||
|
||||
try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
|
||||
try listener.listen(128);
|
||||
|
||||
var binded_address = try listener.getLocalAddress();
|
||||
switch (binded_address) {
|
||||
.ipv4 => |*ipv4| ipv4.host = IPv4.localhost,
|
||||
.ipv6 => |*ipv6| ipv6.host = IPv6.localhost,
|
||||
}
|
||||
|
||||
const client = try tcp.Client.init(.ip, os.SOCK_CLOEXEC);
|
||||
defer client.deinit();
|
||||
|
||||
try client.connect(binded_address);
|
||||
|
||||
const conn = try listener.accept(os.SOCK_CLOEXEC);
|
||||
defer conn.deinit();
|
||||
}
|
||||
|
||||
test "tcp/client: set read timeout of 1 millisecond on blocking client" {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
|
||||
defer listener.deinit();
|
||||
|
||||
try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
|
||||
try listener.listen(128);
|
||||
|
||||
var binded_address = try listener.getLocalAddress();
|
||||
switch (binded_address) {
|
||||
.ipv4 => |*ipv4| ipv4.host = IPv4.localhost,
|
||||
.ipv6 => |*ipv6| ipv6.host = IPv6.localhost,
|
||||
}
|
||||
|
||||
const client = try tcp.Client.init(.ip, os.SOCK_CLOEXEC);
|
||||
defer client.deinit();
|
||||
|
||||
try client.connect(binded_address);
|
||||
try client.setReadTimeout(1);
|
||||
|
||||
const conn = try listener.accept(os.SOCK_CLOEXEC);
|
||||
defer conn.deinit();
|
||||
|
||||
var buf: [1]u8 = undefined;
|
||||
testing.expectError(error.WouldBlock, client.read(&buf));
|
||||
}
|
||||
|
||||
test "tcp/listener: bind to unspecified ipv4 address" {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
|
||||
defer listener.deinit();
|
||||
|
||||
try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
|
||||
try listener.listen(128);
|
||||
|
||||
const address = try listener.getLocalAddress();
|
||||
testing.expect(address == .ipv4);
|
||||
}
|
||||
|
||||
test "tcp/listener: bind to unspecified ipv6 address" {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
const listener = try tcp.Listener.init(.ipv6, os.SOCK_CLOEXEC);
|
||||
defer listener.deinit();
|
||||
|
||||
try listener.bind(ip.Address.initIPv6(IPv6.unspecified, 0));
|
||||
try listener.listen(128);
|
||||
|
||||
const address = try listener.getLocalAddress();
|
||||
testing.expect(address == .ipv6);
|
||||
}
|
||||
+115
-96
@@ -1,18 +1,110 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2015-2021 Zig Contributors
|
||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
||||
// The MIT license requires this copyright notice to be included in all copies
|
||||
// and substantial portions of the software.
|
||||
|
||||
const std = @import("../../std.zig");
|
||||
const net = @import("net.zig");
|
||||
|
||||
const os = std.os;
|
||||
const fmt = std.fmt;
|
||||
const mem = std.mem;
|
||||
const net = std.net;
|
||||
const time = std.time;
|
||||
const builtin = std.builtin;
|
||||
const testing = std.testing;
|
||||
|
||||
/// A generic socket abstraction.
|
||||
const Socket = @This();
|
||||
|
||||
/// A socket-address pair.
|
||||
pub const Connection = struct {
|
||||
socket: Socket,
|
||||
address: net.Address,
|
||||
address: Socket.Address,
|
||||
|
||||
/// Enclose a socket and address into a socket-address pair.
|
||||
pub fn from(socket: Socket, address: Socket.Address) Socket.Connection {
|
||||
return .{ .socket = socket, .address = address };
|
||||
}
|
||||
};
|
||||
|
||||
/// A generic socket address abstraction. It is safe to directly access and modify
|
||||
/// the fields of a `Socket.Address`.
|
||||
pub const Address = union(enum) {
|
||||
ipv4: net.IPv4.Address,
|
||||
ipv6: net.IPv6.Address,
|
||||
|
||||
/// Instantiate a new address with a IPv4 host and port.
|
||||
pub fn initIPv4(host: net.IPv4, port: u16) Socket.Address {
|
||||
return .{ .ipv4 = .{ .host = host, .port = port } };
|
||||
}
|
||||
|
||||
/// Instantiate a new address with a IPv6 host and port.
|
||||
pub fn initIPv6(host: net.IPv6, port: u16) Socket.Address {
|
||||
return .{ .ipv6 = .{ .host = host, .port = port } };
|
||||
}
|
||||
|
||||
/// Parses a `sockaddr` into a generic socket address.
|
||||
pub fn fromNative(address: *align(4) const os.sockaddr) Socket.Address {
|
||||
switch (address.family) {
|
||||
os.AF_INET => {
|
||||
const info = @ptrCast(*const os.sockaddr_in, address);
|
||||
const host = net.IPv4{ .octets = @bitCast([4]u8, info.addr) };
|
||||
const port = mem.bigToNative(u16, info.port);
|
||||
return Socket.Address.initIPv4(host, port);
|
||||
},
|
||||
os.AF_INET6 => {
|
||||
const info = @ptrCast(*const os.sockaddr_in6, address);
|
||||
const host = net.IPv6{ .octets = info.addr, .scope_id = info.scope_id };
|
||||
const port = mem.bigToNative(u16, info.port);
|
||||
return Socket.Address.initIPv6(host, port);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
/// Encodes a generic socket address into an extern union that may be reliably
|
||||
/// casted into a `sockaddr` which may be passed into socket syscalls.
|
||||
pub fn toNative(self: Socket.Address) extern union {
|
||||
ipv4: os.sockaddr_in,
|
||||
ipv6: os.sockaddr_in6,
|
||||
} {
|
||||
return switch (self) {
|
||||
.ipv4 => |address| .{
|
||||
.ipv4 = .{
|
||||
.addr = @bitCast(u32, address.host.octets),
|
||||
.port = mem.nativeToBig(u16, address.port),
|
||||
},
|
||||
},
|
||||
.ipv6 => |address| .{
|
||||
.ipv6 = .{
|
||||
.addr = address.host.octets,
|
||||
.port = mem.nativeToBig(u16, address.port),
|
||||
.scope_id = address.host.scope_id,
|
||||
.flowinfo = 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the number of bytes that make up the `sockaddr` equivalent to the address.
|
||||
pub fn getNativeSize(self: Socket.Address) u32 {
|
||||
return switch (self) {
|
||||
.ipv4 => @sizeOf(os.sockaddr_in),
|
||||
.ipv6 => @sizeOf(os.sockaddr_in6),
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements the `std.fmt.format` API.
|
||||
pub fn format(
|
||||
self: Socket.Address,
|
||||
comptime layout: []const u8,
|
||||
opts: fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
switch (self) {
|
||||
.ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
|
||||
.ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// The underlying handle of a socket.
|
||||
@@ -23,19 +115,24 @@ pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {
|
||||
return Socket{ .fd = try os.socket(domain, socket_type, protocol) };
|
||||
}
|
||||
|
||||
/// Enclose a socket abstraction over an existing socket file descriptor.
|
||||
pub fn from(fd: os.socket_t) Socket {
|
||||
return Socket{ .fd = fd };
|
||||
}
|
||||
|
||||
/// Closes the socket.
|
||||
pub fn deinit(self: Socket) void {
|
||||
os.closeSocket(self.fd);
|
||||
}
|
||||
|
||||
/// Shutdown either the read side, or write side, or the entirety of a socket.
|
||||
/// Shutdown either the read side, write side, or all side of the socket.
|
||||
pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {
|
||||
return os.shutdown(self.fd, how);
|
||||
}
|
||||
|
||||
/// Binds the socket to an address.
|
||||
pub fn bind(self: Socket, address: net.Address) !void {
|
||||
return os.bind(self.fd, &address.any, address.getOsSockLen());
|
||||
pub fn bind(self: Socket, address: Socket.Address) !void {
|
||||
return os.bind(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
|
||||
}
|
||||
|
||||
/// Start listening for incoming connections on the socket.
|
||||
@@ -44,8 +141,8 @@ pub fn listen(self: Socket, max_backlog_size: u31) !void {
|
||||
}
|
||||
|
||||
/// Have the socket attempt to the connect to an address.
|
||||
pub fn connect(self: Socket, address: net.Address) !void {
|
||||
return os.connect(self.fd, &address.any, address.getOsSockLen());
|
||||
pub fn connect(self: Socket, address: Socket.Address) !void {
|
||||
return os.connect(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
|
||||
}
|
||||
|
||||
/// Accept a pending incoming connection queued to the kernel backlog
|
||||
@@ -54,12 +151,10 @@ pub fn accept(self: Socket, flags: u32) !Socket.Connection {
|
||||
var address: os.sockaddr = undefined;
|
||||
var address_len: u32 = @sizeOf(os.sockaddr);
|
||||
|
||||
const fd = try os.accept(self.fd, &address, &address_len, flags);
|
||||
const socket = Socket{ .fd = try os.accept(self.fd, &address, &address_len, flags) };
|
||||
const socket_address = Socket.Address.fromNative(@alignCast(4, &address));
|
||||
|
||||
return Connection{
|
||||
.socket = Socket{ .fd = fd },
|
||||
.address = net.Address.initPosix(@alignCast(4, &address)),
|
||||
};
|
||||
return Socket.Connection.from(socket, socket_address);
|
||||
}
|
||||
|
||||
/// Read data from the socket into the buffer provided. It returns the
|
||||
@@ -100,11 +195,11 @@ pub fn sendmsg(self: Socket, msg: os.msghdr_const, flags: u32) !usize {
|
||||
}
|
||||
|
||||
/// Query the address that the socket is locally bounded to.
|
||||
pub fn getLocalAddress(self: Socket) !net.Address {
|
||||
pub fn getLocalAddress(self: Socket) !Socket.Address {
|
||||
var address: os.sockaddr = undefined;
|
||||
var address_len: u32 = @sizeOf(os.sockaddr);
|
||||
try os.getsockname(self.fd, &address, &address_len);
|
||||
return net.Address.initPosix(@alignCast(4, &address));
|
||||
return Socket.Address.fromNative(@alignCast(4, &address));
|
||||
}
|
||||
|
||||
/// Query and return the latest cached error on the socket.
|
||||
@@ -164,33 +259,6 @@ pub fn setReusePort(self: Socket, enabled: bool) !void {
|
||||
return error.UnsupportedSocketOption;
|
||||
}
|
||||
|
||||
/// Disable Nagle's algorithm on a TCP socket. It returns `error.UnsupportedSocketOption` if the host does not support
|
||||
/// sockets disabling Nagle's algorithm.
|
||||
pub fn setNoDelay(self: Socket, enabled: bool) !void {
|
||||
if (comptime @hasDecl(os, "TCP_NODELAY")) {
|
||||
return os.setsockopt(self.fd, os.IPPROTO_TCP, os.TCP_NODELAY, mem.asBytes(&@as(usize, @boolToInt(enabled))));
|
||||
}
|
||||
return error.UnsupportedSocketOption;
|
||||
}
|
||||
|
||||
/// Enables TCP Fast Open (RFC 7413) on a TCP socket. It returns `error.UnsupportedSocketOption` if the host does not
|
||||
/// support TCP Fast Open.
|
||||
pub fn setFastOpen(self: Socket, enabled: bool) !void {
|
||||
if (comptime @hasDecl(os, "TCP_FASTOPEN")) {
|
||||
return os.setsockopt(self.fd, os.IPPROTO_TCP, os.TCP_FASTOPEN, mem.asBytes(&@as(usize, @boolToInt(enabled))));
|
||||
}
|
||||
return error.UnsupportedSocketOption;
|
||||
}
|
||||
|
||||
/// Enables TCP Quick ACK on a TCP socket to immediately send rather than delay ACKs when necessary. It returns
|
||||
/// `error.UnsupportedSocketOption` if the host does not support TCP Quick ACK.
|
||||
pub fn setQuickACK(self: Socket, enabled: bool) !void {
|
||||
if (comptime @hasDecl(os, "TCP_QUICKACK")) {
|
||||
return os.setsockopt(self.fd, os.IPPROTO_TCP, os.TCP_QUICKACK, mem.asBytes(&@as(usize, @boolToInt(enabled))));
|
||||
}
|
||||
return error.UnsupportedSocketOption;
|
||||
}
|
||||
|
||||
/// Set the write buffer size of the socket.
|
||||
pub fn setWriteBufferSize(self: Socket, size: u32) !void {
|
||||
return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&size));
|
||||
@@ -206,8 +274,8 @@ pub fn setReadBufferSize(self: Socket, size: u32) !void {
|
||||
/// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
|
||||
pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void {
|
||||
const timeout = os.timeval{
|
||||
.tv_sec = @intCast(isize, milliseconds / time.ms_per_s),
|
||||
.tv_usec = @intCast(isize, (milliseconds % time.ms_per_s) * time.us_per_ms),
|
||||
.tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
|
||||
.tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
|
||||
};
|
||||
|
||||
return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDTIMEO, mem.asBytes(&timeout));
|
||||
@@ -219,58 +287,9 @@ pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void {
|
||||
/// exceeded.
|
||||
pub fn setReadTimeout(self: Socket, milliseconds: usize) !void {
|
||||
const timeout = os.timeval{
|
||||
.tv_sec = @intCast(isize, milliseconds / time.ms_per_s),
|
||||
.tv_usec = @intCast(isize, (milliseconds % time.ms_per_s) * time.us_per_ms),
|
||||
.tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
|
||||
.tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
|
||||
};
|
||||
|
||||
return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVTIMEO, mem.asBytes(&timeout));
|
||||
}
|
||||
|
||||
test {
|
||||
testing.refAllDecls(@This());
|
||||
}
|
||||
|
||||
test "socket/linux: set read timeout of 1 millisecond on blocking socket" {
|
||||
if (builtin.os.tag != .linux) return error.SkipZigTest;
|
||||
|
||||
const a = try Socket.init(os.AF_INET, os.SOCK_STREAM | os.SOCK_CLOEXEC, os.IPPROTO_TCP);
|
||||
defer a.deinit();
|
||||
|
||||
try a.bind(net.Address.initIp4([_]u8{ 0, 0, 0, 0 }, 0));
|
||||
try a.listen(128);
|
||||
|
||||
const binded_address = try a.getLocalAddress();
|
||||
|
||||
const b = try Socket.init(os.AF_INET, os.SOCK_STREAM | os.SOCK_CLOEXEC, os.IPPROTO_TCP);
|
||||
defer b.deinit();
|
||||
|
||||
try b.connect(binded_address);
|
||||
try b.setReadTimeout(1);
|
||||
|
||||
const ab = try a.accept(os.SOCK_CLOEXEC);
|
||||
defer ab.socket.deinit();
|
||||
|
||||
var buf: [1]u8 = undefined;
|
||||
testing.expectError(error.WouldBlock, b.read(&buf));
|
||||
}
|
||||
|
||||
test "socket/linux: create non-blocking socket pair" {
|
||||
if (builtin.os.tag != .linux) return error.SkipZigTest;
|
||||
|
||||
const a = try Socket.init(os.AF_INET, os.SOCK_STREAM | os.SOCK_NONBLOCK | os.SOCK_CLOEXEC, os.IPPROTO_TCP);
|
||||
defer a.deinit();
|
||||
|
||||
try a.bind(net.Address.initIp4([_]u8{ 0, 0, 0, 0 }, 0));
|
||||
try a.listen(128);
|
||||
|
||||
const binded_address = try a.getLocalAddress();
|
||||
|
||||
const b = try Socket.init(os.AF_INET, os.SOCK_STREAM | os.SOCK_NONBLOCK | os.SOCK_CLOEXEC, os.IPPROTO_TCP);
|
||||
defer b.deinit();
|
||||
|
||||
testing.expectError(error.WouldBlock, b.connect(binded_address));
|
||||
try b.getError();
|
||||
|
||||
const ab = try a.accept(os.SOCK_NONBLOCK | os.SOCK_CLOEXEC);
|
||||
defer ab.socket.deinit();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,567 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2015-2021 Zig Contributors
|
||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
||||
// The MIT license requires this copyright notice to be included in all copies
|
||||
// and substantial portions of the software.
|
||||
|
||||
const std = @import("../../std.zig");
|
||||
|
||||
const os = std.os;
|
||||
const fmt = std.fmt;
|
||||
const mem = std.mem;
|
||||
const math = std.math;
|
||||
const builtin = std.builtin;
|
||||
const testing = std.testing;
|
||||
|
||||
/// Resolves a network interface name into a scope/zone ID. It returns
|
||||
/// an error if either resolution fails, or if the interface name is
|
||||
/// too long.
|
||||
pub fn resolveScopeID(name: []const u8) !u32 {
|
||||
if (comptime @hasDecl(os, "IFNAMESIZE")) {
|
||||
if (name.len >= os.IFNAMESIZE - 1) return error.NameTooLong;
|
||||
|
||||
const fd = try os.socket(os.AF_UNIX, os.SOCK_DGRAM, 0);
|
||||
defer os.closeSocket(fd);
|
||||
|
||||
var f: os.ifreq = undefined;
|
||||
mem.copy(u8, &f.ifrn.name, name);
|
||||
f.ifrn.name[name.len] = 0;
|
||||
|
||||
try os.ioctl_SIOCGIFINDEX(fd, &f);
|
||||
|
||||
return @bitCast(u32, f.ifru.ivalue);
|
||||
}
|
||||
return error.Unsupported;
|
||||
}
|
||||
|
||||
/// An IPv4 address comprised of 4 bytes.
|
||||
pub const IPv4 = extern struct {
|
||||
/// A IPv4 host-port pair.
|
||||
pub const Address = extern struct {
|
||||
host: IPv4,
|
||||
port: u16,
|
||||
};
|
||||
|
||||
/// Octets of a IPv4 address designating the local host.
|
||||
pub const localhost_octets = [_]u8{ 127, 0, 0, 1 };
|
||||
|
||||
/// The IPv4 address of the local host.
|
||||
pub const localhost: IPv4 = .{ .octets = localhost_octets };
|
||||
|
||||
/// Octets of an unspecified IPv4 address.
|
||||
pub const unspecified_octets = [_]u8{0} ** 4;
|
||||
|
||||
/// An unspecified IPv4 address.
|
||||
pub const unspecified: IPv4 = .{ .octets = unspecified_octets };
|
||||
|
||||
/// Octets of a broadcast IPv4 address.
|
||||
pub const broadcast_octets = [_]u8{255} ** 4;
|
||||
|
||||
/// An IPv4 broadcast address.
|
||||
pub const broadcast: IPv4 = .{ .octets = broadcast_octets };
|
||||
|
||||
/// The prefix octet pattern of a link-local IPv4 address.
|
||||
pub const link_local_prefix = [_]u8{ 169, 254 };
|
||||
|
||||
/// The prefix octet patterns of IPv4 addresses intended for
|
||||
/// documentation.
|
||||
pub const documentation_prefixes = [_][]const u8{
|
||||
&[_]u8{ 192, 0, 2 },
|
||||
&[_]u8{ 198, 51, 100 },
|
||||
&[_]u8{ 203, 0, 113 },
|
||||
};
|
||||
|
||||
octets: [4]u8,
|
||||
|
||||
/// Returns whether or not the two addresses are equal to, less than, or
|
||||
/// greater than each other.
|
||||
pub fn cmp(self: IPv4, other: IPv4) math.Order {
|
||||
return mem.order(u8, &self.octets, &other.octets);
|
||||
}
|
||||
|
||||
/// Returns true if both addresses are semantically equivalent.
|
||||
pub fn eql(self: IPv4, other: IPv4) bool {
|
||||
return mem.eql(u8, &self.octets, &other.octets);
|
||||
}
|
||||
|
||||
/// Returns true if the address is a loopback address.
|
||||
pub fn isLoopback(self: IPv4) bool {
|
||||
return self.octets[0] == 127;
|
||||
}
|
||||
|
||||
/// Returns true if the address is an unspecified IPv4 address.
|
||||
pub fn isUnspecified(self: IPv4) bool {
|
||||
return mem.eql(u8, &self.octets, &unspecified_octets);
|
||||
}
|
||||
|
||||
/// Returns true if the address is a private IPv4 address.
|
||||
pub fn isPrivate(self: IPv4) bool {
|
||||
return self.octets[0] == 10 or
|
||||
(self.octets[0] == 172 and self.octets[1] >= 16 and self.octets[1] <= 31) or
|
||||
(self.octets[0] == 192 and self.octets[1] == 168);
|
||||
}
|
||||
|
||||
/// Returns true if the address is a link-local IPv4 address.
|
||||
pub fn isLinkLocal(self: IPv4) bool {
|
||||
return mem.startsWith(u8, &self.octets, &link_local_prefix);
|
||||
}
|
||||
|
||||
/// Returns true if the address is a multicast IPv4 address.
|
||||
pub fn isMulticast(self: IPv4) bool {
|
||||
return self.octets[0] >= 224 and self.octets[0] <= 239;
|
||||
}
|
||||
|
||||
/// Returns true if the address is a IPv4 broadcast address.
|
||||
pub fn isBroadcast(self: IPv4) bool {
|
||||
return mem.eql(u8, &self.octets, &broadcast_octets);
|
||||
}
|
||||
|
||||
/// Returns true if the address is in a range designated for documentation. Refer
|
||||
/// to IETF RFC 5737 for more details.
|
||||
pub fn isDocumentation(self: IPv4) bool {
|
||||
inline for (documentation_prefixes) |prefix| {
|
||||
if (mem.startsWith(u8, &self.octets, prefix)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Implements the `std.fmt.format` API.
|
||||
pub fn format(
|
||||
self: IPv4,
|
||||
comptime layout: []const u8,
|
||||
opts: fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
if (comptime layout.len != 0 and layout[0] != 's') {
|
||||
@compileError("Unsupported format specifier for IPv4 type '" ++ layout ++ "'.");
|
||||
}
|
||||
|
||||
try fmt.format(writer, "{}.{}.{}.{}", .{
|
||||
self.octets[0],
|
||||
self.octets[1],
|
||||
self.octets[2],
|
||||
self.octets[3],
|
||||
});
|
||||
}
|
||||
|
||||
/// Set of possible errors that may encountered when parsing an IPv4
|
||||
/// address.
|
||||
pub const ParseError = error{
|
||||
UnexpectedEndOfOctet,
|
||||
TooManyOctets,
|
||||
OctetOverflow,
|
||||
UnexpectedToken,
|
||||
IncompleteAddress,
|
||||
};
|
||||
|
||||
/// Parses an arbitrary IPv4 address.
|
||||
pub fn parse(buf: []const u8) ParseError!IPv4 {
|
||||
var octets: [4]u8 = undefined;
|
||||
var octet: u8 = 0;
|
||||
|
||||
var index: u8 = 0;
|
||||
var saw_any_digits: bool = false;
|
||||
|
||||
for (buf) |c| {
|
||||
switch (c) {
|
||||
'.' => {
|
||||
if (!saw_any_digits) return error.UnexpectedEndOfOctet;
|
||||
if (index == 3) return error.TooManyOctets;
|
||||
octets[index] = octet;
|
||||
index += 1;
|
||||
octet = 0;
|
||||
saw_any_digits = false;
|
||||
},
|
||||
'0'...'9' => {
|
||||
saw_any_digits = true;
|
||||
octet = math.mul(u8, octet, 10) catch return error.OctetOverflow;
|
||||
octet = math.add(u8, octet, c - '0') catch return error.OctetOverflow;
|
||||
},
|
||||
else => return error.UnexpectedToken,
|
||||
}
|
||||
}
|
||||
|
||||
if (index == 3 and saw_any_digits) {
|
||||
octets[index] = octet;
|
||||
return IPv4{ .octets = octets };
|
||||
}
|
||||
|
||||
return error.IncompleteAddress;
|
||||
}
|
||||
|
||||
/// Maps the address to its IPv6 equivalent. In most cases, you would
|
||||
/// want to map the address to its IPv6 equivalent rather than directly
|
||||
/// re-interpreting the address.
|
||||
pub fn mapToIPv6(self: IPv4) IPv6 {
|
||||
var octets: [16]u8 = undefined;
|
||||
mem.copy(u8, octets[0..12], &IPv6.v4_mapped_prefix);
|
||||
mem.copy(u8, octets[12..], &self.octets);
|
||||
return IPv6{ .octets = octets, .scope_id = IPv6.no_scope_id };
|
||||
}
|
||||
|
||||
/// Directly re-interprets the address to its IPv6 equivalent. In most
|
||||
/// cases, you would want to map the address to its IPv6 equivalent rather
|
||||
/// than directly re-interpreting the address.
|
||||
pub fn toIPv6(self: IPv4) IPv6 {
|
||||
var octets: [16]u8 = undefined;
|
||||
mem.set(u8, octets[0..12], 0);
|
||||
mem.copy(u8, octets[12..], &self.octets);
|
||||
return IPv6{ .octets = octets, .scope_id = IPv6.no_scope_id };
|
||||
}
|
||||
};
|
||||
|
||||
/// An IPv6 address comprised of 16 bytes for an address, and 4 bytes
|
||||
/// for a scope ID; cumulatively summing to 20 bytes in total.
|
||||
pub const IPv6 = extern struct {
|
||||
/// A IPv6 host-port pair.
|
||||
pub const Address = extern struct {
|
||||
host: IPv6,
|
||||
port: u16,
|
||||
};
|
||||
|
||||
/// Octets of a IPv6 address designating the local host.
|
||||
pub const localhost_octets = [_]u8{0} ** 15 ++ [_]u8{0x01};
|
||||
|
||||
/// The IPv6 address of the local host.
|
||||
pub const localhost: IPv6 = .{
|
||||
.octets = localhost_octets,
|
||||
.scope_id = no_scope_id,
|
||||
};
|
||||
|
||||
/// Octets of an unspecified IPv6 address.
|
||||
pub const unspecified_octets = [_]u8{0} ** 16;
|
||||
|
||||
/// An unspecified IPv6 address.
|
||||
pub const unspecified: IPv6 = .{
|
||||
.octets = unspecified_octets,
|
||||
.scope_id = no_scope_id,
|
||||
};
|
||||
|
||||
/// The prefix of a IPv6 address that is mapped to a IPv4 address.
|
||||
pub const v4_mapped_prefix = [_]u8{0} ** 10 ++ [_]u8{0xFF} ** 2;
|
||||
|
||||
/// A marker value used to designate an IPv6 address with no
|
||||
/// associated scope ID.
|
||||
pub const no_scope_id = math.maxInt(u32);
|
||||
|
||||
octets: [16]u8,
|
||||
scope_id: u32,
|
||||
|
||||
/// Returns whether or not the two addresses are equal to, less than, or
|
||||
/// greater than each other.
|
||||
pub fn cmp(self: IPv6, other: IPv6) math.Order {
|
||||
return switch (mem.order(u8, self.octets, other.octets)) {
|
||||
.eq => math.order(self.scope_id, other.scope_id),
|
||||
else => |order| order,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns true if both addresses are semantically equivalent.
|
||||
pub fn eql(self: IPv6, other: IPv6) bool {
|
||||
return self.scope_id == other.scope_id and mem.eql(u8, &self.octets, &other.octets);
|
||||
}
|
||||
|
||||
/// Returns true if the address is an unspecified IPv6 address.
|
||||
pub fn isUnspecified(self: IPv6) bool {
|
||||
return mem.eql(u8, &self.octets, &unspecified_octets);
|
||||
}
|
||||
|
||||
/// Returns true if the address is a loopback address.
|
||||
pub fn isLoopback(self: IPv6) bool {
|
||||
return mem.eql(u8, self.octets[0..3], &[_]u8{ 0, 0, 0 }) and
|
||||
mem.eql(u8, self.octets[12..], &[_]u8{ 0, 0, 0, 1 });
|
||||
}
|
||||
|
||||
/// Returns true if the address maps to an IPv4 address.
|
||||
pub fn mapsToIPv4(self: IPv6) bool {
|
||||
return mem.startsWith(u8, &self.octets, &v4_mapped_prefix);
|
||||
}
|
||||
|
||||
/// Returns an IPv4 address representative of the address should
|
||||
/// it the address be mapped to an IPv4 address. It returns null
|
||||
/// otherwise.
|
||||
pub fn toIPv4(self: IPv6) ?IPv4 {
|
||||
if (!self.mapsToIPv4()) return null;
|
||||
return IPv4{ .octets = self.octets[12..][0..4].* };
|
||||
}
|
||||
|
||||
/// Returns true if the address is a multicast IPv6 address.
|
||||
pub fn isMulticast(self: IPv6) bool {
|
||||
return self.octets[0] == 0xFF;
|
||||
}
|
||||
|
||||
/// Returns true if the address is a unicast link local IPv6 address.
|
||||
pub fn isLinkLocal(self: IPv6) bool {
|
||||
return self.octets[0] == 0xFE and self.octets[1] & 0xC0 == 0x80;
|
||||
}
|
||||
|
||||
/// Returns true if the address is a deprecated unicast site local
|
||||
/// IPv6 address. Refer to IETF RFC 3879 for more details as to
|
||||
/// why they are deprecated.
|
||||
pub fn isSiteLocal(self: IPv6) bool {
|
||||
return self.octets[0] == 0xFE and self.octets[1] & 0xC0 == 0xC0;
|
||||
}
|
||||
|
||||
/// IPv6 multicast address scopes.
|
||||
pub const Scope = enum(u8) {
|
||||
interface = 1,
|
||||
link = 2,
|
||||
realm = 3,
|
||||
admin = 4,
|
||||
site = 5,
|
||||
organization = 8,
|
||||
global = 14,
|
||||
unknown = 0xFF,
|
||||
};
|
||||
|
||||
/// Returns the multicast scope of the address.
|
||||
pub fn scope(self: IPv6) Scope {
|
||||
if (!self.isMulticast()) return .unknown;
|
||||
|
||||
return switch (self.octets[0] & 0x0F) {
|
||||
1 => .interface,
|
||||
2 => .link,
|
||||
3 => .realm,
|
||||
4 => .admin,
|
||||
5 => .site,
|
||||
8 => .organization,
|
||||
14 => .global,
|
||||
else => .unknown,
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements the `std.fmt.format` API. Specifying 'x' or 's' formats the
|
||||
/// address lower-cased octets, while specifying 'X' or 'S' formats the
|
||||
/// address using upper-cased ASCII octets.
|
||||
///
|
||||
/// The default specifier is 'x'.
|
||||
pub fn format(
|
||||
self: IPv6,
|
||||
comptime layout: []const u8,
|
||||
opts: fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
comptime const specifier = &[_]u8{if (layout.len == 0) 'x' else switch (layout[0]) {
|
||||
'x', 'X' => |specifier| specifier,
|
||||
's' => 'x',
|
||||
'S' => 'X',
|
||||
else => @compileError("Unsupported format specifier for IPv6 type '" ++ layout ++ "'."),
|
||||
}};
|
||||
|
||||
if (mem.startsWith(u8, &self.octets, &v4_mapped_prefix)) {
|
||||
return fmt.format(writer, "::{" ++ specifier ++ "}{" ++ specifier ++ "}:{}.{}.{}.{}", .{
|
||||
0xFF,
|
||||
0xFF,
|
||||
self.octets[12],
|
||||
self.octets[13],
|
||||
self.octets[14],
|
||||
self.octets[15],
|
||||
});
|
||||
}
|
||||
|
||||
const zero_span = span: {
|
||||
var i: usize = 0;
|
||||
while (i < self.octets.len) : (i += 2) {
|
||||
if (self.octets[i] == 0 and self.octets[i + 1] == 0) break;
|
||||
} else break :span .{ .from = 0, .to = 0 };
|
||||
|
||||
const from = i;
|
||||
|
||||
while (i < self.octets.len) : (i += 2) {
|
||||
if (self.octets[i] != 0 or self.octets[i + 1] != 0) break;
|
||||
}
|
||||
|
||||
break :span .{ .from = from, .to = i };
|
||||
};
|
||||
|
||||
var i: usize = 0;
|
||||
while (i != 16) : (i += 2) {
|
||||
if (zero_span.from != zero_span.to and i == zero_span.from) {
|
||||
try writer.writeAll("::");
|
||||
} else if (i >= zero_span.from and i < zero_span.to) {} else {
|
||||
if (i != 0 and i != zero_span.to) try writer.writeAll(":");
|
||||
|
||||
const val = @as(u16, self.octets[i]) << 8 | self.octets[i + 1];
|
||||
try fmt.formatIntValue(val, specifier, .{}, writer);
|
||||
}
|
||||
}
|
||||
|
||||
if (self.scope_id != no_scope_id and self.scope_id != 0) {
|
||||
try fmt.format(writer, "%{d}", .{self.scope_id});
|
||||
}
|
||||
}
|
||||
|
||||
/// Set of possible errors that may encountered when parsing an IPv6
|
||||
/// address.
|
||||
pub const ParseError = error{
|
||||
MalformedV4Mapping,
|
||||
BadScopeID,
|
||||
} || IPv4.ParseError;
|
||||
|
||||
/// Parses an arbitrary IPv6 address, including link-local addresses.
|
||||
pub fn parse(buf: []const u8) ParseError!IPv6 {
|
||||
if (mem.lastIndexOfScalar(u8, buf, '%')) |index| {
|
||||
const ip_slice = buf[0..index];
|
||||
const scope_id_slice = buf[index + 1 ..];
|
||||
|
||||
if (scope_id_slice.len == 0) return error.BadScopeID;
|
||||
|
||||
const scope_id: u32 = switch (scope_id_slice[0]) {
|
||||
'0'...'9' => fmt.parseInt(u32, scope_id_slice, 10),
|
||||
else => resolveScopeID(scope_id_slice),
|
||||
} catch return error.BadScopeID;
|
||||
|
||||
return parseWithScopeID(ip_slice, scope_id);
|
||||
}
|
||||
|
||||
return parseWithScopeID(buf, no_scope_id);
|
||||
}
|
||||
|
||||
/// Parses an IPv6 address with a pre-specified scope ID. Presumes
|
||||
/// that the address is not a link-local address.
|
||||
pub fn parseWithScopeID(buf: []const u8, scope_id: u32) ParseError!IPv6 {
|
||||
var octets: [16]u8 = undefined;
|
||||
var octet: u16 = 0;
|
||||
var tail: [16]u8 = undefined;
|
||||
|
||||
var out: []u8 = &octets;
|
||||
var index: u8 = 0;
|
||||
|
||||
var saw_any_digits: bool = false;
|
||||
var abbrv: bool = false;
|
||||
|
||||
for (buf) |c, i| {
|
||||
switch (c) {
|
||||
':' => {
|
||||
if (!saw_any_digits) {
|
||||
if (abbrv) return error.UnexpectedToken;
|
||||
if (i != 0) abbrv = true;
|
||||
mem.set(u8, out[index..], 0);
|
||||
out = &tail;
|
||||
index = 0;
|
||||
continue;
|
||||
}
|
||||
if (index == 14) return error.TooManyOctets;
|
||||
|
||||
out[index] = @truncate(u8, octet >> 8);
|
||||
index += 1;
|
||||
out[index] = @truncate(u8, octet);
|
||||
index += 1;
|
||||
|
||||
octet = 0;
|
||||
saw_any_digits = false;
|
||||
},
|
||||
'.' => {
|
||||
if (!abbrv or out[0] != 0xFF and out[1] != 0xFF) {
|
||||
return error.MalformedV4Mapping;
|
||||
}
|
||||
const start_index = mem.lastIndexOfScalar(u8, buf[0..i], ':').? + 1;
|
||||
const v4 = try IPv4.parse(buf[start_index..]);
|
||||
octets[10] = 0xFF;
|
||||
octets[11] = 0xFF;
|
||||
mem.copy(u8, octets[12..], &v4.octets);
|
||||
|
||||
return IPv6{ .octets = octets, .scope_id = scope_id };
|
||||
},
|
||||
else => {
|
||||
saw_any_digits = true;
|
||||
const digit = fmt.charToDigit(c, 16) catch return error.UnexpectedToken;
|
||||
octet = math.mul(u16, octet, 16) catch return error.OctetOverflow;
|
||||
octet = math.add(u16, octet, digit) catch return error.OctetOverflow;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (!saw_any_digits and !abbrv) {
|
||||
return error.IncompleteAddress;
|
||||
}
|
||||
|
||||
if (index == 14) {
|
||||
out[14] = @truncate(u8, octet >> 8);
|
||||
out[15] = @truncate(u8, octet);
|
||||
} else {
|
||||
out[index] = @truncate(u8, octet >> 8);
|
||||
index += 1;
|
||||
out[index] = @truncate(u8, octet);
|
||||
index += 1;
|
||||
mem.copy(u8, octets[16 - index ..], out[0..index]);
|
||||
}
|
||||
|
||||
return IPv6{ .octets = octets, .scope_id = scope_id };
|
||||
}
|
||||
};
|
||||
|
||||
test {
|
||||
testing.refAllDecls(@This());
|
||||
}
|
||||
|
||||
test "ip: convert to and from ipv6" {
|
||||
try testing.expectFmt("::7f00:1", "{}", .{IPv4.localhost.toIPv6()});
|
||||
testing.expect(!IPv4.localhost.toIPv6().mapsToIPv4());
|
||||
|
||||
try testing.expectFmt("::ffff:127.0.0.1", "{}", .{IPv4.localhost.mapToIPv6()});
|
||||
testing.expect(IPv4.localhost.mapToIPv6().mapsToIPv4());
|
||||
|
||||
testing.expect(IPv4.localhost.toIPv6().toIPv4() == null);
|
||||
try testing.expectFmt("127.0.0.1", "{}", .{IPv4.localhost.mapToIPv6().toIPv4()});
|
||||
}
|
||||
|
||||
test "ipv4: parse & format" {
|
||||
const cases = [_][]const u8{
|
||||
"0.0.0.0",
|
||||
"255.255.255.255",
|
||||
"1.2.3.4",
|
||||
"123.255.0.91",
|
||||
"127.0.0.1",
|
||||
};
|
||||
|
||||
for (cases) |case| {
|
||||
try testing.expectFmt(case, "{}", .{try IPv4.parse(case)});
|
||||
}
|
||||
}
|
||||
|
||||
test "ipv6: parse & format" {
|
||||
const inputs = [_][]const u8{
|
||||
"FF01:0:0:0:0:0:0:FB",
|
||||
"FF01::Fb",
|
||||
"::1",
|
||||
"::",
|
||||
"2001:db8::",
|
||||
"::1234:5678",
|
||||
"2001:db8::1234:5678",
|
||||
"::ffff:123.5.123.5",
|
||||
};
|
||||
|
||||
const outputs = [_][]const u8{
|
||||
"ff01::fb",
|
||||
"ff01::fb",
|
||||
"::1",
|
||||
"::",
|
||||
"2001:db8::",
|
||||
"::1234:5678",
|
||||
"2001:db8::1234:5678",
|
||||
"::ffff:123.5.123.5",
|
||||
};
|
||||
|
||||
for (inputs) |input, i| {
|
||||
try testing.expectFmt(outputs[i], "{}", .{try IPv6.parse(input)});
|
||||
}
|
||||
}
|
||||
|
||||
test "ipv6: parse & format addresses with scope ids" {
|
||||
if (!@hasDecl(os, "IFNAMESIZE")) return error.SkipZigTest;
|
||||
|
||||
const inputs = [_][]const u8{
|
||||
"FF01::FB%lo",
|
||||
};
|
||||
|
||||
const outputs = [_][]const u8{
|
||||
"ff01::fb%1",
|
||||
};
|
||||
|
||||
for (inputs) |input, i| {
|
||||
try testing.expectFmt(outputs[i], "{}", .{try IPv6.parse(input)});
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
const std = @import("../../std.zig");
|
||||
|
||||
const testing = std.testing;
|
||||
|
||||
pub const Socket = @import("Socket.zig");
|
||||
|
||||
test {
|
||||
testing.refAllDecls(@This());
|
||||
}
|
||||
+13
-7
@@ -1979,20 +1979,26 @@ pub const Tree = struct {
|
||||
// asm ("foo" :: [_] "" (y) : "a", "b");
|
||||
const last_input = result.inputs[result.inputs.len - 1];
|
||||
const rparen = tree.lastToken(last_input);
|
||||
if (token_tags[rparen + 1] == .colon and
|
||||
token_tags[rparen + 2] == .string_literal)
|
||||
var i = rparen + 1;
|
||||
// Allow a (useless) comma right after the closing parenthesis.
|
||||
if (token_tags[i] == .comma) i += 1;
|
||||
if (token_tags[i] == .colon and
|
||||
token_tags[i + 1] == .string_literal)
|
||||
{
|
||||
result.first_clobber = rparen + 2;
|
||||
result.first_clobber = i + 1;
|
||||
}
|
||||
} else {
|
||||
// asm ("foo" : [_] "" (x) :: "a", "b");
|
||||
const last_output = result.outputs[result.outputs.len - 1];
|
||||
const rparen = tree.lastToken(last_output);
|
||||
if (token_tags[rparen + 1] == .colon and
|
||||
token_tags[rparen + 2] == .colon and
|
||||
token_tags[rparen + 3] == .string_literal)
|
||||
var i = rparen + 1;
|
||||
// Allow a (useless) comma right after the closing parenthesis.
|
||||
if (token_tags[i] == .comma) i += 1;
|
||||
if (token_tags[i] == .colon and
|
||||
token_tags[i + 1] == .colon and
|
||||
token_tags[i + 2] == .string_literal)
|
||||
{
|
||||
result.first_clobber = rparen + 3;
|
||||
result.first_clobber = i + 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,38 @@
|
||||
// The MIT license requires this copyright notice to be included in all copies
|
||||
// and substantial portions of the software.
|
||||
|
||||
test "zig fmt: preserves clobbers in inline asm with stray comma" {
|
||||
try testTransform(
|
||||
\\fn foo() void {
|
||||
\\ asm volatile (""
|
||||
\\ : [_] "" (-> type),
|
||||
\\ :
|
||||
\\ : "clobber"
|
||||
\\ );
|
||||
\\ asm volatile (""
|
||||
\\ :
|
||||
\\ : [_] "" (type),
|
||||
\\ : "clobber"
|
||||
\\ );
|
||||
\\}
|
||||
\\
|
||||
,
|
||||
\\fn foo() void {
|
||||
\\ asm volatile (""
|
||||
\\ : [_] "" (-> type)
|
||||
\\ :
|
||||
\\ : "clobber"
|
||||
\\ );
|
||||
\\ asm volatile (""
|
||||
\\ :
|
||||
\\ : [_] "" (type)
|
||||
\\ : "clobber"
|
||||
\\ );
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: respect line breaks in struct field value declaration" {
|
||||
try testCanonical(
|
||||
\\const Foo = struct {
|
||||
|
||||
@@ -53,7 +53,7 @@ const SparcCpuinfoImpl = struct {
|
||||
// At the moment we only support 64bit SPARC systems.
|
||||
assert(self.is_64bit);
|
||||
|
||||
const model = self.model orelse Target.Cpu.Model.generic(arch);
|
||||
const model = self.model orelse return null;
|
||||
return Target.Cpu{
|
||||
.arch = arch,
|
||||
.model = model,
|
||||
@@ -65,7 +65,7 @@ const SparcCpuinfoImpl = struct {
|
||||
const SparcCpuinfoParser = CpuinfoParser(SparcCpuinfoImpl);
|
||||
|
||||
test "cpuinfo: SPARC" {
|
||||
try testParser(SparcCpuinfoParser, &Target.sparc.cpu.niagara2,
|
||||
try testParser(SparcCpuinfoParser, .sparcv9, &Target.sparc.cpu.niagara2,
|
||||
\\cpu : UltraSparc T2 (Niagara2)
|
||||
\\fpu : UltraSparc T2 integrated FPU
|
||||
\\pmu : niagara2
|
||||
@@ -119,7 +119,7 @@ const PowerpcCpuinfoImpl = struct {
|
||||
}
|
||||
|
||||
fn finalize(self: *const PowerpcCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {
|
||||
const model = self.model orelse Target.Cpu.Model.generic(arch);
|
||||
const model = self.model orelse return null;
|
||||
return Target.Cpu{
|
||||
.arch = arch,
|
||||
.model = model,
|
||||
@@ -131,13 +131,13 @@ const PowerpcCpuinfoImpl = struct {
|
||||
const PowerpcCpuinfoParser = CpuinfoParser(PowerpcCpuinfoImpl);
|
||||
|
||||
test "cpuinfo: PowerPC" {
|
||||
try testParser(PowerpcCpuinfoParser, &Target.powerpc.cpu.@"970",
|
||||
try testParser(PowerpcCpuinfoParser, .powerpc, &Target.powerpc.cpu.@"970",
|
||||
\\processor : 0
|
||||
\\cpu : PPC970MP, altivec supported
|
||||
\\clock : 1250.000000MHz
|
||||
\\revision : 1.1 (pvr 0044 0101)
|
||||
);
|
||||
try testParser(PowerpcCpuinfoParser, &Target.powerpc.cpu.pwr8,
|
||||
try testParser(PowerpcCpuinfoParser, .powerpc64le, &Target.powerpc.cpu.pwr8,
|
||||
\\processor : 0
|
||||
\\cpu : POWER8 (raw), altivec supported
|
||||
\\clock : 2926.000000MHz
|
||||
@@ -145,9 +145,275 @@ test "cpuinfo: PowerPC" {
|
||||
);
|
||||
}
|
||||
|
||||
fn testParser(parser: anytype, expected_model: *const Target.Cpu.Model, input: []const u8) !void {
|
||||
const ArmCpuinfoImpl = struct {
|
||||
cores: [4]CoreInfo = undefined,
|
||||
core_no: usize = 0,
|
||||
have_fields: usize = 0,
|
||||
|
||||
const CoreInfo = struct {
|
||||
architecture: u8 = 0,
|
||||
implementer: u8 = 0,
|
||||
variant: u8 = 0,
|
||||
part: u16 = 0,
|
||||
is_really_v6: bool = false,
|
||||
};
|
||||
|
||||
const cpu_models = struct {
|
||||
// Shorthands to simplify the tables below.
|
||||
const A32 = Target.arm.cpu;
|
||||
const A64 = Target.aarch64.cpu;
|
||||
|
||||
const E = struct {
|
||||
part: u16,
|
||||
variant: ?u8 = null, // null if matches any variant
|
||||
m32: ?*const Target.Cpu.Model = null,
|
||||
m64: ?*const Target.Cpu.Model = null,
|
||||
};
|
||||
|
||||
// implementer = 0x41
|
||||
const ARM = [_]E{
|
||||
E{ .part = 0x926, .m32 = &A32.arm926ej_s, .m64 = null },
|
||||
E{ .part = 0xb02, .m32 = &A32.mpcore, .m64 = null },
|
||||
E{ .part = 0xb36, .m32 = &A32.arm1136j_s, .m64 = null },
|
||||
E{ .part = 0xb56, .m32 = &A32.arm1156t2_s, .m64 = null },
|
||||
E{ .part = 0xb76, .m32 = &A32.arm1176jz_s, .m64 = null },
|
||||
E{ .part = 0xc05, .m32 = &A32.cortex_a5, .m64 = null },
|
||||
E{ .part = 0xc07, .m32 = &A32.cortex_a7, .m64 = null },
|
||||
E{ .part = 0xc08, .m32 = &A32.cortex_a8, .m64 = null },
|
||||
E{ .part = 0xc09, .m32 = &A32.cortex_a9, .m64 = null },
|
||||
E{ .part = 0xc0d, .m32 = &A32.cortex_a17, .m64 = null },
|
||||
E{ .part = 0xc0f, .m32 = &A32.cortex_a15, .m64 = null },
|
||||
E{ .part = 0xc0e, .m32 = &A32.cortex_a17, .m64 = null },
|
||||
E{ .part = 0xc14, .m32 = &A32.cortex_r4, .m64 = null },
|
||||
E{ .part = 0xc15, .m32 = &A32.cortex_r5, .m64 = null },
|
||||
E{ .part = 0xc17, .m32 = &A32.cortex_r7, .m64 = null },
|
||||
E{ .part = 0xc18, .m32 = &A32.cortex_r8, .m64 = null },
|
||||
E{ .part = 0xc20, .m32 = &A32.cortex_m0, .m64 = null },
|
||||
E{ .part = 0xc21, .m32 = &A32.cortex_m1, .m64 = null },
|
||||
E{ .part = 0xc23, .m32 = &A32.cortex_m3, .m64 = null },
|
||||
E{ .part = 0xc24, .m32 = &A32.cortex_m4, .m64 = null },
|
||||
E{ .part = 0xc27, .m32 = &A32.cortex_m7, .m64 = null },
|
||||
E{ .part = 0xc60, .m32 = &A32.cortex_m0plus, .m64 = null },
|
||||
E{ .part = 0xd01, .m32 = &A32.cortex_a32, .m64 = null },
|
||||
E{ .part = 0xd03, .m32 = &A32.cortex_a53, .m64 = &A64.cortex_a53 },
|
||||
E{ .part = 0xd04, .m32 = &A32.cortex_a35, .m64 = &A64.cortex_a35 },
|
||||
E{ .part = 0xd05, .m32 = &A32.cortex_a55, .m64 = &A64.cortex_a55 },
|
||||
E{ .part = 0xd07, .m32 = &A32.cortex_a57, .m64 = &A64.cortex_a57 },
|
||||
E{ .part = 0xd08, .m32 = &A32.cortex_a72, .m64 = &A64.cortex_a72 },
|
||||
E{ .part = 0xd09, .m32 = &A32.cortex_a73, .m64 = &A64.cortex_a73 },
|
||||
E{ .part = 0xd0a, .m32 = &A32.cortex_a75, .m64 = &A64.cortex_a75 },
|
||||
E{ .part = 0xd0b, .m32 = &A32.cortex_a76, .m64 = &A64.cortex_a76 },
|
||||
E{ .part = 0xd0c, .m32 = &A32.neoverse_n1, .m64 = null },
|
||||
E{ .part = 0xd0d, .m32 = &A32.cortex_a77, .m64 = &A64.cortex_a77 },
|
||||
E{ .part = 0xd13, .m32 = &A32.cortex_r52, .m64 = null },
|
||||
E{ .part = 0xd20, .m32 = &A32.cortex_m23, .m64 = null },
|
||||
E{ .part = 0xd21, .m32 = &A32.cortex_m33, .m64 = null },
|
||||
E{ .part = 0xd41, .m32 = &A32.cortex_a78, .m64 = &A64.cortex_a78 },
|
||||
E{ .part = 0xd4b, .m32 = &A32.cortex_a78c, .m64 = &A64.cortex_a78c },
|
||||
E{ .part = 0xd44, .m32 = &A32.cortex_x1, .m64 = &A64.cortex_x1 },
|
||||
E{ .part = 0xd02, .m64 = &A64.cortex_a34 },
|
||||
E{ .part = 0xd06, .m64 = &A64.cortex_a65 },
|
||||
E{ .part = 0xd43, .m64 = &A64.cortex_a65ae },
|
||||
};
|
||||
// implementer = 0x42
|
||||
const Broadcom = [_]E{
|
||||
E{ .part = 0x516, .m64 = &A64.thunderx2t99 },
|
||||
};
|
||||
// implementer = 0x43
|
||||
const Cavium = [_]E{
|
||||
E{ .part = 0x0a0, .m64 = &A64.thunderx },
|
||||
E{ .part = 0x0a2, .m64 = &A64.thunderxt81 },
|
||||
E{ .part = 0x0a3, .m64 = &A64.thunderxt83 },
|
||||
E{ .part = 0x0a1, .m64 = &A64.thunderxt88 },
|
||||
E{ .part = 0x0af, .m64 = &A64.thunderx2t99 },
|
||||
};
|
||||
// implementer = 0x46
|
||||
const Fujitsu = [_]E{
|
||||
E{ .part = 0x001, .m64 = &A64.a64fx },
|
||||
};
|
||||
// implementer = 0x48
|
||||
const HiSilicon = [_]E{
|
||||
E{ .part = 0xd01, .m64 = &A64.tsv110 },
|
||||
};
|
||||
// implementer = 0x4e
|
||||
const Nvidia = [_]E{
|
||||
E{ .part = 0x004, .m64 = &A64.carmel },
|
||||
};
|
||||
// implementer = 0x50
|
||||
const Ampere = [_]E{
|
||||
E{ .part = 0x000, .variant = 3, .m64 = &A64.emag },
|
||||
E{ .part = 0x000, .m64 = &A64.xgene1 },
|
||||
};
|
||||
// implementer = 0x51
|
||||
const Qualcomm = [_]E{
|
||||
E{ .part = 0x06f, .m32 = &A32.krait },
|
||||
E{ .part = 0x201, .m64 = &A64.kryo, .m32 = &A64.kryo },
|
||||
E{ .part = 0x205, .m64 = &A64.kryo, .m32 = &A64.kryo },
|
||||
E{ .part = 0x211, .m64 = &A64.kryo, .m32 = &A64.kryo },
|
||||
E{ .part = 0x800, .m64 = &A64.cortex_a73, .m32 = &A64.cortex_a73 },
|
||||
E{ .part = 0x801, .m64 = &A64.cortex_a73, .m32 = &A64.cortex_a73 },
|
||||
E{ .part = 0x802, .m64 = &A64.cortex_a75, .m32 = &A64.cortex_a75 },
|
||||
E{ .part = 0x803, .m64 = &A64.cortex_a75, .m32 = &A64.cortex_a75 },
|
||||
E{ .part = 0x804, .m64 = &A64.cortex_a76, .m32 = &A64.cortex_a76 },
|
||||
E{ .part = 0x805, .m64 = &A64.cortex_a76, .m32 = &A64.cortex_a76 },
|
||||
E{ .part = 0xc00, .m64 = &A64.falkor },
|
||||
E{ .part = 0xc01, .m64 = &A64.saphira },
|
||||
};
|
||||
|
||||
fn isKnown(core: CoreInfo, is_64bit: bool) ?*const Target.Cpu.Model {
|
||||
const models = switch (core.implementer) {
|
||||
0x41 => &ARM,
|
||||
0x42 => &Broadcom,
|
||||
0x43 => &Cavium,
|
||||
0x46 => &Fujitsu,
|
||||
0x48 => &HiSilicon,
|
||||
0x50 => &Ampere,
|
||||
0x51 => &Qualcomm,
|
||||
else => return null,
|
||||
};
|
||||
|
||||
for (models) |model| {
|
||||
if (model.part == core.part and
|
||||
(model.variant == null or model.variant.? == core.variant))
|
||||
return if (is_64bit) model.m64 else model.m32;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
fn addOne(self: *ArmCpuinfoImpl) void {
|
||||
if (self.have_fields == 4 and self.core_no < self.cores.len) {
|
||||
if (self.core_no > 0) {
|
||||
// Deduplicate the core info.
|
||||
for (self.cores[0..self.core_no]) |it| {
|
||||
if (std.meta.eql(it, self.cores[self.core_no]))
|
||||
return;
|
||||
}
|
||||
}
|
||||
self.core_no += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn line_hook(self: *ArmCpuinfoImpl, key: []const u8, value: []const u8) !bool {
|
||||
const info = &self.cores[self.core_no];
|
||||
|
||||
if (mem.eql(u8, key, "processor")) {
|
||||
// Handle both old-style and new-style cpuinfo formats.
|
||||
// The former prints a sequence of "processor: N" lines for each
|
||||
// core and then the info for the core that's executing this code(!)
|
||||
// while the latter prints the infos for each core right after the
|
||||
// "processor" key.
|
||||
self.have_fields = 0;
|
||||
self.cores[self.core_no] = .{};
|
||||
} else if (mem.eql(u8, key, "CPU implementer")) {
|
||||
info.implementer = try fmt.parseInt(u8, value, 0);
|
||||
self.have_fields += 1;
|
||||
} else if (mem.eql(u8, key, "CPU architecture")) {
|
||||
// "AArch64" on older kernels.
|
||||
info.architecture = if (mem.startsWith(u8, value, "AArch64"))
|
||||
8
|
||||
else
|
||||
try fmt.parseInt(u8, value, 0);
|
||||
self.have_fields += 1;
|
||||
} else if (mem.eql(u8, key, "CPU variant")) {
|
||||
info.variant = try fmt.parseInt(u8, value, 0);
|
||||
self.have_fields += 1;
|
||||
} else if (mem.eql(u8, key, "CPU part")) {
|
||||
info.part = try fmt.parseInt(u16, value, 0);
|
||||
self.have_fields += 1;
|
||||
} else if (mem.eql(u8, key, "model name")) {
|
||||
// ARMv6 cores report "CPU architecture" equal to 7.
|
||||
if (mem.indexOf(u8, value, "(v6l)")) |_| {
|
||||
info.is_really_v6 = true;
|
||||
}
|
||||
} else if (mem.eql(u8, key, "CPU revision")) {
|
||||
// This field is always the last one for each CPU section.
|
||||
_ = self.addOne();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn finalize(self: *ArmCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {
|
||||
if (self.core_no == 0) return null;
|
||||
|
||||
const is_64bit = switch (arch) {
|
||||
.aarch64, .aarch64_be, .aarch64_32 => true,
|
||||
else => false,
|
||||
};
|
||||
|
||||
var known_models: [self.cores.len]?*const Target.Cpu.Model = undefined;
|
||||
for (self.cores[0..self.core_no]) |core, i| {
|
||||
known_models[i] = cpu_models.isKnown(core, is_64bit);
|
||||
}
|
||||
|
||||
// XXX We pick the first core on big.LITTLE systems, hopefully the
|
||||
// LITTLE one.
|
||||
const model = known_models[0] orelse return null;
|
||||
return Target.Cpu{
|
||||
.arch = arch,
|
||||
.model = model,
|
||||
.features = model.features,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const ArmCpuinfoParser = CpuinfoParser(ArmCpuinfoImpl);
|
||||
|
||||
test "cpuinfo: ARM" {
|
||||
try testParser(ArmCpuinfoParser, .arm, &Target.arm.cpu.arm1176jz_s,
|
||||
\\processor : 0
|
||||
\\model name : ARMv6-compatible processor rev 7 (v6l)
|
||||
\\BogoMIPS : 997.08
|
||||
\\Features : half thumb fastmult vfp edsp java tls
|
||||
\\CPU implementer : 0x41
|
||||
\\CPU architecture: 7
|
||||
\\CPU variant : 0x0
|
||||
\\CPU part : 0xb76
|
||||
\\CPU revision : 7
|
||||
);
|
||||
try testParser(ArmCpuinfoParser, .arm, &Target.arm.cpu.cortex_a7,
|
||||
\\processor : 0
|
||||
\\model name : ARMv7 Processor rev 3 (v7l)
|
||||
\\BogoMIPS : 18.00
|
||||
\\Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
|
||||
\\CPU implementer : 0x41
|
||||
\\CPU architecture: 7
|
||||
\\CPU variant : 0x0
|
||||
\\CPU part : 0xc07
|
||||
\\CPU revision : 3
|
||||
\\
|
||||
\\processor : 4
|
||||
\\model name : ARMv7 Processor rev 3 (v7l)
|
||||
\\BogoMIPS : 90.00
|
||||
\\Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
|
||||
\\CPU implementer : 0x41
|
||||
\\CPU architecture: 7
|
||||
\\CPU variant : 0x2
|
||||
\\CPU part : 0xc0f
|
||||
\\CPU revision : 3
|
||||
);
|
||||
try testParser(ArmCpuinfoParser, .aarch64, &Target.aarch64.cpu.cortex_a72,
|
||||
\\processor : 0
|
||||
\\BogoMIPS : 108.00
|
||||
\\Features : fp asimd evtstrm crc32 cpuid
|
||||
\\CPU implementer : 0x41
|
||||
\\CPU architecture: 8
|
||||
\\CPU variant : 0x0
|
||||
\\CPU part : 0xd08
|
||||
\\CPU revision : 3
|
||||
);
|
||||
}
|
||||
|
||||
fn testParser(
|
||||
parser: anytype,
|
||||
arch: Target.Cpu.Arch,
|
||||
expected_model: *const Target.Cpu.Model,
|
||||
input: []const u8,
|
||||
) !void {
|
||||
var fbs = io.fixedBufferStream(input);
|
||||
const result = try parser.parse(.powerpc, fbs.reader());
|
||||
const result = try parser.parse(arch, fbs.reader());
|
||||
testing.expectEqual(expected_model, result.?.model);
|
||||
testing.expect(expected_model.features.eql(result.?.features));
|
||||
}
|
||||
@@ -186,6 +452,9 @@ pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
|
||||
|
||||
const current_arch = std.Target.current.cpu.arch;
|
||||
switch (current_arch) {
|
||||
.arm, .armeb, .thumb, .thumbeb, .aarch64, .aarch64_be, .aarch64_32 => {
|
||||
return ArmCpuinfoParser.parse(current_arch, f.reader()) catch null;
|
||||
},
|
||||
.sparcv9 => {
|
||||
return SparcCpuinfoParser.parse(current_arch, f.reader()) catch null;
|
||||
},
|
||||
|
||||
@@ -239,7 +239,6 @@ pub const CObject = struct {
|
||||
pub fn destroy(em: *ErrorMsg, gpa: *Allocator) void {
|
||||
gpa.free(em.msg);
|
||||
gpa.destroy(em);
|
||||
em.* = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+80
-98
@@ -43,17 +43,13 @@ dwarf_debug_str_index: ?u16 = null,
|
||||
dwarf_debug_line_index: ?u16 = null,
|
||||
dwarf_debug_ranges_index: ?u16 = null,
|
||||
|
||||
symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
|
||||
strtab: std.ArrayListUnmanaged(u8) = .{},
|
||||
symbols: std.ArrayListUnmanaged(*Symbol) = .{},
|
||||
initializers: std.ArrayListUnmanaged(*Symbol) = .{},
|
||||
data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
|
||||
|
||||
locals: std.StringArrayHashMapUnmanaged(Symbol) = .{},
|
||||
stabs: std.ArrayListUnmanaged(Stab) = .{},
|
||||
tu_path: ?[]const u8 = null,
|
||||
tu_mtime: ?u64 = null,
|
||||
|
||||
initializers: std.ArrayListUnmanaged(CppStatic) = .{},
|
||||
data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
|
||||
|
||||
pub const Section = struct {
|
||||
inner: macho.section_64,
|
||||
code: []u8,
|
||||
@@ -71,23 +67,6 @@ pub const Section = struct {
|
||||
}
|
||||
};
|
||||
|
||||
const CppStatic = struct {
|
||||
symbol: u32,
|
||||
target_addr: u64,
|
||||
};
|
||||
|
||||
const Stab = struct {
|
||||
tag: Tag,
|
||||
symbol: u32,
|
||||
size: ?u64 = null,
|
||||
|
||||
const Tag = enum {
|
||||
function,
|
||||
global,
|
||||
static,
|
||||
};
|
||||
};
|
||||
|
||||
const DebugInfo = struct {
|
||||
inner: dwarf.DwarfInfo,
|
||||
debug_info: []u8,
|
||||
@@ -169,14 +148,12 @@ pub fn deinit(self: *Object) void {
|
||||
}
|
||||
self.sections.deinit(self.allocator);
|
||||
|
||||
for (self.locals.items()) |*entry| {
|
||||
entry.value.deinit(self.allocator);
|
||||
for (self.symbols.items) |sym| {
|
||||
sym.deinit(self.allocator);
|
||||
self.allocator.destroy(sym);
|
||||
}
|
||||
self.locals.deinit(self.allocator);
|
||||
self.symbols.deinit(self.allocator);
|
||||
|
||||
self.symtab.deinit(self.allocator);
|
||||
self.strtab.deinit(self.allocator);
|
||||
self.stabs.deinit(self.allocator);
|
||||
self.data_in_code_entries.deinit(self.allocator);
|
||||
self.initializers.deinit(self.allocator);
|
||||
|
||||
@@ -222,9 +199,9 @@ pub fn parse(self: *Object) !void {
|
||||
}
|
||||
|
||||
try self.readLoadCommands(reader);
|
||||
try self.parseSymbols();
|
||||
try self.parseSections();
|
||||
if (self.symtab_cmd_index != null) try self.parseSymtab();
|
||||
if (self.data_in_code_cmd_index != null) try self.readDataInCode();
|
||||
try self.parseDataInCode();
|
||||
try self.parseInitializers();
|
||||
try self.parseDebugInfo();
|
||||
}
|
||||
@@ -298,9 +275,10 @@ pub fn readLoadCommands(self: *Object, reader: anytype) !void {
|
||||
}
|
||||
|
||||
pub fn parseSections(self: *Object) !void {
|
||||
log.debug("parsing sections in {s}", .{self.name.?});
|
||||
const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
|
||||
|
||||
log.debug("parsing sections in {s}", .{self.name.?});
|
||||
|
||||
try self.sections.ensureCapacity(self.allocator, seg.sections.items.len);
|
||||
|
||||
for (seg.sections.items) |sect| {
|
||||
@@ -327,6 +305,7 @@ pub fn parseSections(self: *Object) !void {
|
||||
self.arch.?,
|
||||
section.code,
|
||||
mem.bytesAsSlice(macho.relocation_info, raw_relocs),
|
||||
self.symbols.items,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -344,60 +323,70 @@ pub fn parseInitializers(self: *Object) !void {
|
||||
const relocs = section.relocs orelse unreachable;
|
||||
try self.initializers.ensureCapacity(self.allocator, relocs.len);
|
||||
for (relocs) |rel| {
|
||||
self.initializers.appendAssumeCapacity(.{
|
||||
.symbol = rel.target.symbol,
|
||||
.target_addr = undefined,
|
||||
});
|
||||
self.initializers.appendAssumeCapacity(rel.target.symbol);
|
||||
}
|
||||
|
||||
mem.reverse(CppStatic, self.initializers.items);
|
||||
|
||||
for (self.initializers.items) |initializer| {
|
||||
const sym = self.symtab.items[initializer.symbol];
|
||||
const sym_name = self.getString(sym.n_strx);
|
||||
log.debug(" | {s}", .{sym_name});
|
||||
}
|
||||
mem.reverse(*Symbol, self.initializers.items);
|
||||
}
|
||||
|
||||
pub fn parseSymtab(self: *Object) !void {
|
||||
const symtab_cmd = self.load_commands.items[self.symtab_cmd_index.?].Symtab;
|
||||
pub fn parseSymbols(self: *Object) !void {
|
||||
const index = self.symtab_cmd_index orelse return;
|
||||
const symtab_cmd = self.load_commands.items[index].Symtab;
|
||||
|
||||
var symtab = try self.allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);
|
||||
defer self.allocator.free(symtab);
|
||||
|
||||
_ = try self.file.?.preadAll(symtab, symtab_cmd.symoff);
|
||||
const slice = @alignCast(@alignOf(macho.nlist_64), mem.bytesAsSlice(macho.nlist_64, symtab));
|
||||
try self.symtab.appendSlice(self.allocator, slice);
|
||||
|
||||
var strtab = try self.allocator.alloc(u8, symtab_cmd.strsize);
|
||||
defer self.allocator.free(strtab);
|
||||
|
||||
_ = try self.file.?.preadAll(strtab, symtab_cmd.stroff);
|
||||
try self.strtab.appendSlice(self.allocator, strtab);
|
||||
|
||||
for (self.symtab.items) |sym, sym_id| {
|
||||
if (Symbol.isStab(sym) or Symbol.isUndef(sym)) continue;
|
||||
for (slice) |sym| {
|
||||
if (Symbol.isStab(sym)) {
|
||||
log.err("TODO handle stabs embedded within object files", .{});
|
||||
return error.HandleStabsInObjects;
|
||||
}
|
||||
|
||||
const sym_name = self.getString(sym.n_strx);
|
||||
const tag: Symbol.Tag = tag: {
|
||||
if (Symbol.isLocal(sym)) {
|
||||
if (self.arch.? == .aarch64 and mem.startsWith(u8, sym_name, "l")) continue;
|
||||
break :tag .local;
|
||||
}
|
||||
if (Symbol.isWeakDef(sym)) {
|
||||
break :tag .weak;
|
||||
}
|
||||
break :tag .strong;
|
||||
};
|
||||
const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx));
|
||||
const name = try self.allocator.dupe(u8, sym_name);
|
||||
|
||||
try self.locals.putNoClobber(self.allocator, name, .{
|
||||
.tag = tag,
|
||||
.name = name,
|
||||
.address = 0,
|
||||
.section = 0,
|
||||
.index = @intCast(u32, sym_id),
|
||||
});
|
||||
const symbol: *Symbol = symbol: {
|
||||
if (Symbol.isSect(sym)) {
|
||||
const linkage: Symbol.Regular.Linkage = linkage: {
|
||||
if (!Symbol.isExt(sym)) break :linkage .translation_unit;
|
||||
if (Symbol.isWeakDef(sym) or Symbol.isPext(sym)) break :linkage .linkage_unit;
|
||||
break :linkage .global;
|
||||
};
|
||||
const regular = try self.allocator.create(Symbol.Regular);
|
||||
errdefer self.allocator.destroy(regular);
|
||||
regular.* = .{
|
||||
.base = .{
|
||||
.@"type" = .regular,
|
||||
.name = name,
|
||||
},
|
||||
.linkage = linkage,
|
||||
.address = sym.n_value,
|
||||
.section = sym.n_sect - 1,
|
||||
.weak_ref = Symbol.isWeakRef(sym),
|
||||
.file = self,
|
||||
};
|
||||
break :symbol ®ular.base;
|
||||
}
|
||||
|
||||
const undef = try self.allocator.create(Symbol.Unresolved);
|
||||
errdefer self.allocator.destroy(undef);
|
||||
undef.* = .{
|
||||
.base = .{
|
||||
.@"type" = .unresolved,
|
||||
.name = name,
|
||||
},
|
||||
.file = self,
|
||||
};
|
||||
break :symbol &undef.base;
|
||||
};
|
||||
|
||||
try self.symbols.append(self.allocator, symbol);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,38 +418,31 @@ pub fn parseDebugInfo(self: *Object) !void {
|
||||
break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000));
|
||||
};
|
||||
|
||||
for (self.locals.items()) |entry, index| {
|
||||
const local = entry.value;
|
||||
const source_sym = self.symtab.items[local.index.?];
|
||||
const size = blk: for (debug_info.inner.func_list.items) |func| {
|
||||
if (func.pc_range) |range| {
|
||||
if (source_sym.n_value >= range.start and source_sym.n_value < range.end) {
|
||||
break :blk range.end - range.start;
|
||||
for (self.symbols.items) |sym| {
|
||||
if (sym.cast(Symbol.Regular)) |reg| {
|
||||
const size: u64 = blk: for (debug_info.inner.func_list.items) |func| {
|
||||
if (func.pc_range) |range| {
|
||||
if (reg.address >= range.start and reg.address < range.end) {
|
||||
break :blk range.end - range.start;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else null;
|
||||
const tag: Stab.Tag = tag: {
|
||||
if (size != null) break :tag .function;
|
||||
switch (local.tag) {
|
||||
.weak, .strong => break :tag .global,
|
||||
else => break :tag .static,
|
||||
}
|
||||
};
|
||||
} else 0;
|
||||
|
||||
try self.stabs.append(self.allocator, .{
|
||||
.tag = tag,
|
||||
.size = size,
|
||||
.symbol = @intCast(u32, index),
|
||||
});
|
||||
reg.stab = .{
|
||||
.kind = kind: {
|
||||
if (size > 0) break :kind .function;
|
||||
switch (reg.linkage) {
|
||||
.translation_unit => break :kind .static,
|
||||
else => break :kind .global,
|
||||
}
|
||||
},
|
||||
.size = size,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getString(self: *const Object, str_off: u32) []const u8 {
|
||||
assert(str_off < self.strtab.items.len);
|
||||
return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + str_off));
|
||||
}
|
||||
|
||||
pub fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 {
|
||||
fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 {
|
||||
const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
|
||||
const sect = seg.sections.items[index];
|
||||
var buffer = try allocator.alloc(u8, sect.size);
|
||||
@@ -468,7 +450,7 @@ pub fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
pub fn readDataInCode(self: *Object) !void {
|
||||
pub fn parseDataInCode(self: *Object) !void {
|
||||
const index = self.data_in_code_cmd_index orelse return;
|
||||
const data_in_code = self.load_commands.items[index].LinkeditData;
|
||||
|
||||
|
||||
+101
-30
@@ -2,31 +2,113 @@ const Symbol = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Allocator = mem.Allocator;
|
||||
const Object = @import("Object.zig");
|
||||
|
||||
pub const Tag = enum {
|
||||
local,
|
||||
weak,
|
||||
strong,
|
||||
import,
|
||||
undef,
|
||||
pub const Type = enum {
|
||||
regular,
|
||||
proxy,
|
||||
unresolved,
|
||||
};
|
||||
|
||||
tag: Tag,
|
||||
/// Symbol type.
|
||||
@"type": Type,
|
||||
|
||||
/// Symbol name. Owned slice.
|
||||
name: []u8,
|
||||
address: u64,
|
||||
section: u8,
|
||||
|
||||
/// Index of file where to locate this symbol.
|
||||
/// Depending on context, this is either an object file, or a dylib.
|
||||
file: ?u16 = null,
|
||||
/// Alias of.
|
||||
alias: ?*Symbol = null,
|
||||
|
||||
/// Index of this symbol within the file's symbol table.
|
||||
index: ?u32 = null,
|
||||
/// Index in GOT table for indirection.
|
||||
got_index: ?u32 = null,
|
||||
|
||||
pub fn deinit(self: *Symbol, allocator: *Allocator) void {
|
||||
allocator.free(self.name);
|
||||
/// Index in stubs table for late binding.
|
||||
stubs_index: ?u32 = null,
|
||||
|
||||
pub const Regular = struct {
|
||||
base: Symbol,
|
||||
|
||||
/// Linkage type.
|
||||
linkage: Linkage,
|
||||
|
||||
/// Symbol address.
|
||||
address: u64,
|
||||
|
||||
/// Section ID where the symbol resides.
|
||||
section: u8,
|
||||
|
||||
/// Whether the symbol is a weak ref.
|
||||
weak_ref: bool,
|
||||
|
||||
/// File where to locate this symbol.
|
||||
file: *Object,
|
||||
|
||||
/// Debug stab if defined.
|
||||
stab: ?struct {
|
||||
/// Stab kind
|
||||
kind: enum {
|
||||
function,
|
||||
global,
|
||||
static,
|
||||
},
|
||||
|
||||
/// Size of the stab.
|
||||
size: u64,
|
||||
} = null,
|
||||
|
||||
pub const base_type: Symbol.Type = .regular;
|
||||
|
||||
pub const Linkage = enum {
|
||||
translation_unit,
|
||||
linkage_unit,
|
||||
global,
|
||||
};
|
||||
|
||||
pub fn isTemp(regular: *Regular) bool {
|
||||
if (regular.linkage == .translation_unit) {
|
||||
return mem.startsWith(u8, regular.base.name, "l") or mem.startsWith(u8, regular.base.name, "L");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Proxy = struct {
|
||||
base: Symbol,
|
||||
|
||||
/// Dylib ordinal.
|
||||
dylib: u16,
|
||||
|
||||
pub const base_type: Symbol.Type = .proxy;
|
||||
};
|
||||
|
||||
pub const Unresolved = struct {
|
||||
base: Symbol,
|
||||
|
||||
/// File where this symbol was referenced.
|
||||
file: *Object,
|
||||
|
||||
pub const base_type: Symbol.Type = .unresolved;
|
||||
};
|
||||
|
||||
pub fn deinit(base: *Symbol, allocator: *Allocator) void {
|
||||
allocator.free(base.name);
|
||||
}
|
||||
|
||||
pub fn cast(base: *Symbol, comptime T: type) ?*T {
|
||||
if (base.@"type" != T.base_type) {
|
||||
return null;
|
||||
}
|
||||
return @fieldParentPtr(T, "base", base);
|
||||
}
|
||||
|
||||
pub fn getTopmostAlias(base: *Symbol) *Symbol {
|
||||
if (base.alias) |alias| {
|
||||
return alias.getTopmostAlias();
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
pub fn isStab(sym: macho.nlist_64) bool {
|
||||
@@ -55,17 +137,6 @@ pub fn isWeakDef(sym: macho.nlist_64) bool {
|
||||
return (sym.n_desc & macho.N_WEAK_DEF) != 0;
|
||||
}
|
||||
|
||||
/// Symbol is local if it is defined and not an extern.
|
||||
pub fn isLocal(sym: macho.nlist_64) bool {
|
||||
return isSect(sym) and !isExt(sym);
|
||||
}
|
||||
|
||||
/// Symbol is global if it is defined and an extern.
|
||||
pub fn isGlobal(sym: macho.nlist_64) bool {
|
||||
return isSect(sym) and isExt(sym);
|
||||
}
|
||||
|
||||
/// Symbol is undefined if it is not defined and an extern.
|
||||
pub fn isUndef(sym: macho.nlist_64) bool {
|
||||
return isUndf(sym) and isExt(sym);
|
||||
pub fn isWeakRef(sym: macho.nlist_64) bool {
|
||||
return (sym.n_desc & macho.N_WEAK_REF) != 0;
|
||||
}
|
||||
|
||||
+421
-447
@@ -29,8 +29,8 @@ page_size: ?u16 = null,
|
||||
file: ?fs.File = null,
|
||||
out_path: ?[]const u8 = null,
|
||||
|
||||
objects: std.ArrayListUnmanaged(Object) = .{},
|
||||
archives: std.ArrayListUnmanaged(Archive) = .{},
|
||||
objects: std.ArrayListUnmanaged(*Object) = .{},
|
||||
archives: std.ArrayListUnmanaged(*Archive) = .{},
|
||||
|
||||
load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
|
||||
|
||||
@@ -58,6 +58,7 @@ stubs_section_index: ?u16 = null,
|
||||
stub_helper_section_index: ?u16 = null,
|
||||
text_const_section_index: ?u16 = null,
|
||||
cstring_section_index: ?u16 = null,
|
||||
ustring_section_index: ?u16 = null,
|
||||
|
||||
// __DATA_CONST segment sections
|
||||
got_section_index: ?u16 = null,
|
||||
@@ -74,30 +75,23 @@ data_section_index: ?u16 = null,
|
||||
bss_section_index: ?u16 = null,
|
||||
common_section_index: ?u16 = null,
|
||||
|
||||
symtab: std.StringArrayHashMapUnmanaged(Symbol) = .{},
|
||||
globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
|
||||
imports: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
|
||||
unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
|
||||
|
||||
strtab: std.ArrayListUnmanaged(u8) = .{},
|
||||
strtab_dir: std.StringHashMapUnmanaged(u32) = .{},
|
||||
|
||||
threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},
|
||||
local_rebases: std.ArrayListUnmanaged(Pointer) = .{},
|
||||
stubs: std.StringArrayHashMapUnmanaged(u32) = .{},
|
||||
got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{},
|
||||
stubs: std.ArrayListUnmanaged(*Symbol) = .{},
|
||||
got_entries: std.ArrayListUnmanaged(*Symbol) = .{},
|
||||
|
||||
stub_helper_stubs_start_off: ?u64 = null,
|
||||
|
||||
mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},
|
||||
unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},
|
||||
|
||||
const GotEntry = struct {
|
||||
tag: enum {
|
||||
local,
|
||||
import,
|
||||
},
|
||||
index: u32,
|
||||
target_addr: u64,
|
||||
file: u16,
|
||||
};
|
||||
|
||||
const MappingKey = struct {
|
||||
object_id: u16,
|
||||
source_sect_id: u16,
|
||||
@@ -124,15 +118,7 @@ pub fn init(allocator: *Allocator) Zld {
|
||||
pub fn deinit(self: *Zld) void {
|
||||
self.threadlocal_offsets.deinit(self.allocator);
|
||||
self.local_rebases.deinit(self.allocator);
|
||||
|
||||
for (self.stubs.items()) |entry| {
|
||||
self.allocator.free(entry.key);
|
||||
}
|
||||
self.stubs.deinit(self.allocator);
|
||||
|
||||
for (self.got_entries.items()) |entry| {
|
||||
self.allocator.free(entry.key);
|
||||
}
|
||||
self.got_entries.deinit(self.allocator);
|
||||
|
||||
for (self.load_commands.items) |*lc| {
|
||||
@@ -140,23 +126,22 @@ pub fn deinit(self: *Zld) void {
|
||||
}
|
||||
self.load_commands.deinit(self.allocator);
|
||||
|
||||
for (self.objects.items) |*object| {
|
||||
for (self.objects.items) |object| {
|
||||
object.deinit();
|
||||
self.allocator.destroy(object);
|
||||
}
|
||||
self.objects.deinit(self.allocator);
|
||||
|
||||
for (self.archives.items) |*archive| {
|
||||
for (self.archives.items) |archive| {
|
||||
archive.deinit();
|
||||
self.allocator.destroy(archive);
|
||||
}
|
||||
self.archives.deinit(self.allocator);
|
||||
|
||||
self.mappings.deinit(self.allocator);
|
||||
self.unhandled_sections.deinit(self.allocator);
|
||||
|
||||
for (self.symtab.items()) |*entry| {
|
||||
entry.value.deinit(self.allocator);
|
||||
}
|
||||
self.symtab.deinit(self.allocator);
|
||||
self.globals.deinit(self.allocator);
|
||||
self.strtab.deinit(self.allocator);
|
||||
|
||||
{
|
||||
@@ -224,10 +209,6 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
|
||||
try self.allocateDataSegment();
|
||||
self.allocateLinkeditSegment();
|
||||
try self.allocateSymbols();
|
||||
try self.allocateStubsAndGotEntries();
|
||||
try self.allocateCppStatics();
|
||||
try self.writeStubHelperCommon();
|
||||
try self.resolveRelocsAndWriteSections();
|
||||
try self.flush();
|
||||
}
|
||||
|
||||
@@ -291,7 +272,10 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
for (classified.items) |input| {
|
||||
switch (input.kind) {
|
||||
.object => {
|
||||
var object = Object.init(self.allocator);
|
||||
const object = try self.allocator.create(Object);
|
||||
errdefer self.allocator.destroy(object);
|
||||
|
||||
object.* = Object.init(self.allocator);
|
||||
object.arch = self.arch.?;
|
||||
object.name = try self.allocator.dupe(u8, input.name);
|
||||
object.file = input.file;
|
||||
@@ -299,7 +283,10 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
try self.objects.append(self.allocator, object);
|
||||
},
|
||||
.archive => {
|
||||
var archive = Archive.init(self.allocator);
|
||||
const archive = try self.allocator.create(Archive);
|
||||
errdefer self.allocator.destroy(archive);
|
||||
|
||||
archive.* = Archive.init(self.allocator);
|
||||
archive.arch = self.arch.?;
|
||||
archive.name = try self.allocator.dupe(u8, input.name);
|
||||
archive.file = input.file;
|
||||
@@ -367,23 +354,43 @@ fn updateMetadata(self: *Zld) !void {
|
||||
switch (flags) {
|
||||
macho.S_REGULAR, macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
|
||||
if (mem.eql(u8, segname, "__TEXT")) {
|
||||
if (self.text_const_section_index != null) continue;
|
||||
if (mem.eql(u8, sectname, "__ustring")) {
|
||||
if (self.ustring_section_index != null) continue;
|
||||
|
||||
self.text_const_section_index = @intCast(u16, text_seg.sections.items.len);
|
||||
try text_seg.addSection(self.allocator, .{
|
||||
.sectname = makeStaticString("__const"),
|
||||
.segname = makeStaticString("__TEXT"),
|
||||
.addr = 0,
|
||||
.size = 0,
|
||||
.offset = 0,
|
||||
.@"align" = 0,
|
||||
.reloff = 0,
|
||||
.nreloc = 0,
|
||||
.flags = macho.S_REGULAR,
|
||||
.reserved1 = 0,
|
||||
.reserved2 = 0,
|
||||
.reserved3 = 0,
|
||||
});
|
||||
self.ustring_section_index = @intCast(u16, text_seg.sections.items.len);
|
||||
try text_seg.addSection(self.allocator, .{
|
||||
.sectname = makeStaticString("__ustring"),
|
||||
.segname = makeStaticString("__TEXT"),
|
||||
.addr = 0,
|
||||
.size = 0,
|
||||
.offset = 0,
|
||||
.@"align" = 0,
|
||||
.reloff = 0,
|
||||
.nreloc = 0,
|
||||
.flags = macho.S_REGULAR,
|
||||
.reserved1 = 0,
|
||||
.reserved2 = 0,
|
||||
.reserved3 = 0,
|
||||
});
|
||||
} else {
|
||||
if (self.text_const_section_index != null) continue;
|
||||
|
||||
self.text_const_section_index = @intCast(u16, text_seg.sections.items.len);
|
||||
try text_seg.addSection(self.allocator, .{
|
||||
.sectname = makeStaticString("__const"),
|
||||
.segname = makeStaticString("__TEXT"),
|
||||
.addr = 0,
|
||||
.size = 0,
|
||||
.offset = 0,
|
||||
.@"align" = 0,
|
||||
.reloff = 0,
|
||||
.nreloc = 0,
|
||||
.flags = macho.S_REGULAR,
|
||||
.reserved1 = 0,
|
||||
.reserved2 = 0,
|
||||
.reserved3 = 0,
|
||||
});
|
||||
}
|
||||
} else if (mem.eql(u8, segname, "__DATA")) {
|
||||
if (!mem.eql(u8, sectname, "__const")) continue;
|
||||
if (self.data_const_section_index != null) continue;
|
||||
@@ -599,6 +606,50 @@ fn updateMetadata(self: *Zld) !void {
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
tlv_align: {
|
||||
const has_tlv =
|
||||
self.tlv_section_index != null or
|
||||
self.tlv_data_section_index != null or
|
||||
self.tlv_bss_section_index != null;
|
||||
|
||||
if (!has_tlv) break :tlv_align;
|
||||
|
||||
const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
|
||||
|
||||
if (self.tlv_section_index) |index| {
|
||||
const sect = &seg.sections.items[index];
|
||||
sect.@"align" = 3; // __thread_vars is always 8byte aligned
|
||||
}
|
||||
|
||||
// Apparently __tlv_data and __tlv_bss need to have matching alignment, so fix it up.
|
||||
// <rdar://problem/24221680> All __thread_data and __thread_bss sections must have same alignment
|
||||
// https://github.com/apple-opensource/ld64/blob/e28c028b20af187a16a7161d89e91868a450cadc/src/ld/ld.cpp#L1172
|
||||
const data_align: u32 = data: {
|
||||
if (self.tlv_data_section_index) |index| {
|
||||
const sect = &seg.sections.items[index];
|
||||
break :data sect.@"align";
|
||||
}
|
||||
break :tlv_align;
|
||||
};
|
||||
const bss_align: u32 = bss: {
|
||||
if (self.tlv_bss_section_index) |index| {
|
||||
const sect = &seg.sections.items[index];
|
||||
break :bss sect.@"align";
|
||||
}
|
||||
break :tlv_align;
|
||||
};
|
||||
const max_align = math.max(data_align, bss_align);
|
||||
|
||||
if (self.tlv_data_section_index) |index| {
|
||||
const sect = &seg.sections.items[index];
|
||||
sect.@"align" = max_align;
|
||||
}
|
||||
if (self.tlv_bss_section_index) |index| {
|
||||
const sect = &seg.sections.items[index];
|
||||
sect.@"align" = max_align;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const MatchingSection = struct {
|
||||
@@ -674,10 +725,17 @@ fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection {
|
||||
},
|
||||
macho.S_REGULAR => {
|
||||
if (mem.eql(u8, segname, "__TEXT")) {
|
||||
break :blk .{
|
||||
.seg = self.text_segment_cmd_index.?,
|
||||
.sect = self.text_const_section_index.?,
|
||||
};
|
||||
if (mem.eql(u8, sectname, "__ustring")) {
|
||||
break :blk .{
|
||||
.seg = self.text_segment_cmd_index.?,
|
||||
.sect = self.ustring_section_index.?,
|
||||
};
|
||||
} else {
|
||||
break :blk .{
|
||||
.seg = self.text_segment_cmd_index.?,
|
||||
.sect = self.text_const_section_index.?,
|
||||
};
|
||||
}
|
||||
} else if (mem.eql(u8, segname, "__DATA")) {
|
||||
if (mem.eql(u8, sectname, "__data")) {
|
||||
break :blk .{
|
||||
@@ -723,6 +781,7 @@ fn sortSections(self: *Zld) !void {
|
||||
&self.stub_helper_section_index,
|
||||
&self.text_const_section_index,
|
||||
&self.cstring_section_index,
|
||||
&self.ustring_section_index,
|
||||
};
|
||||
for (indices) |maybe_index| {
|
||||
const new_index: u16 = if (maybe_index.*) |index| blk: {
|
||||
@@ -805,7 +864,7 @@ fn sortSections(self: *Zld) !void {
|
||||
|
||||
fn allocateTextSegment(self: *Zld) !void {
|
||||
const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
|
||||
const nstubs = @intCast(u32, self.stubs.items().len);
|
||||
const nstubs = @intCast(u32, self.stubs.items.len);
|
||||
|
||||
const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
|
||||
seg.inner.fileoff = 0;
|
||||
@@ -856,7 +915,7 @@ fn allocateTextSegment(self: *Zld) !void {
|
||||
|
||||
fn allocateDataConstSegment(self: *Zld) !void {
|
||||
const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
|
||||
const nentries = @intCast(u32, self.got_entries.items().len);
|
||||
const nentries = @intCast(u32, self.got_entries.items.len);
|
||||
|
||||
const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
|
||||
seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;
|
||||
@@ -871,7 +930,7 @@ fn allocateDataConstSegment(self: *Zld) !void {
|
||||
|
||||
fn allocateDataSegment(self: *Zld) !void {
|
||||
const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
|
||||
const nstubs = @intCast(u32, self.stubs.items().len);
|
||||
const nstubs = @intCast(u32, self.stubs.items.len);
|
||||
|
||||
const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
|
||||
seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize;
|
||||
@@ -914,95 +973,46 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void {
|
||||
}
|
||||
|
||||
fn allocateSymbols(self: *Zld) !void {
|
||||
for (self.objects.items) |*object, object_id| {
|
||||
for (object.locals.items()) |*entry| {
|
||||
const source_sym = object.symtab.items[entry.value.index.?];
|
||||
const source_sect_id = source_sym.n_sect - 1;
|
||||
for (self.objects.items) |object, object_id| {
|
||||
for (object.symbols.items) |sym| {
|
||||
const reg = sym.cast(Symbol.Regular) orelse continue;
|
||||
|
||||
// TODO I am more and more convinced we should store the mapping as part of the Object struct.
|
||||
const target_mapping = self.mappings.get(.{
|
||||
.object_id = @intCast(u16, object_id),
|
||||
.source_sect_id = source_sect_id,
|
||||
.source_sect_id = reg.section,
|
||||
}) orelse {
|
||||
if (self.unhandled_sections.get(.{
|
||||
.object_id = @intCast(u16, object_id),
|
||||
.source_sect_id = source_sect_id,
|
||||
.source_sect_id = reg.section,
|
||||
}) != null) continue;
|
||||
|
||||
log.err("section not mapped for symbol '{s}'", .{entry.value.name});
|
||||
log.err("section not mapped for symbol '{s}'", .{sym.name});
|
||||
return error.SectionNotMappedForSymbol;
|
||||
};
|
||||
|
||||
const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
|
||||
const source_sect = source_seg.sections.items[source_sect_id];
|
||||
const source_sect = source_seg.sections.items[reg.section];
|
||||
const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;
|
||||
const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
|
||||
const target_addr = target_sect.addr + target_mapping.offset;
|
||||
const n_value = source_sym.n_value - source_sect.addr + target_addr;
|
||||
const address = reg.address - source_sect.addr + target_addr;
|
||||
|
||||
log.debug("resolving local symbol '{s}' at 0x{x}", .{ entry.value.name, n_value });
|
||||
log.debug("resolving symbol '{s}' at 0x{x}", .{ sym.name, address });
|
||||
|
||||
// TODO there might be a more generic way of doing this.
|
||||
var n_sect: u8 = 0;
|
||||
var section: u8 = 0;
|
||||
for (self.load_commands.items) |cmd, cmd_id| {
|
||||
if (cmd != .Segment) break;
|
||||
if (cmd_id == target_mapping.target_seg_id) {
|
||||
n_sect += @intCast(u8, target_mapping.target_sect_id) + 1;
|
||||
section += @intCast(u8, target_mapping.target_sect_id) + 1;
|
||||
break;
|
||||
}
|
||||
n_sect += @intCast(u8, cmd.Segment.sections.items.len);
|
||||
section += @intCast(u8, cmd.Segment.sections.items.len);
|
||||
}
|
||||
|
||||
entry.value.address = n_value;
|
||||
entry.value.section = n_sect;
|
||||
}
|
||||
}
|
||||
|
||||
for (self.symtab.items()) |*entry| {
|
||||
if (entry.value.tag == .import) continue;
|
||||
|
||||
const object_id = entry.value.file orelse unreachable;
|
||||
const object = self.objects.items[object_id];
|
||||
const local = object.locals.get(entry.key) orelse unreachable;
|
||||
|
||||
log.debug("resolving {} symbol '{s}' at 0x{x}", .{ entry.value.tag, entry.key, local.address });
|
||||
|
||||
entry.value.address = local.address;
|
||||
entry.value.section = local.section;
|
||||
}
|
||||
}
|
||||
|
||||
fn allocateStubsAndGotEntries(self: *Zld) !void {
|
||||
for (self.got_entries.items()) |*entry| {
|
||||
if (entry.value.tag == .import) continue;
|
||||
|
||||
const object = self.objects.items[entry.value.file];
|
||||
entry.value.target_addr = target_addr: {
|
||||
if (object.locals.get(entry.key)) |local| {
|
||||
break :target_addr local.address;
|
||||
}
|
||||
const global = self.symtab.get(entry.key) orelse unreachable;
|
||||
break :target_addr global.address;
|
||||
};
|
||||
|
||||
log.debug("resolving GOT entry '{s}' at 0x{x}", .{
|
||||
entry.key,
|
||||
entry.value.target_addr,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn allocateCppStatics(self: *Zld) !void {
|
||||
for (self.objects.items) |*object| {
|
||||
for (object.initializers.items) |*initializer| {
|
||||
const sym = object.symtab.items[initializer.symbol];
|
||||
const sym_name = object.getString(sym.n_strx);
|
||||
initializer.target_addr = object.locals.get(sym_name).?.address;
|
||||
|
||||
log.debug("resolving C++ initializer '{s}' at 0x{x}", .{
|
||||
sym_name,
|
||||
initializer.target_addr,
|
||||
});
|
||||
reg.address = address;
|
||||
reg.section = section;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1037,8 +1047,8 @@ fn writeStubHelperCommon(self: *Zld) !void {
|
||||
code[9] = 0xff;
|
||||
code[10] = 0x25;
|
||||
{
|
||||
const dyld_stub_binder = self.got_entries.get("dyld_stub_binder").?;
|
||||
const addr = (got.addr + dyld_stub_binder.index * @sizeOf(u64));
|
||||
const dyld_stub_binder = self.imports.get("dyld_stub_binder").?;
|
||||
const addr = (got.addr + dyld_stub_binder.got_index.? * @sizeOf(u64));
|
||||
const displacement = try math.cast(u32, addr - stub_helper.addr - code_size);
|
||||
mem.writeIntLittle(u32, code[11..], displacement);
|
||||
}
|
||||
@@ -1081,9 +1091,9 @@ fn writeStubHelperCommon(self: *Zld) !void {
|
||||
code[10] = 0xbf;
|
||||
code[11] = 0xa9;
|
||||
binder_blk_outer: {
|
||||
const dyld_stub_binder = self.got_entries.get("dyld_stub_binder").?;
|
||||
const dyld_stub_binder = self.imports.get("dyld_stub_binder").?;
|
||||
const this_addr = stub_helper.addr + 3 * @sizeOf(u32);
|
||||
const target_addr = (got.addr + dyld_stub_binder.index * @sizeOf(u64));
|
||||
const target_addr = (got.addr + dyld_stub_binder.got_index.? * @sizeOf(u64));
|
||||
binder_blk: {
|
||||
const displacement = math.divExact(u64, target_addr - this_addr, 4) catch |_| break :binder_blk;
|
||||
const literal = math.cast(u18, displacement) catch |_| break :binder_blk;
|
||||
@@ -1134,8 +1144,9 @@ fn writeStubHelperCommon(self: *Zld) !void {
|
||||
}
|
||||
};
|
||||
|
||||
for (self.stubs.items()) |entry| {
|
||||
const index = entry.value;
|
||||
for (self.stubs.items) |sym| {
|
||||
// TODO weak bound pointers
|
||||
const index = sym.stubs_index orelse unreachable;
|
||||
try self.writeLazySymbolPointer(index);
|
||||
try self.writeStub(index);
|
||||
try self.writeStubInStubHelper(index);
|
||||
@@ -1274,145 +1285,154 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void {
|
||||
try self.file.?.pwriteAll(code, stub_off);
|
||||
}
|
||||
|
||||
fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void {
|
||||
const object = self.objects.items[object_id];
|
||||
fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
|
||||
log.debug("resolving symbols in '{s}'", .{object.name});
|
||||
|
||||
for (object.symtab.items) |sym, sym_id| {
|
||||
if (Symbol.isLocal(sym)) {
|
||||
// If symbol is local to CU, we don't put it in the global symbol table.
|
||||
continue;
|
||||
} else if (Symbol.isGlobal(sym)) {
|
||||
const sym_name = object.getString(sym.n_strx);
|
||||
const is_weak = Symbol.isWeakDef(sym) or Symbol.isPext(sym);
|
||||
const global = self.symtab.getEntry(sym_name) orelse {
|
||||
for (object.symbols.items) |sym| {
|
||||
if (sym.cast(Symbol.Regular)) |reg| {
|
||||
if (reg.linkage == .translation_unit) continue; // Symbol local to TU.
|
||||
|
||||
if (self.unresolved.swapRemove(sym.name)) |entry| {
|
||||
// Create link to the global.
|
||||
entry.value.alias = sym;
|
||||
}
|
||||
const entry = self.globals.getEntry(sym.name) orelse {
|
||||
// Put new global symbol into the symbol table.
|
||||
const name = try self.allocator.dupe(u8, sym_name);
|
||||
try self.symtab.putNoClobber(self.allocator, name, .{
|
||||
.tag = if (is_weak) .weak else .strong,
|
||||
.name = name,
|
||||
.address = 0,
|
||||
.section = 0,
|
||||
.file = object_id,
|
||||
.index = @intCast(u32, sym_id),
|
||||
});
|
||||
try self.globals.putNoClobber(self.allocator, sym.name, sym);
|
||||
continue;
|
||||
};
|
||||
const g_sym = entry.value;
|
||||
const g_reg = g_sym.cast(Symbol.Regular) orelse unreachable;
|
||||
|
||||
switch (global.value.tag) {
|
||||
.weak => {
|
||||
if (is_weak) continue; // Nothing to do for weak symbol.
|
||||
switch (g_reg.linkage) {
|
||||
.translation_unit => unreachable,
|
||||
.linkage_unit => {
|
||||
if (reg.linkage == .linkage_unit) {
|
||||
// Create link to the first encountered linkage_unit symbol.
|
||||
sym.alias = g_sym;
|
||||
continue;
|
||||
}
|
||||
},
|
||||
.strong => {
|
||||
if (!is_weak) {
|
||||
log.debug("strong symbol '{s}' defined multiple times", .{sym_name});
|
||||
.global => {
|
||||
if (reg.linkage == .global) {
|
||||
log.debug("symbol '{s}' defined multiple times", .{reg.base.name});
|
||||
return error.MultipleSymbolDefinitions;
|
||||
}
|
||||
sym.alias = g_sym;
|
||||
continue;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
global.value.tag = if (is_weak) .weak else .strong;
|
||||
global.value.file = object_id;
|
||||
global.value.index = @intCast(u32, sym_id);
|
||||
} else if (Symbol.isUndef(sym)) {
|
||||
const sym_name = object.getString(sym.n_strx);
|
||||
if (self.symtab.contains(sym_name)) continue; // Nothing to do if we already found a definition.
|
||||
|
||||
const name = try self.allocator.dupe(u8, sym_name);
|
||||
try self.symtab.putNoClobber(self.allocator, name, .{
|
||||
.tag = .undef,
|
||||
.name = name,
|
||||
.address = 0,
|
||||
.section = 0,
|
||||
});
|
||||
g_sym.alias = sym;
|
||||
entry.value = sym;
|
||||
} else if (sym.cast(Symbol.Unresolved)) |und| {
|
||||
if (self.globals.get(sym.name)) |g_sym| {
|
||||
sym.alias = g_sym;
|
||||
continue;
|
||||
}
|
||||
if (self.unresolved.get(sym.name)) |u_sym| {
|
||||
sym.alias = u_sym;
|
||||
continue;
|
||||
}
|
||||
try self.unresolved.putNoClobber(self.allocator, sym.name, sym);
|
||||
} else unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
fn resolveSymbols(self: *Zld) !void {
|
||||
// First pass, resolve symbols in provided objects.
|
||||
for (self.objects.items) |object, object_id| {
|
||||
try self.resolveSymbolsInObject(@intCast(u16, object_id));
|
||||
for (self.objects.items) |object| {
|
||||
try self.resolveSymbolsInObject(object);
|
||||
}
|
||||
|
||||
// Second pass, resolve symbols in static libraries.
|
||||
var next_sym: usize = 0;
|
||||
var nsyms: usize = self.symtab.items().len;
|
||||
while (next_sym < nsyms) : (next_sym += 1) {
|
||||
const sym = self.symtab.items()[next_sym];
|
||||
if (sym.value.tag != .undef) continue;
|
||||
while (true) {
|
||||
if (next_sym == self.unresolved.count()) break;
|
||||
|
||||
const sym_name = sym.value.name;
|
||||
const entry = self.unresolved.items()[next_sym];
|
||||
const sym = entry.value;
|
||||
|
||||
var reset: bool = false;
|
||||
for (self.archives.items) |archive| {
|
||||
// Check if the entry exists in a static archive.
|
||||
const offsets = archive.toc.get(sym_name) orelse {
|
||||
const offsets = archive.toc.get(sym.name) orelse {
|
||||
// No hit.
|
||||
continue;
|
||||
};
|
||||
assert(offsets.items.len > 0);
|
||||
|
||||
const object = try archive.parseObject(offsets.items[0]);
|
||||
const object_id = @intCast(u16, self.objects.items.len);
|
||||
try self.objects.append(self.allocator, object);
|
||||
try self.resolveSymbolsInObject(object_id);
|
||||
const object = try self.allocator.create(Object);
|
||||
errdefer self.allocator.destroy(object);
|
||||
|
||||
nsyms = self.symtab.items().len;
|
||||
object.* = try archive.parseObject(offsets.items[0]);
|
||||
try self.objects.append(self.allocator, object);
|
||||
try self.resolveSymbolsInObject(object);
|
||||
|
||||
reset = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (reset) {
|
||||
next_sym = 0;
|
||||
} else {
|
||||
next_sym += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Third pass, resolve symbols in dynamic libraries.
|
||||
// TODO Implement libSystem as a hard-coded library, or ship with
|
||||
// a libSystem.B.tbd definition file?
|
||||
for (self.symtab.items()) |*entry| {
|
||||
if (entry.value.tag != .undef) continue;
|
||||
try self.imports.ensureCapacity(self.allocator, self.unresolved.count());
|
||||
for (self.unresolved.items()) |entry| {
|
||||
const proxy = try self.allocator.create(Symbol.Proxy);
|
||||
errdefer self.allocator.destroy(proxy);
|
||||
|
||||
entry.value.tag = .import;
|
||||
entry.value.file = 0;
|
||||
proxy.* = .{
|
||||
.base = .{
|
||||
.@"type" = .proxy,
|
||||
.name = try self.allocator.dupe(u8, entry.key),
|
||||
},
|
||||
.dylib = 0,
|
||||
};
|
||||
|
||||
self.imports.putAssumeCapacityNoClobber(proxy.base.name, &proxy.base);
|
||||
entry.value.alias = &proxy.base;
|
||||
}
|
||||
self.unresolved.clearAndFree(self.allocator);
|
||||
|
||||
// If there are any undefs left, flag an error.
|
||||
var has_unresolved = false;
|
||||
for (self.symtab.items()) |entry| {
|
||||
if (entry.value.tag != .undef) continue;
|
||||
|
||||
has_unresolved = true;
|
||||
log.err("undefined reference to symbol '{s}'", .{entry.value.name});
|
||||
}
|
||||
if (has_unresolved) {
|
||||
if (self.unresolved.count() > 0) {
|
||||
for (self.unresolved.items()) |entry| {
|
||||
log.err("undefined reference to symbol '{s}'", .{entry.key});
|
||||
log.err(" | referenced in {s}", .{
|
||||
entry.value.cast(Symbol.Unresolved).?.file.name.?,
|
||||
});
|
||||
}
|
||||
return error.UndefinedSymbolReference;
|
||||
}
|
||||
|
||||
// Finally put dyld_stub_binder as an Import
|
||||
var name = try self.allocator.dupe(u8, "dyld_stub_binder");
|
||||
try self.symtab.putNoClobber(self.allocator, name, .{
|
||||
.tag = .import,
|
||||
.name = name,
|
||||
.address = 0,
|
||||
.section = 0,
|
||||
.file = 0,
|
||||
});
|
||||
const dyld_stub_binder = try self.allocator.create(Symbol.Proxy);
|
||||
errdefer self.allocator.destroy(dyld_stub_binder);
|
||||
|
||||
{
|
||||
log.debug("symtab", .{});
|
||||
for (self.symtab.items()) |sym| {
|
||||
switch (sym.value.tag) {
|
||||
.weak, .strong => {
|
||||
log.debug(" | {s} => {s}", .{ sym.key, self.objects.items[sym.value.file.?].name.? });
|
||||
},
|
||||
.import => {
|
||||
log.debug(" | {s} => libSystem.B.dylib", .{sym.key});
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
}
|
||||
dyld_stub_binder.* = .{
|
||||
.base = .{
|
||||
.@"type" = .proxy,
|
||||
.name = try self.allocator.dupe(u8, "dyld_stub_binder"),
|
||||
},
|
||||
.dylib = 0,
|
||||
};
|
||||
|
||||
try self.imports.putNoClobber(
|
||||
self.allocator,
|
||||
dyld_stub_binder.base.name,
|
||||
&dyld_stub_binder.base,
|
||||
);
|
||||
}
|
||||
|
||||
fn resolveStubsAndGotEntries(self: *Zld) !void {
|
||||
for (self.objects.items) |object, object_id| {
|
||||
for (self.objects.items) |object| {
|
||||
log.debug("resolving stubs and got entries from {s}", .{object.name});
|
||||
|
||||
for (object.sections.items) |sect| {
|
||||
@@ -1421,42 +1441,32 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
|
||||
switch (rel.@"type") {
|
||||
.unsigned => continue,
|
||||
.got_page, .got_page_off, .got_load, .got => {
|
||||
const sym = object.symtab.items[rel.target.symbol];
|
||||
const sym_name = object.getString(sym.n_strx);
|
||||
const sym = rel.target.symbol.getTopmostAlias();
|
||||
if (sym.got_index != null) continue;
|
||||
|
||||
if (self.got_entries.contains(sym_name)) continue;
|
||||
const index = @intCast(u32, self.got_entries.items.len);
|
||||
sym.got_index = index;
|
||||
try self.got_entries.append(self.allocator, sym);
|
||||
|
||||
// TODO clean this up
|
||||
const is_import = self.symtab.get(sym_name).?.tag == .import;
|
||||
var name = try self.allocator.dupe(u8, sym_name);
|
||||
const index = @intCast(u32, self.got_entries.items().len);
|
||||
try self.got_entries.putNoClobber(self.allocator, name, .{
|
||||
.tag = if (is_import) .import else .local,
|
||||
.index = index,
|
||||
.target_addr = 0,
|
||||
.file = if (is_import) 0 else @intCast(u16, object_id),
|
||||
});
|
||||
|
||||
log.debug(" | found GOT entry {s}: {}", .{ sym_name, self.got_entries.get(sym_name) });
|
||||
log.debug(" | found GOT entry {s}: {*}", .{ sym.name, sym });
|
||||
},
|
||||
else => {
|
||||
if (rel.target != .symbol) continue;
|
||||
|
||||
const sym = object.symtab.items[rel.target.symbol];
|
||||
const sym_name = object.getString(sym.n_strx);
|
||||
const sym = rel.target.symbol.getTopmostAlias();
|
||||
assert(sym.@"type" != .unresolved);
|
||||
|
||||
if (!Symbol.isUndef(sym)) continue;
|
||||
if (sym.stubs_index != null) continue;
|
||||
if (sym.@"type" != .proxy) continue;
|
||||
// if (sym.cast(Symbol.Regular)) |reg| {
|
||||
// if (!reg.weak_ref) continue;
|
||||
// }
|
||||
|
||||
const in_globals = self.symtab.get(sym_name) orelse unreachable;
|
||||
const index = @intCast(u32, self.stubs.items.len);
|
||||
sym.stubs_index = index;
|
||||
try self.stubs.append(self.allocator, sym);
|
||||
|
||||
if (in_globals.tag != .import) continue;
|
||||
if (self.stubs.contains(sym_name)) continue;
|
||||
|
||||
var name = try self.allocator.dupe(u8, sym_name);
|
||||
const index = @intCast(u32, self.stubs.items().len);
|
||||
try self.stubs.putNoClobber(self.allocator, name, index);
|
||||
|
||||
log.debug(" | found stub {s}: {}", .{ sym_name, self.stubs.get(sym_name) });
|
||||
log.debug(" | found stub {s}: {*}", .{ sym.name, sym });
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1464,16 +1474,12 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
|
||||
}
|
||||
|
||||
// Finally, put dyld_stub_binder as the final GOT entry
|
||||
var name = try self.allocator.dupe(u8, "dyld_stub_binder");
|
||||
const index = @intCast(u32, self.got_entries.items().len);
|
||||
try self.got_entries.putNoClobber(self.allocator, name, .{
|
||||
.tag = .import,
|
||||
.index = index,
|
||||
.target_addr = 0,
|
||||
.file = 0,
|
||||
});
|
||||
const sym = self.imports.get("dyld_stub_binder") orelse unreachable;
|
||||
const index = @intCast(u32, self.got_entries.items.len);
|
||||
sym.got_index = index;
|
||||
try self.got_entries.append(self.allocator, sym);
|
||||
|
||||
log.debug(" | found GOT entry dyld_stub_binder: {}", .{self.got_entries.get("dyld_stub_binder")});
|
||||
log.debug(" | found GOT entry {s}: {*}", .{ sym.name, sym });
|
||||
}
|
||||
|
||||
fn resolveRelocsAndWriteSections(self: *Zld) !void {
|
||||
@@ -1547,11 +1553,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
|
||||
// TLV is handled via a separate offset mechanism.
|
||||
// Calculate the offset to the initializer.
|
||||
if (target_sect.flags == macho.S_THREAD_LOCAL_VARIABLES) tlv: {
|
||||
const sym = object.symtab.items[rel.target.symbol];
|
||||
const sym_name = object.getString(sym.n_strx);
|
||||
|
||||
// TODO we don't want to save offset to tlv_bootstrap
|
||||
if (mem.eql(u8, sym_name, "__tlv_bootstrap")) break :tlv;
|
||||
if (mem.eql(u8, rel.target.symbol.name, "__tlv_bootstrap")) break :tlv;
|
||||
|
||||
const base_addr = blk: {
|
||||
if (self.tlv_data_section_index) |index| {
|
||||
@@ -1570,10 +1573,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
|
||||
.got_page, .got_page_off, .got_load, .got => {
|
||||
const dc_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
|
||||
const got = dc_seg.sections.items[self.got_section_index.?];
|
||||
const sym = object.symtab.items[rel.target.symbol];
|
||||
const sym_name = object.getString(sym.n_strx);
|
||||
const entry = self.got_entries.get(sym_name) orelse unreachable;
|
||||
args.target_addr = got.addr + entry.index * @sizeOf(u64);
|
||||
const final = rel.target.symbol.getTopmostAlias();
|
||||
args.target_addr = got.addr + final.got_index.? * @sizeOf(u64);
|
||||
},
|
||||
else => |tt| {
|
||||
if (tt == .signed and rel.target == .section) {
|
||||
@@ -1620,58 +1621,27 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
|
||||
}
|
||||
|
||||
fn relocTargetAddr(self: *Zld, object_id: u16, target: reloc.Relocation.Target) !u64 {
|
||||
const object = self.objects.items[object_id];
|
||||
const target_addr = blk: {
|
||||
switch (target) {
|
||||
.symbol => |sym_id| {
|
||||
const sym = object.symtab.items[sym_id];
|
||||
const sym_name = object.getString(sym.n_strx);
|
||||
|
||||
if (Symbol.isSect(sym)) {
|
||||
log.debug(" | local symbol '{s}'", .{sym_name});
|
||||
if (object.locals.get(sym_name)) |local| {
|
||||
break :blk local.address;
|
||||
.symbol => |sym| {
|
||||
const final = sym.getTopmostAlias();
|
||||
if (final.cast(Symbol.Regular)) |reg| {
|
||||
log.debug(" | regular '{s}'", .{sym.name});
|
||||
break :blk reg.address;
|
||||
} else if (final.cast(Symbol.Proxy)) |proxy| {
|
||||
if (mem.eql(u8, sym.name, "__tlv_bootstrap")) {
|
||||
log.debug(" | symbol '__tlv_bootstrap'", .{});
|
||||
const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
|
||||
const tlv = segment.sections.items[self.tlv_section_index.?];
|
||||
break :blk tlv.addr;
|
||||
}
|
||||
// For temp locals, i.e., symbols prefixed with l... we relocate
|
||||
// based on section addressing.
|
||||
const source_sect_id = sym.n_sect - 1;
|
||||
const target_mapping = self.mappings.get(.{
|
||||
.object_id = object_id,
|
||||
.source_sect_id = source_sect_id,
|
||||
}) orelse unreachable;
|
||||
|
||||
const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
|
||||
const source_sect = source_seg.sections.items[source_sect_id];
|
||||
const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;
|
||||
const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
|
||||
const target_addr = target_sect.addr + target_mapping.offset;
|
||||
break :blk sym.n_value - source_sect.addr + target_addr;
|
||||
} else if (self.symtab.get(sym_name)) |global| {
|
||||
switch (global.tag) {
|
||||
.weak, .strong => {
|
||||
log.debug(" | global symbol '{s}'", .{sym_name});
|
||||
break :blk global.address;
|
||||
},
|
||||
.import => {
|
||||
if (self.stubs.get(sym_name)) |index| {
|
||||
log.debug(" | symbol stub '{s}'", .{sym_name});
|
||||
const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
|
||||
const stubs = segment.sections.items[self.stubs_section_index.?];
|
||||
break :blk stubs.addr + index * stubs.reserved2;
|
||||
} else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) {
|
||||
log.debug(" | symbol '__tlv_bootstrap'", .{});
|
||||
const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
|
||||
const tlv = segment.sections.items[self.tlv_section_index.?];
|
||||
break :blk tlv.addr;
|
||||
} else {
|
||||
log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name});
|
||||
return error.FailedToResolveRelocationTarget;
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
log.debug(" | symbol stub '{s}'", .{sym.name});
|
||||
const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
|
||||
const stubs = segment.sections.items[self.stubs_section_index.?];
|
||||
break :blk stubs.addr + proxy.base.stubs_index.? * stubs.reserved2;
|
||||
} else {
|
||||
log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name});
|
||||
log.err("failed to resolve symbol '{s}' as a relocation target", .{sym.name});
|
||||
return error.FailedToResolveRelocationTarget;
|
||||
}
|
||||
},
|
||||
@@ -2091,6 +2061,9 @@ fn populateMetadata(self: *Zld) !void {
|
||||
}
|
||||
|
||||
fn flush(self: *Zld) !void {
|
||||
try self.writeStubHelperCommon();
|
||||
try self.resolveRelocsAndWriteSections();
|
||||
|
||||
if (self.common_section_index) |index| {
|
||||
const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
|
||||
const sect = &seg.sections.items[index];
|
||||
@@ -2136,10 +2109,10 @@ fn flush(self: *Zld) !void {
|
||||
var initializers = std.ArrayList(u64).init(self.allocator);
|
||||
defer initializers.deinit();
|
||||
|
||||
// TODO sort the initializers globally
|
||||
for (self.objects.items) |object| {
|
||||
for (object.initializers.items) |initializer| {
|
||||
try initializers.append(initializer.target_addr);
|
||||
const address = initializer.cast(Symbol.Regular).?.address;
|
||||
try initializers.append(address);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2193,14 +2166,15 @@ fn writeGotEntries(self: *Zld) !void {
|
||||
const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
|
||||
const sect = seg.sections.items[self.got_section_index.?];
|
||||
|
||||
var buffer = try self.allocator.alloc(u8, self.got_entries.items().len * @sizeOf(u64));
|
||||
var buffer = try self.allocator.alloc(u8, self.got_entries.items.len * @sizeOf(u64));
|
||||
defer self.allocator.free(buffer);
|
||||
|
||||
var stream = std.io.fixedBufferStream(buffer);
|
||||
var writer = stream.writer();
|
||||
|
||||
for (self.got_entries.items()) |entry| {
|
||||
try writer.writeIntLittle(u64, entry.value.target_addr);
|
||||
for (self.got_entries.items) |sym| {
|
||||
const address: u64 = if (sym.cast(Symbol.Regular)) |reg| reg.address else 0;
|
||||
try writer.writeIntLittle(u64, address);
|
||||
}
|
||||
|
||||
log.debug("writing GOT pointers at 0x{x} to 0x{x}", .{ sect.offset, sect.offset + buffer.len });
|
||||
@@ -2213,7 +2187,8 @@ fn setEntryPoint(self: *Zld) !void {
|
||||
// entrypoint. For now, assume default of `_main`.
|
||||
const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
|
||||
const text = seg.sections.items[self.text_section_index.?];
|
||||
const entry_sym = self.symtab.get("_main") orelse return error.MissingMainEntrypoint;
|
||||
const sym = self.globals.get("_main") orelse return error.MissingMainEntrypoint;
|
||||
const entry_sym = sym.cast(Symbol.Regular) orelse unreachable;
|
||||
const ec = &self.load_commands.items[self.main_cmd_index.?].Main;
|
||||
ec.entryoff = @intCast(u32, entry_sym.address - seg.inner.vmaddr);
|
||||
}
|
||||
@@ -2226,24 +2201,21 @@ fn writeRebaseInfoTable(self: *Zld) !void {
|
||||
pointers.appendSliceAssumeCapacity(self.local_rebases.items);
|
||||
|
||||
if (self.got_section_index) |idx| {
|
||||
// TODO this should be cleaned up!
|
||||
const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
|
||||
const sect = seg.sections.items[idx];
|
||||
const base_offset = sect.addr - seg.inner.vmaddr;
|
||||
const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
|
||||
|
||||
for (self.got_entries.items()) |entry| {
|
||||
if (entry.value.tag == .import) continue;
|
||||
|
||||
for (self.got_entries.items) |sym| {
|
||||
if (sym.@"type" == .proxy) continue;
|
||||
try pointers.append(.{
|
||||
.offset = base_offset + entry.value.index * @sizeOf(u64),
|
||||
.offset = base_offset + sym.got_index.? * @sizeOf(u64),
|
||||
.segment_id = segment_id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (self.mod_init_func_section_index) |idx| {
|
||||
// TODO audit and investigate this.
|
||||
const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
|
||||
const sect = seg.sections.items[idx];
|
||||
const base_offset = sect.addr - seg.inner.vmaddr;
|
||||
@@ -2267,10 +2239,10 @@ fn writeRebaseInfoTable(self: *Zld) !void {
|
||||
const base_offset = sect.addr - seg.inner.vmaddr;
|
||||
const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
|
||||
|
||||
try pointers.ensureCapacity(pointers.items.len + self.stubs.items().len);
|
||||
for (self.stubs.items()) |entry| {
|
||||
try pointers.ensureCapacity(pointers.items.len + self.stubs.items.len);
|
||||
for (self.stubs.items) |sym| {
|
||||
pointers.appendAssumeCapacity(.{
|
||||
.offset = base_offset + entry.value * @sizeOf(u64),
|
||||
.offset = base_offset + sym.stubs_index.? * @sizeOf(u64),
|
||||
.segment_id = segment_id,
|
||||
});
|
||||
}
|
||||
@@ -2306,21 +2278,16 @@ fn writeBindInfoTable(self: *Zld) !void {
|
||||
const base_offset = sect.addr - seg.inner.vmaddr;
|
||||
const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
|
||||
|
||||
for (self.got_entries.items()) |entry| {
|
||||
if (entry.value.tag == .local) continue;
|
||||
|
||||
const dylib_ordinal = dylib_ordinal: {
|
||||
const sym = self.symtab.get(entry.key) orelse continue; // local indirection
|
||||
if (sym.tag != .import) continue; // local indirection
|
||||
break :dylib_ordinal sym.file.? + 1;
|
||||
};
|
||||
|
||||
try pointers.append(.{
|
||||
.offset = base_offset + entry.value.index * @sizeOf(u64),
|
||||
.segment_id = segment_id,
|
||||
.dylib_ordinal = dylib_ordinal,
|
||||
.name = entry.key,
|
||||
});
|
||||
for (self.got_entries.items) |sym| {
|
||||
if (sym.cast(Symbol.Proxy)) |proxy| {
|
||||
const dylib_ordinal = proxy.dylib + 1;
|
||||
try pointers.append(.{
|
||||
.offset = base_offset + proxy.base.got_index.? * @sizeOf(u64),
|
||||
.segment_id = segment_id,
|
||||
.dylib_ordinal = dylib_ordinal,
|
||||
.name = proxy.base.name,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2330,14 +2297,15 @@ fn writeBindInfoTable(self: *Zld) !void {
|
||||
const base_offset = sect.addr - seg.inner.vmaddr;
|
||||
const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
|
||||
|
||||
const sym = self.symtab.get("__tlv_bootstrap") orelse unreachable;
|
||||
const dylib_ordinal = sym.file.? + 1;
|
||||
const sym = self.imports.get("__tlv_bootstrap") orelse unreachable;
|
||||
const proxy = sym.cast(Symbol.Proxy) orelse unreachable;
|
||||
const dylib_ordinal = proxy.dylib + 1;
|
||||
|
||||
try pointers.append(.{
|
||||
.offset = base_offset,
|
||||
.segment_id = segment_id,
|
||||
.dylib_ordinal = dylib_ordinal,
|
||||
.name = "__tlv_bootstrap",
|
||||
.name = proxy.base.name,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2369,20 +2337,16 @@ fn writeLazyBindInfoTable(self: *Zld) !void {
|
||||
const base_offset = sect.addr - seg.inner.vmaddr;
|
||||
const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
|
||||
|
||||
try pointers.ensureCapacity(self.stubs.items().len);
|
||||
|
||||
for (self.stubs.items()) |entry| {
|
||||
const dylib_ordinal = dylib_ordinal: {
|
||||
const sym = self.symtab.get(entry.key) orelse unreachable;
|
||||
assert(sym.tag == .import);
|
||||
break :dylib_ordinal sym.file.? + 1;
|
||||
};
|
||||
try pointers.ensureCapacity(self.stubs.items.len);
|
||||
|
||||
for (self.stubs.items) |sym| {
|
||||
const proxy = sym.cast(Symbol.Proxy) orelse unreachable;
|
||||
const dylib_ordinal = proxy.dylib + 1;
|
||||
pointers.appendAssumeCapacity(.{
|
||||
.offset = base_offset + entry.value * @sizeOf(u64),
|
||||
.offset = base_offset + sym.stubs_index.? * @sizeOf(u64),
|
||||
.segment_id = segment_id,
|
||||
.dylib_ordinal = dylib_ordinal,
|
||||
.name = entry.key,
|
||||
.name = sym.name,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2451,7 +2415,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void {
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
assert(self.stubs.items().len <= offsets.items.len);
|
||||
assert(self.stubs.items.len <= offsets.items.len);
|
||||
|
||||
const stub_size: u4 = switch (self.arch.?) {
|
||||
.x86_64 => 10,
|
||||
@@ -2464,9 +2428,10 @@ fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void {
|
||||
else => unreachable,
|
||||
};
|
||||
var buf: [@sizeOf(u32)]u8 = undefined;
|
||||
for (self.stubs.items()) |entry| {
|
||||
const placeholder_off = self.stub_helper_stubs_start_off.? + entry.value * stub_size + off;
|
||||
mem.writeIntLittle(u32, &buf, offsets.items[entry.value]);
|
||||
for (self.stubs.items) |sym| {
|
||||
const index = sym.stubs_index orelse unreachable;
|
||||
const placeholder_off = self.stub_helper_stubs_start_off.? + index * stub_size + off;
|
||||
mem.writeIntLittle(u32, &buf, offsets.items[index]);
|
||||
try self.file.?.pwriteAll(&buf, placeholder_off);
|
||||
}
|
||||
}
|
||||
@@ -2478,12 +2443,13 @@ fn writeExportInfo(self: *Zld) !void {
|
||||
const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
|
||||
|
||||
// TODO export items for dylibs
|
||||
const sym = self.symtab.get("_main") orelse return error.MissingMainEntrypoint;
|
||||
assert(sym.address >= text_segment.inner.vmaddr);
|
||||
const sym = self.globals.get("_main") orelse return error.MissingMainEntrypoint;
|
||||
const reg = sym.cast(Symbol.Regular) orelse unreachable;
|
||||
assert(reg.address >= text_segment.inner.vmaddr);
|
||||
|
||||
try trie.put(.{
|
||||
.name = "_main",
|
||||
.vmaddr_offset = sym.address - text_segment.inner.vmaddr,
|
||||
.name = sym.name,
|
||||
.vmaddr_offset = reg.address - text_segment.inner.vmaddr,
|
||||
.export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
|
||||
});
|
||||
|
||||
@@ -2511,7 +2477,7 @@ fn writeDebugInfo(self: *Zld) !void {
|
||||
var stabs = std.ArrayList(macho.nlist_64).init(self.allocator);
|
||||
defer stabs.deinit();
|
||||
|
||||
for (self.objects.items) |object, object_id| {
|
||||
for (self.objects.items) |object| {
|
||||
const tu_path = object.tu_path orelse continue;
|
||||
const tu_mtime = object.tu_mtime orelse continue;
|
||||
const dirname = std.fs.path.dirname(tu_path) orelse "./";
|
||||
@@ -2540,39 +2506,42 @@ fn writeDebugInfo(self: *Zld) !void {
|
||||
.n_value = 0, //tu_mtime, TODO figure out why precalculated mtime value doesn't work
|
||||
});
|
||||
|
||||
for (object.stabs.items) |stab| {
|
||||
const entry = object.locals.items()[stab.symbol];
|
||||
const sym = entry.value;
|
||||
for (object.symbols.items) |sym| {
|
||||
if (sym.@"type" != .regular) continue;
|
||||
const reg = sym.cast(Symbol.Regular) orelse unreachable;
|
||||
|
||||
switch (stab.tag) {
|
||||
if (reg.isTemp() or reg.stab == null) continue;
|
||||
const stab = reg.stab orelse unreachable;
|
||||
|
||||
switch (stab.kind) {
|
||||
.function => {
|
||||
try stabs.append(.{
|
||||
.n_strx = 0,
|
||||
.n_type = macho.N_BNSYM,
|
||||
.n_sect = sym.section,
|
||||
.n_sect = reg.section,
|
||||
.n_desc = 0,
|
||||
.n_value = sym.address,
|
||||
.n_value = reg.address,
|
||||
});
|
||||
try stabs.append(.{
|
||||
.n_strx = try self.makeString(sym.name),
|
||||
.n_type = macho.N_FUN,
|
||||
.n_sect = sym.section,
|
||||
.n_sect = reg.section,
|
||||
.n_desc = 0,
|
||||
.n_value = sym.address,
|
||||
.n_value = reg.address,
|
||||
});
|
||||
try stabs.append(.{
|
||||
.n_strx = 0,
|
||||
.n_type = macho.N_FUN,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = stab.size.?,
|
||||
.n_value = stab.size,
|
||||
});
|
||||
try stabs.append(.{
|
||||
.n_strx = 0,
|
||||
.n_type = macho.N_ENSYM,
|
||||
.n_sect = sym.section,
|
||||
.n_sect = reg.section,
|
||||
.n_desc = 0,
|
||||
.n_value = stab.size.?,
|
||||
.n_value = stab.size,
|
||||
});
|
||||
},
|
||||
.global => {
|
||||
@@ -2588,9 +2557,9 @@ fn writeDebugInfo(self: *Zld) !void {
|
||||
try stabs.append(.{
|
||||
.n_strx = try self.makeString(sym.name),
|
||||
.n_type = macho.N_STSYM,
|
||||
.n_sect = sym.section,
|
||||
.n_sect = reg.section,
|
||||
.n_desc = 0,
|
||||
.n_value = sym.address,
|
||||
.n_value = reg.address,
|
||||
});
|
||||
},
|
||||
}
|
||||
@@ -2626,27 +2595,6 @@ fn writeDebugInfo(self: *Zld) !void {
|
||||
dysymtab.nlocalsym = symtab.nsyms;
|
||||
}
|
||||
|
||||
fn populateStringTable(self: *Zld) !void {
|
||||
for (self.objects.items) |*object| {
|
||||
for (object.symtab.items) |*sym| {
|
||||
switch (sym.tag) {
|
||||
.undef, .import => continue,
|
||||
else => {},
|
||||
}
|
||||
const sym_name = object.getString(sym.inner.n_strx);
|
||||
const n_strx = try self.makeString(sym_name);
|
||||
sym.inner.n_strx = n_strx;
|
||||
}
|
||||
}
|
||||
|
||||
for (self.symtab.items()) |*entry| {
|
||||
if (entry.value.tag != .import) continue;
|
||||
|
||||
const n_strx = try self.makeString(entry.key);
|
||||
entry.value.inner.n_strx = n_strx;
|
||||
}
|
||||
}
|
||||
|
||||
fn writeSymbolTable(self: *Zld) !void {
|
||||
const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
|
||||
const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
|
||||
@@ -2654,56 +2602,52 @@ fn writeSymbolTable(self: *Zld) !void {
|
||||
var locals = std.ArrayList(macho.nlist_64).init(self.allocator);
|
||||
defer locals.deinit();
|
||||
|
||||
for (self.objects.items) |object| {
|
||||
for (object.locals.items()) |entry| {
|
||||
const sym = entry.value;
|
||||
if (sym.tag != .local) continue;
|
||||
|
||||
try locals.append(.{
|
||||
.n_strx = try self.makeString(sym.name),
|
||||
.n_type = macho.N_SECT,
|
||||
.n_sect = sym.section,
|
||||
.n_desc = 0,
|
||||
.n_value = sym.address,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var exports = std.ArrayList(macho.nlist_64).init(self.allocator);
|
||||
defer exports.deinit();
|
||||
|
||||
for (self.objects.items) |object| {
|
||||
for (object.symbols.items) |sym| {
|
||||
const final = sym.getTopmostAlias();
|
||||
if (final.@"type" != .regular) continue;
|
||||
|
||||
const reg = final.cast(Symbol.Regular) orelse unreachable;
|
||||
if (reg.isTemp()) continue;
|
||||
|
||||
switch (reg.linkage) {
|
||||
.translation_unit => {
|
||||
try locals.append(.{
|
||||
.n_strx = try self.makeString(sym.name),
|
||||
.n_type = macho.N_SECT,
|
||||
.n_sect = reg.section,
|
||||
.n_desc = 0,
|
||||
.n_value = reg.address,
|
||||
});
|
||||
},
|
||||
else => {
|
||||
try exports.append(.{
|
||||
.n_strx = try self.makeString(sym.name),
|
||||
.n_type = macho.N_SECT | macho.N_EXT,
|
||||
.n_sect = reg.section,
|
||||
.n_desc = 0,
|
||||
.n_value = reg.address,
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var undefs = std.ArrayList(macho.nlist_64).init(self.allocator);
|
||||
defer undefs.deinit();
|
||||
|
||||
var undefs_ids = std.StringHashMap(u32).init(self.allocator);
|
||||
defer undefs_ids.deinit();
|
||||
|
||||
var undef_id: u32 = 0;
|
||||
for (self.symtab.items()) |entry| {
|
||||
for (self.imports.items()) |entry| {
|
||||
const sym = entry.value;
|
||||
switch (sym.tag) {
|
||||
.weak, .strong => {
|
||||
try exports.append(.{
|
||||
.n_strx = try self.makeString(sym.name),
|
||||
.n_type = macho.N_SECT | macho.N_EXT,
|
||||
.n_sect = sym.section,
|
||||
.n_desc = 0,
|
||||
.n_value = sym.address,
|
||||
});
|
||||
},
|
||||
.import => {
|
||||
try undefs.append(.{
|
||||
.n_strx = try self.makeString(sym.name),
|
||||
.n_type = macho.N_UNDF | macho.N_EXT,
|
||||
.n_sect = 0,
|
||||
.n_desc = macho.N_SYMBOL_RESOLVER | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY,
|
||||
.n_value = 0,
|
||||
});
|
||||
try undefs_ids.putNoClobber(sym.name, undef_id);
|
||||
undef_id += 1;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
try undefs.append(.{
|
||||
.n_strx = try self.makeString(sym.name),
|
||||
.n_type = macho.N_UNDF | macho.N_EXT,
|
||||
.n_sect = 0,
|
||||
.n_desc = macho.N_SYMBOL_RESOLVER | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY,
|
||||
.n_value = 0,
|
||||
});
|
||||
}
|
||||
|
||||
const nlocals = locals.items.len;
|
||||
@@ -2743,8 +2687,8 @@ fn writeSymbolTable(self: *Zld) !void {
|
||||
const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
|
||||
const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
|
||||
|
||||
const nstubs = @intCast(u32, self.stubs.items().len);
|
||||
const ngot_entries = @intCast(u32, self.got_entries.items().len);
|
||||
const nstubs = @intCast(u32, self.stubs.items.len);
|
||||
const ngot_entries = @intCast(u32, self.got_entries.items.len);
|
||||
|
||||
dysymtab.indirectsymoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
|
||||
dysymtab.nindirectsyms = nstubs * 2 + ngot_entries;
|
||||
@@ -2764,25 +2708,25 @@ fn writeSymbolTable(self: *Zld) !void {
|
||||
var writer = stream.writer();
|
||||
|
||||
stubs.reserved1 = 0;
|
||||
for (self.stubs.items()) |entry| {
|
||||
const id = undefs_ids.get(entry.key) orelse unreachable;
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + id);
|
||||
for (self.stubs.items) |sym| {
|
||||
const id = self.imports.getIndex(sym.name) orelse unreachable;
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + @intCast(u32, id));
|
||||
}
|
||||
|
||||
got.reserved1 = nstubs;
|
||||
for (self.got_entries.items()) |entry| {
|
||||
if (entry.value.tag == .import) {
|
||||
const id = undefs_ids.get(entry.key) orelse unreachable;
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + id);
|
||||
for (self.got_entries.items) |sym| {
|
||||
if (sym.@"type" == .proxy) {
|
||||
const id = self.imports.getIndex(sym.name) orelse unreachable;
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + @intCast(u32, id));
|
||||
} else {
|
||||
try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);
|
||||
}
|
||||
}
|
||||
|
||||
la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries;
|
||||
for (self.stubs.items()) |entry| {
|
||||
const id = undefs_ids.get(entry.key) orelse unreachable;
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + id);
|
||||
for (self.stubs.items) |sym| {
|
||||
const id = self.imports.getIndex(sym.name) orelse unreachable;
|
||||
try writer.writeIntLittle(u32, dysymtab.iundefsym + @intCast(u32, id));
|
||||
}
|
||||
|
||||
try self.file.?.pwriteAll(buf, dysymtab.indirectsymoff);
|
||||
@@ -2979,3 +2923,33 @@ pub fn parseName(name: *const [16]u8) []const u8 {
|
||||
const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len;
|
||||
return name[0..len];
|
||||
}
|
||||
|
||||
fn printSymbols(self: *Zld) void {
|
||||
log.debug("globals", .{});
|
||||
for (self.globals.items()) |entry| {
|
||||
const sym = entry.value.cast(Symbol.Regular) orelse unreachable;
|
||||
log.debug(" | {s} @ {*}", .{ sym.base.name, entry.value });
|
||||
log.debug(" => alias of {*}", .{sym.base.alias});
|
||||
log.debug(" => linkage {s}", .{sym.linkage});
|
||||
log.debug(" => defined in {s}", .{sym.file.name.?});
|
||||
}
|
||||
for (self.objects.items) |object| {
|
||||
log.debug("locals in {s}", .{object.name.?});
|
||||
for (object.symbols.items) |sym| {
|
||||
log.debug(" | {s} @ {*}", .{ sym.name, sym });
|
||||
log.debug(" => alias of {*}", .{sym.alias});
|
||||
if (sym.cast(Symbol.Regular)) |reg| {
|
||||
log.debug(" => linkage {s}", .{reg.linkage});
|
||||
} else {
|
||||
log.debug(" => unresolved", .{});
|
||||
}
|
||||
}
|
||||
}
|
||||
log.debug("proxies", .{});
|
||||
for (self.imports.items()) |entry| {
|
||||
const sym = entry.value.cast(Symbol.Proxy) orelse unreachable;
|
||||
log.debug(" | {s} @ {*}", .{ sym.base.name, entry.value });
|
||||
log.debug(" => alias of {*}", .{sym.base.alias});
|
||||
log.debug(" => defined in libSystem.B.dylib", .{});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ const aarch64 = @import("reloc/aarch64.zig");
|
||||
const x86_64 = @import("reloc/x86_64.zig");
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Symbol = @import("Symbol.zig");
|
||||
|
||||
pub const Relocation = struct {
|
||||
@"type": Type,
|
||||
@@ -75,12 +76,12 @@ pub const Relocation = struct {
|
||||
};
|
||||
|
||||
pub const Target = union(enum) {
|
||||
symbol: u32,
|
||||
symbol: *Symbol,
|
||||
section: u16,
|
||||
|
||||
pub fn from_reloc(reloc: macho.relocation_info) Target {
|
||||
pub fn from_reloc(reloc: macho.relocation_info, symbols: []*Symbol) Target {
|
||||
return if (reloc.r_extern == 1) .{
|
||||
.symbol = reloc.r_symbolnum,
|
||||
.symbol = symbols[reloc.r_symbolnum],
|
||||
} else .{
|
||||
.section = @intCast(u16, reloc.r_symbolnum - 1),
|
||||
};
|
||||
@@ -136,6 +137,7 @@ pub fn parse(
|
||||
arch: std.Target.Cpu.Arch,
|
||||
code: []u8,
|
||||
relocs: []const macho.relocation_info,
|
||||
symbols: []*Symbol,
|
||||
) ![]*Relocation {
|
||||
var it = RelocIterator{
|
||||
.buffer = relocs,
|
||||
@@ -148,6 +150,7 @@ pub fn parse(
|
||||
.it = &it,
|
||||
.code = code,
|
||||
.parsed = std.ArrayList(*Relocation).init(allocator),
|
||||
.symbols = symbols,
|
||||
};
|
||||
defer parser.deinit();
|
||||
try parser.parse();
|
||||
@@ -160,6 +163,7 @@ pub fn parse(
|
||||
.it = &it,
|
||||
.code = code,
|
||||
.parsed = std.ArrayList(*Relocation).init(allocator),
|
||||
.symbols = symbols,
|
||||
};
|
||||
defer parser.deinit();
|
||||
try parser.parse();
|
||||
|
||||
@@ -10,6 +10,7 @@ const reloc = @import("../reloc.zig");
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Relocation = reloc.Relocation;
|
||||
const Symbol = @import("../Symbol.zig");
|
||||
|
||||
pub const Branch = struct {
|
||||
base: Relocation,
|
||||
@@ -188,6 +189,7 @@ pub const Parser = struct {
|
||||
it: *reloc.RelocIterator,
|
||||
code: []u8,
|
||||
parsed: std.ArrayList(*Relocation),
|
||||
symbols: []*Symbol,
|
||||
addend: ?u32 = null,
|
||||
subtractor: ?Relocation.Target = null,
|
||||
|
||||
@@ -273,7 +275,7 @@ pub const Parser = struct {
|
||||
var branch = try parser.allocator.create(Branch);
|
||||
errdefer parser.allocator.destroy(branch);
|
||||
|
||||
const target = Relocation.Target.from_reloc(rel);
|
||||
const target = Relocation.Target.from_reloc(rel, parser.symbols);
|
||||
|
||||
branch.* = .{
|
||||
.base = .{
|
||||
@@ -294,7 +296,7 @@ pub const Parser = struct {
|
||||
assert(rel.r_length == 2);
|
||||
|
||||
const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
|
||||
const target = Relocation.Target.from_reloc(rel);
|
||||
const target = Relocation.Target.from_reloc(rel, parser.symbols);
|
||||
|
||||
const offset = @intCast(u32, rel.r_address);
|
||||
const inst = parser.code[offset..][0..4];
|
||||
@@ -400,7 +402,7 @@ pub const Parser = struct {
|
||||
aarch64.Instruction.load_store_register,
|
||||
), inst) };
|
||||
}
|
||||
const target = Relocation.Target.from_reloc(rel);
|
||||
const target = Relocation.Target.from_reloc(rel, parser.symbols);
|
||||
|
||||
var page_off = try parser.allocator.create(PageOff);
|
||||
errdefer parser.allocator.destroy(page_off);
|
||||
@@ -437,7 +439,7 @@ pub const Parser = struct {
|
||||
), inst);
|
||||
assert(parsed_inst.size == 3);
|
||||
|
||||
const target = Relocation.Target.from_reloc(rel);
|
||||
const target = Relocation.Target.from_reloc(rel, parser.symbols);
|
||||
|
||||
var page_off = try parser.allocator.create(GotPageOff);
|
||||
errdefer parser.allocator.destroy(page_off);
|
||||
@@ -496,7 +498,7 @@ pub const Parser = struct {
|
||||
}
|
||||
};
|
||||
|
||||
const target = Relocation.Target.from_reloc(rel);
|
||||
const target = Relocation.Target.from_reloc(rel, parser.symbols);
|
||||
|
||||
var page_off = try parser.allocator.create(TlvpPageOff);
|
||||
errdefer parser.allocator.destroy(page_off);
|
||||
@@ -531,7 +533,7 @@ pub const Parser = struct {
|
||||
assert(rel.r_pcrel == 0);
|
||||
assert(parser.subtractor == null);
|
||||
|
||||
parser.subtractor = Relocation.Target.from_reloc(rel);
|
||||
parser.subtractor = Relocation.Target.from_reloc(rel, parser.symbols);
|
||||
|
||||
// Verify SUBTRACTOR is followed by UNSIGNED.
|
||||
const next = @intToEnum(macho.reloc_type_arm64, parser.it.peek().r_type);
|
||||
@@ -554,7 +556,7 @@ pub const Parser = struct {
|
||||
var unsigned = try parser.allocator.create(reloc.Unsigned);
|
||||
errdefer parser.allocator.destroy(unsigned);
|
||||
|
||||
const target = Relocation.Target.from_reloc(rel);
|
||||
const target = Relocation.Target.from_reloc(rel, parser.symbols);
|
||||
const is_64bit: bool = switch (rel.r_length) {
|
||||
3 => true,
|
||||
2 => false,
|
||||
|
||||
@@ -9,6 +9,7 @@ const reloc = @import("../reloc.zig");
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Relocation = reloc.Relocation;
|
||||
const Symbol = @import("../Symbol.zig");
|
||||
|
||||
pub const Branch = struct {
|
||||
base: Relocation,
|
||||
@@ -95,6 +96,7 @@ pub const Parser = struct {
|
||||
it: *reloc.RelocIterator,
|
||||
code: []u8,
|
||||
parsed: std.ArrayList(*Relocation),
|
||||
symbols: []*Symbol,
|
||||
subtractor: ?Relocation.Target = null,
|
||||
|
||||
pub fn deinit(parser: *Parser) void {
|
||||
@@ -145,7 +147,7 @@ pub const Parser = struct {
|
||||
var branch = try parser.allocator.create(Branch);
|
||||
errdefer parser.allocator.destroy(branch);
|
||||
|
||||
const target = Relocation.Target.from_reloc(rel);
|
||||
const target = Relocation.Target.from_reloc(rel, parser.symbols);
|
||||
|
||||
branch.* = .{
|
||||
.base = .{
|
||||
@@ -165,7 +167,7 @@ pub const Parser = struct {
|
||||
assert(rel.r_length == 2);
|
||||
|
||||
const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
|
||||
const target = Relocation.Target.from_reloc(rel);
|
||||
const target = Relocation.Target.from_reloc(rel, parser.symbols);
|
||||
const is_extern = rel.r_extern == 1;
|
||||
|
||||
const offset = @intCast(u32, rel.r_address);
|
||||
@@ -211,7 +213,7 @@ pub const Parser = struct {
|
||||
|
||||
const offset = @intCast(u32, rel.r_address);
|
||||
const inst = parser.code[offset..][0..4];
|
||||
const target = Relocation.Target.from_reloc(rel);
|
||||
const target = Relocation.Target.from_reloc(rel, parser.symbols);
|
||||
|
||||
var got_load = try parser.allocator.create(GotLoad);
|
||||
errdefer parser.allocator.destroy(got_load);
|
||||
@@ -237,7 +239,7 @@ pub const Parser = struct {
|
||||
|
||||
const offset = @intCast(u32, rel.r_address);
|
||||
const inst = parser.code[offset..][0..4];
|
||||
const target = Relocation.Target.from_reloc(rel);
|
||||
const target = Relocation.Target.from_reloc(rel, parser.symbols);
|
||||
|
||||
var got = try parser.allocator.create(Got);
|
||||
errdefer parser.allocator.destroy(got);
|
||||
@@ -263,7 +265,7 @@ pub const Parser = struct {
|
||||
|
||||
const offset = @intCast(u32, rel.r_address);
|
||||
const inst = parser.code[offset..][0..4];
|
||||
const target = Relocation.Target.from_reloc(rel);
|
||||
const target = Relocation.Target.from_reloc(rel, parser.symbols);
|
||||
|
||||
var tlv = try parser.allocator.create(Tlv);
|
||||
errdefer parser.allocator.destroy(tlv);
|
||||
@@ -288,7 +290,7 @@ pub const Parser = struct {
|
||||
assert(rel.r_pcrel == 0);
|
||||
assert(parser.subtractor == null);
|
||||
|
||||
parser.subtractor = Relocation.Target.from_reloc(rel);
|
||||
parser.subtractor = Relocation.Target.from_reloc(rel, parser.symbols);
|
||||
|
||||
// Verify SUBTRACTOR is followed by UNSIGNED.
|
||||
const next = @intToEnum(macho.reloc_type_x86_64, parser.it.peek().r_type);
|
||||
@@ -311,7 +313,7 @@ pub const Parser = struct {
|
||||
var unsigned = try parser.allocator.create(reloc.Unsigned);
|
||||
errdefer parser.allocator.destroy(unsigned);
|
||||
|
||||
const target = Relocation.Target.from_reloc(rel);
|
||||
const target = Relocation.Target.from_reloc(rel, parser.symbols);
|
||||
const is_64bit: bool = switch (rel.r_length) {
|
||||
3 => true,
|
||||
2 => false,
|
||||
|
||||
+4
-1
@@ -56,7 +56,7 @@ enum TargetSubsystem {
|
||||
|
||||
|
||||
// ABI warning
|
||||
// Synchronize with target.cpp::os_list
|
||||
// Synchronize with std.Target.Os.Tag and target.cpp::os_list
|
||||
enum Os {
|
||||
OsFreestanding,
|
||||
OsAnanas,
|
||||
@@ -94,6 +94,9 @@ enum Os {
|
||||
OsWASI,
|
||||
OsEmscripten,
|
||||
OsUefi,
|
||||
OsOpenCL,
|
||||
OsGLSL450,
|
||||
OsVulkan,
|
||||
OsOther,
|
||||
};
|
||||
|
||||
|
||||
@@ -122,6 +122,9 @@ static const Os os_list[] = {
|
||||
OsWASI,
|
||||
OsEmscripten,
|
||||
OsUefi,
|
||||
OsOpenCL,
|
||||
OsGLSL450,
|
||||
OsVulkan,
|
||||
OsOther,
|
||||
};
|
||||
|
||||
@@ -213,6 +216,9 @@ Os target_os_enum(size_t index) {
|
||||
ZigLLVM_OSType get_llvm_os_type(Os os_type) {
|
||||
switch (os_type) {
|
||||
case OsFreestanding:
|
||||
case OsOpenCL:
|
||||
case OsGLSL450:
|
||||
case OsVulkan:
|
||||
case OsOther:
|
||||
return ZigLLVM_UnknownOS;
|
||||
case OsAnanas:
|
||||
@@ -330,6 +336,9 @@ const char *target_os_name(Os os_type) {
|
||||
case OsHurd:
|
||||
case OsWASI:
|
||||
case OsEmscripten:
|
||||
case OsOpenCL:
|
||||
case OsGLSL450:
|
||||
case OsVulkan:
|
||||
return ZigLLVMGetOSTypeName(get_llvm_os_type(os_type));
|
||||
}
|
||||
zig_unreachable();
|
||||
@@ -733,6 +742,9 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
|
||||
case OsAMDPAL:
|
||||
case OsHermitCore:
|
||||
case OsHurd:
|
||||
case OsOpenCL:
|
||||
case OsGLSL450:
|
||||
case OsVulkan:
|
||||
zig_panic("TODO c type size in bits for this target");
|
||||
}
|
||||
zig_unreachable();
|
||||
@@ -999,6 +1011,10 @@ ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) {
|
||||
case OsWASI:
|
||||
case OsEmscripten:
|
||||
return ZigLLVM_Musl;
|
||||
case OsOpenCL:
|
||||
case OsGLSL450:
|
||||
case OsVulkan:
|
||||
return ZigLLVM_UnknownEnvironment;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
@@ -239,6 +239,28 @@ const llvm_targets = [_]LlvmTarget{
|
||||
"zcz_fp",
|
||||
},
|
||||
},
|
||||
.{
|
||||
.llvm_name = null,
|
||||
.zig_name = "xgene1",
|
||||
.features = &.{
|
||||
"fp_armv8",
|
||||
"neon",
|
||||
"perfmon",
|
||||
"v8a",
|
||||
},
|
||||
},
|
||||
.{
|
||||
.llvm_name = null,
|
||||
.zig_name = "emag",
|
||||
.features = &.{
|
||||
"crc",
|
||||
"crypto",
|
||||
"fp_armv8",
|
||||
"neon",
|
||||
"perfmon",
|
||||
"v8a",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
.{
|
||||
|
||||
Reference in New Issue
Block a user