From 807bb7c03fc98e3792ece7e0573e226727c18129 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 30 Apr 2021 17:11:03 +0200 Subject: [PATCH 01/47] std: Improve spinloop hint * Add a yield pattern for PowerPC64 * Fix compile error on pre-v6 ARM targets * Use isb instead of yield on AArch64 to give the CPU a chance to enter low-power states. * Make the hint an inline function, the call overhead can be avoided. --- lib/std/Thread.zig | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig index 01405b104f..39d37f2e5f 100644 --- a/lib/std/Thread.zig +++ b/lib/std/Thread.zig @@ -68,11 +68,28 @@ 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.featureSetHas(std.Target.current.cpu.features, .has_v6m); + if (can_yield) asm volatile ("yield" ::: "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"); + }, } } From b49d99b246bc18d94b6eed0c225464078b05f12a Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 30 Apr 2021 23:41:28 +0200 Subject: [PATCH 02/47] Azure CI: Test std.* and the rest separately On CI, we have been running into OOM issues when running the test suite on Windows for quite some time. Unfortunately, we are very close to having the same issues on Linux as well. Some additional comptime work immediately makes these builds fail as well. Add a new `test-toolchain` step, that tests everything except `std.*` and documentation. On CI, call `test-toolchain`, `test-std` and `docs` separately instead of the `test` big hammer that emcompasses all of them. Change the special case we made for Windows to the same code as other platforms. This is a stopgap measure that stage2 will eventually make useless. Until then, it gives us some headroom. Change `linux_script` by the way to only output the log of failing steps. This shrinks the Linux CI log from a bazilion lines down to something more humanely manageable. --- build.zig | 42 +++++++++++++++++--------------- ci/azure/linux_script | 12 ++++++++- ci/azure/macos_script | 14 +++++++++-- ci/azure/windows_msvc_script.bat | 14 +---------- 4 files changed, 47 insertions(+), 35 deletions(-) diff --git a/build.zig b/build.zig index d15766c08e..a0bc6a89c3 100644 --- a/build.zig +++ b/build.zig @@ -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); @@ -90,7 +90,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(bool, "skip_non_native", skip_non_native); @@ -233,7 +233,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; @@ -257,33 +257,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/stage1/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/stage1/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); } diff --git a/ci/azure/linux_script b/ci/azure/linux_script index d9e017cc1d..2b0e9c46aa 100755 --- a/ci/azure/linux_script +++ b/ci/azure/linux_script @@ -65,7 +65,17 @@ make $JOBS install cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig" make $JOBS install -release/bin/zig build test -Denable-qemu -Denable-wasmtime +set +x +LOG=$(mktemp) +for step in test-toolchain test-std docs; do + echo "* Running step: [$step]" + if ! release/bin/zig build $step -Denable-qemu -Denable-wasmtime 2>"$LOG" >&2; then + cat "$LOG" >&2 + exit 1 + fi + echo " Done." +done +set -x # Look for HTML errors. tidy -qe ../zig-cache/langref.html diff --git a/ci/azure/macos_script b/ci/azure/macos_script index da3d4de915..c05a6871fb 100755 --- a/ci/azure/macos_script +++ b/ci/azure/macos_script @@ -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,17 @@ make $JOBS install cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig" -DZIG_TARGET_MCPU="x86_64_v2" make $JOBS install -release/bin/zig build test +set +x +LOG=$(mktemp) +for step in test-toolchain test-std docs; do + echo "* Running step: [$step]" + if ! release/bin/zig build $step -Denable-qemu -Denable-wasmtime 2>"$LOG" >&2; then + cat "$LOG" >&2 + exit 1 + fi + echo " Done." +done +set -x if [ "${BUILD_REASON}" != "PullRequest" ]; then mv ../LICENSE release/ diff --git a/ci/azure/windows_msvc_script.bat b/ci/azure/windows_msvc_script.bat index e45b53f4ad..fc17c80ea2 100644 --- a/ci/azure/windows_msvc_script.bat +++ b/ci/azure/windows_msvc_script.bat @@ -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" From 3e389d01ed13374aa3a362dfa505eb00718b318c Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sat, 1 May 2021 00:38:54 +0200 Subject: [PATCH 03/47] CI: no need to try qemu and wasmtime on macOS builds --- ci/azure/macos_script | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/azure/macos_script b/ci/azure/macos_script index c05a6871fb..4aa7629352 100755 --- a/ci/azure/macos_script +++ b/ci/azure/macos_script @@ -59,7 +59,7 @@ set +x LOG=$(mktemp) for step in test-toolchain test-std docs; do echo "* Running step: [$step]" - if ! release/bin/zig build $step -Denable-qemu -Denable-wasmtime 2>"$LOG" >&2; then + if ! release/bin/zig build $step 2>"$LOG" >&2; then cat "$LOG" >&2 exit 1 fi From fe8781357afc0fa763f6a60eb8959acd05f4dfa3 Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Sat, 1 May 2021 08:14:32 +0200 Subject: [PATCH 04/47] std.crypto: add support for the NIST P-256 curve (#8627) Uses verified code generated by fiat-crypto for field arithmetic, and complete formulas to avoid side channels. There's still plenty of room for optimizations, especially with a fixed base. But this gives us a framework to easily add other similar curves. --- lib/std/crypto.zig | 1 + lib/std/crypto/pcurves/p256.zig | 412 ++++++ lib/std/crypto/pcurves/p256/field.zig | 261 ++++ lib/std/crypto/pcurves/p256/p256_64.zig | 1774 +++++++++++++++++++++++ lib/std/crypto/pcurves/p256/scalar.zig | 219 +++ lib/std/crypto/pcurves/tests.zig | 103 ++ 6 files changed, 2770 insertions(+) create mode 100644 lib/std/crypto/pcurves/p256.zig create mode 100644 lib/std/crypto/pcurves/p256/field.zig create mode 100644 lib/std/crypto/pcurves/p256/p256_64.zig create mode 100644 lib/std/crypto/pcurves/p256/scalar.zig create mode 100644 lib/std/crypto/pcurves/tests.zig diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig index e4ec50f5b7..af23af9460 100644 --- a/lib/std/crypto.zig +++ b/lib/std/crypto.zig @@ -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; }; diff --git a/lib/std/crypto/pcurves/p256.zig b/lib/std/crypto/pcurves/p256.zig new file mode 100644 index 0000000000..0b1c584fa9 --- /dev/null +++ b/lib/std/crypto/pcurves/p256.zig @@ -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"); +} diff --git a/lib/std/crypto/pcurves/p256/field.zig b/lib/std/crypto/pcurves/p256/field.zig new file mode 100644 index 0000000000..68659e4601 --- /dev/null +++ b/lib/std/crypto/pcurves/p256/field.zig @@ -0,0 +1,261 @@ +// 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 debug = std.debug; +const mem = std.mem; +const meta = std.meta; + +const fiat = @import("p256_64.zig"); + +const NonCanonicalError = crypto.errors.NonCanonicalError; +const NotSquareError = crypto.errors.NotSquareError; + +const Limbs = fiat.Limbs; + +/// A field element, internally stored in Montgomery domain. +pub const Fe = struct { + limbs: Limbs, + + /// Field size. + pub const field_order = 115792089210356248762697446949407573530086143415290314195533631308867097853951; + + /// Numer of bits that can be saturated without overflowing. + pub const saturated_bits = 255; + + /// Zero. + pub const zero: Fe = Fe{ .limbs = mem.zeroes(Limbs) }; + + /// One. + pub const one = comptime one: { + var fe: Fe = undefined; + fiat.p256SetOne(&fe.limbs); + break :one fe; + }; + + /// Reject non-canonical encodings of an element. + pub fn rejectNonCanonical(s_: [32]u8, endian: builtin.Endian) NonCanonicalError!void { + var s = if (endian == .Little) s_ else orderSwap(s_); + const field_order_s = comptime fos: { + var fos: [32]u8 = undefined; + mem.writeIntLittle(u256, &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: [32]u8) [32]u8 { + var t = s; + for (s) |x, i| t[t.len - 1 - i] = x; + return t; + } + + /// Unpack a field element. + pub fn fromBytes(s_: [32]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.p256FromBytes(&limbs_z, s); + var limbs: Limbs = undefined; + fiat.p256ToMontgomery(&limbs, limbs_z); + return Fe{ .limbs = limbs }; + } + + /// Pack a field element. + pub fn toBytes(fe: Fe, endian: builtin.Endian) [32]u8 { + var limbs_z: Limbs = undefined; + fiat.p256FromMontgomery(&limbs_z, fe.limbs); + var s: [32]u8 = undefined; + fiat.p256ToBytes(&s, limbs_z); + return if (endian == .Little) s else orderSwap(s); + } + + /// Create a field element from an integer. + pub fn fromInt(comptime x: u256) NonCanonicalError!Fe { + var s: [32]u8 = undefined; + mem.writeIntLittle(u256, &s, x); + return fromBytes(s, .Little); + } + + /// Return the field element as an integer. + pub fn toInt(fe: Fe) u256 { + const s = fe.toBytes(.Little); + return mem.readIntLittle(u256, &s); + } + + /// Return true if the field element is zero. + pub fn isZero(fe: Fe) bool { + var z: @TypeOf(fe.limbs[0]) = undefined; + fiat.p256Nonzero(&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.p256Selectznz(&fe.limbs, c, fe.limbs, a.limbs); + } + + /// Add field elements. + pub fn add(a: Fe, b: Fe) Fe { + var fe: Fe = undefined; + fiat.p256Add(&fe.limbs, a.limbs, b.limbs); + return fe; + } + + /// Subtract field elements. + pub fn sub(a: Fe, b: Fe) Fe { + var fe: Fe = undefined; + fiat.p256Sub(&fe.limbs, a.limbs, b.limbs); + return fe; + } + + /// Double a field element. + pub fn dbl(a: Fe) Fe { + var fe: Fe = undefined; + fiat.p256Add(&fe.limbs, a.limbs, a.limbs); + return fe; + } + + /// Multiply field elements. + pub fn mul(a: Fe, b: Fe) Fe { + var fe: Fe = undefined; + fiat.p256Mul(&fe.limbs, a.limbs, b.limbs); + return fe; + } + + /// Square a field element. + pub fn sq(a: Fe) Fe { + var fe: Fe = undefined; + fiat.p256Square(&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.p256Opp(&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 len_prime = 256; + const iterations = (49 * len_prime + 57) / 17; + const Word = @TypeOf(a.limbs[0]); + const XLimbs = [a.limbs.len + 1]Word; + + var d: Word = 1; + var f: XLimbs = undefined; + fiat.p256Msat(&f); + + var g: XLimbs = undefined; + fiat.p256FromMontgomery(g[0..a.limbs.len], a.limbs); + g[g.len - 1] = 0; + + var r: Limbs = undefined; + fiat.p256SetOne(&r); + var v = mem.zeroes(Limbs); + + var precomp: Limbs = undefined; + fiat.p256DivstepPrecomp(&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.p256Divstep(&out1, &out2, &out3, &out4, &out5, d, f, g, v, r); + fiat.p256Divstep(&d, &f, &g, &v, &r, out1, out2, out3, out4, out5); + } + if (iterations % 2 != 0) { + fiat.p256Divstep(&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.p256Opp(&v_opp, v); + fiat.p256Selectznz(&v, @truncate(u1, f[f.len - 1] >> (meta.bitCount(Word) - 1)), v, v_opp); + var fe: Fe = undefined; + fiat.p256Mul(&fe.limbs, v, precomp); + return fe; + } + + /// Return true if the field element is a square. + pub fn isSquare(x2: Fe) bool { + 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); // Legendre symbol, (p-1)/2 + 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); + 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); + } + + /// 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; + } +}; diff --git a/lib/std/crypto/pcurves/p256/p256_64.zig b/lib/std/crypto/pcurves/p256/p256_64.zig new file mode 100644 index 0000000000..9f3d6c22f8 --- /dev/null +++ b/lib/std/crypto/pcurves/p256/p256_64.zig @@ -0,0 +1,1774 @@ +// 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. + +// Autogenerated: 'src/ExtractionOCaml/word_by_word_montgomery' --lang Zig --internal-static --public-function-case camelCase --private-function-case camelCase 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: 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) + +pub const Limbs = [4]u64; + +/// The function p256AddcarryxU64 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 p256AddcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void { + 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 p256SubborrowxU64 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 p256SubborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void { + 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 p256MulxU64 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 p256MulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) callconv(.Inline) void { + const x = @as(u128, arg1) * @as(u128, arg2); + out1.* = @truncate(u64, x); + out2.* = @truncate(u64, x >> 64); +} + +/// The function p256CmovznzU64 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 p256CmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void { + const mask = 0 -% @as(u64, arg1); + out1.* = (mask & arg3) | ((~mask) & arg2); +} + +/// The function p256Mul 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 p256Mul(out1: *Limbs, arg1: Limbs, arg2: Limbs) void { + const x1: u64 = (arg1[1]); + const x2: u64 = (arg1[2]); + const x3: u64 = (arg1[3]); + const x4: u64 = (arg1[0]); + var x5: u64 = undefined; + var x6: u64 = undefined; + p256MulxU64(&x5, &x6, x4, (arg2[3])); + var x7: u64 = undefined; + var x8: u64 = undefined; + p256MulxU64(&x7, &x8, x4, (arg2[2])); + var x9: u64 = undefined; + var x10: u64 = undefined; + p256MulxU64(&x9, &x10, x4, (arg2[1])); + var x11: u64 = undefined; + var x12: u64 = undefined; + p256MulxU64(&x11, &x12, x4, (arg2[0])); + var x13: u64 = undefined; + var x14: u1 = undefined; + p256AddcarryxU64(&x13, &x14, 0x0, x12, x9); + var x15: u64 = undefined; + var x16: u1 = undefined; + p256AddcarryxU64(&x15, &x16, x14, x10, x7); + var x17: u64 = undefined; + var x18: u1 = undefined; + p256AddcarryxU64(&x17, &x18, x16, x8, x5); + const x19: u64 = (@intCast(u64, x18) + x6); + var x20: u64 = undefined; + var x21: u64 = undefined; + p256MulxU64(&x20, &x21, x11, 0xffffffff00000001); + var x22: u64 = undefined; + var x23: u64 = undefined; + p256MulxU64(&x22, &x23, x11, 0xffffffff); + var x24: u64 = undefined; + var x25: u64 = undefined; + p256MulxU64(&x24, &x25, x11, 0xffffffffffffffff); + var x26: u64 = undefined; + var x27: u1 = undefined; + p256AddcarryxU64(&x26, &x27, 0x0, x25, x22); + const x28: u64 = (@intCast(u64, x27) + x23); + var x29: u64 = undefined; + var x30: u1 = undefined; + p256AddcarryxU64(&x29, &x30, 0x0, x11, x24); + var x31: u64 = undefined; + var x32: u1 = undefined; + p256AddcarryxU64(&x31, &x32, x30, x13, x26); + var x33: u64 = undefined; + var x34: u1 = undefined; + p256AddcarryxU64(&x33, &x34, x32, x15, x28); + var x35: u64 = undefined; + var x36: u1 = undefined; + p256AddcarryxU64(&x35, &x36, x34, x17, x20); + var x37: u64 = undefined; + var x38: u1 = undefined; + p256AddcarryxU64(&x37, &x38, x36, x19, x21); + var x39: u64 = undefined; + var x40: u64 = undefined; + p256MulxU64(&x39, &x40, x1, (arg2[3])); + var x41: u64 = undefined; + var x42: u64 = undefined; + p256MulxU64(&x41, &x42, x1, (arg2[2])); + var x43: u64 = undefined; + var x44: u64 = undefined; + p256MulxU64(&x43, &x44, x1, (arg2[1])); + var x45: u64 = undefined; + var x46: u64 = undefined; + p256MulxU64(&x45, &x46, x1, (arg2[0])); + var x47: u64 = undefined; + var x48: u1 = undefined; + p256AddcarryxU64(&x47, &x48, 0x0, x46, x43); + var x49: u64 = undefined; + var x50: u1 = undefined; + p256AddcarryxU64(&x49, &x50, x48, x44, x41); + var x51: u64 = undefined; + var x52: u1 = undefined; + p256AddcarryxU64(&x51, &x52, x50, x42, x39); + const x53: u64 = (@intCast(u64, x52) + x40); + var x54: u64 = undefined; + var x55: u1 = undefined; + p256AddcarryxU64(&x54, &x55, 0x0, x31, x45); + var x56: u64 = undefined; + var x57: u1 = undefined; + p256AddcarryxU64(&x56, &x57, x55, x33, x47); + var x58: u64 = undefined; + var x59: u1 = undefined; + p256AddcarryxU64(&x58, &x59, x57, x35, x49); + var x60: u64 = undefined; + var x61: u1 = undefined; + p256AddcarryxU64(&x60, &x61, x59, x37, x51); + var x62: u64 = undefined; + var x63: u1 = undefined; + p256AddcarryxU64(&x62, &x63, x61, @intCast(u64, x38), x53); + var x64: u64 = undefined; + var x65: u64 = undefined; + p256MulxU64(&x64, &x65, x54, 0xffffffff00000001); + var x66: u64 = undefined; + var x67: u64 = undefined; + p256MulxU64(&x66, &x67, x54, 0xffffffff); + var x68: u64 = undefined; + var x69: u64 = undefined; + p256MulxU64(&x68, &x69, x54, 0xffffffffffffffff); + var x70: u64 = undefined; + var x71: u1 = undefined; + p256AddcarryxU64(&x70, &x71, 0x0, x69, x66); + const x72: u64 = (@intCast(u64, x71) + x67); + var x73: u64 = undefined; + var x74: u1 = undefined; + p256AddcarryxU64(&x73, &x74, 0x0, x54, x68); + var x75: u64 = undefined; + var x76: u1 = undefined; + p256AddcarryxU64(&x75, &x76, x74, x56, x70); + var x77: u64 = undefined; + var x78: u1 = undefined; + p256AddcarryxU64(&x77, &x78, x76, x58, x72); + var x79: u64 = undefined; + var x80: u1 = undefined; + p256AddcarryxU64(&x79, &x80, x78, x60, x64); + var x81: u64 = undefined; + var x82: u1 = undefined; + p256AddcarryxU64(&x81, &x82, x80, x62, x65); + const x83: u64 = (@intCast(u64, x82) + @intCast(u64, x63)); + var x84: u64 = undefined; + var x85: u64 = undefined; + p256MulxU64(&x84, &x85, x2, (arg2[3])); + var x86: u64 = undefined; + var x87: u64 = undefined; + p256MulxU64(&x86, &x87, x2, (arg2[2])); + var x88: u64 = undefined; + var x89: u64 = undefined; + p256MulxU64(&x88, &x89, x2, (arg2[1])); + var x90: u64 = undefined; + var x91: u64 = undefined; + p256MulxU64(&x90, &x91, x2, (arg2[0])); + var x92: u64 = undefined; + var x93: u1 = undefined; + p256AddcarryxU64(&x92, &x93, 0x0, x91, x88); + var x94: u64 = undefined; + var x95: u1 = undefined; + p256AddcarryxU64(&x94, &x95, x93, x89, x86); + var x96: u64 = undefined; + var x97: u1 = undefined; + p256AddcarryxU64(&x96, &x97, x95, x87, x84); + const x98: u64 = (@intCast(u64, x97) + x85); + var x99: u64 = undefined; + var x100: u1 = undefined; + p256AddcarryxU64(&x99, &x100, 0x0, x75, x90); + var x101: u64 = undefined; + var x102: u1 = undefined; + p256AddcarryxU64(&x101, &x102, x100, x77, x92); + var x103: u64 = undefined; + var x104: u1 = undefined; + p256AddcarryxU64(&x103, &x104, x102, x79, x94); + var x105: u64 = undefined; + var x106: u1 = undefined; + p256AddcarryxU64(&x105, &x106, x104, x81, x96); + var x107: u64 = undefined; + var x108: u1 = undefined; + p256AddcarryxU64(&x107, &x108, x106, x83, x98); + var x109: u64 = undefined; + var x110: u64 = undefined; + p256MulxU64(&x109, &x110, x99, 0xffffffff00000001); + var x111: u64 = undefined; + var x112: u64 = undefined; + p256MulxU64(&x111, &x112, x99, 0xffffffff); + var x113: u64 = undefined; + var x114: u64 = undefined; + p256MulxU64(&x113, &x114, x99, 0xffffffffffffffff); + var x115: u64 = undefined; + var x116: u1 = undefined; + p256AddcarryxU64(&x115, &x116, 0x0, x114, x111); + const x117: u64 = (@intCast(u64, x116) + x112); + var x118: u64 = undefined; + var x119: u1 = undefined; + p256AddcarryxU64(&x118, &x119, 0x0, x99, x113); + var x120: u64 = undefined; + var x121: u1 = undefined; + p256AddcarryxU64(&x120, &x121, x119, x101, x115); + var x122: u64 = undefined; + var x123: u1 = undefined; + p256AddcarryxU64(&x122, &x123, x121, x103, x117); + var x124: u64 = undefined; + var x125: u1 = undefined; + p256AddcarryxU64(&x124, &x125, x123, x105, x109); + var x126: u64 = undefined; + var x127: u1 = undefined; + p256AddcarryxU64(&x126, &x127, x125, x107, x110); + const x128: u64 = (@intCast(u64, x127) + @intCast(u64, x108)); + var x129: u64 = undefined; + var x130: u64 = undefined; + p256MulxU64(&x129, &x130, x3, (arg2[3])); + var x131: u64 = undefined; + var x132: u64 = undefined; + p256MulxU64(&x131, &x132, x3, (arg2[2])); + var x133: u64 = undefined; + var x134: u64 = undefined; + p256MulxU64(&x133, &x134, x3, (arg2[1])); + var x135: u64 = undefined; + var x136: u64 = undefined; + p256MulxU64(&x135, &x136, x3, (arg2[0])); + var x137: u64 = undefined; + var x138: u1 = undefined; + p256AddcarryxU64(&x137, &x138, 0x0, x136, x133); + var x139: u64 = undefined; + var x140: u1 = undefined; + p256AddcarryxU64(&x139, &x140, x138, x134, x131); + var x141: u64 = undefined; + var x142: u1 = undefined; + p256AddcarryxU64(&x141, &x142, x140, x132, x129); + const x143: u64 = (@intCast(u64, x142) + x130); + var x144: u64 = undefined; + var x145: u1 = undefined; + p256AddcarryxU64(&x144, &x145, 0x0, x120, x135); + var x146: u64 = undefined; + var x147: u1 = undefined; + p256AddcarryxU64(&x146, &x147, x145, x122, x137); + var x148: u64 = undefined; + var x149: u1 = undefined; + p256AddcarryxU64(&x148, &x149, x147, x124, x139); + var x150: u64 = undefined; + var x151: u1 = undefined; + p256AddcarryxU64(&x150, &x151, x149, x126, x141); + var x152: u64 = undefined; + var x153: u1 = undefined; + p256AddcarryxU64(&x152, &x153, x151, x128, x143); + var x154: u64 = undefined; + var x155: u64 = undefined; + p256MulxU64(&x154, &x155, x144, 0xffffffff00000001); + var x156: u64 = undefined; + var x157: u64 = undefined; + p256MulxU64(&x156, &x157, x144, 0xffffffff); + var x158: u64 = undefined; + var x159: u64 = undefined; + p256MulxU64(&x158, &x159, x144, 0xffffffffffffffff); + var x160: u64 = undefined; + var x161: u1 = undefined; + p256AddcarryxU64(&x160, &x161, 0x0, x159, x156); + const x162: u64 = (@intCast(u64, x161) + x157); + var x163: u64 = undefined; + var x164: u1 = undefined; + p256AddcarryxU64(&x163, &x164, 0x0, x144, x158); + var x165: u64 = undefined; + var x166: u1 = undefined; + p256AddcarryxU64(&x165, &x166, x164, x146, x160); + var x167: u64 = undefined; + var x168: u1 = undefined; + p256AddcarryxU64(&x167, &x168, x166, x148, x162); + var x169: u64 = undefined; + var x170: u1 = undefined; + p256AddcarryxU64(&x169, &x170, x168, x150, x154); + var x171: u64 = undefined; + var x172: u1 = undefined; + p256AddcarryxU64(&x171, &x172, x170, x152, x155); + const x173: u64 = (@intCast(u64, x172) + @intCast(u64, x153)); + var x174: u64 = undefined; + var x175: u1 = undefined; + p256SubborrowxU64(&x174, &x175, 0x0, x165, 0xffffffffffffffff); + var x176: u64 = undefined; + var x177: u1 = undefined; + p256SubborrowxU64(&x176, &x177, x175, x167, 0xffffffff); + var x178: u64 = undefined; + var x179: u1 = undefined; + p256SubborrowxU64(&x178, &x179, x177, x169, @intCast(u64, 0x0)); + var x180: u64 = undefined; + var x181: u1 = undefined; + p256SubborrowxU64(&x180, &x181, x179, x171, 0xffffffff00000001); + var x182: u64 = undefined; + var x183: u1 = undefined; + p256SubborrowxU64(&x182, &x183, x181, x173, @intCast(u64, 0x0)); + var x184: u64 = undefined; + p256CmovznzU64(&x184, x183, x174, x165); + var x185: u64 = undefined; + p256CmovznzU64(&x185, x183, x176, x167); + var x186: u64 = undefined; + p256CmovznzU64(&x186, x183, x178, x169); + var x187: u64 = undefined; + p256CmovznzU64(&x187, x183, x180, x171); + out1[0] = x184; + out1[1] = x185; + out1[2] = x186; + out1[3] = x187; +} + +/// The function p256Square 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 p256Square(out1: *Limbs, arg1: Limbs) void { + const x1: u64 = (arg1[1]); + const x2: u64 = (arg1[2]); + const x3: u64 = (arg1[3]); + const x4: u64 = (arg1[0]); + var x5: u64 = undefined; + var x6: u64 = undefined; + p256MulxU64(&x5, &x6, x4, (arg1[3])); + var x7: u64 = undefined; + var x8: u64 = undefined; + p256MulxU64(&x7, &x8, x4, (arg1[2])); + var x9: u64 = undefined; + var x10: u64 = undefined; + p256MulxU64(&x9, &x10, x4, (arg1[1])); + var x11: u64 = undefined; + var x12: u64 = undefined; + p256MulxU64(&x11, &x12, x4, (arg1[0])); + var x13: u64 = undefined; + var x14: u1 = undefined; + p256AddcarryxU64(&x13, &x14, 0x0, x12, x9); + var x15: u64 = undefined; + var x16: u1 = undefined; + p256AddcarryxU64(&x15, &x16, x14, x10, x7); + var x17: u64 = undefined; + var x18: u1 = undefined; + p256AddcarryxU64(&x17, &x18, x16, x8, x5); + const x19: u64 = (@intCast(u64, x18) + x6); + var x20: u64 = undefined; + var x21: u64 = undefined; + p256MulxU64(&x20, &x21, x11, 0xffffffff00000001); + var x22: u64 = undefined; + var x23: u64 = undefined; + p256MulxU64(&x22, &x23, x11, 0xffffffff); + var x24: u64 = undefined; + var x25: u64 = undefined; + p256MulxU64(&x24, &x25, x11, 0xffffffffffffffff); + var x26: u64 = undefined; + var x27: u1 = undefined; + p256AddcarryxU64(&x26, &x27, 0x0, x25, x22); + const x28: u64 = (@intCast(u64, x27) + x23); + var x29: u64 = undefined; + var x30: u1 = undefined; + p256AddcarryxU64(&x29, &x30, 0x0, x11, x24); + var x31: u64 = undefined; + var x32: u1 = undefined; + p256AddcarryxU64(&x31, &x32, x30, x13, x26); + var x33: u64 = undefined; + var x34: u1 = undefined; + p256AddcarryxU64(&x33, &x34, x32, x15, x28); + var x35: u64 = undefined; + var x36: u1 = undefined; + p256AddcarryxU64(&x35, &x36, x34, x17, x20); + var x37: u64 = undefined; + var x38: u1 = undefined; + p256AddcarryxU64(&x37, &x38, x36, x19, x21); + var x39: u64 = undefined; + var x40: u64 = undefined; + p256MulxU64(&x39, &x40, x1, (arg1[3])); + var x41: u64 = undefined; + var x42: u64 = undefined; + p256MulxU64(&x41, &x42, x1, (arg1[2])); + var x43: u64 = undefined; + var x44: u64 = undefined; + p256MulxU64(&x43, &x44, x1, (arg1[1])); + var x45: u64 = undefined; + var x46: u64 = undefined; + p256MulxU64(&x45, &x46, x1, (arg1[0])); + var x47: u64 = undefined; + var x48: u1 = undefined; + p256AddcarryxU64(&x47, &x48, 0x0, x46, x43); + var x49: u64 = undefined; + var x50: u1 = undefined; + p256AddcarryxU64(&x49, &x50, x48, x44, x41); + var x51: u64 = undefined; + var x52: u1 = undefined; + p256AddcarryxU64(&x51, &x52, x50, x42, x39); + const x53: u64 = (@intCast(u64, x52) + x40); + var x54: u64 = undefined; + var x55: u1 = undefined; + p256AddcarryxU64(&x54, &x55, 0x0, x31, x45); + var x56: u64 = undefined; + var x57: u1 = undefined; + p256AddcarryxU64(&x56, &x57, x55, x33, x47); + var x58: u64 = undefined; + var x59: u1 = undefined; + p256AddcarryxU64(&x58, &x59, x57, x35, x49); + var x60: u64 = undefined; + var x61: u1 = undefined; + p256AddcarryxU64(&x60, &x61, x59, x37, x51); + var x62: u64 = undefined; + var x63: u1 = undefined; + p256AddcarryxU64(&x62, &x63, x61, @intCast(u64, x38), x53); + var x64: u64 = undefined; + var x65: u64 = undefined; + p256MulxU64(&x64, &x65, x54, 0xffffffff00000001); + var x66: u64 = undefined; + var x67: u64 = undefined; + p256MulxU64(&x66, &x67, x54, 0xffffffff); + var x68: u64 = undefined; + var x69: u64 = undefined; + p256MulxU64(&x68, &x69, x54, 0xffffffffffffffff); + var x70: u64 = undefined; + var x71: u1 = undefined; + p256AddcarryxU64(&x70, &x71, 0x0, x69, x66); + const x72: u64 = (@intCast(u64, x71) + x67); + var x73: u64 = undefined; + var x74: u1 = undefined; + p256AddcarryxU64(&x73, &x74, 0x0, x54, x68); + var x75: u64 = undefined; + var x76: u1 = undefined; + p256AddcarryxU64(&x75, &x76, x74, x56, x70); + var x77: u64 = undefined; + var x78: u1 = undefined; + p256AddcarryxU64(&x77, &x78, x76, x58, x72); + var x79: u64 = undefined; + var x80: u1 = undefined; + p256AddcarryxU64(&x79, &x80, x78, x60, x64); + var x81: u64 = undefined; + var x82: u1 = undefined; + p256AddcarryxU64(&x81, &x82, x80, x62, x65); + const x83: u64 = (@intCast(u64, x82) + @intCast(u64, x63)); + var x84: u64 = undefined; + var x85: u64 = undefined; + p256MulxU64(&x84, &x85, x2, (arg1[3])); + var x86: u64 = undefined; + var x87: u64 = undefined; + p256MulxU64(&x86, &x87, x2, (arg1[2])); + var x88: u64 = undefined; + var x89: u64 = undefined; + p256MulxU64(&x88, &x89, x2, (arg1[1])); + var x90: u64 = undefined; + var x91: u64 = undefined; + p256MulxU64(&x90, &x91, x2, (arg1[0])); + var x92: u64 = undefined; + var x93: u1 = undefined; + p256AddcarryxU64(&x92, &x93, 0x0, x91, x88); + var x94: u64 = undefined; + var x95: u1 = undefined; + p256AddcarryxU64(&x94, &x95, x93, x89, x86); + var x96: u64 = undefined; + var x97: u1 = undefined; + p256AddcarryxU64(&x96, &x97, x95, x87, x84); + const x98: u64 = (@intCast(u64, x97) + x85); + var x99: u64 = undefined; + var x100: u1 = undefined; + p256AddcarryxU64(&x99, &x100, 0x0, x75, x90); + var x101: u64 = undefined; + var x102: u1 = undefined; + p256AddcarryxU64(&x101, &x102, x100, x77, x92); + var x103: u64 = undefined; + var x104: u1 = undefined; + p256AddcarryxU64(&x103, &x104, x102, x79, x94); + var x105: u64 = undefined; + var x106: u1 = undefined; + p256AddcarryxU64(&x105, &x106, x104, x81, x96); + var x107: u64 = undefined; + var x108: u1 = undefined; + p256AddcarryxU64(&x107, &x108, x106, x83, x98); + var x109: u64 = undefined; + var x110: u64 = undefined; + p256MulxU64(&x109, &x110, x99, 0xffffffff00000001); + var x111: u64 = undefined; + var x112: u64 = undefined; + p256MulxU64(&x111, &x112, x99, 0xffffffff); + var x113: u64 = undefined; + var x114: u64 = undefined; + p256MulxU64(&x113, &x114, x99, 0xffffffffffffffff); + var x115: u64 = undefined; + var x116: u1 = undefined; + p256AddcarryxU64(&x115, &x116, 0x0, x114, x111); + const x117: u64 = (@intCast(u64, x116) + x112); + var x118: u64 = undefined; + var x119: u1 = undefined; + p256AddcarryxU64(&x118, &x119, 0x0, x99, x113); + var x120: u64 = undefined; + var x121: u1 = undefined; + p256AddcarryxU64(&x120, &x121, x119, x101, x115); + var x122: u64 = undefined; + var x123: u1 = undefined; + p256AddcarryxU64(&x122, &x123, x121, x103, x117); + var x124: u64 = undefined; + var x125: u1 = undefined; + p256AddcarryxU64(&x124, &x125, x123, x105, x109); + var x126: u64 = undefined; + var x127: u1 = undefined; + p256AddcarryxU64(&x126, &x127, x125, x107, x110); + const x128: u64 = (@intCast(u64, x127) + @intCast(u64, x108)); + var x129: u64 = undefined; + var x130: u64 = undefined; + p256MulxU64(&x129, &x130, x3, (arg1[3])); + var x131: u64 = undefined; + var x132: u64 = undefined; + p256MulxU64(&x131, &x132, x3, (arg1[2])); + var x133: u64 = undefined; + var x134: u64 = undefined; + p256MulxU64(&x133, &x134, x3, (arg1[1])); + var x135: u64 = undefined; + var x136: u64 = undefined; + p256MulxU64(&x135, &x136, x3, (arg1[0])); + var x137: u64 = undefined; + var x138: u1 = undefined; + p256AddcarryxU64(&x137, &x138, 0x0, x136, x133); + var x139: u64 = undefined; + var x140: u1 = undefined; + p256AddcarryxU64(&x139, &x140, x138, x134, x131); + var x141: u64 = undefined; + var x142: u1 = undefined; + p256AddcarryxU64(&x141, &x142, x140, x132, x129); + const x143: u64 = (@intCast(u64, x142) + x130); + var x144: u64 = undefined; + var x145: u1 = undefined; + p256AddcarryxU64(&x144, &x145, 0x0, x120, x135); + var x146: u64 = undefined; + var x147: u1 = undefined; + p256AddcarryxU64(&x146, &x147, x145, x122, x137); + var x148: u64 = undefined; + var x149: u1 = undefined; + p256AddcarryxU64(&x148, &x149, x147, x124, x139); + var x150: u64 = undefined; + var x151: u1 = undefined; + p256AddcarryxU64(&x150, &x151, x149, x126, x141); + var x152: u64 = undefined; + var x153: u1 = undefined; + p256AddcarryxU64(&x152, &x153, x151, x128, x143); + var x154: u64 = undefined; + var x155: u64 = undefined; + p256MulxU64(&x154, &x155, x144, 0xffffffff00000001); + var x156: u64 = undefined; + var x157: u64 = undefined; + p256MulxU64(&x156, &x157, x144, 0xffffffff); + var x158: u64 = undefined; + var x159: u64 = undefined; + p256MulxU64(&x158, &x159, x144, 0xffffffffffffffff); + var x160: u64 = undefined; + var x161: u1 = undefined; + p256AddcarryxU64(&x160, &x161, 0x0, x159, x156); + const x162: u64 = (@intCast(u64, x161) + x157); + var x163: u64 = undefined; + var x164: u1 = undefined; + p256AddcarryxU64(&x163, &x164, 0x0, x144, x158); + var x165: u64 = undefined; + var x166: u1 = undefined; + p256AddcarryxU64(&x165, &x166, x164, x146, x160); + var x167: u64 = undefined; + var x168: u1 = undefined; + p256AddcarryxU64(&x167, &x168, x166, x148, x162); + var x169: u64 = undefined; + var x170: u1 = undefined; + p256AddcarryxU64(&x169, &x170, x168, x150, x154); + var x171: u64 = undefined; + var x172: u1 = undefined; + p256AddcarryxU64(&x171, &x172, x170, x152, x155); + const x173: u64 = (@intCast(u64, x172) + @intCast(u64, x153)); + var x174: u64 = undefined; + var x175: u1 = undefined; + p256SubborrowxU64(&x174, &x175, 0x0, x165, 0xffffffffffffffff); + var x176: u64 = undefined; + var x177: u1 = undefined; + p256SubborrowxU64(&x176, &x177, x175, x167, 0xffffffff); + var x178: u64 = undefined; + var x179: u1 = undefined; + p256SubborrowxU64(&x178, &x179, x177, x169, @intCast(u64, 0x0)); + var x180: u64 = undefined; + var x181: u1 = undefined; + p256SubborrowxU64(&x180, &x181, x179, x171, 0xffffffff00000001); + var x182: u64 = undefined; + var x183: u1 = undefined; + p256SubborrowxU64(&x182, &x183, x181, x173, @intCast(u64, 0x0)); + var x184: u64 = undefined; + p256CmovznzU64(&x184, x183, x174, x165); + var x185: u64 = undefined; + p256CmovznzU64(&x185, x183, x176, x167); + var x186: u64 = undefined; + p256CmovznzU64(&x186, x183, x178, x169); + var x187: u64 = undefined; + p256CmovznzU64(&x187, x183, x180, x171); + out1[0] = x184; + out1[1] = x185; + out1[2] = x186; + out1[3] = x187; +} + +/// The function p256Add 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 p256Add(out1: *Limbs, arg1: Limbs, arg2: Limbs) void { + var x1: u64 = undefined; + var x2: u1 = undefined; + p256AddcarryxU64(&x1, &x2, 0x0, (arg1[0]), (arg2[0])); + var x3: u64 = undefined; + var x4: u1 = undefined; + p256AddcarryxU64(&x3, &x4, x2, (arg1[1]), (arg2[1])); + var x5: u64 = undefined; + var x6: u1 = undefined; + p256AddcarryxU64(&x5, &x6, x4, (arg1[2]), (arg2[2])); + var x7: u64 = undefined; + var x8: u1 = undefined; + p256AddcarryxU64(&x7, &x8, x6, (arg1[3]), (arg2[3])); + var x9: u64 = undefined; + var x10: u1 = undefined; + p256SubborrowxU64(&x9, &x10, 0x0, x1, 0xffffffffffffffff); + var x11: u64 = undefined; + var x12: u1 = undefined; + p256SubborrowxU64(&x11, &x12, x10, x3, 0xffffffff); + var x13: u64 = undefined; + var x14: u1 = undefined; + p256SubborrowxU64(&x13, &x14, x12, x5, @intCast(u64, 0x0)); + var x15: u64 = undefined; + var x16: u1 = undefined; + p256SubborrowxU64(&x15, &x16, x14, x7, 0xffffffff00000001); + var x17: u64 = undefined; + var x18: u1 = undefined; + p256SubborrowxU64(&x17, &x18, x16, @intCast(u64, x8), @intCast(u64, 0x0)); + var x19: u64 = undefined; + p256CmovznzU64(&x19, x18, x9, x1); + var x20: u64 = undefined; + p256CmovznzU64(&x20, x18, x11, x3); + var x21: u64 = undefined; + p256CmovznzU64(&x21, x18, x13, x5); + var x22: u64 = undefined; + p256CmovznzU64(&x22, x18, x15, x7); + out1[0] = x19; + out1[1] = x20; + out1[2] = x21; + out1[3] = x22; +} + +/// The function p256Sub 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 p256Sub(out1: *Limbs, arg1: Limbs, arg2: Limbs) void { + var x1: u64 = undefined; + var x2: u1 = undefined; + p256SubborrowxU64(&x1, &x2, 0x0, (arg1[0]), (arg2[0])); + var x3: u64 = undefined; + var x4: u1 = undefined; + p256SubborrowxU64(&x3, &x4, x2, (arg1[1]), (arg2[1])); + var x5: u64 = undefined; + var x6: u1 = undefined; + p256SubborrowxU64(&x5, &x6, x4, (arg1[2]), (arg2[2])); + var x7: u64 = undefined; + var x8: u1 = undefined; + p256SubborrowxU64(&x7, &x8, x6, (arg1[3]), (arg2[3])); + var x9: u64 = undefined; + p256CmovznzU64(&x9, x8, @intCast(u64, 0x0), 0xffffffffffffffff); + var x10: u64 = undefined; + var x11: u1 = undefined; + p256AddcarryxU64(&x10, &x11, 0x0, x1, x9); + var x12: u64 = undefined; + var x13: u1 = undefined; + p256AddcarryxU64(&x12, &x13, x11, x3, (x9 & 0xffffffff)); + var x14: u64 = undefined; + var x15: u1 = undefined; + p256AddcarryxU64(&x14, &x15, x13, x5, @intCast(u64, 0x0)); + var x16: u64 = undefined; + var x17: u1 = undefined; + p256AddcarryxU64(&x16, &x17, x15, x7, (x9 & 0xffffffff00000001)); + out1[0] = x10; + out1[1] = x12; + out1[2] = x14; + out1[3] = x16; +} + +/// The function p256Opp 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 p256Opp(out1: *Limbs, arg1: Limbs) void { + var x1: u64 = undefined; + var x2: u1 = undefined; + p256SubborrowxU64(&x1, &x2, 0x0, @intCast(u64, 0x0), (arg1[0])); + var x3: u64 = undefined; + var x4: u1 = undefined; + p256SubborrowxU64(&x3, &x4, x2, @intCast(u64, 0x0), (arg1[1])); + var x5: u64 = undefined; + var x6: u1 = undefined; + p256SubborrowxU64(&x5, &x6, x4, @intCast(u64, 0x0), (arg1[2])); + var x7: u64 = undefined; + var x8: u1 = undefined; + p256SubborrowxU64(&x7, &x8, x6, @intCast(u64, 0x0), (arg1[3])); + var x9: u64 = undefined; + p256CmovznzU64(&x9, x8, @intCast(u64, 0x0), 0xffffffffffffffff); + var x10: u64 = undefined; + var x11: u1 = undefined; + p256AddcarryxU64(&x10, &x11, 0x0, x1, x9); + var x12: u64 = undefined; + var x13: u1 = undefined; + p256AddcarryxU64(&x12, &x13, x11, x3, (x9 & 0xffffffff)); + var x14: u64 = undefined; + var x15: u1 = undefined; + p256AddcarryxU64(&x14, &x15, x13, x5, @intCast(u64, 0x0)); + var x16: u64 = undefined; + var x17: u1 = undefined; + p256AddcarryxU64(&x16, &x17, x15, x7, (x9 & 0xffffffff00000001)); + out1[0] = x10; + out1[1] = x12; + out1[2] = x14; + out1[3] = x16; +} + +/// The function p256FromMontgomery 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 p256FromMontgomery(out1: *Limbs, arg1: Limbs) void { + const x1: u64 = (arg1[0]); + var x2: u64 = undefined; + var x3: u64 = undefined; + p256MulxU64(&x2, &x3, x1, 0xffffffff00000001); + var x4: u64 = undefined; + var x5: u64 = undefined; + p256MulxU64(&x4, &x5, x1, 0xffffffff); + var x6: u64 = undefined; + var x7: u64 = undefined; + p256MulxU64(&x6, &x7, x1, 0xffffffffffffffff); + var x8: u64 = undefined; + var x9: u1 = undefined; + p256AddcarryxU64(&x8, &x9, 0x0, x7, x4); + var x10: u64 = undefined; + var x11: u1 = undefined; + p256AddcarryxU64(&x10, &x11, 0x0, x1, x6); + var x12: u64 = undefined; + var x13: u1 = undefined; + p256AddcarryxU64(&x12, &x13, x11, @intCast(u64, 0x0), x8); + var x14: u64 = undefined; + var x15: u1 = undefined; + p256AddcarryxU64(&x14, &x15, 0x0, x12, (arg1[1])); + var x16: u64 = undefined; + var x17: u64 = undefined; + p256MulxU64(&x16, &x17, x14, 0xffffffff00000001); + var x18: u64 = undefined; + var x19: u64 = undefined; + p256MulxU64(&x18, &x19, x14, 0xffffffff); + var x20: u64 = undefined; + var x21: u64 = undefined; + p256MulxU64(&x20, &x21, x14, 0xffffffffffffffff); + var x22: u64 = undefined; + var x23: u1 = undefined; + p256AddcarryxU64(&x22, &x23, 0x0, x21, x18); + var x24: u64 = undefined; + var x25: u1 = undefined; + p256AddcarryxU64(&x24, &x25, 0x0, x14, x20); + var x26: u64 = undefined; + var x27: u1 = undefined; + p256AddcarryxU64(&x26, &x27, x25, (@intCast(u64, x15) + (@intCast(u64, x13) + (@intCast(u64, x9) + x5))), x22); + var x28: u64 = undefined; + var x29: u1 = undefined; + p256AddcarryxU64(&x28, &x29, x27, x2, (@intCast(u64, x23) + x19)); + var x30: u64 = undefined; + var x31: u1 = undefined; + p256AddcarryxU64(&x30, &x31, x29, x3, x16); + var x32: u64 = undefined; + var x33: u1 = undefined; + p256AddcarryxU64(&x32, &x33, 0x0, x26, (arg1[2])); + var x34: u64 = undefined; + var x35: u1 = undefined; + p256AddcarryxU64(&x34, &x35, x33, x28, @intCast(u64, 0x0)); + var x36: u64 = undefined; + var x37: u1 = undefined; + p256AddcarryxU64(&x36, &x37, x35, x30, @intCast(u64, 0x0)); + var x38: u64 = undefined; + var x39: u64 = undefined; + p256MulxU64(&x38, &x39, x32, 0xffffffff00000001); + var x40: u64 = undefined; + var x41: u64 = undefined; + p256MulxU64(&x40, &x41, x32, 0xffffffff); + var x42: u64 = undefined; + var x43: u64 = undefined; + p256MulxU64(&x42, &x43, x32, 0xffffffffffffffff); + var x44: u64 = undefined; + var x45: u1 = undefined; + p256AddcarryxU64(&x44, &x45, 0x0, x43, x40); + var x46: u64 = undefined; + var x47: u1 = undefined; + p256AddcarryxU64(&x46, &x47, 0x0, x32, x42); + var x48: u64 = undefined; + var x49: u1 = undefined; + p256AddcarryxU64(&x48, &x49, x47, x34, x44); + var x50: u64 = undefined; + var x51: u1 = undefined; + p256AddcarryxU64(&x50, &x51, x49, x36, (@intCast(u64, x45) + x41)); + var x52: u64 = undefined; + var x53: u1 = undefined; + p256AddcarryxU64(&x52, &x53, x51, (@intCast(u64, x37) + (@intCast(u64, x31) + x17)), x38); + var x54: u64 = undefined; + var x55: u1 = undefined; + p256AddcarryxU64(&x54, &x55, 0x0, x48, (arg1[3])); + var x56: u64 = undefined; + var x57: u1 = undefined; + p256AddcarryxU64(&x56, &x57, x55, x50, @intCast(u64, 0x0)); + var x58: u64 = undefined; + var x59: u1 = undefined; + p256AddcarryxU64(&x58, &x59, x57, x52, @intCast(u64, 0x0)); + var x60: u64 = undefined; + var x61: u64 = undefined; + p256MulxU64(&x60, &x61, x54, 0xffffffff00000001); + var x62: u64 = undefined; + var x63: u64 = undefined; + p256MulxU64(&x62, &x63, x54, 0xffffffff); + var x64: u64 = undefined; + var x65: u64 = undefined; + p256MulxU64(&x64, &x65, x54, 0xffffffffffffffff); + var x66: u64 = undefined; + var x67: u1 = undefined; + p256AddcarryxU64(&x66, &x67, 0x0, x65, x62); + var x68: u64 = undefined; + var x69: u1 = undefined; + p256AddcarryxU64(&x68, &x69, 0x0, x54, x64); + var x70: u64 = undefined; + var x71: u1 = undefined; + p256AddcarryxU64(&x70, &x71, x69, x56, x66); + var x72: u64 = undefined; + var x73: u1 = undefined; + p256AddcarryxU64(&x72, &x73, x71, x58, (@intCast(u64, x67) + x63)); + var x74: u64 = undefined; + var x75: u1 = undefined; + p256AddcarryxU64(&x74, &x75, x73, (@intCast(u64, x59) + (@intCast(u64, x53) + x39)), x60); + const x76: u64 = (@intCast(u64, x75) + x61); + var x77: u64 = undefined; + var x78: u1 = undefined; + p256SubborrowxU64(&x77, &x78, 0x0, x70, 0xffffffffffffffff); + var x79: u64 = undefined; + var x80: u1 = undefined; + p256SubborrowxU64(&x79, &x80, x78, x72, 0xffffffff); + var x81: u64 = undefined; + var x82: u1 = undefined; + p256SubborrowxU64(&x81, &x82, x80, x74, @intCast(u64, 0x0)); + var x83: u64 = undefined; + var x84: u1 = undefined; + p256SubborrowxU64(&x83, &x84, x82, x76, 0xffffffff00000001); + var x85: u64 = undefined; + var x86: u1 = undefined; + p256SubborrowxU64(&x85, &x86, x84, @intCast(u64, 0x0), @intCast(u64, 0x0)); + var x87: u64 = undefined; + p256CmovznzU64(&x87, x86, x77, x70); + var x88: u64 = undefined; + p256CmovznzU64(&x88, x86, x79, x72); + var x89: u64 = undefined; + p256CmovznzU64(&x89, x86, x81, x74); + var x90: u64 = undefined; + p256CmovznzU64(&x90, x86, x83, x76); + out1[0] = x87; + out1[1] = x88; + out1[2] = x89; + out1[3] = x90; +} + +/// The function p256ToMontgomery 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 p256ToMontgomery(out1: *Limbs, arg1: Limbs) void { + const x1: u64 = (arg1[1]); + const x2: u64 = (arg1[2]); + const x3: u64 = (arg1[3]); + const x4: u64 = (arg1[0]); + var x5: u64 = undefined; + var x6: u64 = undefined; + p256MulxU64(&x5, &x6, x4, 0x4fffffffd); + var x7: u64 = undefined; + var x8: u64 = undefined; + p256MulxU64(&x7, &x8, x4, 0xfffffffffffffffe); + var x9: u64 = undefined; + var x10: u64 = undefined; + p256MulxU64(&x9, &x10, x4, 0xfffffffbffffffff); + var x11: u64 = undefined; + var x12: u64 = undefined; + p256MulxU64(&x11, &x12, x4, 0x3); + var x13: u64 = undefined; + var x14: u1 = undefined; + p256AddcarryxU64(&x13, &x14, 0x0, x12, x9); + var x15: u64 = undefined; + var x16: u1 = undefined; + p256AddcarryxU64(&x15, &x16, x14, x10, x7); + var x17: u64 = undefined; + var x18: u1 = undefined; + p256AddcarryxU64(&x17, &x18, x16, x8, x5); + var x19: u64 = undefined; + var x20: u64 = undefined; + p256MulxU64(&x19, &x20, x11, 0xffffffff00000001); + var x21: u64 = undefined; + var x22: u64 = undefined; + p256MulxU64(&x21, &x22, x11, 0xffffffff); + var x23: u64 = undefined; + var x24: u64 = undefined; + p256MulxU64(&x23, &x24, x11, 0xffffffffffffffff); + var x25: u64 = undefined; + var x26: u1 = undefined; + p256AddcarryxU64(&x25, &x26, 0x0, x24, x21); + var x27: u64 = undefined; + var x28: u1 = undefined; + p256AddcarryxU64(&x27, &x28, 0x0, x11, x23); + var x29: u64 = undefined; + var x30: u1 = undefined; + p256AddcarryxU64(&x29, &x30, x28, x13, x25); + var x31: u64 = undefined; + var x32: u1 = undefined; + p256AddcarryxU64(&x31, &x32, x30, x15, (@intCast(u64, x26) + x22)); + var x33: u64 = undefined; + var x34: u1 = undefined; + p256AddcarryxU64(&x33, &x34, x32, x17, x19); + var x35: u64 = undefined; + var x36: u1 = undefined; + p256AddcarryxU64(&x35, &x36, x34, (@intCast(u64, x18) + x6), x20); + var x37: u64 = undefined; + var x38: u64 = undefined; + p256MulxU64(&x37, &x38, x1, 0x4fffffffd); + var x39: u64 = undefined; + var x40: u64 = undefined; + p256MulxU64(&x39, &x40, x1, 0xfffffffffffffffe); + var x41: u64 = undefined; + var x42: u64 = undefined; + p256MulxU64(&x41, &x42, x1, 0xfffffffbffffffff); + var x43: u64 = undefined; + var x44: u64 = undefined; + p256MulxU64(&x43, &x44, x1, 0x3); + var x45: u64 = undefined; + var x46: u1 = undefined; + p256AddcarryxU64(&x45, &x46, 0x0, x44, x41); + var x47: u64 = undefined; + var x48: u1 = undefined; + p256AddcarryxU64(&x47, &x48, x46, x42, x39); + var x49: u64 = undefined; + var x50: u1 = undefined; + p256AddcarryxU64(&x49, &x50, x48, x40, x37); + var x51: u64 = undefined; + var x52: u1 = undefined; + p256AddcarryxU64(&x51, &x52, 0x0, x29, x43); + var x53: u64 = undefined; + var x54: u1 = undefined; + p256AddcarryxU64(&x53, &x54, x52, x31, x45); + var x55: u64 = undefined; + var x56: u1 = undefined; + p256AddcarryxU64(&x55, &x56, x54, x33, x47); + var x57: u64 = undefined; + var x58: u1 = undefined; + p256AddcarryxU64(&x57, &x58, x56, x35, x49); + var x59: u64 = undefined; + var x60: u64 = undefined; + p256MulxU64(&x59, &x60, x51, 0xffffffff00000001); + var x61: u64 = undefined; + var x62: u64 = undefined; + p256MulxU64(&x61, &x62, x51, 0xffffffff); + var x63: u64 = undefined; + var x64: u64 = undefined; + p256MulxU64(&x63, &x64, x51, 0xffffffffffffffff); + var x65: u64 = undefined; + var x66: u1 = undefined; + p256AddcarryxU64(&x65, &x66, 0x0, x64, x61); + var x67: u64 = undefined; + var x68: u1 = undefined; + p256AddcarryxU64(&x67, &x68, 0x0, x51, x63); + var x69: u64 = undefined; + var x70: u1 = undefined; + p256AddcarryxU64(&x69, &x70, x68, x53, x65); + var x71: u64 = undefined; + var x72: u1 = undefined; + p256AddcarryxU64(&x71, &x72, x70, x55, (@intCast(u64, x66) + x62)); + var x73: u64 = undefined; + var x74: u1 = undefined; + p256AddcarryxU64(&x73, &x74, x72, x57, x59); + var x75: u64 = undefined; + var x76: u1 = undefined; + p256AddcarryxU64(&x75, &x76, x74, ((@intCast(u64, x58) + @intCast(u64, x36)) + (@intCast(u64, x50) + x38)), x60); + var x77: u64 = undefined; + var x78: u64 = undefined; + p256MulxU64(&x77, &x78, x2, 0x4fffffffd); + var x79: u64 = undefined; + var x80: u64 = undefined; + p256MulxU64(&x79, &x80, x2, 0xfffffffffffffffe); + var x81: u64 = undefined; + var x82: u64 = undefined; + p256MulxU64(&x81, &x82, x2, 0xfffffffbffffffff); + var x83: u64 = undefined; + var x84: u64 = undefined; + p256MulxU64(&x83, &x84, x2, 0x3); + var x85: u64 = undefined; + var x86: u1 = undefined; + p256AddcarryxU64(&x85, &x86, 0x0, x84, x81); + var x87: u64 = undefined; + var x88: u1 = undefined; + p256AddcarryxU64(&x87, &x88, x86, x82, x79); + var x89: u64 = undefined; + var x90: u1 = undefined; + p256AddcarryxU64(&x89, &x90, x88, x80, x77); + var x91: u64 = undefined; + var x92: u1 = undefined; + p256AddcarryxU64(&x91, &x92, 0x0, x69, x83); + var x93: u64 = undefined; + var x94: u1 = undefined; + p256AddcarryxU64(&x93, &x94, x92, x71, x85); + var x95: u64 = undefined; + var x96: u1 = undefined; + p256AddcarryxU64(&x95, &x96, x94, x73, x87); + var x97: u64 = undefined; + var x98: u1 = undefined; + p256AddcarryxU64(&x97, &x98, x96, x75, x89); + var x99: u64 = undefined; + var x100: u64 = undefined; + p256MulxU64(&x99, &x100, x91, 0xffffffff00000001); + var x101: u64 = undefined; + var x102: u64 = undefined; + p256MulxU64(&x101, &x102, x91, 0xffffffff); + var x103: u64 = undefined; + var x104: u64 = undefined; + p256MulxU64(&x103, &x104, x91, 0xffffffffffffffff); + var x105: u64 = undefined; + var x106: u1 = undefined; + p256AddcarryxU64(&x105, &x106, 0x0, x104, x101); + var x107: u64 = undefined; + var x108: u1 = undefined; + p256AddcarryxU64(&x107, &x108, 0x0, x91, x103); + var x109: u64 = undefined; + var x110: u1 = undefined; + p256AddcarryxU64(&x109, &x110, x108, x93, x105); + var x111: u64 = undefined; + var x112: u1 = undefined; + p256AddcarryxU64(&x111, &x112, x110, x95, (@intCast(u64, x106) + x102)); + var x113: u64 = undefined; + var x114: u1 = undefined; + p256AddcarryxU64(&x113, &x114, x112, x97, x99); + var x115: u64 = undefined; + var x116: u1 = undefined; + p256AddcarryxU64(&x115, &x116, x114, ((@intCast(u64, x98) + @intCast(u64, x76)) + (@intCast(u64, x90) + x78)), x100); + var x117: u64 = undefined; + var x118: u64 = undefined; + p256MulxU64(&x117, &x118, x3, 0x4fffffffd); + var x119: u64 = undefined; + var x120: u64 = undefined; + p256MulxU64(&x119, &x120, x3, 0xfffffffffffffffe); + var x121: u64 = undefined; + var x122: u64 = undefined; + p256MulxU64(&x121, &x122, x3, 0xfffffffbffffffff); + var x123: u64 = undefined; + var x124: u64 = undefined; + p256MulxU64(&x123, &x124, x3, 0x3); + var x125: u64 = undefined; + var x126: u1 = undefined; + p256AddcarryxU64(&x125, &x126, 0x0, x124, x121); + var x127: u64 = undefined; + var x128: u1 = undefined; + p256AddcarryxU64(&x127, &x128, x126, x122, x119); + var x129: u64 = undefined; + var x130: u1 = undefined; + p256AddcarryxU64(&x129, &x130, x128, x120, x117); + var x131: u64 = undefined; + var x132: u1 = undefined; + p256AddcarryxU64(&x131, &x132, 0x0, x109, x123); + var x133: u64 = undefined; + var x134: u1 = undefined; + p256AddcarryxU64(&x133, &x134, x132, x111, x125); + var x135: u64 = undefined; + var x136: u1 = undefined; + p256AddcarryxU64(&x135, &x136, x134, x113, x127); + var x137: u64 = undefined; + var x138: u1 = undefined; + p256AddcarryxU64(&x137, &x138, x136, x115, x129); + var x139: u64 = undefined; + var x140: u64 = undefined; + p256MulxU64(&x139, &x140, x131, 0xffffffff00000001); + var x141: u64 = undefined; + var x142: u64 = undefined; + p256MulxU64(&x141, &x142, x131, 0xffffffff); + var x143: u64 = undefined; + var x144: u64 = undefined; + p256MulxU64(&x143, &x144, x131, 0xffffffffffffffff); + var x145: u64 = undefined; + var x146: u1 = undefined; + p256AddcarryxU64(&x145, &x146, 0x0, x144, x141); + var x147: u64 = undefined; + var x148: u1 = undefined; + p256AddcarryxU64(&x147, &x148, 0x0, x131, x143); + var x149: u64 = undefined; + var x150: u1 = undefined; + p256AddcarryxU64(&x149, &x150, x148, x133, x145); + var x151: u64 = undefined; + var x152: u1 = undefined; + p256AddcarryxU64(&x151, &x152, x150, x135, (@intCast(u64, x146) + x142)); + var x153: u64 = undefined; + var x154: u1 = undefined; + p256AddcarryxU64(&x153, &x154, x152, x137, x139); + var x155: u64 = undefined; + var x156: u1 = undefined; + p256AddcarryxU64(&x155, &x156, x154, ((@intCast(u64, x138) + @intCast(u64, x116)) + (@intCast(u64, x130) + x118)), x140); + var x157: u64 = undefined; + var x158: u1 = undefined; + p256SubborrowxU64(&x157, &x158, 0x0, x149, 0xffffffffffffffff); + var x159: u64 = undefined; + var x160: u1 = undefined; + p256SubborrowxU64(&x159, &x160, x158, x151, 0xffffffff); + var x161: u64 = undefined; + var x162: u1 = undefined; + p256SubborrowxU64(&x161, &x162, x160, x153, @intCast(u64, 0x0)); + var x163: u64 = undefined; + var x164: u1 = undefined; + p256SubborrowxU64(&x163, &x164, x162, x155, 0xffffffff00000001); + var x165: u64 = undefined; + var x166: u1 = undefined; + p256SubborrowxU64(&x165, &x166, x164, @intCast(u64, x156), @intCast(u64, 0x0)); + var x167: u64 = undefined; + p256CmovznzU64(&x167, x166, x157, x149); + var x168: u64 = undefined; + p256CmovznzU64(&x168, x166, x159, x151); + var x169: u64 = undefined; + p256CmovznzU64(&x169, x166, x161, x153); + var x170: u64 = undefined; + p256CmovznzU64(&x170, x166, x163, x155); + out1[0] = x167; + out1[1] = x168; + out1[2] = x169; + out1[3] = x170; +} + +/// The function p256Nonzero 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 p256Nonzero(out1: *u64, arg1: Limbs) void { + const x1: u64 = ((arg1[0]) | ((arg1[1]) | ((arg1[2]) | (arg1[3])))); + out1.* = x1; +} + +/// The function p256Selectznz 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 p256Selectznz(out1: *Limbs, arg1: u1, arg2: Limbs, arg3: Limbs) void { + var x1: u64 = undefined; + p256CmovznzU64(&x1, arg1, (arg2[0]), (arg3[0])); + var x2: u64 = undefined; + p256CmovznzU64(&x2, arg1, (arg2[1]), (arg3[1])); + var x3: u64 = undefined; + p256CmovznzU64(&x3, arg1, (arg2[2]), (arg3[2])); + var x4: u64 = undefined; + p256CmovznzU64(&x4, arg1, (arg2[3]), (arg3[3])); + out1[0] = x1; + out1[1] = x2; + out1[2] = x3; + out1[3] = x4; +} + +/// The function p256ToBytes 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 p256ToBytes(out1: *[32]u8, arg1: Limbs) void { + const x1: u64 = (arg1[3]); + const x2: u64 = (arg1[2]); + const x3: u64 = (arg1[1]); + const x4: u64 = (arg1[0]); + const x5: u8 = @intCast(u8, (x4 & @intCast(u64, 0xff))); + const x6: u64 = (x4 >> 8); + const x7: u8 = @intCast(u8, (x6 & @intCast(u64, 0xff))); + const x8: u64 = (x6 >> 8); + const x9: u8 = @intCast(u8, (x8 & @intCast(u64, 0xff))); + const x10: u64 = (x8 >> 8); + const x11: u8 = @intCast(u8, (x10 & @intCast(u64, 0xff))); + const x12: u64 = (x10 >> 8); + const x13: u8 = @intCast(u8, (x12 & @intCast(u64, 0xff))); + const x14: u64 = (x12 >> 8); + const x15: u8 = @intCast(u8, (x14 & @intCast(u64, 0xff))); + const x16: u64 = (x14 >> 8); + const x17: u8 = @intCast(u8, (x16 & @intCast(u64, 0xff))); + const x18: u8 = @intCast(u8, (x16 >> 8)); + const x19: u8 = @intCast(u8, (x3 & @intCast(u64, 0xff))); + const x20: u64 = (x3 >> 8); + const x21: u8 = @intCast(u8, (x20 & @intCast(u64, 0xff))); + const x22: u64 = (x20 >> 8); + const x23: u8 = @intCast(u8, (x22 & @intCast(u64, 0xff))); + const x24: u64 = (x22 >> 8); + const x25: u8 = @intCast(u8, (x24 & @intCast(u64, 0xff))); + const x26: u64 = (x24 >> 8); + const x27: u8 = @intCast(u8, (x26 & @intCast(u64, 0xff))); + const x28: u64 = (x26 >> 8); + const x29: u8 = @intCast(u8, (x28 & @intCast(u64, 0xff))); + const x30: u64 = (x28 >> 8); + const x31: u8 = @intCast(u8, (x30 & @intCast(u64, 0xff))); + const x32: u8 = @intCast(u8, (x30 >> 8)); + const x33: u8 = @intCast(u8, (x2 & @intCast(u64, 0xff))); + const x34: u64 = (x2 >> 8); + const x35: u8 = @intCast(u8, (x34 & @intCast(u64, 0xff))); + const x36: u64 = (x34 >> 8); + const x37: u8 = @intCast(u8, (x36 & @intCast(u64, 0xff))); + const x38: u64 = (x36 >> 8); + const x39: u8 = @intCast(u8, (x38 & @intCast(u64, 0xff))); + const x40: u64 = (x38 >> 8); + const x41: u8 = @intCast(u8, (x40 & @intCast(u64, 0xff))); + const x42: u64 = (x40 >> 8); + const x43: u8 = @intCast(u8, (x42 & @intCast(u64, 0xff))); + const x44: u64 = (x42 >> 8); + const x45: u8 = @intCast(u8, (x44 & @intCast(u64, 0xff))); + const x46: u8 = @intCast(u8, (x44 >> 8)); + const x47: u8 = @intCast(u8, (x1 & @intCast(u64, 0xff))); + const x48: u64 = (x1 >> 8); + const x49: u8 = @intCast(u8, (x48 & @intCast(u64, 0xff))); + const x50: u64 = (x48 >> 8); + const x51: u8 = @intCast(u8, (x50 & @intCast(u64, 0xff))); + const x52: u64 = (x50 >> 8); + const x53: u8 = @intCast(u8, (x52 & @intCast(u64, 0xff))); + const x54: u64 = (x52 >> 8); + const x55: u8 = @intCast(u8, (x54 & @intCast(u64, 0xff))); + const x56: u64 = (x54 >> 8); + const x57: u8 = @intCast(u8, (x56 & @intCast(u64, 0xff))); + const x58: u64 = (x56 >> 8); + const x59: u8 = @intCast(u8, (x58 & @intCast(u64, 0xff))); + const x60: u8 = @intCast(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 p256FromBytes 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 p256FromBytes(out1: *Limbs, arg1: [32]u8) void { + const x1: u64 = (@intCast(u64, (arg1[31])) << 56); + const x2: u64 = (@intCast(u64, (arg1[30])) << 48); + const x3: u64 = (@intCast(u64, (arg1[29])) << 40); + const x4: u64 = (@intCast(u64, (arg1[28])) << 32); + const x5: u64 = (@intCast(u64, (arg1[27])) << 24); + const x6: u64 = (@intCast(u64, (arg1[26])) << 16); + const x7: u64 = (@intCast(u64, (arg1[25])) << 8); + const x8: u8 = (arg1[24]); + const x9: u64 = (@intCast(u64, (arg1[23])) << 56); + const x10: u64 = (@intCast(u64, (arg1[22])) << 48); + const x11: u64 = (@intCast(u64, (arg1[21])) << 40); + const x12: u64 = (@intCast(u64, (arg1[20])) << 32); + const x13: u64 = (@intCast(u64, (arg1[19])) << 24); + const x14: u64 = (@intCast(u64, (arg1[18])) << 16); + const x15: u64 = (@intCast(u64, (arg1[17])) << 8); + const x16: u8 = (arg1[16]); + const x17: u64 = (@intCast(u64, (arg1[15])) << 56); + const x18: u64 = (@intCast(u64, (arg1[14])) << 48); + const x19: u64 = (@intCast(u64, (arg1[13])) << 40); + const x20: u64 = (@intCast(u64, (arg1[12])) << 32); + const x21: u64 = (@intCast(u64, (arg1[11])) << 24); + const x22: u64 = (@intCast(u64, (arg1[10])) << 16); + const x23: u64 = (@intCast(u64, (arg1[9])) << 8); + const x24: u8 = (arg1[8]); + const x25: u64 = (@intCast(u64, (arg1[7])) << 56); + const x26: u64 = (@intCast(u64, (arg1[6])) << 48); + const x27: u64 = (@intCast(u64, (arg1[5])) << 40); + const x28: u64 = (@intCast(u64, (arg1[4])) << 32); + const x29: u64 = (@intCast(u64, (arg1[3])) << 24); + const x30: u64 = (@intCast(u64, (arg1[2])) << 16); + const x31: u64 = (@intCast(u64, (arg1[1])) << 8); + const x32: u8 = (arg1[0]); + const x33: u64 = (x31 + @intCast(u64, x32)); + const x34: u64 = (x30 + x33); + const x35: u64 = (x29 + x34); + const x36: u64 = (x28 + x35); + const x37: u64 = (x27 + x36); + const x38: u64 = (x26 + x37); + const x39: u64 = (x25 + x38); + const x40: u64 = (x23 + @intCast(u64, x24)); + const x41: u64 = (x22 + x40); + const x42: u64 = (x21 + x41); + const x43: u64 = (x20 + x42); + const x44: u64 = (x19 + x43); + const x45: u64 = (x18 + x44); + const x46: u64 = (x17 + x45); + const x47: u64 = (x15 + @intCast(u64, x16)); + const x48: u64 = (x14 + x47); + const x49: u64 = (x13 + x48); + const x50: u64 = (x12 + x49); + const x51: u64 = (x11 + x50); + const x52: u64 = (x10 + x51); + const x53: u64 = (x9 + x52); + const x54: u64 = (x7 + @intCast(u64, x8)); + const x55: u64 = (x6 + x54); + const x56: u64 = (x5 + x55); + const x57: u64 = (x4 + x56); + const x58: u64 = (x3 + x57); + const x59: u64 = (x2 + x58); + const x60: u64 = (x1 + x59); + out1[0] = x39; + out1[1] = x46; + out1[2] = x53; + out1[3] = x60; +} + +/// The function p256SetOne 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 p256SetOne(out1: *Limbs) void { + out1[0] = @intCast(u64, 0x1); + out1[1] = 0xffffffff00000000; + out1[2] = 0xffffffffffffffff; + out1[3] = 0xfffffffe; +} + +/// The function p256Msat 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 p256Msat(out1: *[5]u64) void { + out1[0] = 0xffffffffffffffff; + out1[1] = 0xffffffff; + out1[2] = @intCast(u64, 0x0); + out1[3] = 0xffffffff00000001; + out1[4] = @intCast(u64, 0x0); +} + +/// The function p256Divstep 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 p256Divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *Limbs, out5: *Limbs, arg1: u64, arg2: [5]u64, arg3: [5]u64, arg4: Limbs, arg5: Limbs) void { + var x1: u64 = undefined; + var x2: u1 = undefined; + p256AddcarryxU64(&x1, &x2, 0x0, (~arg1), @intCast(u64, 0x1)); + const x3: u1 = (@intCast(u1, (x1 >> 63)) & @intCast(u1, ((arg3[0]) & @intCast(u64, 0x1)))); + var x4: u64 = undefined; + var x5: u1 = undefined; + p256AddcarryxU64(&x4, &x5, 0x0, (~arg1), @intCast(u64, 0x1)); + var x6: u64 = undefined; + p256CmovznzU64(&x6, x3, arg1, x4); + var x7: u64 = undefined; + p256CmovznzU64(&x7, x3, (arg2[0]), (arg3[0])); + var x8: u64 = undefined; + p256CmovznzU64(&x8, x3, (arg2[1]), (arg3[1])); + var x9: u64 = undefined; + p256CmovznzU64(&x9, x3, (arg2[2]), (arg3[2])); + var x10: u64 = undefined; + p256CmovznzU64(&x10, x3, (arg2[3]), (arg3[3])); + var x11: u64 = undefined; + p256CmovznzU64(&x11, x3, (arg2[4]), (arg3[4])); + var x12: u64 = undefined; + var x13: u1 = undefined; + p256AddcarryxU64(&x12, &x13, 0x0, @intCast(u64, 0x1), (~(arg2[0]))); + var x14: u64 = undefined; + var x15: u1 = undefined; + p256AddcarryxU64(&x14, &x15, x13, @intCast(u64, 0x0), (~(arg2[1]))); + var x16: u64 = undefined; + var x17: u1 = undefined; + p256AddcarryxU64(&x16, &x17, x15, @intCast(u64, 0x0), (~(arg2[2]))); + var x18: u64 = undefined; + var x19: u1 = undefined; + p256AddcarryxU64(&x18, &x19, x17, @intCast(u64, 0x0), (~(arg2[3]))); + var x20: u64 = undefined; + var x21: u1 = undefined; + p256AddcarryxU64(&x20, &x21, x19, @intCast(u64, 0x0), (~(arg2[4]))); + var x22: u64 = undefined; + p256CmovznzU64(&x22, x3, (arg3[0]), x12); + var x23: u64 = undefined; + p256CmovznzU64(&x23, x3, (arg3[1]), x14); + var x24: u64 = undefined; + p256CmovznzU64(&x24, x3, (arg3[2]), x16); + var x25: u64 = undefined; + p256CmovznzU64(&x25, x3, (arg3[3]), x18); + var x26: u64 = undefined; + p256CmovznzU64(&x26, x3, (arg3[4]), x20); + var x27: u64 = undefined; + p256CmovznzU64(&x27, x3, (arg4[0]), (arg5[0])); + var x28: u64 = undefined; + p256CmovznzU64(&x28, x3, (arg4[1]), (arg5[1])); + var x29: u64 = undefined; + p256CmovznzU64(&x29, x3, (arg4[2]), (arg5[2])); + var x30: u64 = undefined; + p256CmovznzU64(&x30, x3, (arg4[3]), (arg5[3])); + var x31: u64 = undefined; + var x32: u1 = undefined; + p256AddcarryxU64(&x31, &x32, 0x0, x27, x27); + var x33: u64 = undefined; + var x34: u1 = undefined; + p256AddcarryxU64(&x33, &x34, x32, x28, x28); + var x35: u64 = undefined; + var x36: u1 = undefined; + p256AddcarryxU64(&x35, &x36, x34, x29, x29); + var x37: u64 = undefined; + var x38: u1 = undefined; + p256AddcarryxU64(&x37, &x38, x36, x30, x30); + var x39: u64 = undefined; + var x40: u1 = undefined; + p256SubborrowxU64(&x39, &x40, 0x0, x31, 0xffffffffffffffff); + var x41: u64 = undefined; + var x42: u1 = undefined; + p256SubborrowxU64(&x41, &x42, x40, x33, 0xffffffff); + var x43: u64 = undefined; + var x44: u1 = undefined; + p256SubborrowxU64(&x43, &x44, x42, x35, @intCast(u64, 0x0)); + var x45: u64 = undefined; + var x46: u1 = undefined; + p256SubborrowxU64(&x45, &x46, x44, x37, 0xffffffff00000001); + var x47: u64 = undefined; + var x48: u1 = undefined; + p256SubborrowxU64(&x47, &x48, x46, @intCast(u64, x38), @intCast(u64, 0x0)); + const x49: u64 = (arg4[3]); + const x50: u64 = (arg4[2]); + const x51: u64 = (arg4[1]); + const x52: u64 = (arg4[0]); + var x53: u64 = undefined; + var x54: u1 = undefined; + p256SubborrowxU64(&x53, &x54, 0x0, @intCast(u64, 0x0), x52); + var x55: u64 = undefined; + var x56: u1 = undefined; + p256SubborrowxU64(&x55, &x56, x54, @intCast(u64, 0x0), x51); + var x57: u64 = undefined; + var x58: u1 = undefined; + p256SubborrowxU64(&x57, &x58, x56, @intCast(u64, 0x0), x50); + var x59: u64 = undefined; + var x60: u1 = undefined; + p256SubborrowxU64(&x59, &x60, x58, @intCast(u64, 0x0), x49); + var x61: u64 = undefined; + p256CmovznzU64(&x61, x60, @intCast(u64, 0x0), 0xffffffffffffffff); + var x62: u64 = undefined; + var x63: u1 = undefined; + p256AddcarryxU64(&x62, &x63, 0x0, x53, x61); + var x64: u64 = undefined; + var x65: u1 = undefined; + p256AddcarryxU64(&x64, &x65, x63, x55, (x61 & 0xffffffff)); + var x66: u64 = undefined; + var x67: u1 = undefined; + p256AddcarryxU64(&x66, &x67, x65, x57, @intCast(u64, 0x0)); + var x68: u64 = undefined; + var x69: u1 = undefined; + p256AddcarryxU64(&x68, &x69, x67, x59, (x61 & 0xffffffff00000001)); + var x70: u64 = undefined; + p256CmovznzU64(&x70, x3, (arg5[0]), x62); + var x71: u64 = undefined; + p256CmovznzU64(&x71, x3, (arg5[1]), x64); + var x72: u64 = undefined; + p256CmovznzU64(&x72, x3, (arg5[2]), x66); + var x73: u64 = undefined; + p256CmovznzU64(&x73, x3, (arg5[3]), x68); + const x74: u1 = @intCast(u1, (x22 & @intCast(u64, 0x1))); + var x75: u64 = undefined; + p256CmovznzU64(&x75, x74, @intCast(u64, 0x0), x7); + var x76: u64 = undefined; + p256CmovznzU64(&x76, x74, @intCast(u64, 0x0), x8); + var x77: u64 = undefined; + p256CmovznzU64(&x77, x74, @intCast(u64, 0x0), x9); + var x78: u64 = undefined; + p256CmovznzU64(&x78, x74, @intCast(u64, 0x0), x10); + var x79: u64 = undefined; + p256CmovznzU64(&x79, x74, @intCast(u64, 0x0), x11); + var x80: u64 = undefined; + var x81: u1 = undefined; + p256AddcarryxU64(&x80, &x81, 0x0, x22, x75); + var x82: u64 = undefined; + var x83: u1 = undefined; + p256AddcarryxU64(&x82, &x83, x81, x23, x76); + var x84: u64 = undefined; + var x85: u1 = undefined; + p256AddcarryxU64(&x84, &x85, x83, x24, x77); + var x86: u64 = undefined; + var x87: u1 = undefined; + p256AddcarryxU64(&x86, &x87, x85, x25, x78); + var x88: u64 = undefined; + var x89: u1 = undefined; + p256AddcarryxU64(&x88, &x89, x87, x26, x79); + var x90: u64 = undefined; + p256CmovznzU64(&x90, x74, @intCast(u64, 0x0), x27); + var x91: u64 = undefined; + p256CmovznzU64(&x91, x74, @intCast(u64, 0x0), x28); + var x92: u64 = undefined; + p256CmovznzU64(&x92, x74, @intCast(u64, 0x0), x29); + var x93: u64 = undefined; + p256CmovznzU64(&x93, x74, @intCast(u64, 0x0), x30); + var x94: u64 = undefined; + var x95: u1 = undefined; + p256AddcarryxU64(&x94, &x95, 0x0, x70, x90); + var x96: u64 = undefined; + var x97: u1 = undefined; + p256AddcarryxU64(&x96, &x97, x95, x71, x91); + var x98: u64 = undefined; + var x99: u1 = undefined; + p256AddcarryxU64(&x98, &x99, x97, x72, x92); + var x100: u64 = undefined; + var x101: u1 = undefined; + p256AddcarryxU64(&x100, &x101, x99, x73, x93); + var x102: u64 = undefined; + var x103: u1 = undefined; + p256SubborrowxU64(&x102, &x103, 0x0, x94, 0xffffffffffffffff); + var x104: u64 = undefined; + var x105: u1 = undefined; + p256SubborrowxU64(&x104, &x105, x103, x96, 0xffffffff); + var x106: u64 = undefined; + var x107: u1 = undefined; + p256SubborrowxU64(&x106, &x107, x105, x98, @intCast(u64, 0x0)); + var x108: u64 = undefined; + var x109: u1 = undefined; + p256SubborrowxU64(&x108, &x109, x107, x100, 0xffffffff00000001); + var x110: u64 = undefined; + var x111: u1 = undefined; + p256SubborrowxU64(&x110, &x111, x109, @intCast(u64, x101), @intCast(u64, 0x0)); + var x112: u64 = undefined; + var x113: u1 = undefined; + p256AddcarryxU64(&x112, &x113, 0x0, x6, @intCast(u64, 0x1)); + const x114: u64 = ((x80 >> 1) | ((x82 << 63) & 0xffffffffffffffff)); + const x115: u64 = ((x82 >> 1) | ((x84 << 63) & 0xffffffffffffffff)); + const x116: u64 = ((x84 >> 1) | ((x86 << 63) & 0xffffffffffffffff)); + const x117: u64 = ((x86 >> 1) | ((x88 << 63) & 0xffffffffffffffff)); + const x118: u64 = ((x88 & 0x8000000000000000) | (x88 >> 1)); + var x119: u64 = undefined; + p256CmovznzU64(&x119, x48, x39, x31); + var x120: u64 = undefined; + p256CmovznzU64(&x120, x48, x41, x33); + var x121: u64 = undefined; + p256CmovznzU64(&x121, x48, x43, x35); + var x122: u64 = undefined; + p256CmovznzU64(&x122, x48, x45, x37); + var x123: u64 = undefined; + p256CmovznzU64(&x123, x111, x102, x94); + var x124: u64 = undefined; + p256CmovznzU64(&x124, x111, x104, x96); + var x125: u64 = undefined; + p256CmovznzU64(&x125, x111, x106, x98); + var x126: u64 = undefined; + p256CmovznzU64(&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 p256DivstepPrecomp 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 p256DivstepPrecomp(out1: *Limbs) void { + out1[0] = 0x67ffffffb8000000; + out1[1] = 0xc000000038000000; + out1[2] = 0xd80000007fffffff; + out1[3] = 0x2fffffffffffffff; +} diff --git a/lib/std/crypto/pcurves/p256/scalar.zig b/lib/std/crypto/pcurves/p256/scalar.zig new file mode 100644 index 0000000000..e047f6a8d6 --- /dev/null +++ b/lib/std/crypto/pcurves/p256/scalar.zig @@ -0,0 +1,219 @@ +// 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 debug = std.debug; +const math = std.math; +const mem = std.mem; + +const Fe = @import("field.zig").Fe; + +const NonCanonicalError = std.crypto.errors.NonCanonicalError; +const NotSquareError = std.crypto.errors.NotSquareError; + +/// A compressed scalar, in canonical form. +pub const CompressedScalar = [32]u8; + +/// Reject a scalar whose encoding is not canonical. +pub fn rejectNonCanonical(s: CompressedScalar) NonCanonicalError!void { + return Fe.rejectNonCanonical(s); +} + +/// Reduce a 48-bytes scalar to the field size. +pub fn reduce48(s: [48]u8) CompressedScalar { + return Scalar.fromBytes48(s).toBytes(); +} + +/// Reduce a 64-bytes scalar to the field size. +pub fn reduce64(s: [64]u8) CompressedScalar { + return ScalarDouble.fromBytes64(s).toBytes(); +} + +/// 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} ** 32; + 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} ** 32; + 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} ** 32; + 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 }; + } +}; diff --git a/lib/std/crypto/pcurves/tests.zig b/lib/std/crypto/pcurves/tests.zig new file mode 100644 index 0000000000..4e8e08a7fe --- /dev/null +++ b/lib/std/crypto/pcurves/tests.zig @@ -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)); +} From e9e91b4ed058f4c4e3f3380ec06cb914becd04a8 Mon Sep 17 00:00:00 2001 From: g-w1 <58830309+g-w1@users.noreply.github.com> Date: Sat, 1 May 2021 02:17:17 -0400 Subject: [PATCH 05/47] std.build: if using a RunStep, show the command run on verbose (#8571) --- lib/std/build/run.zig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/std/build/run.zig b/lib/std/build/run.zig index ca39b0216e..1e16813cb8 100644 --- a/lib/std/build/run.zig +++ b/lib/std/build/run.zig @@ -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; From 51f80deaf6e7377f34c3fd4d68b8ad03b5de3bfb Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 1 May 2021 11:02:04 +0200 Subject: [PATCH 06/47] std: Fix stack overflow in SPARC clone() impl Leave the minimum amount of stack space required by the ABI (16 * 8 bytes for the window contents plus 6 * 8 bytes for the input arguments) on the new thread stack. --- lib/std/special/c.zig | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig index 379c4a40da..c7084f3a11 100644 --- a/lib/std/special/c.zig +++ b/lib/std/special/c.zig @@ -614,23 +614,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 From 527053a4e40acb1403dcb3e1c8534fe0de07b3e3 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 1 May 2021 11:03:59 +0200 Subject: [PATCH 07/47] std: Import correct errno defs for SPARC Taken from Linux arch/sparc/include/uapi/asm/errno.h --- lib/std/os/bits/linux.zig | 1 + lib/std/os/bits/linux/errno-mips.zig | 4 + lib/std/os/bits/linux/errno-sparc.zig | 144 ++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 lib/std/os/bits/linux/errno-sparc.zig diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index 86d89016f3..6ef95fa035 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -10,6 +10,7 @@ usingnamespace @import("../bits.zig"); pub usingnamespace switch (builtin.arch) { .mips, .mipsel => @import("linux/errno-mips.zig"), + .sparc, .sparcel, .sparcv9 => @import("linux/errno-sparc.zig"), else => @import("linux/errno-generic.zig"), }; diff --git a/lib/std/os/bits/linux/errno-mips.zig b/lib/std/os/bits/linux/errno-mips.zig index 2c74fa6f8c..2c22290288 100644 --- a/lib/std/os/bits/linux/errno-mips.zig +++ b/lib/std/os/bits/linux/errno-mips.zig @@ -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; diff --git a/lib/std/os/bits/linux/errno-sparc.zig b/lib/std/os/bits/linux/errno-sparc.zig new file mode 100644 index 0000000000..bbeabaaef0 --- /dev/null +++ b/lib/std/os/bits/linux/errno-sparc.zig @@ -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; From 69a9c1488d901e45440c195d42e7837a4c247f2b Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 1 May 2021 12:25:40 +0200 Subject: [PATCH 08/47] std: Add signal numbers for SPARC --- lib/std/os/bits/linux.zig | 106 ++++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 34 deletions(-) diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index 6ef95fa035..94da5cc99a 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -248,40 +248,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; From 718b43504eae6af063f8b9cf5803a82758c7e37b Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 1 May 2021 15:46:28 +0200 Subject: [PATCH 09/47] std: Fix pwrite/pread syscalls on SPARC targets --- lib/std/os/linux.zig | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index d8c7e99905..5cfcb88e64 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -386,7 +386,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( @@ -409,8 +409,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, @@ -450,7 +452,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( @@ -478,7 +480,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) { @@ -502,8 +504,10 @@ pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: u64) usize { ); } } else { + // Some architectures (eg. 64bit SPARC) pwrite is called pread64. + 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, From 9f6edfd2016177883c952cd72bbcfab87025703c Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 23 Mar 2021 09:17:57 +0100 Subject: [PATCH 10/47] std: Implement signbit for f128 --- lib/std/math/signbit.zig | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/std/math/signbit.zig b/lib/std/math/signbit.zig index 9fb245c3c6..08963b3d94 100644 --- a/lib/std/math/signbit.zig +++ b/lib/std/math/signbit.zig @@ -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)); +} From 236dba8ba926c3214e759df23d20f2f5880b6235 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 29 Apr 2021 09:00:29 +0200 Subject: [PATCH 11/47] std: Implement copysign for f128 --- lib/std/math/copysign.zig | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/std/math/copysign.zig b/lib/std/math/copysign.zig index 2804d10495..7861cda8eb 100644 --- a/lib/std/math/copysign.zig +++ b/lib/std/math/copysign.zig @@ -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); +} From 06b2fee05eeb4280fd4363a8a8da73f59f977b73 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 29 Apr 2021 09:05:33 +0200 Subject: [PATCH 12/47] std: Implement isFinite for f128 --- lib/std/math/isfinite.zig | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/std/math/isfinite.zig b/lib/std/math/isfinite.zig index 5266b918df..11a352b042 100644 --- a/lib/std/math/isfinite.zig +++ b/lib/std/math/isfinite.zig @@ -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))); } From d788181a3b96ec653f5bef42916a8129837cdac4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 1 May 2021 18:07:26 -0400 Subject: [PATCH 13/47] fix typo Co-authored-by: Maciej Walczak <14938807+xackus@users.noreply.github.com> --- lib/std/os/linux.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 5cfcb88e64..4a67ca7685 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -504,7 +504,7 @@ pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: u64) usize { ); } } else { - // Some architectures (eg. 64bit SPARC) pwrite is called pread64. + // Some architectures (eg. 64bit SPARC) pwrite is called pwrite64. const S = if (!@hasField(SYS, "pwrite") and @hasField(SYS, "pwrite64")) .pwrite64 else .pwrite; return syscall4( S, From 9a637f81e021cacd8e38be6793a86b01ef735704 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sun, 2 May 2021 02:07:59 +0200 Subject: [PATCH 14/47] Restore the CI logging as before --- ci/azure/linux_script | 10 +--------- ci/azure/macos_script | 10 +--------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/ci/azure/linux_script b/ci/azure/linux_script index 2b0e9c46aa..912a2518bb 100755 --- a/ci/azure/linux_script +++ b/ci/azure/linux_script @@ -65,17 +65,9 @@ make $JOBS install cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig" make $JOBS install -set +x -LOG=$(mktemp) for step in test-toolchain test-std docs; do - echo "* Running step: [$step]" - if ! release/bin/zig build $step -Denable-qemu -Denable-wasmtime 2>"$LOG" >&2; then - cat "$LOG" >&2 - exit 1 - fi - echo " Done." + release/bin/zig build $step -Denable-qemu -Denable-wasmtime done -set -x # Look for HTML errors. tidy -qe ../zig-cache/langref.html diff --git a/ci/azure/macos_script b/ci/azure/macos_script index 4aa7629352..d6d32612cc 100755 --- a/ci/azure/macos_script +++ b/ci/azure/macos_script @@ -55,17 +55,9 @@ make $JOBS install cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig" -DZIG_TARGET_MCPU="x86_64_v2" make $JOBS install -set +x -LOG=$(mktemp) for step in test-toolchain test-std docs; do - echo "* Running step: [$step]" - if ! release/bin/zig build $step 2>"$LOG" >&2; then - cat "$LOG" >&2 - exit 1 - fi - echo " Done." + release/bin/zig build $step done -set -x if [ "${BUILD_REASON}" != "PullRequest" ]; then mv ../LICENSE release/ From c47028cd025f4ce405a9395fa979ff14a3e6349a Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 2 May 2021 16:03:13 -0300 Subject: [PATCH 15/47] ci: freebsd: use py38-s3cmd --- ci/srht/freebsd_script | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/srht/freebsd_script b/ci/srht/freebsd_script index 0d59e92d02..4999ad7634 100755 --- a/ci/srht/freebsd_script +++ b/ci/srht/freebsd_script @@ -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" From 2ab588049e41a96337a4fa8c2d9507320bc4278b Mon Sep 17 00:00:00 2001 From: lithdew Date: Fri, 30 Apr 2021 18:17:39 +0900 Subject: [PATCH 16/47] x/os, x/net: layout tcp, ipv4/ipv6, and socket abstractions The `Socket` abstraction was refactored to only comprise of methods that can be generically used/applied to all socket domains and protocols. A more comprehensive IPv4/IPv6 module derived from @LemonBoy's earlier work was implemented under `std.x.os.IPv4` and `std.x.os.IPv6`. Using this module, one can then combine them together into a union for example in order to optimize memory usage when dealing with socket addresses. A `TCP.Client` and `TCP.Listener` abstraction is introduced that is one layer over the `Socket` abstraction, which isolates methods that can only be applied to a "client socket" and a "listening socket". All prior tests from the `Socket` abstraction, which all previously operated assuming the socket is operating via. TCP/IP, were moved. All TCP socket options were also moved into the `TCP.Client` and `TCP.Listener` abstractions respectively away from the `Socket` abstraction. Some additional socket options from @LemonBoy's prior PR for Darwin were also moved in (i.e. SIGNOPIPE). --- lib/std/os/bits/darwin.zig | 7 + lib/std/x.zig | 9 +- lib/std/x/net/TCP.zig | 399 ++++++++++++++++++++++++++++ lib/std/x/os/Socket.zig | 124 ++------- lib/std/x/os/net.zig | 532 +++++++++++++++++++++++++++++++++++++ lib/std/x/os/os.zig | 9 - 6 files changed, 967 insertions(+), 113 deletions(-) create mode 100644 lib/std/x/net/TCP.zig create mode 100644 lib/std/x/os/net.zig delete mode 100644 lib/std/x/os/os.zig diff --git a/lib/std/os/bits/darwin.zig b/lib/std/os/bits/darwin.zig index aca24b1c0c..e8a477c5d6 100644 --- a/lib/std/os/bits/darwin.zig +++ b/lib/std/os/bits/darwin.zig @@ -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; } diff --git a/lib/std/x.zig b/lib/std/x.zig index df7debf121..02742f29ec 100644 --- a/lib/std/x.zig +++ b/lib/std/x.zig @@ -1 +1,8 @@ -pub const os = @import("x/os/os.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 TCP = @import("x/net/TCP.zig"); +}; diff --git a/lib/std/x/net/TCP.zig b/lib/std/x/net/TCP.zig new file mode 100644 index 0000000000..5e81dbc060 --- /dev/null +++ b/lib/std/x/net/TCP.zig @@ -0,0 +1,399 @@ +const std = @import("../../std.zig"); + +const os = std.os; +const fmt = std.fmt; +const mem = std.mem; +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: TCP.Address, + + /// Enclose a TCP client and address into a client-address pair. + pub fn from(socket: Socket, address: TCP.Address) Connection { + return .{ .client = TCP.Client.from(socket), .address = address }; + } + + /// 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: TCP.Address) !void { + return self.socket.connect(TCP.Address, address); + } + + /// 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) !TCP.Address { + return self.socket.getLocalAddress(TCP.Address); + } + + /// 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: TCP.Address) !void { + return self.socket.bind(TCP.Address, address); + } + + /// 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 self.socket.accept(TCP.Connection, TCP.Address, 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) !TCP.Address { + return self.socket.getLocalAddress(TCP.Address); + } + + /// 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); + } +}; + +/// A TCP socket address designated by a host IP and port. A TCP socket +/// address comprises of 28 bytes. It may freely be used in place of +/// `sockaddr` when working with socket syscalls. +/// +/// It is not recommended to touch the fields of an `Address`, but to +/// instead make use of its available accessor methods. +pub const Address = extern struct { + family: u16, + port: u16, + host: extern union { + ipv4: extern struct { + address: IPv4, + }, + ipv6: extern struct { + flow_info: u32 = 0, + address: IPv6, + }, + }, + + /// Instantiate a new TCP address with a IPv4 host and port. + pub fn initIPv4(host: IPv4, port: u16) Address { + return Address{ + .family = os.AF_INET, + .port = mem.nativeToBig(u16, port), + .host = .{ + .ipv4 = .{ + .address = host, + }, + }, + }; + } + + /// Instantiate a new TCP address with a IPv6 host and port. + pub fn initIPv6(host: IPv6, port: u16) Address { + return Address{ + .family = os.AF_INET6, + .port = mem.nativeToBig(u16, port), + .host = .{ + .ipv6 = .{ + .address = host, + }, + }, + }; + } + + /// Extract the host of the address. + pub fn getHost(self: Address) union(enum) { v4: IPv4, v6: IPv6 } { + return switch (self.family) { + os.AF_INET => .{ .v4 = self.host.ipv4.address }, + os.AF_INET6 => .{ .v6 = self.host.ipv6.address }, + else => unreachable, + }; + } + + /// Extract the port of the address. + pub fn getPort(self: Address) u16 { + return mem.nativeToBig(u16, self.port); + } + + /// Set the port of the address. + pub fn setPort(self: *Address, port: u16) void { + self.port = mem.nativeToBig(u16, port); + } + + /// Implements the `std.fmt.format` API. + pub fn format( + self: Address, + comptime layout: []const u8, + opts: fmt.FormatOptions, + writer: anytype, + ) !void { + switch (self.getHost()) { + .v4 => |host| try fmt.format(writer, "{}:{}", .{ host, self.getPort() }), + .v6 => |host| try fmt.format(writer, "{}:{}", .{ host, self.getPort() }), + } + } +}; + +test { + testing.refAllDecls(@This()); +} + +test "tcp: create non-blocking pair" { + const a = try TCP.Listener.init(.ip, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC); + defer a.deinit(); + + try a.bind(TCP.Address.initIPv4(IPv4.unspecified, 0)); + try a.listen(128); + + const binded_address = try a.getLocalAddress(); + + const b = try TCP.Client.init(.ip, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC); + 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.deinit(); +} + +test "tcp/client: set read timeout of 1 millisecond on blocking client" { + const a = try TCP.Listener.init(.ip, os.SOCK_CLOEXEC); + defer a.deinit(); + + try a.bind(TCP.Address.initIPv4(IPv4.unspecified, 0)); + try a.listen(128); + + const binded_address = try a.getLocalAddress(); + + const b = try TCP.Client.init(.ip, os.SOCK_CLOEXEC); + defer b.deinit(); + + try b.connect(binded_address); + try b.setReadTimeout(1); + + const ab = try a.accept(os.SOCK_CLOEXEC); + defer ab.deinit(); + + var buf: [1]u8 = undefined; + testing.expectError(error.WouldBlock, b.read(&buf)); +} + +test "tcp/listener: bind to unspecified ipv4 address" { + const socket = try TCP.Listener.init(.ip, os.SOCK_CLOEXEC); + defer socket.deinit(); + + try socket.bind(TCP.Address.initIPv4(IPv4.unspecified, 0)); + try socket.listen(128); + + const address = try socket.getLocalAddress(); + testing.expect(address.getHost() == .v4); +} + +test "tcp/listener: bind to unspecified ipv6 address" { + const socket = try TCP.Listener.init(.ipv6, os.SOCK_CLOEXEC); + defer socket.deinit(); + + try socket.bind(TCP.Address.initIPv6(IPv6.unspecified, 0)); + try socket.listen(128); + + const address = try socket.getLocalAddress(); + testing.expect(address.getHost() == .v6); +} diff --git a/lib/std/x/os/Socket.zig b/lib/std/x/os/Socket.zig index 3f1971a877..96e64c97ef 100644 --- a/lib/std/x/os/Socket.zig +++ b/lib/std/x/os/Socket.zig @@ -2,19 +2,11 @@ const std = @import("../../std.zig"); const os = std.os; 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, -}; - /// The underlying handle of a socket. fd: os.socket_t, @@ -23,19 +15,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, comptime Address: type, address: Address) !void { + return os.bind(self.fd, @ptrCast(*const os.sockaddr, &address), @sizeOf(Address)); } /// Start listening for incoming connections on the socket. @@ -44,22 +41,19 @@ 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, comptime Address: type, address: Address) !void { + return os.connect(self.fd, @ptrCast(*const os.sockaddr, &address), @sizeOf(Address)); } /// Accept a pending incoming connection queued to the kernel backlog /// of the socket. -pub fn accept(self: Socket, flags: u32) !Socket.Connection { - var address: os.sockaddr = undefined; - var address_len: u32 = @sizeOf(os.sockaddr); +pub fn accept(self: Socket, comptime Connection: type, comptime Address: type, flags: u32) !Connection { + var address: Address = undefined; + var address_len: u32 = @sizeOf(Address); - const fd = try os.accept(self.fd, &address, &address_len, flags); + const fd = try os.accept(self.fd, @ptrCast(*os.sockaddr, &address), &address_len, flags); - return Connection{ - .socket = Socket{ .fd = fd }, - .address = net.Address.initPosix(@alignCast(4, &address)), - }; + return Connection.from(.{ .fd = fd }, address); } /// Read data from the socket into the buffer provided. It returns the @@ -100,11 +94,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 { - 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)); +pub fn getLocalAddress(self: Socket, comptime Address: type) !Address { + var address: Address = undefined; + var address_len: u32 = @sizeOf(Address); + try os.getsockname(self.fd, @ptrCast(*os.sockaddr, &address), &address_len); + return address; } /// Query and return the latest cached error on the socket. @@ -164,33 +158,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)); @@ -225,52 +192,3 @@ pub fn setReadTimeout(self: Socket, milliseconds: usize) !void { 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(); -} diff --git a/lib/std/x/os/net.zig b/lib/std/x/os/net.zig new file mode 100644 index 0000000000..dddb3b73e0 --- /dev/null +++ b/lib/std/x/os/net.zig @@ -0,0 +1,532 @@ +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 (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); +} + +/// An IPv4 address comprised of 4 bytes. +pub const IPv4 = extern struct { + /// 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 { + /// 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", + "FF01::FB%lo", + }; + + const outputs = [_][]const u8{ + "ff01::fb", + "ff01::fb", + "::1", + "::", + "2001:db8::", + "::1234:5678", + "2001:db8::1234:5678", + "::ffff:123.5.123.5", + "ff01::fb%1", + }; + + for (inputs) |input, i| { + try testing.expectFmt(outputs[i], "{}", .{try IPv6.parse(input)}); + } +} diff --git a/lib/std/x/os/os.zig b/lib/std/x/os/os.zig deleted file mode 100644 index 1d1b8edc7c..0000000000 --- a/lib/std/x/os/os.zig +++ /dev/null @@ -1,9 +0,0 @@ -const std = @import("../../std.zig"); - -const testing = std.testing; - -pub const Socket = @import("Socket.zig"); - -test { - testing.refAllDecls(@This()); -} From 13068da43e8fbd0ae5d03aff27fb4e8802e1218c Mon Sep 17 00:00:00 2001 From: lithdew Date: Fri, 30 Apr 2021 21:08:49 +0900 Subject: [PATCH 17/47] x/os, x/net: re-approach `Address`, rename namespace `TCP -> tcp` Address comments from @ifreund and @MasterQ32 to address unsafeness and ergonomics of the `Address` API. Rename the `TCP` namespace to `tcp` as it does not contain any top-level fields. Fix missing reference to `sockaddr` which was identified by @kprotty in os/bits/linux/arm64.zig. --- lib/std/builtin.zig | 18 +-- lib/std/compress/deflate.zig | 6 +- lib/std/os/bits/linux/arm64.zig | 1 + lib/std/x.zig | 16 +- lib/std/x/net/{TCP.zig => tcp.zig} | 246 ++++++++++++++--------------- lib/std/x/os/Socket.zig | 128 +++++++++++++-- lib/std/x/os/net.zig | 18 +++ 7 files changed, 266 insertions(+), 167 deletions(-) rename lib/std/x/net/{TCP.zig => tcp.zig} (67%) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index a4da9ba2f3..c5fa77bb7c 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -150,23 +150,7 @@ pub const Mode = enum { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. -pub const CallingConvention = enum { - Unspecified, - C, - Naked, - Async, - Inline, - Interrupt, - Signal, - Stdcall, - Fastcall, - Vectorcall, - Thiscall, - APCS, - AAPCS, - AAPCSVFP, - SysV -}; +pub const CallingConvention = enum { Unspecified, C, Naked, Async, Inline, Interrupt, Signal, Stdcall, Fastcall, Vectorcall, Thiscall, APCS, AAPCS, AAPCSVFP, SysV }; /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. diff --git a/lib/std/compress/deflate.zig b/lib/std/compress/deflate.zig index 09e162933c..88b9ec8672 100644 --- a/lib/std/compress/deflate.zig +++ b/lib/std/compress/deflate.zig @@ -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)); } diff --git a/lib/std/os/bits/linux/arm64.zig b/lib/std/os/bits/linux/arm64.zig index e373d978e1..9737a68de1 100644 --- a/lib/std/os/bits/linux/arm64.zig +++ b/lib/std/os/bits/linux/arm64.zig @@ -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; diff --git a/lib/std/x.zig b/lib/std/x.zig index 02742f29ec..0c23f3f035 100644 --- a/lib/std/x.zig +++ b/lib/std/x.zig @@ -1,8 +1,22 @@ +// 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 TCP = @import("x/net/TCP.zig"); + pub const tcp = @import("x/net/tcp.zig"); }; + +test { + inline for (.{ os, net }) |module| { + std.testing.refAllDecls(module); + } +} diff --git a/lib/std/x/net/TCP.zig b/lib/std/x/net/tcp.zig similarity index 67% rename from lib/std/x/net/TCP.zig rename to lib/std/x/net/tcp.zig index 5e81dbc060..4c65310f51 100644 --- a/lib/std/x/net/TCP.zig +++ b/lib/std/x/net/tcp.zig @@ -1,3 +1,9 @@ +// 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; @@ -10,20 +16,76 @@ const IPv6 = std.x.os.IPv6; const Socket = std.x.os.Socket; /// A generic TCP socket abstraction. -const TCP = @This(); +const tcp = @This(); + +/// A union of all eligible types of socket addresses over TCP. +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 a TCP socket address. + pub fn from(address: Socket.Address) tcp.Address { + return switch (address) { + .ipv4 => |ipv4_address| .{ .ipv4 = ipv4_address }, + .ipv6 => |ipv6_address| .{ .ipv6 = ipv6_address }, + }; + } + + /// Re-interpret a TCP socket address into a generic socket address. + pub fn into(self: tcp.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: tcp.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 }), + } + } +}; /// A TCP client-address pair. pub const Connection = struct { - client: TCP.Client, - address: TCP.Address, + client: tcp.Client, + address: tcp.Address, /// Enclose a TCP client and address into a client-address pair. - pub fn from(socket: Socket, address: TCP.Address) Connection { - return .{ .client = TCP.Client.from(socket), .address = address }; + pub fn from(conn: Socket.Connection) tcp.Connection { + return .{ + .client = tcp.Client.from(conn.socket), + .address = tcp.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 { + pub fn deinit(self: tcp.Connection) void { self.client.deinit(); } }; @@ -39,7 +101,7 @@ pub const Client = struct { socket: Socket, /// Opens a new client. - pub fn init(domain: TCP.Domain, flags: u32) !Client { + pub fn init(domain: tcp.Domain, flags: u32) !Client { return Client{ .socket = try Socket.init( @enumToInt(domain), @@ -65,8 +127,8 @@ pub const Client = struct { } /// Have the client attempt to the connect to an address. - pub fn connect(self: Client, address: TCP.Address) !void { - return self.socket.connect(TCP.Address, address); + pub fn connect(self: Client, address: tcp.Address) !void { + return self.socket.connect(address.into()); } /// Read data from the socket into the buffer provided. It returns the @@ -122,8 +184,8 @@ pub const Client = struct { } /// Query the address that the client's socket is locally bounded to. - pub fn getLocalAddress(self: Client) !TCP.Address { - return self.socket.getLocalAddress(TCP.Address); + pub fn getLocalAddress(self: Client) !tcp.Address { + return tcp.Address.from(try self.socket.getLocalAddress()); } /// Disable Nagle's algorithm on a TCP socket. It returns `error.UnsupportedSocketOption` if @@ -167,7 +229,7 @@ pub const Listener = struct { socket: Socket, /// Opens a new listener. - pub fn init(domain: TCP.Domain, flags: u32) !Listener { + pub fn init(domain: tcp.Domain, flags: u32) !Listener { return Listener{ .socket = try Socket.init( @enumToInt(domain), @@ -190,8 +252,8 @@ pub const Listener = struct { } /// Binds the listener's socket to an address. - pub fn bind(self: Listener, address: TCP.Address) !void { - return self.socket.bind(TCP.Address, address); + pub fn bind(self: Listener, address: tcp.Address) !void { + return self.socket.bind(address.into()); } /// Start listening for incoming connections. @@ -201,8 +263,8 @@ pub const Listener = struct { /// 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 self.socket.accept(TCP.Connection, TCP.Address, flags); + 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. @@ -211,8 +273,8 @@ pub const Listener = struct { } /// Query the address that the listener's socket is locally bounded to. - pub fn getLocalAddress(self: Listener) !TCP.Address { - return self.socket.getLocalAddress(TCP.Address); + pub fn getLocalAddress(self: Listener) !tcp.Address { + return tcp.Address.from(try self.socket.getLocalAddress()); } /// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if @@ -253,147 +315,69 @@ pub const Listener = struct { } }; -/// A TCP socket address designated by a host IP and port. A TCP socket -/// address comprises of 28 bytes. It may freely be used in place of -/// `sockaddr` when working with socket syscalls. -/// -/// It is not recommended to touch the fields of an `Address`, but to -/// instead make use of its available accessor methods. -pub const Address = extern struct { - family: u16, - port: u16, - host: extern union { - ipv4: extern struct { - address: IPv4, - }, - ipv6: extern struct { - flow_info: u32 = 0, - address: IPv6, - }, - }, - - /// Instantiate a new TCP address with a IPv4 host and port. - pub fn initIPv4(host: IPv4, port: u16) Address { - return Address{ - .family = os.AF_INET, - .port = mem.nativeToBig(u16, port), - .host = .{ - .ipv4 = .{ - .address = host, - }, - }, - }; - } - - /// Instantiate a new TCP address with a IPv6 host and port. - pub fn initIPv6(host: IPv6, port: u16) Address { - return Address{ - .family = os.AF_INET6, - .port = mem.nativeToBig(u16, port), - .host = .{ - .ipv6 = .{ - .address = host, - }, - }, - }; - } - - /// Extract the host of the address. - pub fn getHost(self: Address) union(enum) { v4: IPv4, v6: IPv6 } { - return switch (self.family) { - os.AF_INET => .{ .v4 = self.host.ipv4.address }, - os.AF_INET6 => .{ .v6 = self.host.ipv6.address }, - else => unreachable, - }; - } - - /// Extract the port of the address. - pub fn getPort(self: Address) u16 { - return mem.nativeToBig(u16, self.port); - } - - /// Set the port of the address. - pub fn setPort(self: *Address, port: u16) void { - self.port = mem.nativeToBig(u16, port); - } - - /// Implements the `std.fmt.format` API. - pub fn format( - self: Address, - comptime layout: []const u8, - opts: fmt.FormatOptions, - writer: anytype, - ) !void { - switch (self.getHost()) { - .v4 => |host| try fmt.format(writer, "{}:{}", .{ host, self.getPort() }), - .v6 => |host| try fmt.format(writer, "{}:{}", .{ host, self.getPort() }), - } - } -}; - test { testing.refAllDecls(@This()); } test "tcp: create non-blocking pair" { - const a = try TCP.Listener.init(.ip, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC); - defer a.deinit(); + const listener = try tcp.Listener.init(.ip, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC); + defer listener.deinit(); - try a.bind(TCP.Address.initIPv4(IPv4.unspecified, 0)); - try a.listen(128); + try listener.bind(tcp.Address.initIPv4(IPv4.unspecified, 0)); + try listener.listen(128); - const binded_address = try a.getLocalAddress(); + const binded_address = try listener.getLocalAddress(); - const b = try TCP.Client.init(.ip, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC); - defer b.deinit(); + const client = try tcp.Client.init(.ip, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC); + defer client.deinit(); - testing.expectError(error.WouldBlock, b.connect(binded_address)); - try b.getError(); + testing.expectError(error.WouldBlock, client.connect(binded_address)); + try client.getError(); - const ab = try a.accept(os.SOCK_NONBLOCK | os.SOCK_CLOEXEC); - defer ab.deinit(); + const conn = try listener.accept(os.SOCK_NONBLOCK | os.SOCK_CLOEXEC); + defer conn.deinit(); } test "tcp/client: set read timeout of 1 millisecond on blocking client" { - const a = try TCP.Listener.init(.ip, os.SOCK_CLOEXEC); - defer a.deinit(); + const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC); + defer listener.deinit(); - try a.bind(TCP.Address.initIPv4(IPv4.unspecified, 0)); - try a.listen(128); + try listener.bind(tcp.Address.initIPv4(IPv4.unspecified, 0)); + try listener.listen(128); - const binded_address = try a.getLocalAddress(); + const binded_address = try listener.getLocalAddress(); - const b = try TCP.Client.init(.ip, os.SOCK_CLOEXEC); - defer b.deinit(); + const client = try tcp.Client.init(.ip, os.SOCK_CLOEXEC); + defer client.deinit(); - try b.connect(binded_address); - try b.setReadTimeout(1); + try client.connect(binded_address); + try client.setReadTimeout(1); - const ab = try a.accept(os.SOCK_CLOEXEC); - defer ab.deinit(); + const conn = try listener.accept(os.SOCK_CLOEXEC); + defer conn.deinit(); var buf: [1]u8 = undefined; - testing.expectError(error.WouldBlock, b.read(&buf)); + testing.expectError(error.WouldBlock, client.read(&buf)); } test "tcp/listener: bind to unspecified ipv4 address" { - const socket = try TCP.Listener.init(.ip, os.SOCK_CLOEXEC); - defer socket.deinit(); + const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC); + defer listener.deinit(); - try socket.bind(TCP.Address.initIPv4(IPv4.unspecified, 0)); - try socket.listen(128); + try listener.bind(tcp.Address.initIPv4(IPv4.unspecified, 0)); + try listener.listen(128); - const address = try socket.getLocalAddress(); - testing.expect(address.getHost() == .v4); + const address = try listener.getLocalAddress(); + testing.expect(address == .ipv4); } test "tcp/listener: bind to unspecified ipv6 address" { - const socket = try TCP.Listener.init(.ipv6, os.SOCK_CLOEXEC); - defer socket.deinit(); + const listener = try tcp.Listener.init(.ipv6, os.SOCK_CLOEXEC); + defer listener.deinit(); - try socket.bind(TCP.Address.initIPv6(IPv6.unspecified, 0)); - try socket.listen(128); + try listener.bind(tcp.Address.initIPv6(IPv6.unspecified, 0)); + try listener.listen(128); - const address = try socket.getLocalAddress(); - testing.expect(address.getHost() == .v6); + const address = try listener.getLocalAddress(); + testing.expect(address == .ipv6); } diff --git a/lib/std/x/os/Socket.zig b/lib/std/x/os/Socket.zig index 96e64c97ef..33e463e731 100644 --- a/lib/std/x/os/Socket.zig +++ b/lib/std/x/os/Socket.zig @@ -1,4 +1,11 @@ +// 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 mem = std.mem; @@ -7,6 +14,98 @@ const time = std.time; /// A generic socket abstraction. const Socket = @This(); +/// A socket-address pair. +pub const Connection = struct { + socket: Socket, + 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. fd: os.socket_t, @@ -31,8 +130,8 @@ pub fn shutdown(self: Socket, how: os.ShutdownHow) !void { } /// Binds the socket to an address. -pub fn bind(self: Socket, comptime Address: type, address: Address) !void { - return os.bind(self.fd, @ptrCast(*const os.sockaddr, &address), @sizeOf(Address)); +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. @@ -41,19 +140,20 @@ 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, comptime Address: type, address: Address) !void { - return os.connect(self.fd, @ptrCast(*const os.sockaddr, &address), @sizeOf(Address)); +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 /// of the socket. -pub fn accept(self: Socket, comptime Connection: type, comptime Address: type, flags: u32) !Connection { - var address: Address = undefined; - var address_len: u32 = @sizeOf(Address); +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, @ptrCast(*os.sockaddr, &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.from(.{ .fd = fd }, address); + return Socket.Connection.from(socket, socket_address); } /// Read data from the socket into the buffer provided. It returns the @@ -94,11 +194,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, comptime Address: type) !Address { - var address: Address = undefined; - var address_len: u32 = @sizeOf(Address); - try os.getsockname(self.fd, @ptrCast(*os.sockaddr, &address), &address_len); - return 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 Socket.Address.fromNative(@alignCast(4, &address)); } /// Query and return the latest cached error on the socket. diff --git a/lib/std/x/os/net.zig b/lib/std/x/os/net.zig index dddb3b73e0..78de60e6c1 100644 --- a/lib/std/x/os/net.zig +++ b/lib/std/x/os/net.zig @@ -1,3 +1,9 @@ +// 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; @@ -27,6 +33,12 @@ pub fn resolveScopeID(name: []const u8) !u32 { /// 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 }; @@ -200,6 +212,12 @@ pub const IPv4 = extern struct { /// 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}; From 76304a36afb6d2cc77902a0e60906382b53d7baa Mon Sep 17 00:00:00 2001 From: lithdew Date: Fri, 30 Apr 2021 21:10:36 +0900 Subject: [PATCH 18/47] std/builtin: add missing comma to CallingConvention --- lib/std/builtin.zig | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index c5fa77bb7c..53c27f0bf5 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -150,7 +150,23 @@ pub const Mode = enum { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. -pub const CallingConvention = enum { Unspecified, C, Naked, Async, Inline, Interrupt, Signal, Stdcall, Fastcall, Vectorcall, Thiscall, APCS, AAPCS, AAPCSVFP, SysV }; +pub const CallingConvention = enum { + Unspecified, + C, + Naked, + Async, + Inline, + Interrupt, + Signal, + Stdcall, + Fastcall, + Vectorcall, + Thiscall, + APCS, + AAPCS, + AAPCSVFP, + SysV, +}; /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. From 8ef9d98e6dd24bf9c3def1e938e3eab66b39667c Mon Sep 17 00:00:00 2001 From: lithdew Date: Fri, 30 Apr 2021 21:59:02 +0900 Subject: [PATCH 19/47] x/os: fix compile errors on mac and linux Use i32 instead of isize for os.timeval's for socket read/write timeouts. Add a comptime check to resolveScopeID to see if `IFNAMESIZE` is available on the host. If it is not available, return an error indicating that resolving the scope ID of a IPv6 address is not yet supported on the host platform. --- lib/std/x/os/Socket.zig | 8 ++++---- lib/std/x/os/net.zig | 19 +++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/std/x/os/Socket.zig b/lib/std/x/os/Socket.zig index 33e463e731..bb984af97a 100644 --- a/lib/std/x/os/Socket.zig +++ b/lib/std/x/os/Socket.zig @@ -273,8 +273,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)); @@ -286,8 +286,8 @@ 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)); diff --git a/lib/std/x/os/net.zig b/lib/std/x/os/net.zig index 78de60e6c1..2534570c53 100644 --- a/lib/std/x/os/net.zig +++ b/lib/std/x/os/net.zig @@ -17,18 +17,21 @@ const testing = std.testing; /// an error if either resolution fails, or if the interface name is /// too long. pub fn resolveScopeID(name: []const u8) !u32 { - if (name.len >= os.IFNAMESIZE - 1) return error.NameTooLong; + 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); + 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; + var f: os.ifreq = undefined; + mem.copy(u8, &f.ifrn.name, name); + f.ifrn.name[name.len] = 0; - try os.ioctl_SIOCGIFINDEX(fd, &f); + try os.ioctl_SIOCGIFINDEX(fd, &f); - return @bitCast(u32, f.ifru.ivalue); + return @bitCast(u32, f.ifru.ivalue); + } + return error.Unsupported; } /// An IPv4 address comprised of 4 bytes. From 9a7c57144da9057c80059a3a1ec37aec44dcdc7a Mon Sep 17 00:00:00 2001 From: lithdew Date: Fri, 30 Apr 2021 22:09:12 +0900 Subject: [PATCH 20/47] x/net: disable tcp tests on wasi --- lib/std/x/net/tcp.zig | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/std/x/net/tcp.zig b/lib/std/x/net/tcp.zig index 4c65310f51..70cbc52f4e 100644 --- a/lib/std/x/net/tcp.zig +++ b/lib/std/x/net/tcp.zig @@ -9,6 +9,7 @@ const std = @import("../../std.zig"); const os = std.os; const fmt = std.fmt; const mem = std.mem; +const builtin = std.builtin; const testing = std.testing; const IPv4 = std.x.os.IPv4; @@ -315,11 +316,9 @@ pub const Listener = struct { } }; -test { - testing.refAllDecls(@This()); -} - test "tcp: create non-blocking pair" { + if (builtin.os.tag == .wasi) return error.SkipZigTest; + const listener = try tcp.Listener.init(.ip, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC); defer listener.deinit(); @@ -339,6 +338,8 @@ test "tcp: create non-blocking pair" { } 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(); @@ -361,6 +362,8 @@ test "tcp/client: set read timeout of 1 millisecond on blocking client" { } 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(); @@ -372,6 +375,8 @@ test "tcp/listener: bind to unspecified ipv4 address" { } 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(); From aa15699269b416f46f3c10469d842b930ac26fc9 Mon Sep 17 00:00:00 2001 From: lithdew Date: Fri, 30 Apr 2021 22:45:10 +0900 Subject: [PATCH 21/47] x/os/net: skip ipv6 scope id parse test on unsupported platforms --- lib/std/x/os/net.zig | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/std/x/os/net.zig b/lib/std/x/os/net.zig index 2534570c53..a8d9f095d3 100644 --- a/lib/std/x/os/net.zig +++ b/lib/std/x/os/net.zig @@ -532,7 +532,6 @@ test "ipv6: parse & format" { "::1234:5678", "2001:db8::1234:5678", "::ffff:123.5.123.5", - "FF01::FB%lo", }; const outputs = [_][]const u8{ @@ -544,6 +543,21 @@ test "ipv6: parse & format" { "::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", }; From a799ad05b37c4b04f73ad79f9e3c67c4036138ec Mon Sep 17 00:00:00 2001 From: lithdew Date: Sun, 2 May 2021 16:50:56 +0900 Subject: [PATCH 22/47] x/net/tcp: make tcp tests blocking to avoid unit test races --- lib/std/x/net/tcp.zig | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/std/x/net/tcp.zig b/lib/std/x/net/tcp.zig index 70cbc52f4e..9804699f48 100644 --- a/lib/std/x/net/tcp.zig +++ b/lib/std/x/net/tcp.zig @@ -316,10 +316,10 @@ pub const Listener = struct { } }; -test "tcp: create non-blocking pair" { +test "tcp: create client/listener pair" { if (builtin.os.tag == .wasi) return error.SkipZigTest; - const listener = try tcp.Listener.init(.ip, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC); + const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC); defer listener.deinit(); try listener.bind(tcp.Address.initIPv4(IPv4.unspecified, 0)); @@ -327,13 +327,12 @@ test "tcp: create non-blocking pair" { const binded_address = try listener.getLocalAddress(); - const client = try tcp.Client.init(.ip, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC); + const client = try tcp.Client.init(.ip, os.SOCK_CLOEXEC); defer client.deinit(); - testing.expectError(error.WouldBlock, client.connect(binded_address)); - try client.getError(); + try client.connect(binded_address); - const conn = try listener.accept(os.SOCK_NONBLOCK | os.SOCK_CLOEXEC); + const conn = try listener.accept(os.SOCK_CLOEXEC); defer conn.deinit(); } From cc6714a92923075d32adc44ade226ededc5da7db Mon Sep 17 00:00:00 2001 From: lithdew Date: Sun, 2 May 2021 18:41:48 +0900 Subject: [PATCH 23/47] std/os/bits: add timeval struct for riscv64 linux --- lib/std/os/bits/linux/riscv64.zig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/std/os/bits/linux/riscv64.zig b/lib/std/os/bits/linux/riscv64.zig index 0cbdea415c..192a2a4f71 100644 --- a/lib/std/os/bits/linux/riscv64.zig +++ b/lib/std/os/bits/linux/riscv64.zig @@ -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, From 5c4fbc40140ec6e30aa2954c13a5799b40e7afe4 Mon Sep 17 00:00:00 2001 From: lithdew Date: Sun, 2 May 2021 18:51:32 +0900 Subject: [PATCH 24/47] x/net: generalize `tcp.Address` into `ip.Address` Generalize `tcp.Address` into `ip.Address` given that multiple transport protocols apart from TCP (i.e. UDP) operate solely over IP. --- lib/std/x.zig | 1 + lib/std/x/net/ip.zig | 52 +++++++++++++++++++++++++++++++ lib/std/x/net/tcp.zig | 71 +++++++++---------------------------------- 3 files changed, 67 insertions(+), 57 deletions(-) create mode 100644 lib/std/x/net/ip.zig diff --git a/lib/std/x.zig b/lib/std/x.zig index 0c23f3f035..a123591470 100644 --- a/lib/std/x.zig +++ b/lib/std/x.zig @@ -12,6 +12,7 @@ pub const os = struct { }; pub const net = struct { + pub const ip = @import("x/net/ip.zig"); pub const tcp = @import("x/net/tcp.zig"); }; diff --git a/lib/std/x/net/ip.zig b/lib/std/x/net/ip.zig new file mode 100644 index 0000000000..5f6bf5ac48 --- /dev/null +++ b/lib/std/x/net/ip.zig @@ -0,0 +1,52 @@ +const std = @import("../../std.zig"); + +const IPv4 = std.x.os.IPv4; +const IPv6 = std.x.os.IPv6; +const Socket = std.x.os.Socket; + +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 }), + } + } +}; diff --git a/lib/std/x/net/tcp.zig b/lib/std/x/net/tcp.zig index 9804699f48..8d6254fd0d 100644 --- a/lib/std/x/net/tcp.zig +++ b/lib/std/x/net/tcp.zig @@ -7,6 +7,8 @@ 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; @@ -19,61 +21,16 @@ const Socket = std.x.os.Socket; /// A generic TCP socket abstraction. const tcp = @This(); -/// A union of all eligible types of socket addresses over TCP. -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 a TCP socket address. - pub fn from(address: Socket.Address) tcp.Address { - return switch (address) { - .ipv4 => |ipv4_address| .{ .ipv4 = ipv4_address }, - .ipv6 => |ipv6_address| .{ .ipv6 = ipv6_address }, - }; - } - - /// Re-interpret a TCP socket address into a generic socket address. - pub fn into(self: tcp.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: tcp.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 }), - } - } -}; - /// A TCP client-address pair. pub const Connection = struct { client: tcp.Client, - address: tcp.Address, + 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 = tcp.Address.from(conn.address), + .address = ip.Address.from(conn.address), }; } @@ -128,7 +85,7 @@ pub const Client = struct { } /// Have the client attempt to the connect to an address. - pub fn connect(self: Client, address: tcp.Address) !void { + pub fn connect(self: Client, address: ip.Address) !void { return self.socket.connect(address.into()); } @@ -185,8 +142,8 @@ pub const Client = struct { } /// Query the address that the client's socket is locally bounded to. - pub fn getLocalAddress(self: Client) !tcp.Address { - return tcp.Address.from(try self.socket.getLocalAddress()); + 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 @@ -253,7 +210,7 @@ pub const Listener = struct { } /// Binds the listener's socket to an address. - pub fn bind(self: Listener, address: tcp.Address) !void { + pub fn bind(self: Listener, address: ip.Address) !void { return self.socket.bind(address.into()); } @@ -274,8 +231,8 @@ pub const Listener = struct { } /// Query the address that the listener's socket is locally bounded to. - pub fn getLocalAddress(self: Listener) !tcp.Address { - return tcp.Address.from(try self.socket.getLocalAddress()); + 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 @@ -322,7 +279,7 @@ test "tcp: create client/listener pair" { const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC); defer listener.deinit(); - try listener.bind(tcp.Address.initIPv4(IPv4.unspecified, 0)); + try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0)); try listener.listen(128); const binded_address = try listener.getLocalAddress(); @@ -342,7 +299,7 @@ test "tcp/client: set read timeout of 1 millisecond on blocking client" { const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC); defer listener.deinit(); - try listener.bind(tcp.Address.initIPv4(IPv4.unspecified, 0)); + try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0)); try listener.listen(128); const binded_address = try listener.getLocalAddress(); @@ -366,7 +323,7 @@ test "tcp/listener: bind to unspecified ipv4 address" { const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC); defer listener.deinit(); - try listener.bind(tcp.Address.initIPv4(IPv4.unspecified, 0)); + try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0)); try listener.listen(128); const address = try listener.getLocalAddress(); @@ -379,7 +336,7 @@ test "tcp/listener: bind to unspecified ipv6 address" { const listener = try tcp.Listener.init(.ipv6, os.SOCK_CLOEXEC); defer listener.deinit(); - try listener.bind(tcp.Address.initIPv6(IPv6.unspecified, 0)); + try listener.bind(ip.Address.initIPv6(IPv6.unspecified, 0)); try listener.listen(128); const address = try listener.getLocalAddress(); From af057c888b99316808165926847577869dae32e8 Mon Sep 17 00:00:00 2001 From: lithdew Date: Sun, 2 May 2021 18:54:35 +0900 Subject: [PATCH 25/47] x/net/ip: add copyright header --- lib/std/x/net/ip.zig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/std/x/net/ip.zig b/lib/std/x/net/ip.zig index 5f6bf5ac48..6d1632a50d 100644 --- a/lib/std/x/net/ip.zig +++ b/lib/std/x/net/ip.zig @@ -1,9 +1,16 @@ +// 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 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. From 16fc1b904c115d37dc335c35177b8433d91fa271 Mon Sep 17 00:00:00 2001 From: lithdew Date: Sun, 2 May 2021 20:32:22 +0900 Subject: [PATCH 26/47] std/os/linux/bits: correct socket option codes for ppc/ppc64 --- lib/std/os/bits/linux.zig | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index 94da5cc99a..74f9b14ca2 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -32,6 +32,7 @@ pub usingnamespace @import("linux/prctl.zig"); pub usingnamespace @import("linux/securebits.zig"); const is_mips = builtin.arch.isMIPS(); +const is_ppc = builtin.arch.isPPC(); const is_ppc64 = builtin.arch.isPPC64(); const is_sparc = builtin.arch.isSPARC(); @@ -458,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; @@ -487,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; From 96fe49ef620cfd8423e878262420f58d5983d58c Mon Sep 17 00:00:00 2001 From: lithdew Date: Mon, 3 May 2021 14:48:51 +0900 Subject: [PATCH 27/47] std/os/bits/windows: add `timeval` extern struct --- lib/std/os/bits/windows.zig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/std/os/bits/windows.zig b/lib/std/os/bits/windows.zig index 28a6a251f8..00ca2a1532 100644 --- a/lib/std/os/bits/windows.zig +++ b/lib/std/os/bits/windows.zig @@ -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 From 97779442d0a551d96f2a0b1799e96944918af32e Mon Sep 17 00:00:00 2001 From: Frank Denis <124872+jedisct1@users.noreply.github.com> Date: Mon, 3 May 2021 09:57:45 +0200 Subject: [PATCH 28/47] Prepare std/crypto/pcurves for ecdsa and other curves (#8670) Functions generated by Fiat-crypto are not prefixed by their description any more. This matches an upstream change. We can now use a single type for different curves and implementations. The field type is now generic, so we can properly handle the base field and scalars without code duplication. --- lib/std/crypto/pcurves/common.zig | 284 +++ lib/std/crypto/pcurves/p256/field.zig | 261 +-- lib/std/crypto/pcurves/p256/p256_64.zig | 1308 +++++------ .../crypto/pcurves/p256/p256_scalar_64.zig | 2016 +++++++++++++++++ lib/std/crypto/pcurves/p256/scalar.zig | 34 +- 5 files changed, 3005 insertions(+), 898 deletions(-) create mode 100644 lib/std/crypto/pcurves/common.zig create mode 100644 lib/std/crypto/pcurves/p256/p256_scalar_64.zig diff --git a/lib/std/crypto/pcurves/common.zig b/lib/std/crypto/pcurves/common.zig new file mode 100644 index 0000000000..5a979fe3e5 --- /dev/null +++ b/lib/std/crypto/pcurves/common.zig @@ -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; + } + }; +} diff --git a/lib/std/crypto/pcurves/p256/field.zig b/lib/std/crypto/pcurves/p256/field.zig index 68659e4601..15de1fe43e 100644 --- a/lib/std/crypto/pcurves/p256/field.zig +++ b/lib/std/crypto/pcurves/p256/field.zig @@ -5,257 +5,14 @@ // and substantial portions of the software. 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 common = @import("../common.zig"); -const fiat = @import("p256_64.zig"); +const Field = common.Field; -const NonCanonicalError = crypto.errors.NonCanonicalError; -const NotSquareError = crypto.errors.NotSquareError; - -const Limbs = fiat.Limbs; - -/// A field element, internally stored in Montgomery domain. -pub const Fe = struct { - limbs: Limbs, - - /// Field size. - pub const field_order = 115792089210356248762697446949407573530086143415290314195533631308867097853951; - - /// Numer of bits that can be saturated without overflowing. - pub const saturated_bits = 255; - - /// Zero. - pub const zero: Fe = Fe{ .limbs = mem.zeroes(Limbs) }; - - /// One. - pub const one = comptime one: { - var fe: Fe = undefined; - fiat.p256SetOne(&fe.limbs); - break :one fe; - }; - - /// Reject non-canonical encodings of an element. - pub fn rejectNonCanonical(s_: [32]u8, endian: builtin.Endian) NonCanonicalError!void { - var s = if (endian == .Little) s_ else orderSwap(s_); - const field_order_s = comptime fos: { - var fos: [32]u8 = undefined; - mem.writeIntLittle(u256, &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: [32]u8) [32]u8 { - var t = s; - for (s) |x, i| t[t.len - 1 - i] = x; - return t; - } - - /// Unpack a field element. - pub fn fromBytes(s_: [32]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.p256FromBytes(&limbs_z, s); - var limbs: Limbs = undefined; - fiat.p256ToMontgomery(&limbs, limbs_z); - return Fe{ .limbs = limbs }; - } - - /// Pack a field element. - pub fn toBytes(fe: Fe, endian: builtin.Endian) [32]u8 { - var limbs_z: Limbs = undefined; - fiat.p256FromMontgomery(&limbs_z, fe.limbs); - var s: [32]u8 = undefined; - fiat.p256ToBytes(&s, limbs_z); - return if (endian == .Little) s else orderSwap(s); - } - - /// Create a field element from an integer. - pub fn fromInt(comptime x: u256) NonCanonicalError!Fe { - var s: [32]u8 = undefined; - mem.writeIntLittle(u256, &s, x); - return fromBytes(s, .Little); - } - - /// Return the field element as an integer. - pub fn toInt(fe: Fe) u256 { - const s = fe.toBytes(.Little); - return mem.readIntLittle(u256, &s); - } - - /// Return true if the field element is zero. - pub fn isZero(fe: Fe) bool { - var z: @TypeOf(fe.limbs[0]) = undefined; - fiat.p256Nonzero(&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.p256Selectznz(&fe.limbs, c, fe.limbs, a.limbs); - } - - /// Add field elements. - pub fn add(a: Fe, b: Fe) Fe { - var fe: Fe = undefined; - fiat.p256Add(&fe.limbs, a.limbs, b.limbs); - return fe; - } - - /// Subtract field elements. - pub fn sub(a: Fe, b: Fe) Fe { - var fe: Fe = undefined; - fiat.p256Sub(&fe.limbs, a.limbs, b.limbs); - return fe; - } - - /// Double a field element. - pub fn dbl(a: Fe) Fe { - var fe: Fe = undefined; - fiat.p256Add(&fe.limbs, a.limbs, a.limbs); - return fe; - } - - /// Multiply field elements. - pub fn mul(a: Fe, b: Fe) Fe { - var fe: Fe = undefined; - fiat.p256Mul(&fe.limbs, a.limbs, b.limbs); - return fe; - } - - /// Square a field element. - pub fn sq(a: Fe) Fe { - var fe: Fe = undefined; - fiat.p256Square(&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.p256Opp(&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 len_prime = 256; - const iterations = (49 * len_prime + 57) / 17; - const Word = @TypeOf(a.limbs[0]); - const XLimbs = [a.limbs.len + 1]Word; - - var d: Word = 1; - var f: XLimbs = undefined; - fiat.p256Msat(&f); - - var g: XLimbs = undefined; - fiat.p256FromMontgomery(g[0..a.limbs.len], a.limbs); - g[g.len - 1] = 0; - - var r: Limbs = undefined; - fiat.p256SetOne(&r); - var v = mem.zeroes(Limbs); - - var precomp: Limbs = undefined; - fiat.p256DivstepPrecomp(&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.p256Divstep(&out1, &out2, &out3, &out4, &out5, d, f, g, v, r); - fiat.p256Divstep(&d, &f, &g, &v, &r, out1, out2, out3, out4, out5); - } - if (iterations % 2 != 0) { - fiat.p256Divstep(&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.p256Opp(&v_opp, v); - fiat.p256Selectznz(&v, @truncate(u1, f[f.len - 1] >> (meta.bitCount(Word) - 1)), v, v_opp); - var fe: Fe = undefined; - fiat.p256Mul(&fe.limbs, v, precomp); - return fe; - } - - /// Return true if the field element is a square. - pub fn isSquare(x2: Fe) bool { - 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); // Legendre symbol, (p-1)/2 - 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); - 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); - } - - /// 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; - } -}; +pub const Fe = Field(.{ + .fiat = @import("p256_64.zig"), + .field_order = 115792089210356248762697446949407573530086143415290314195533631308867097853951, + .field_bits = 256, + .saturated_bits = 255, + .encoded_length = 32, +}); diff --git a/lib/std/crypto/pcurves/p256/p256_64.zig b/lib/std/crypto/pcurves/p256/p256_64.zig index 9f3d6c22f8..ca04ee961d 100644 --- a/lib/std/crypto/pcurves/p256/p256_64.zig +++ b/lib/std/crypto/pcurves/p256/p256_64.zig @@ -1,11 +1,5 @@ -// 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. - -// Autogenerated: 'src/ExtractionOCaml/word_by_word_montgomery' --lang Zig --internal-static --public-function-case camelCase --private-function-case camelCase 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: p256 +// 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") @@ -20,10 +14,16 @@ // 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 p256AddcarryxU64 is an addition with carry. +/// The function addcarryxU64 is an addition with carry. /// Postconditions: /// out1 = (arg1 + arg2 + arg3) mod 2^64 /// out2 = ⌊(arg1 + arg2 + arg3) / 2^64⌋ @@ -35,14 +35,16 @@ pub const Limbs = [4]u64; /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] /// out2: [0x0 ~> 0x1] -fn p256AddcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void { +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 p256SubborrowxU64 is a subtraction with borrow. +/// The function subborrowxU64 is a subtraction with borrow. /// Postconditions: /// out1 = (-arg1 + arg2 + -arg3) mod 2^64 /// out2 = -⌊(-arg1 + arg2 + -arg3) / 2^64⌋ @@ -54,14 +56,16 @@ fn p256AddcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) callc /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] /// out2: [0x0 ~> 0x1] -fn p256SubborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void { +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 p256MulxU64 is a multiplication, returning the full double-width result. +/// The function mulxU64 is a multiplication, returning the full double-width result. /// Postconditions: /// out1 = (arg1 * arg2) mod 2^64 /// out2 = ⌊arg1 * arg2 / 2^64⌋ @@ -72,13 +76,15 @@ fn p256SubborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) call /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] /// out2: [0x0 ~> 0xffffffffffffffff] -fn p256MulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) callconv(.Inline) void { +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 p256CmovznzU64 is a single-word conditional move. +/// The function cmovznzU64 is a single-word conditional move. /// Postconditions: /// out1 = (if arg1 = 0 then arg2 else arg3) /// @@ -88,12 +94,14 @@ fn p256MulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) callconv(.Inline) v /// arg3: [0x0 ~> 0xffffffffffffffff] /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] -fn p256CmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void { +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 p256Mul multiplies two field elements in the Montgomery domain. +/// The function mul multiplies two field elements in the Montgomery domain. /// Preconditions: /// 0 ≤ eval arg1 < m /// 0 ≤ eval arg2 < m @@ -106,289 +114,291 @@ fn p256CmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) /// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] -pub fn p256Mul(out1: *Limbs, arg1: Limbs, arg2: Limbs) void { - const x1: u64 = (arg1[1]); - const x2: u64 = (arg1[2]); - const x3: u64 = (arg1[3]); - const x4: u64 = (arg1[0]); +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; - p256MulxU64(&x5, &x6, x4, (arg2[3])); + mulxU64(&x5, &x6, x4, (arg2[3])); var x7: u64 = undefined; var x8: u64 = undefined; - p256MulxU64(&x7, &x8, x4, (arg2[2])); + mulxU64(&x7, &x8, x4, (arg2[2])); var x9: u64 = undefined; var x10: u64 = undefined; - p256MulxU64(&x9, &x10, x4, (arg2[1])); + mulxU64(&x9, &x10, x4, (arg2[1])); var x11: u64 = undefined; var x12: u64 = undefined; - p256MulxU64(&x11, &x12, x4, (arg2[0])); + mulxU64(&x11, &x12, x4, (arg2[0])); var x13: u64 = undefined; var x14: u1 = undefined; - p256AddcarryxU64(&x13, &x14, 0x0, x12, x9); + addcarryxU64(&x13, &x14, 0x0, x12, x9); var x15: u64 = undefined; var x16: u1 = undefined; - p256AddcarryxU64(&x15, &x16, x14, x10, x7); + addcarryxU64(&x15, &x16, x14, x10, x7); var x17: u64 = undefined; var x18: u1 = undefined; - p256AddcarryxU64(&x17, &x18, x16, x8, x5); - const x19: u64 = (@intCast(u64, x18) + x6); + addcarryxU64(&x17, &x18, x16, x8, x5); + const x19 = (cast(u64, x18) + x6); var x20: u64 = undefined; var x21: u64 = undefined; - p256MulxU64(&x20, &x21, x11, 0xffffffff00000001); + mulxU64(&x20, &x21, x11, 0xffffffff00000001); var x22: u64 = undefined; var x23: u64 = undefined; - p256MulxU64(&x22, &x23, x11, 0xffffffff); + mulxU64(&x22, &x23, x11, 0xffffffff); var x24: u64 = undefined; var x25: u64 = undefined; - p256MulxU64(&x24, &x25, x11, 0xffffffffffffffff); + mulxU64(&x24, &x25, x11, 0xffffffffffffffff); var x26: u64 = undefined; var x27: u1 = undefined; - p256AddcarryxU64(&x26, &x27, 0x0, x25, x22); - const x28: u64 = (@intCast(u64, x27) + x23); + addcarryxU64(&x26, &x27, 0x0, x25, x22); + const x28 = (cast(u64, x27) + x23); var x29: u64 = undefined; var x30: u1 = undefined; - p256AddcarryxU64(&x29, &x30, 0x0, x11, x24); + addcarryxU64(&x29, &x30, 0x0, x11, x24); var x31: u64 = undefined; var x32: u1 = undefined; - p256AddcarryxU64(&x31, &x32, x30, x13, x26); + addcarryxU64(&x31, &x32, x30, x13, x26); var x33: u64 = undefined; var x34: u1 = undefined; - p256AddcarryxU64(&x33, &x34, x32, x15, x28); + addcarryxU64(&x33, &x34, x32, x15, x28); var x35: u64 = undefined; var x36: u1 = undefined; - p256AddcarryxU64(&x35, &x36, x34, x17, x20); + addcarryxU64(&x35, &x36, x34, x17, x20); var x37: u64 = undefined; var x38: u1 = undefined; - p256AddcarryxU64(&x37, &x38, x36, x19, x21); + addcarryxU64(&x37, &x38, x36, x19, x21); var x39: u64 = undefined; var x40: u64 = undefined; - p256MulxU64(&x39, &x40, x1, (arg2[3])); + mulxU64(&x39, &x40, x1, (arg2[3])); var x41: u64 = undefined; var x42: u64 = undefined; - p256MulxU64(&x41, &x42, x1, (arg2[2])); + mulxU64(&x41, &x42, x1, (arg2[2])); var x43: u64 = undefined; var x44: u64 = undefined; - p256MulxU64(&x43, &x44, x1, (arg2[1])); + mulxU64(&x43, &x44, x1, (arg2[1])); var x45: u64 = undefined; var x46: u64 = undefined; - p256MulxU64(&x45, &x46, x1, (arg2[0])); + mulxU64(&x45, &x46, x1, (arg2[0])); var x47: u64 = undefined; var x48: u1 = undefined; - p256AddcarryxU64(&x47, &x48, 0x0, x46, x43); + addcarryxU64(&x47, &x48, 0x0, x46, x43); var x49: u64 = undefined; var x50: u1 = undefined; - p256AddcarryxU64(&x49, &x50, x48, x44, x41); + addcarryxU64(&x49, &x50, x48, x44, x41); var x51: u64 = undefined; var x52: u1 = undefined; - p256AddcarryxU64(&x51, &x52, x50, x42, x39); - const x53: u64 = (@intCast(u64, x52) + x40); + addcarryxU64(&x51, &x52, x50, x42, x39); + const x53 = (cast(u64, x52) + x40); var x54: u64 = undefined; var x55: u1 = undefined; - p256AddcarryxU64(&x54, &x55, 0x0, x31, x45); + addcarryxU64(&x54, &x55, 0x0, x31, x45); var x56: u64 = undefined; var x57: u1 = undefined; - p256AddcarryxU64(&x56, &x57, x55, x33, x47); + addcarryxU64(&x56, &x57, x55, x33, x47); var x58: u64 = undefined; var x59: u1 = undefined; - p256AddcarryxU64(&x58, &x59, x57, x35, x49); + addcarryxU64(&x58, &x59, x57, x35, x49); var x60: u64 = undefined; var x61: u1 = undefined; - p256AddcarryxU64(&x60, &x61, x59, x37, x51); + addcarryxU64(&x60, &x61, x59, x37, x51); var x62: u64 = undefined; var x63: u1 = undefined; - p256AddcarryxU64(&x62, &x63, x61, @intCast(u64, x38), x53); + addcarryxU64(&x62, &x63, x61, cast(u64, x38), x53); var x64: u64 = undefined; var x65: u64 = undefined; - p256MulxU64(&x64, &x65, x54, 0xffffffff00000001); + mulxU64(&x64, &x65, x54, 0xffffffff00000001); var x66: u64 = undefined; var x67: u64 = undefined; - p256MulxU64(&x66, &x67, x54, 0xffffffff); + mulxU64(&x66, &x67, x54, 0xffffffff); var x68: u64 = undefined; var x69: u64 = undefined; - p256MulxU64(&x68, &x69, x54, 0xffffffffffffffff); + mulxU64(&x68, &x69, x54, 0xffffffffffffffff); var x70: u64 = undefined; var x71: u1 = undefined; - p256AddcarryxU64(&x70, &x71, 0x0, x69, x66); - const x72: u64 = (@intCast(u64, x71) + x67); + addcarryxU64(&x70, &x71, 0x0, x69, x66); + const x72 = (cast(u64, x71) + x67); var x73: u64 = undefined; var x74: u1 = undefined; - p256AddcarryxU64(&x73, &x74, 0x0, x54, x68); + addcarryxU64(&x73, &x74, 0x0, x54, x68); var x75: u64 = undefined; var x76: u1 = undefined; - p256AddcarryxU64(&x75, &x76, x74, x56, x70); + addcarryxU64(&x75, &x76, x74, x56, x70); var x77: u64 = undefined; var x78: u1 = undefined; - p256AddcarryxU64(&x77, &x78, x76, x58, x72); + addcarryxU64(&x77, &x78, x76, x58, x72); var x79: u64 = undefined; var x80: u1 = undefined; - p256AddcarryxU64(&x79, &x80, x78, x60, x64); + addcarryxU64(&x79, &x80, x78, x60, x64); var x81: u64 = undefined; var x82: u1 = undefined; - p256AddcarryxU64(&x81, &x82, x80, x62, x65); - const x83: u64 = (@intCast(u64, x82) + @intCast(u64, x63)); + addcarryxU64(&x81, &x82, x80, x62, x65); + const x83 = (cast(u64, x82) + cast(u64, x63)); var x84: u64 = undefined; var x85: u64 = undefined; - p256MulxU64(&x84, &x85, x2, (arg2[3])); + mulxU64(&x84, &x85, x2, (arg2[3])); var x86: u64 = undefined; var x87: u64 = undefined; - p256MulxU64(&x86, &x87, x2, (arg2[2])); + mulxU64(&x86, &x87, x2, (arg2[2])); var x88: u64 = undefined; var x89: u64 = undefined; - p256MulxU64(&x88, &x89, x2, (arg2[1])); + mulxU64(&x88, &x89, x2, (arg2[1])); var x90: u64 = undefined; var x91: u64 = undefined; - p256MulxU64(&x90, &x91, x2, (arg2[0])); + mulxU64(&x90, &x91, x2, (arg2[0])); var x92: u64 = undefined; var x93: u1 = undefined; - p256AddcarryxU64(&x92, &x93, 0x0, x91, x88); + addcarryxU64(&x92, &x93, 0x0, x91, x88); var x94: u64 = undefined; var x95: u1 = undefined; - p256AddcarryxU64(&x94, &x95, x93, x89, x86); + addcarryxU64(&x94, &x95, x93, x89, x86); var x96: u64 = undefined; var x97: u1 = undefined; - p256AddcarryxU64(&x96, &x97, x95, x87, x84); - const x98: u64 = (@intCast(u64, x97) + x85); + addcarryxU64(&x96, &x97, x95, x87, x84); + const x98 = (cast(u64, x97) + x85); var x99: u64 = undefined; var x100: u1 = undefined; - p256AddcarryxU64(&x99, &x100, 0x0, x75, x90); + addcarryxU64(&x99, &x100, 0x0, x75, x90); var x101: u64 = undefined; var x102: u1 = undefined; - p256AddcarryxU64(&x101, &x102, x100, x77, x92); + addcarryxU64(&x101, &x102, x100, x77, x92); var x103: u64 = undefined; var x104: u1 = undefined; - p256AddcarryxU64(&x103, &x104, x102, x79, x94); + addcarryxU64(&x103, &x104, x102, x79, x94); var x105: u64 = undefined; var x106: u1 = undefined; - p256AddcarryxU64(&x105, &x106, x104, x81, x96); + addcarryxU64(&x105, &x106, x104, x81, x96); var x107: u64 = undefined; var x108: u1 = undefined; - p256AddcarryxU64(&x107, &x108, x106, x83, x98); + addcarryxU64(&x107, &x108, x106, x83, x98); var x109: u64 = undefined; var x110: u64 = undefined; - p256MulxU64(&x109, &x110, x99, 0xffffffff00000001); + mulxU64(&x109, &x110, x99, 0xffffffff00000001); var x111: u64 = undefined; var x112: u64 = undefined; - p256MulxU64(&x111, &x112, x99, 0xffffffff); + mulxU64(&x111, &x112, x99, 0xffffffff); var x113: u64 = undefined; var x114: u64 = undefined; - p256MulxU64(&x113, &x114, x99, 0xffffffffffffffff); + mulxU64(&x113, &x114, x99, 0xffffffffffffffff); var x115: u64 = undefined; var x116: u1 = undefined; - p256AddcarryxU64(&x115, &x116, 0x0, x114, x111); - const x117: u64 = (@intCast(u64, x116) + x112); + addcarryxU64(&x115, &x116, 0x0, x114, x111); + const x117 = (cast(u64, x116) + x112); var x118: u64 = undefined; var x119: u1 = undefined; - p256AddcarryxU64(&x118, &x119, 0x0, x99, x113); + addcarryxU64(&x118, &x119, 0x0, x99, x113); var x120: u64 = undefined; var x121: u1 = undefined; - p256AddcarryxU64(&x120, &x121, x119, x101, x115); + addcarryxU64(&x120, &x121, x119, x101, x115); var x122: u64 = undefined; var x123: u1 = undefined; - p256AddcarryxU64(&x122, &x123, x121, x103, x117); + addcarryxU64(&x122, &x123, x121, x103, x117); var x124: u64 = undefined; var x125: u1 = undefined; - p256AddcarryxU64(&x124, &x125, x123, x105, x109); + addcarryxU64(&x124, &x125, x123, x105, x109); var x126: u64 = undefined; var x127: u1 = undefined; - p256AddcarryxU64(&x126, &x127, x125, x107, x110); - const x128: u64 = (@intCast(u64, x127) + @intCast(u64, x108)); + addcarryxU64(&x126, &x127, x125, x107, x110); + const x128 = (cast(u64, x127) + cast(u64, x108)); var x129: u64 = undefined; var x130: u64 = undefined; - p256MulxU64(&x129, &x130, x3, (arg2[3])); + mulxU64(&x129, &x130, x3, (arg2[3])); var x131: u64 = undefined; var x132: u64 = undefined; - p256MulxU64(&x131, &x132, x3, (arg2[2])); + mulxU64(&x131, &x132, x3, (arg2[2])); var x133: u64 = undefined; var x134: u64 = undefined; - p256MulxU64(&x133, &x134, x3, (arg2[1])); + mulxU64(&x133, &x134, x3, (arg2[1])); var x135: u64 = undefined; var x136: u64 = undefined; - p256MulxU64(&x135, &x136, x3, (arg2[0])); + mulxU64(&x135, &x136, x3, (arg2[0])); var x137: u64 = undefined; var x138: u1 = undefined; - p256AddcarryxU64(&x137, &x138, 0x0, x136, x133); + addcarryxU64(&x137, &x138, 0x0, x136, x133); var x139: u64 = undefined; var x140: u1 = undefined; - p256AddcarryxU64(&x139, &x140, x138, x134, x131); + addcarryxU64(&x139, &x140, x138, x134, x131); var x141: u64 = undefined; var x142: u1 = undefined; - p256AddcarryxU64(&x141, &x142, x140, x132, x129); - const x143: u64 = (@intCast(u64, x142) + x130); + addcarryxU64(&x141, &x142, x140, x132, x129); + const x143 = (cast(u64, x142) + x130); var x144: u64 = undefined; var x145: u1 = undefined; - p256AddcarryxU64(&x144, &x145, 0x0, x120, x135); + addcarryxU64(&x144, &x145, 0x0, x120, x135); var x146: u64 = undefined; var x147: u1 = undefined; - p256AddcarryxU64(&x146, &x147, x145, x122, x137); + addcarryxU64(&x146, &x147, x145, x122, x137); var x148: u64 = undefined; var x149: u1 = undefined; - p256AddcarryxU64(&x148, &x149, x147, x124, x139); + addcarryxU64(&x148, &x149, x147, x124, x139); var x150: u64 = undefined; var x151: u1 = undefined; - p256AddcarryxU64(&x150, &x151, x149, x126, x141); + addcarryxU64(&x150, &x151, x149, x126, x141); var x152: u64 = undefined; var x153: u1 = undefined; - p256AddcarryxU64(&x152, &x153, x151, x128, x143); + addcarryxU64(&x152, &x153, x151, x128, x143); var x154: u64 = undefined; var x155: u64 = undefined; - p256MulxU64(&x154, &x155, x144, 0xffffffff00000001); + mulxU64(&x154, &x155, x144, 0xffffffff00000001); var x156: u64 = undefined; var x157: u64 = undefined; - p256MulxU64(&x156, &x157, x144, 0xffffffff); + mulxU64(&x156, &x157, x144, 0xffffffff); var x158: u64 = undefined; var x159: u64 = undefined; - p256MulxU64(&x158, &x159, x144, 0xffffffffffffffff); + mulxU64(&x158, &x159, x144, 0xffffffffffffffff); var x160: u64 = undefined; var x161: u1 = undefined; - p256AddcarryxU64(&x160, &x161, 0x0, x159, x156); - const x162: u64 = (@intCast(u64, x161) + x157); + addcarryxU64(&x160, &x161, 0x0, x159, x156); + const x162 = (cast(u64, x161) + x157); var x163: u64 = undefined; var x164: u1 = undefined; - p256AddcarryxU64(&x163, &x164, 0x0, x144, x158); + addcarryxU64(&x163, &x164, 0x0, x144, x158); var x165: u64 = undefined; var x166: u1 = undefined; - p256AddcarryxU64(&x165, &x166, x164, x146, x160); + addcarryxU64(&x165, &x166, x164, x146, x160); var x167: u64 = undefined; var x168: u1 = undefined; - p256AddcarryxU64(&x167, &x168, x166, x148, x162); + addcarryxU64(&x167, &x168, x166, x148, x162); var x169: u64 = undefined; var x170: u1 = undefined; - p256AddcarryxU64(&x169, &x170, x168, x150, x154); + addcarryxU64(&x169, &x170, x168, x150, x154); var x171: u64 = undefined; var x172: u1 = undefined; - p256AddcarryxU64(&x171, &x172, x170, x152, x155); - const x173: u64 = (@intCast(u64, x172) + @intCast(u64, x153)); + addcarryxU64(&x171, &x172, x170, x152, x155); + const x173 = (cast(u64, x172) + cast(u64, x153)); var x174: u64 = undefined; var x175: u1 = undefined; - p256SubborrowxU64(&x174, &x175, 0x0, x165, 0xffffffffffffffff); + subborrowxU64(&x174, &x175, 0x0, x165, 0xffffffffffffffff); var x176: u64 = undefined; var x177: u1 = undefined; - p256SubborrowxU64(&x176, &x177, x175, x167, 0xffffffff); + subborrowxU64(&x176, &x177, x175, x167, 0xffffffff); var x178: u64 = undefined; var x179: u1 = undefined; - p256SubborrowxU64(&x178, &x179, x177, x169, @intCast(u64, 0x0)); + subborrowxU64(&x178, &x179, x177, x169, cast(u64, 0x0)); var x180: u64 = undefined; var x181: u1 = undefined; - p256SubborrowxU64(&x180, &x181, x179, x171, 0xffffffff00000001); + subborrowxU64(&x180, &x181, x179, x171, 0xffffffff00000001); var x182: u64 = undefined; var x183: u1 = undefined; - p256SubborrowxU64(&x182, &x183, x181, x173, @intCast(u64, 0x0)); + subborrowxU64(&x182, &x183, x181, x173, cast(u64, 0x0)); var x184: u64 = undefined; - p256CmovznzU64(&x184, x183, x174, x165); + cmovznzU64(&x184, x183, x174, x165); var x185: u64 = undefined; - p256CmovznzU64(&x185, x183, x176, x167); + cmovznzU64(&x185, x183, x176, x167); var x186: u64 = undefined; - p256CmovznzU64(&x186, x183, x178, x169); + cmovznzU64(&x186, x183, x178, x169); var x187: u64 = undefined; - p256CmovznzU64(&x187, x183, x180, x171); + cmovznzU64(&x187, x183, x180, x171); out1[0] = x184; out1[1] = x185; out1[2] = x186; out1[3] = x187; } -/// The function p256Square squares a field element in the Montgomery domain. +/// The function square squares a field element in the Montgomery domain. /// Preconditions: /// 0 ≤ eval arg1 < m /// Postconditions: @@ -399,289 +409,291 @@ pub fn p256Mul(out1: *Limbs, arg1: Limbs, arg2: Limbs) void { /// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] -pub fn p256Square(out1: *Limbs, arg1: Limbs) void { - const x1: u64 = (arg1[1]); - const x2: u64 = (arg1[2]); - const x3: u64 = (arg1[3]); - const x4: u64 = (arg1[0]); +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; - p256MulxU64(&x5, &x6, x4, (arg1[3])); + mulxU64(&x5, &x6, x4, (arg1[3])); var x7: u64 = undefined; var x8: u64 = undefined; - p256MulxU64(&x7, &x8, x4, (arg1[2])); + mulxU64(&x7, &x8, x4, (arg1[2])); var x9: u64 = undefined; var x10: u64 = undefined; - p256MulxU64(&x9, &x10, x4, (arg1[1])); + mulxU64(&x9, &x10, x4, (arg1[1])); var x11: u64 = undefined; var x12: u64 = undefined; - p256MulxU64(&x11, &x12, x4, (arg1[0])); + mulxU64(&x11, &x12, x4, (arg1[0])); var x13: u64 = undefined; var x14: u1 = undefined; - p256AddcarryxU64(&x13, &x14, 0x0, x12, x9); + addcarryxU64(&x13, &x14, 0x0, x12, x9); var x15: u64 = undefined; var x16: u1 = undefined; - p256AddcarryxU64(&x15, &x16, x14, x10, x7); + addcarryxU64(&x15, &x16, x14, x10, x7); var x17: u64 = undefined; var x18: u1 = undefined; - p256AddcarryxU64(&x17, &x18, x16, x8, x5); - const x19: u64 = (@intCast(u64, x18) + x6); + addcarryxU64(&x17, &x18, x16, x8, x5); + const x19 = (cast(u64, x18) + x6); var x20: u64 = undefined; var x21: u64 = undefined; - p256MulxU64(&x20, &x21, x11, 0xffffffff00000001); + mulxU64(&x20, &x21, x11, 0xffffffff00000001); var x22: u64 = undefined; var x23: u64 = undefined; - p256MulxU64(&x22, &x23, x11, 0xffffffff); + mulxU64(&x22, &x23, x11, 0xffffffff); var x24: u64 = undefined; var x25: u64 = undefined; - p256MulxU64(&x24, &x25, x11, 0xffffffffffffffff); + mulxU64(&x24, &x25, x11, 0xffffffffffffffff); var x26: u64 = undefined; var x27: u1 = undefined; - p256AddcarryxU64(&x26, &x27, 0x0, x25, x22); - const x28: u64 = (@intCast(u64, x27) + x23); + addcarryxU64(&x26, &x27, 0x0, x25, x22); + const x28 = (cast(u64, x27) + x23); var x29: u64 = undefined; var x30: u1 = undefined; - p256AddcarryxU64(&x29, &x30, 0x0, x11, x24); + addcarryxU64(&x29, &x30, 0x0, x11, x24); var x31: u64 = undefined; var x32: u1 = undefined; - p256AddcarryxU64(&x31, &x32, x30, x13, x26); + addcarryxU64(&x31, &x32, x30, x13, x26); var x33: u64 = undefined; var x34: u1 = undefined; - p256AddcarryxU64(&x33, &x34, x32, x15, x28); + addcarryxU64(&x33, &x34, x32, x15, x28); var x35: u64 = undefined; var x36: u1 = undefined; - p256AddcarryxU64(&x35, &x36, x34, x17, x20); + addcarryxU64(&x35, &x36, x34, x17, x20); var x37: u64 = undefined; var x38: u1 = undefined; - p256AddcarryxU64(&x37, &x38, x36, x19, x21); + addcarryxU64(&x37, &x38, x36, x19, x21); var x39: u64 = undefined; var x40: u64 = undefined; - p256MulxU64(&x39, &x40, x1, (arg1[3])); + mulxU64(&x39, &x40, x1, (arg1[3])); var x41: u64 = undefined; var x42: u64 = undefined; - p256MulxU64(&x41, &x42, x1, (arg1[2])); + mulxU64(&x41, &x42, x1, (arg1[2])); var x43: u64 = undefined; var x44: u64 = undefined; - p256MulxU64(&x43, &x44, x1, (arg1[1])); + mulxU64(&x43, &x44, x1, (arg1[1])); var x45: u64 = undefined; var x46: u64 = undefined; - p256MulxU64(&x45, &x46, x1, (arg1[0])); + mulxU64(&x45, &x46, x1, (arg1[0])); var x47: u64 = undefined; var x48: u1 = undefined; - p256AddcarryxU64(&x47, &x48, 0x0, x46, x43); + addcarryxU64(&x47, &x48, 0x0, x46, x43); var x49: u64 = undefined; var x50: u1 = undefined; - p256AddcarryxU64(&x49, &x50, x48, x44, x41); + addcarryxU64(&x49, &x50, x48, x44, x41); var x51: u64 = undefined; var x52: u1 = undefined; - p256AddcarryxU64(&x51, &x52, x50, x42, x39); - const x53: u64 = (@intCast(u64, x52) + x40); + addcarryxU64(&x51, &x52, x50, x42, x39); + const x53 = (cast(u64, x52) + x40); var x54: u64 = undefined; var x55: u1 = undefined; - p256AddcarryxU64(&x54, &x55, 0x0, x31, x45); + addcarryxU64(&x54, &x55, 0x0, x31, x45); var x56: u64 = undefined; var x57: u1 = undefined; - p256AddcarryxU64(&x56, &x57, x55, x33, x47); + addcarryxU64(&x56, &x57, x55, x33, x47); var x58: u64 = undefined; var x59: u1 = undefined; - p256AddcarryxU64(&x58, &x59, x57, x35, x49); + addcarryxU64(&x58, &x59, x57, x35, x49); var x60: u64 = undefined; var x61: u1 = undefined; - p256AddcarryxU64(&x60, &x61, x59, x37, x51); + addcarryxU64(&x60, &x61, x59, x37, x51); var x62: u64 = undefined; var x63: u1 = undefined; - p256AddcarryxU64(&x62, &x63, x61, @intCast(u64, x38), x53); + addcarryxU64(&x62, &x63, x61, cast(u64, x38), x53); var x64: u64 = undefined; var x65: u64 = undefined; - p256MulxU64(&x64, &x65, x54, 0xffffffff00000001); + mulxU64(&x64, &x65, x54, 0xffffffff00000001); var x66: u64 = undefined; var x67: u64 = undefined; - p256MulxU64(&x66, &x67, x54, 0xffffffff); + mulxU64(&x66, &x67, x54, 0xffffffff); var x68: u64 = undefined; var x69: u64 = undefined; - p256MulxU64(&x68, &x69, x54, 0xffffffffffffffff); + mulxU64(&x68, &x69, x54, 0xffffffffffffffff); var x70: u64 = undefined; var x71: u1 = undefined; - p256AddcarryxU64(&x70, &x71, 0x0, x69, x66); - const x72: u64 = (@intCast(u64, x71) + x67); + addcarryxU64(&x70, &x71, 0x0, x69, x66); + const x72 = (cast(u64, x71) + x67); var x73: u64 = undefined; var x74: u1 = undefined; - p256AddcarryxU64(&x73, &x74, 0x0, x54, x68); + addcarryxU64(&x73, &x74, 0x0, x54, x68); var x75: u64 = undefined; var x76: u1 = undefined; - p256AddcarryxU64(&x75, &x76, x74, x56, x70); + addcarryxU64(&x75, &x76, x74, x56, x70); var x77: u64 = undefined; var x78: u1 = undefined; - p256AddcarryxU64(&x77, &x78, x76, x58, x72); + addcarryxU64(&x77, &x78, x76, x58, x72); var x79: u64 = undefined; var x80: u1 = undefined; - p256AddcarryxU64(&x79, &x80, x78, x60, x64); + addcarryxU64(&x79, &x80, x78, x60, x64); var x81: u64 = undefined; var x82: u1 = undefined; - p256AddcarryxU64(&x81, &x82, x80, x62, x65); - const x83: u64 = (@intCast(u64, x82) + @intCast(u64, x63)); + addcarryxU64(&x81, &x82, x80, x62, x65); + const x83 = (cast(u64, x82) + cast(u64, x63)); var x84: u64 = undefined; var x85: u64 = undefined; - p256MulxU64(&x84, &x85, x2, (arg1[3])); + mulxU64(&x84, &x85, x2, (arg1[3])); var x86: u64 = undefined; var x87: u64 = undefined; - p256MulxU64(&x86, &x87, x2, (arg1[2])); + mulxU64(&x86, &x87, x2, (arg1[2])); var x88: u64 = undefined; var x89: u64 = undefined; - p256MulxU64(&x88, &x89, x2, (arg1[1])); + mulxU64(&x88, &x89, x2, (arg1[1])); var x90: u64 = undefined; var x91: u64 = undefined; - p256MulxU64(&x90, &x91, x2, (arg1[0])); + mulxU64(&x90, &x91, x2, (arg1[0])); var x92: u64 = undefined; var x93: u1 = undefined; - p256AddcarryxU64(&x92, &x93, 0x0, x91, x88); + addcarryxU64(&x92, &x93, 0x0, x91, x88); var x94: u64 = undefined; var x95: u1 = undefined; - p256AddcarryxU64(&x94, &x95, x93, x89, x86); + addcarryxU64(&x94, &x95, x93, x89, x86); var x96: u64 = undefined; var x97: u1 = undefined; - p256AddcarryxU64(&x96, &x97, x95, x87, x84); - const x98: u64 = (@intCast(u64, x97) + x85); + addcarryxU64(&x96, &x97, x95, x87, x84); + const x98 = (cast(u64, x97) + x85); var x99: u64 = undefined; var x100: u1 = undefined; - p256AddcarryxU64(&x99, &x100, 0x0, x75, x90); + addcarryxU64(&x99, &x100, 0x0, x75, x90); var x101: u64 = undefined; var x102: u1 = undefined; - p256AddcarryxU64(&x101, &x102, x100, x77, x92); + addcarryxU64(&x101, &x102, x100, x77, x92); var x103: u64 = undefined; var x104: u1 = undefined; - p256AddcarryxU64(&x103, &x104, x102, x79, x94); + addcarryxU64(&x103, &x104, x102, x79, x94); var x105: u64 = undefined; var x106: u1 = undefined; - p256AddcarryxU64(&x105, &x106, x104, x81, x96); + addcarryxU64(&x105, &x106, x104, x81, x96); var x107: u64 = undefined; var x108: u1 = undefined; - p256AddcarryxU64(&x107, &x108, x106, x83, x98); + addcarryxU64(&x107, &x108, x106, x83, x98); var x109: u64 = undefined; var x110: u64 = undefined; - p256MulxU64(&x109, &x110, x99, 0xffffffff00000001); + mulxU64(&x109, &x110, x99, 0xffffffff00000001); var x111: u64 = undefined; var x112: u64 = undefined; - p256MulxU64(&x111, &x112, x99, 0xffffffff); + mulxU64(&x111, &x112, x99, 0xffffffff); var x113: u64 = undefined; var x114: u64 = undefined; - p256MulxU64(&x113, &x114, x99, 0xffffffffffffffff); + mulxU64(&x113, &x114, x99, 0xffffffffffffffff); var x115: u64 = undefined; var x116: u1 = undefined; - p256AddcarryxU64(&x115, &x116, 0x0, x114, x111); - const x117: u64 = (@intCast(u64, x116) + x112); + addcarryxU64(&x115, &x116, 0x0, x114, x111); + const x117 = (cast(u64, x116) + x112); var x118: u64 = undefined; var x119: u1 = undefined; - p256AddcarryxU64(&x118, &x119, 0x0, x99, x113); + addcarryxU64(&x118, &x119, 0x0, x99, x113); var x120: u64 = undefined; var x121: u1 = undefined; - p256AddcarryxU64(&x120, &x121, x119, x101, x115); + addcarryxU64(&x120, &x121, x119, x101, x115); var x122: u64 = undefined; var x123: u1 = undefined; - p256AddcarryxU64(&x122, &x123, x121, x103, x117); + addcarryxU64(&x122, &x123, x121, x103, x117); var x124: u64 = undefined; var x125: u1 = undefined; - p256AddcarryxU64(&x124, &x125, x123, x105, x109); + addcarryxU64(&x124, &x125, x123, x105, x109); var x126: u64 = undefined; var x127: u1 = undefined; - p256AddcarryxU64(&x126, &x127, x125, x107, x110); - const x128: u64 = (@intCast(u64, x127) + @intCast(u64, x108)); + addcarryxU64(&x126, &x127, x125, x107, x110); + const x128 = (cast(u64, x127) + cast(u64, x108)); var x129: u64 = undefined; var x130: u64 = undefined; - p256MulxU64(&x129, &x130, x3, (arg1[3])); + mulxU64(&x129, &x130, x3, (arg1[3])); var x131: u64 = undefined; var x132: u64 = undefined; - p256MulxU64(&x131, &x132, x3, (arg1[2])); + mulxU64(&x131, &x132, x3, (arg1[2])); var x133: u64 = undefined; var x134: u64 = undefined; - p256MulxU64(&x133, &x134, x3, (arg1[1])); + mulxU64(&x133, &x134, x3, (arg1[1])); var x135: u64 = undefined; var x136: u64 = undefined; - p256MulxU64(&x135, &x136, x3, (arg1[0])); + mulxU64(&x135, &x136, x3, (arg1[0])); var x137: u64 = undefined; var x138: u1 = undefined; - p256AddcarryxU64(&x137, &x138, 0x0, x136, x133); + addcarryxU64(&x137, &x138, 0x0, x136, x133); var x139: u64 = undefined; var x140: u1 = undefined; - p256AddcarryxU64(&x139, &x140, x138, x134, x131); + addcarryxU64(&x139, &x140, x138, x134, x131); var x141: u64 = undefined; var x142: u1 = undefined; - p256AddcarryxU64(&x141, &x142, x140, x132, x129); - const x143: u64 = (@intCast(u64, x142) + x130); + addcarryxU64(&x141, &x142, x140, x132, x129); + const x143 = (cast(u64, x142) + x130); var x144: u64 = undefined; var x145: u1 = undefined; - p256AddcarryxU64(&x144, &x145, 0x0, x120, x135); + addcarryxU64(&x144, &x145, 0x0, x120, x135); var x146: u64 = undefined; var x147: u1 = undefined; - p256AddcarryxU64(&x146, &x147, x145, x122, x137); + addcarryxU64(&x146, &x147, x145, x122, x137); var x148: u64 = undefined; var x149: u1 = undefined; - p256AddcarryxU64(&x148, &x149, x147, x124, x139); + addcarryxU64(&x148, &x149, x147, x124, x139); var x150: u64 = undefined; var x151: u1 = undefined; - p256AddcarryxU64(&x150, &x151, x149, x126, x141); + addcarryxU64(&x150, &x151, x149, x126, x141); var x152: u64 = undefined; var x153: u1 = undefined; - p256AddcarryxU64(&x152, &x153, x151, x128, x143); + addcarryxU64(&x152, &x153, x151, x128, x143); var x154: u64 = undefined; var x155: u64 = undefined; - p256MulxU64(&x154, &x155, x144, 0xffffffff00000001); + mulxU64(&x154, &x155, x144, 0xffffffff00000001); var x156: u64 = undefined; var x157: u64 = undefined; - p256MulxU64(&x156, &x157, x144, 0xffffffff); + mulxU64(&x156, &x157, x144, 0xffffffff); var x158: u64 = undefined; var x159: u64 = undefined; - p256MulxU64(&x158, &x159, x144, 0xffffffffffffffff); + mulxU64(&x158, &x159, x144, 0xffffffffffffffff); var x160: u64 = undefined; var x161: u1 = undefined; - p256AddcarryxU64(&x160, &x161, 0x0, x159, x156); - const x162: u64 = (@intCast(u64, x161) + x157); + addcarryxU64(&x160, &x161, 0x0, x159, x156); + const x162 = (cast(u64, x161) + x157); var x163: u64 = undefined; var x164: u1 = undefined; - p256AddcarryxU64(&x163, &x164, 0x0, x144, x158); + addcarryxU64(&x163, &x164, 0x0, x144, x158); var x165: u64 = undefined; var x166: u1 = undefined; - p256AddcarryxU64(&x165, &x166, x164, x146, x160); + addcarryxU64(&x165, &x166, x164, x146, x160); var x167: u64 = undefined; var x168: u1 = undefined; - p256AddcarryxU64(&x167, &x168, x166, x148, x162); + addcarryxU64(&x167, &x168, x166, x148, x162); var x169: u64 = undefined; var x170: u1 = undefined; - p256AddcarryxU64(&x169, &x170, x168, x150, x154); + addcarryxU64(&x169, &x170, x168, x150, x154); var x171: u64 = undefined; var x172: u1 = undefined; - p256AddcarryxU64(&x171, &x172, x170, x152, x155); - const x173: u64 = (@intCast(u64, x172) + @intCast(u64, x153)); + addcarryxU64(&x171, &x172, x170, x152, x155); + const x173 = (cast(u64, x172) + cast(u64, x153)); var x174: u64 = undefined; var x175: u1 = undefined; - p256SubborrowxU64(&x174, &x175, 0x0, x165, 0xffffffffffffffff); + subborrowxU64(&x174, &x175, 0x0, x165, 0xffffffffffffffff); var x176: u64 = undefined; var x177: u1 = undefined; - p256SubborrowxU64(&x176, &x177, x175, x167, 0xffffffff); + subborrowxU64(&x176, &x177, x175, x167, 0xffffffff); var x178: u64 = undefined; var x179: u1 = undefined; - p256SubborrowxU64(&x178, &x179, x177, x169, @intCast(u64, 0x0)); + subborrowxU64(&x178, &x179, x177, x169, cast(u64, 0x0)); var x180: u64 = undefined; var x181: u1 = undefined; - p256SubborrowxU64(&x180, &x181, x179, x171, 0xffffffff00000001); + subborrowxU64(&x180, &x181, x179, x171, 0xffffffff00000001); var x182: u64 = undefined; var x183: u1 = undefined; - p256SubborrowxU64(&x182, &x183, x181, x173, @intCast(u64, 0x0)); + subborrowxU64(&x182, &x183, x181, x173, cast(u64, 0x0)); var x184: u64 = undefined; - p256CmovznzU64(&x184, x183, x174, x165); + cmovznzU64(&x184, x183, x174, x165); var x185: u64 = undefined; - p256CmovznzU64(&x185, x183, x176, x167); + cmovznzU64(&x185, x183, x176, x167); var x186: u64 = undefined; - p256CmovznzU64(&x186, x183, x178, x169); + cmovznzU64(&x186, x183, x178, x169); var x187: u64 = undefined; - p256CmovznzU64(&x187, x183, x180, x171); + cmovznzU64(&x187, x183, x180, x171); out1[0] = x184; out1[1] = x185; out1[2] = x186; out1[3] = x187; } -/// The function p256Add adds two field elements in the Montgomery domain. +/// The function add adds two field elements in the Montgomery domain. /// Preconditions: /// 0 ≤ eval arg1 < m /// 0 ≤ eval arg2 < m @@ -694,49 +706,51 @@ pub fn p256Square(out1: *Limbs, arg1: Limbs) void { /// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] -pub fn p256Add(out1: *Limbs, arg1: Limbs, arg2: Limbs) void { +pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void { + @setRuntimeSafety(mode == .Debug); + var x1: u64 = undefined; var x2: u1 = undefined; - p256AddcarryxU64(&x1, &x2, 0x0, (arg1[0]), (arg2[0])); + addcarryxU64(&x1, &x2, 0x0, (arg1[0]), (arg2[0])); var x3: u64 = undefined; var x4: u1 = undefined; - p256AddcarryxU64(&x3, &x4, x2, (arg1[1]), (arg2[1])); + addcarryxU64(&x3, &x4, x2, (arg1[1]), (arg2[1])); var x5: u64 = undefined; var x6: u1 = undefined; - p256AddcarryxU64(&x5, &x6, x4, (arg1[2]), (arg2[2])); + addcarryxU64(&x5, &x6, x4, (arg1[2]), (arg2[2])); var x7: u64 = undefined; var x8: u1 = undefined; - p256AddcarryxU64(&x7, &x8, x6, (arg1[3]), (arg2[3])); + addcarryxU64(&x7, &x8, x6, (arg1[3]), (arg2[3])); var x9: u64 = undefined; var x10: u1 = undefined; - p256SubborrowxU64(&x9, &x10, 0x0, x1, 0xffffffffffffffff); + subborrowxU64(&x9, &x10, 0x0, x1, 0xffffffffffffffff); var x11: u64 = undefined; var x12: u1 = undefined; - p256SubborrowxU64(&x11, &x12, x10, x3, 0xffffffff); + subborrowxU64(&x11, &x12, x10, x3, 0xffffffff); var x13: u64 = undefined; var x14: u1 = undefined; - p256SubborrowxU64(&x13, &x14, x12, x5, @intCast(u64, 0x0)); + subborrowxU64(&x13, &x14, x12, x5, cast(u64, 0x0)); var x15: u64 = undefined; var x16: u1 = undefined; - p256SubborrowxU64(&x15, &x16, x14, x7, 0xffffffff00000001); + subborrowxU64(&x15, &x16, x14, x7, 0xffffffff00000001); var x17: u64 = undefined; var x18: u1 = undefined; - p256SubborrowxU64(&x17, &x18, x16, @intCast(u64, x8), @intCast(u64, 0x0)); + subborrowxU64(&x17, &x18, x16, cast(u64, x8), cast(u64, 0x0)); var x19: u64 = undefined; - p256CmovznzU64(&x19, x18, x9, x1); + cmovznzU64(&x19, x18, x9, x1); var x20: u64 = undefined; - p256CmovznzU64(&x20, x18, x11, x3); + cmovznzU64(&x20, x18, x11, x3); var x21: u64 = undefined; - p256CmovznzU64(&x21, x18, x13, x5); + cmovznzU64(&x21, x18, x13, x5); var x22: u64 = undefined; - p256CmovznzU64(&x22, x18, x15, x7); + cmovznzU64(&x22, x18, x15, x7); out1[0] = x19; out1[1] = x20; out1[2] = x21; out1[3] = x22; } -/// The function p256Sub subtracts two field elements in the Montgomery domain. +/// The function sub subtracts two field elements in the Montgomery domain. /// Preconditions: /// 0 ≤ eval arg1 < m /// 0 ≤ eval arg2 < m @@ -749,40 +763,42 @@ pub fn p256Add(out1: *Limbs, arg1: Limbs, arg2: Limbs) void { /// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] -pub fn p256Sub(out1: *Limbs, arg1: Limbs, arg2: Limbs) void { +pub fn sub(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void { + @setRuntimeSafety(mode == .Debug); + var x1: u64 = undefined; var x2: u1 = undefined; - p256SubborrowxU64(&x1, &x2, 0x0, (arg1[0]), (arg2[0])); + subborrowxU64(&x1, &x2, 0x0, (arg1[0]), (arg2[0])); var x3: u64 = undefined; var x4: u1 = undefined; - p256SubborrowxU64(&x3, &x4, x2, (arg1[1]), (arg2[1])); + subborrowxU64(&x3, &x4, x2, (arg1[1]), (arg2[1])); var x5: u64 = undefined; var x6: u1 = undefined; - p256SubborrowxU64(&x5, &x6, x4, (arg1[2]), (arg2[2])); + subborrowxU64(&x5, &x6, x4, (arg1[2]), (arg2[2])); var x7: u64 = undefined; var x8: u1 = undefined; - p256SubborrowxU64(&x7, &x8, x6, (arg1[3]), (arg2[3])); + subborrowxU64(&x7, &x8, x6, (arg1[3]), (arg2[3])); var x9: u64 = undefined; - p256CmovznzU64(&x9, x8, @intCast(u64, 0x0), 0xffffffffffffffff); + cmovznzU64(&x9, x8, cast(u64, 0x0), 0xffffffffffffffff); var x10: u64 = undefined; var x11: u1 = undefined; - p256AddcarryxU64(&x10, &x11, 0x0, x1, x9); + addcarryxU64(&x10, &x11, 0x0, x1, x9); var x12: u64 = undefined; var x13: u1 = undefined; - p256AddcarryxU64(&x12, &x13, x11, x3, (x9 & 0xffffffff)); + addcarryxU64(&x12, &x13, x11, x3, (x9 & 0xffffffff)); var x14: u64 = undefined; var x15: u1 = undefined; - p256AddcarryxU64(&x14, &x15, x13, x5, @intCast(u64, 0x0)); + addcarryxU64(&x14, &x15, x13, x5, cast(u64, 0x0)); var x16: u64 = undefined; var x17: u1 = undefined; - p256AddcarryxU64(&x16, &x17, x15, x7, (x9 & 0xffffffff00000001)); + addcarryxU64(&x16, &x17, x15, x7, (x9 & 0xffffffff00000001)); out1[0] = x10; out1[1] = x12; out1[2] = x14; out1[3] = x16; } -/// The function p256Opp negates a field element in the Montgomery domain. +/// The function opp negates a field element in the Montgomery domain. /// Preconditions: /// 0 ≤ eval arg1 < m /// Postconditions: @@ -793,40 +809,42 @@ pub fn p256Sub(out1: *Limbs, arg1: Limbs, arg2: Limbs) void { /// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] -pub fn p256Opp(out1: *Limbs, arg1: Limbs) void { +pub fn opp(out1: *[4]u64, arg1: [4]u64) void { + @setRuntimeSafety(mode == .Debug); + var x1: u64 = undefined; var x2: u1 = undefined; - p256SubborrowxU64(&x1, &x2, 0x0, @intCast(u64, 0x0), (arg1[0])); + subborrowxU64(&x1, &x2, 0x0, cast(u64, 0x0), (arg1[0])); var x3: u64 = undefined; var x4: u1 = undefined; - p256SubborrowxU64(&x3, &x4, x2, @intCast(u64, 0x0), (arg1[1])); + subborrowxU64(&x3, &x4, x2, cast(u64, 0x0), (arg1[1])); var x5: u64 = undefined; var x6: u1 = undefined; - p256SubborrowxU64(&x5, &x6, x4, @intCast(u64, 0x0), (arg1[2])); + subborrowxU64(&x5, &x6, x4, cast(u64, 0x0), (arg1[2])); var x7: u64 = undefined; var x8: u1 = undefined; - p256SubborrowxU64(&x7, &x8, x6, @intCast(u64, 0x0), (arg1[3])); + subborrowxU64(&x7, &x8, x6, cast(u64, 0x0), (arg1[3])); var x9: u64 = undefined; - p256CmovznzU64(&x9, x8, @intCast(u64, 0x0), 0xffffffffffffffff); + cmovznzU64(&x9, x8, cast(u64, 0x0), 0xffffffffffffffff); var x10: u64 = undefined; var x11: u1 = undefined; - p256AddcarryxU64(&x10, &x11, 0x0, x1, x9); + addcarryxU64(&x10, &x11, 0x0, x1, x9); var x12: u64 = undefined; var x13: u1 = undefined; - p256AddcarryxU64(&x12, &x13, x11, x3, (x9 & 0xffffffff)); + addcarryxU64(&x12, &x13, x11, x3, (x9 & 0xffffffff)); var x14: u64 = undefined; var x15: u1 = undefined; - p256AddcarryxU64(&x14, &x15, x13, x5, @intCast(u64, 0x0)); + addcarryxU64(&x14, &x15, x13, x5, cast(u64, 0x0)); var x16: u64 = undefined; var x17: u1 = undefined; - p256AddcarryxU64(&x16, &x17, x15, x7, (x9 & 0xffffffff00000001)); + addcarryxU64(&x16, &x17, x15, x7, (x9 & 0xffffffff00000001)); out1[0] = x10; out1[1] = x12; out1[2] = x14; out1[3] = x16; } -/// The function p256FromMontgomery translates a field element out of the Montgomery domain. +/// The function fromMontgomery translates a field element out of the Montgomery domain. /// Preconditions: /// 0 ≤ eval arg1 < m /// Postconditions: @@ -837,150 +855,152 @@ pub fn p256Opp(out1: *Limbs, arg1: Limbs) void { /// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] -pub fn p256FromMontgomery(out1: *Limbs, arg1: Limbs) void { - const x1: u64 = (arg1[0]); +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; - p256MulxU64(&x2, &x3, x1, 0xffffffff00000001); + mulxU64(&x2, &x3, x1, 0xffffffff00000001); var x4: u64 = undefined; var x5: u64 = undefined; - p256MulxU64(&x4, &x5, x1, 0xffffffff); + mulxU64(&x4, &x5, x1, 0xffffffff); var x6: u64 = undefined; var x7: u64 = undefined; - p256MulxU64(&x6, &x7, x1, 0xffffffffffffffff); + mulxU64(&x6, &x7, x1, 0xffffffffffffffff); var x8: u64 = undefined; var x9: u1 = undefined; - p256AddcarryxU64(&x8, &x9, 0x0, x7, x4); + addcarryxU64(&x8, &x9, 0x0, x7, x4); var x10: u64 = undefined; var x11: u1 = undefined; - p256AddcarryxU64(&x10, &x11, 0x0, x1, x6); + addcarryxU64(&x10, &x11, 0x0, x1, x6); var x12: u64 = undefined; var x13: u1 = undefined; - p256AddcarryxU64(&x12, &x13, x11, @intCast(u64, 0x0), x8); + addcarryxU64(&x12, &x13, x11, cast(u64, 0x0), x8); var x14: u64 = undefined; var x15: u1 = undefined; - p256AddcarryxU64(&x14, &x15, 0x0, x12, (arg1[1])); + addcarryxU64(&x14, &x15, 0x0, x12, (arg1[1])); var x16: u64 = undefined; var x17: u64 = undefined; - p256MulxU64(&x16, &x17, x14, 0xffffffff00000001); + mulxU64(&x16, &x17, x14, 0xffffffff00000001); var x18: u64 = undefined; var x19: u64 = undefined; - p256MulxU64(&x18, &x19, x14, 0xffffffff); + mulxU64(&x18, &x19, x14, 0xffffffff); var x20: u64 = undefined; var x21: u64 = undefined; - p256MulxU64(&x20, &x21, x14, 0xffffffffffffffff); + mulxU64(&x20, &x21, x14, 0xffffffffffffffff); var x22: u64 = undefined; var x23: u1 = undefined; - p256AddcarryxU64(&x22, &x23, 0x0, x21, x18); + addcarryxU64(&x22, &x23, 0x0, x21, x18); var x24: u64 = undefined; var x25: u1 = undefined; - p256AddcarryxU64(&x24, &x25, 0x0, x14, x20); + addcarryxU64(&x24, &x25, 0x0, x14, x20); var x26: u64 = undefined; var x27: u1 = undefined; - p256AddcarryxU64(&x26, &x27, x25, (@intCast(u64, x15) + (@intCast(u64, x13) + (@intCast(u64, x9) + x5))), x22); + addcarryxU64(&x26, &x27, x25, (cast(u64, x15) + (cast(u64, x13) + (cast(u64, x9) + x5))), x22); var x28: u64 = undefined; var x29: u1 = undefined; - p256AddcarryxU64(&x28, &x29, x27, x2, (@intCast(u64, x23) + x19)); + addcarryxU64(&x28, &x29, x27, x2, (cast(u64, x23) + x19)); var x30: u64 = undefined; var x31: u1 = undefined; - p256AddcarryxU64(&x30, &x31, x29, x3, x16); + addcarryxU64(&x30, &x31, x29, x3, x16); var x32: u64 = undefined; var x33: u1 = undefined; - p256AddcarryxU64(&x32, &x33, 0x0, x26, (arg1[2])); + addcarryxU64(&x32, &x33, 0x0, x26, (arg1[2])); var x34: u64 = undefined; var x35: u1 = undefined; - p256AddcarryxU64(&x34, &x35, x33, x28, @intCast(u64, 0x0)); + addcarryxU64(&x34, &x35, x33, x28, cast(u64, 0x0)); var x36: u64 = undefined; var x37: u1 = undefined; - p256AddcarryxU64(&x36, &x37, x35, x30, @intCast(u64, 0x0)); + addcarryxU64(&x36, &x37, x35, x30, cast(u64, 0x0)); var x38: u64 = undefined; var x39: u64 = undefined; - p256MulxU64(&x38, &x39, x32, 0xffffffff00000001); + mulxU64(&x38, &x39, x32, 0xffffffff00000001); var x40: u64 = undefined; var x41: u64 = undefined; - p256MulxU64(&x40, &x41, x32, 0xffffffff); + mulxU64(&x40, &x41, x32, 0xffffffff); var x42: u64 = undefined; var x43: u64 = undefined; - p256MulxU64(&x42, &x43, x32, 0xffffffffffffffff); + mulxU64(&x42, &x43, x32, 0xffffffffffffffff); var x44: u64 = undefined; var x45: u1 = undefined; - p256AddcarryxU64(&x44, &x45, 0x0, x43, x40); + addcarryxU64(&x44, &x45, 0x0, x43, x40); var x46: u64 = undefined; var x47: u1 = undefined; - p256AddcarryxU64(&x46, &x47, 0x0, x32, x42); + addcarryxU64(&x46, &x47, 0x0, x32, x42); var x48: u64 = undefined; var x49: u1 = undefined; - p256AddcarryxU64(&x48, &x49, x47, x34, x44); + addcarryxU64(&x48, &x49, x47, x34, x44); var x50: u64 = undefined; var x51: u1 = undefined; - p256AddcarryxU64(&x50, &x51, x49, x36, (@intCast(u64, x45) + x41)); + addcarryxU64(&x50, &x51, x49, x36, (cast(u64, x45) + x41)); var x52: u64 = undefined; var x53: u1 = undefined; - p256AddcarryxU64(&x52, &x53, x51, (@intCast(u64, x37) + (@intCast(u64, x31) + x17)), x38); + addcarryxU64(&x52, &x53, x51, (cast(u64, x37) + (cast(u64, x31) + x17)), x38); var x54: u64 = undefined; var x55: u1 = undefined; - p256AddcarryxU64(&x54, &x55, 0x0, x48, (arg1[3])); + addcarryxU64(&x54, &x55, 0x0, x48, (arg1[3])); var x56: u64 = undefined; var x57: u1 = undefined; - p256AddcarryxU64(&x56, &x57, x55, x50, @intCast(u64, 0x0)); + addcarryxU64(&x56, &x57, x55, x50, cast(u64, 0x0)); var x58: u64 = undefined; var x59: u1 = undefined; - p256AddcarryxU64(&x58, &x59, x57, x52, @intCast(u64, 0x0)); + addcarryxU64(&x58, &x59, x57, x52, cast(u64, 0x0)); var x60: u64 = undefined; var x61: u64 = undefined; - p256MulxU64(&x60, &x61, x54, 0xffffffff00000001); + mulxU64(&x60, &x61, x54, 0xffffffff00000001); var x62: u64 = undefined; var x63: u64 = undefined; - p256MulxU64(&x62, &x63, x54, 0xffffffff); + mulxU64(&x62, &x63, x54, 0xffffffff); var x64: u64 = undefined; var x65: u64 = undefined; - p256MulxU64(&x64, &x65, x54, 0xffffffffffffffff); + mulxU64(&x64, &x65, x54, 0xffffffffffffffff); var x66: u64 = undefined; var x67: u1 = undefined; - p256AddcarryxU64(&x66, &x67, 0x0, x65, x62); + addcarryxU64(&x66, &x67, 0x0, x65, x62); var x68: u64 = undefined; var x69: u1 = undefined; - p256AddcarryxU64(&x68, &x69, 0x0, x54, x64); + addcarryxU64(&x68, &x69, 0x0, x54, x64); var x70: u64 = undefined; var x71: u1 = undefined; - p256AddcarryxU64(&x70, &x71, x69, x56, x66); + addcarryxU64(&x70, &x71, x69, x56, x66); var x72: u64 = undefined; var x73: u1 = undefined; - p256AddcarryxU64(&x72, &x73, x71, x58, (@intCast(u64, x67) + x63)); + addcarryxU64(&x72, &x73, x71, x58, (cast(u64, x67) + x63)); var x74: u64 = undefined; var x75: u1 = undefined; - p256AddcarryxU64(&x74, &x75, x73, (@intCast(u64, x59) + (@intCast(u64, x53) + x39)), x60); - const x76: u64 = (@intCast(u64, x75) + x61); + 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; - p256SubborrowxU64(&x77, &x78, 0x0, x70, 0xffffffffffffffff); + subborrowxU64(&x77, &x78, 0x0, x70, 0xffffffffffffffff); var x79: u64 = undefined; var x80: u1 = undefined; - p256SubborrowxU64(&x79, &x80, x78, x72, 0xffffffff); + subborrowxU64(&x79, &x80, x78, x72, 0xffffffff); var x81: u64 = undefined; var x82: u1 = undefined; - p256SubborrowxU64(&x81, &x82, x80, x74, @intCast(u64, 0x0)); + subborrowxU64(&x81, &x82, x80, x74, cast(u64, 0x0)); var x83: u64 = undefined; var x84: u1 = undefined; - p256SubborrowxU64(&x83, &x84, x82, x76, 0xffffffff00000001); + subborrowxU64(&x83, &x84, x82, x76, 0xffffffff00000001); var x85: u64 = undefined; var x86: u1 = undefined; - p256SubborrowxU64(&x85, &x86, x84, @intCast(u64, 0x0), @intCast(u64, 0x0)); + subborrowxU64(&x85, &x86, x84, cast(u64, 0x0), cast(u64, 0x0)); var x87: u64 = undefined; - p256CmovznzU64(&x87, x86, x77, x70); + cmovznzU64(&x87, x86, x77, x70); var x88: u64 = undefined; - p256CmovznzU64(&x88, x86, x79, x72); + cmovznzU64(&x88, x86, x79, x72); var x89: u64 = undefined; - p256CmovznzU64(&x89, x86, x81, x74); + cmovznzU64(&x89, x86, x81, x74); var x90: u64 = undefined; - p256CmovznzU64(&x90, x86, x83, x76); + cmovznzU64(&x90, x86, x83, x76); out1[0] = x87; out1[1] = x88; out1[2] = x89; out1[3] = x90; } -/// The function p256ToMontgomery translates a field element into the Montgomery domain. +/// The function toMontgomery translates a field element into the Montgomery domain. /// Preconditions: /// 0 ≤ eval arg1 < m /// Postconditions: @@ -991,269 +1011,271 @@ pub fn p256FromMontgomery(out1: *Limbs, arg1: Limbs) void { /// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] -pub fn p256ToMontgomery(out1: *Limbs, arg1: Limbs) void { - const x1: u64 = (arg1[1]); - const x2: u64 = (arg1[2]); - const x3: u64 = (arg1[3]); - const x4: u64 = (arg1[0]); +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; - p256MulxU64(&x5, &x6, x4, 0x4fffffffd); + mulxU64(&x5, &x6, x4, 0x4fffffffd); var x7: u64 = undefined; var x8: u64 = undefined; - p256MulxU64(&x7, &x8, x4, 0xfffffffffffffffe); + mulxU64(&x7, &x8, x4, 0xfffffffffffffffe); var x9: u64 = undefined; var x10: u64 = undefined; - p256MulxU64(&x9, &x10, x4, 0xfffffffbffffffff); + mulxU64(&x9, &x10, x4, 0xfffffffbffffffff); var x11: u64 = undefined; var x12: u64 = undefined; - p256MulxU64(&x11, &x12, x4, 0x3); + mulxU64(&x11, &x12, x4, 0x3); var x13: u64 = undefined; var x14: u1 = undefined; - p256AddcarryxU64(&x13, &x14, 0x0, x12, x9); + addcarryxU64(&x13, &x14, 0x0, x12, x9); var x15: u64 = undefined; var x16: u1 = undefined; - p256AddcarryxU64(&x15, &x16, x14, x10, x7); + addcarryxU64(&x15, &x16, x14, x10, x7); var x17: u64 = undefined; var x18: u1 = undefined; - p256AddcarryxU64(&x17, &x18, x16, x8, x5); + addcarryxU64(&x17, &x18, x16, x8, x5); var x19: u64 = undefined; var x20: u64 = undefined; - p256MulxU64(&x19, &x20, x11, 0xffffffff00000001); + mulxU64(&x19, &x20, x11, 0xffffffff00000001); var x21: u64 = undefined; var x22: u64 = undefined; - p256MulxU64(&x21, &x22, x11, 0xffffffff); + mulxU64(&x21, &x22, x11, 0xffffffff); var x23: u64 = undefined; var x24: u64 = undefined; - p256MulxU64(&x23, &x24, x11, 0xffffffffffffffff); + mulxU64(&x23, &x24, x11, 0xffffffffffffffff); var x25: u64 = undefined; var x26: u1 = undefined; - p256AddcarryxU64(&x25, &x26, 0x0, x24, x21); + addcarryxU64(&x25, &x26, 0x0, x24, x21); var x27: u64 = undefined; var x28: u1 = undefined; - p256AddcarryxU64(&x27, &x28, 0x0, x11, x23); + addcarryxU64(&x27, &x28, 0x0, x11, x23); var x29: u64 = undefined; var x30: u1 = undefined; - p256AddcarryxU64(&x29, &x30, x28, x13, x25); + addcarryxU64(&x29, &x30, x28, x13, x25); var x31: u64 = undefined; var x32: u1 = undefined; - p256AddcarryxU64(&x31, &x32, x30, x15, (@intCast(u64, x26) + x22)); + addcarryxU64(&x31, &x32, x30, x15, (cast(u64, x26) + x22)); var x33: u64 = undefined; var x34: u1 = undefined; - p256AddcarryxU64(&x33, &x34, x32, x17, x19); + addcarryxU64(&x33, &x34, x32, x17, x19); var x35: u64 = undefined; var x36: u1 = undefined; - p256AddcarryxU64(&x35, &x36, x34, (@intCast(u64, x18) + x6), x20); + addcarryxU64(&x35, &x36, x34, (cast(u64, x18) + x6), x20); var x37: u64 = undefined; var x38: u64 = undefined; - p256MulxU64(&x37, &x38, x1, 0x4fffffffd); + mulxU64(&x37, &x38, x1, 0x4fffffffd); var x39: u64 = undefined; var x40: u64 = undefined; - p256MulxU64(&x39, &x40, x1, 0xfffffffffffffffe); + mulxU64(&x39, &x40, x1, 0xfffffffffffffffe); var x41: u64 = undefined; var x42: u64 = undefined; - p256MulxU64(&x41, &x42, x1, 0xfffffffbffffffff); + mulxU64(&x41, &x42, x1, 0xfffffffbffffffff); var x43: u64 = undefined; var x44: u64 = undefined; - p256MulxU64(&x43, &x44, x1, 0x3); + mulxU64(&x43, &x44, x1, 0x3); var x45: u64 = undefined; var x46: u1 = undefined; - p256AddcarryxU64(&x45, &x46, 0x0, x44, x41); + addcarryxU64(&x45, &x46, 0x0, x44, x41); var x47: u64 = undefined; var x48: u1 = undefined; - p256AddcarryxU64(&x47, &x48, x46, x42, x39); + addcarryxU64(&x47, &x48, x46, x42, x39); var x49: u64 = undefined; var x50: u1 = undefined; - p256AddcarryxU64(&x49, &x50, x48, x40, x37); + addcarryxU64(&x49, &x50, x48, x40, x37); var x51: u64 = undefined; var x52: u1 = undefined; - p256AddcarryxU64(&x51, &x52, 0x0, x29, x43); + addcarryxU64(&x51, &x52, 0x0, x29, x43); var x53: u64 = undefined; var x54: u1 = undefined; - p256AddcarryxU64(&x53, &x54, x52, x31, x45); + addcarryxU64(&x53, &x54, x52, x31, x45); var x55: u64 = undefined; var x56: u1 = undefined; - p256AddcarryxU64(&x55, &x56, x54, x33, x47); + addcarryxU64(&x55, &x56, x54, x33, x47); var x57: u64 = undefined; var x58: u1 = undefined; - p256AddcarryxU64(&x57, &x58, x56, x35, x49); + addcarryxU64(&x57, &x58, x56, x35, x49); var x59: u64 = undefined; var x60: u64 = undefined; - p256MulxU64(&x59, &x60, x51, 0xffffffff00000001); + mulxU64(&x59, &x60, x51, 0xffffffff00000001); var x61: u64 = undefined; var x62: u64 = undefined; - p256MulxU64(&x61, &x62, x51, 0xffffffff); + mulxU64(&x61, &x62, x51, 0xffffffff); var x63: u64 = undefined; var x64: u64 = undefined; - p256MulxU64(&x63, &x64, x51, 0xffffffffffffffff); + mulxU64(&x63, &x64, x51, 0xffffffffffffffff); var x65: u64 = undefined; var x66: u1 = undefined; - p256AddcarryxU64(&x65, &x66, 0x0, x64, x61); + addcarryxU64(&x65, &x66, 0x0, x64, x61); var x67: u64 = undefined; var x68: u1 = undefined; - p256AddcarryxU64(&x67, &x68, 0x0, x51, x63); + addcarryxU64(&x67, &x68, 0x0, x51, x63); var x69: u64 = undefined; var x70: u1 = undefined; - p256AddcarryxU64(&x69, &x70, x68, x53, x65); + addcarryxU64(&x69, &x70, x68, x53, x65); var x71: u64 = undefined; var x72: u1 = undefined; - p256AddcarryxU64(&x71, &x72, x70, x55, (@intCast(u64, x66) + x62)); + addcarryxU64(&x71, &x72, x70, x55, (cast(u64, x66) + x62)); var x73: u64 = undefined; var x74: u1 = undefined; - p256AddcarryxU64(&x73, &x74, x72, x57, x59); + addcarryxU64(&x73, &x74, x72, x57, x59); var x75: u64 = undefined; var x76: u1 = undefined; - p256AddcarryxU64(&x75, &x76, x74, ((@intCast(u64, x58) + @intCast(u64, x36)) + (@intCast(u64, x50) + x38)), x60); + addcarryxU64(&x75, &x76, x74, ((cast(u64, x58) + cast(u64, x36)) + (cast(u64, x50) + x38)), x60); var x77: u64 = undefined; var x78: u64 = undefined; - p256MulxU64(&x77, &x78, x2, 0x4fffffffd); + mulxU64(&x77, &x78, x2, 0x4fffffffd); var x79: u64 = undefined; var x80: u64 = undefined; - p256MulxU64(&x79, &x80, x2, 0xfffffffffffffffe); + mulxU64(&x79, &x80, x2, 0xfffffffffffffffe); var x81: u64 = undefined; var x82: u64 = undefined; - p256MulxU64(&x81, &x82, x2, 0xfffffffbffffffff); + mulxU64(&x81, &x82, x2, 0xfffffffbffffffff); var x83: u64 = undefined; var x84: u64 = undefined; - p256MulxU64(&x83, &x84, x2, 0x3); + mulxU64(&x83, &x84, x2, 0x3); var x85: u64 = undefined; var x86: u1 = undefined; - p256AddcarryxU64(&x85, &x86, 0x0, x84, x81); + addcarryxU64(&x85, &x86, 0x0, x84, x81); var x87: u64 = undefined; var x88: u1 = undefined; - p256AddcarryxU64(&x87, &x88, x86, x82, x79); + addcarryxU64(&x87, &x88, x86, x82, x79); var x89: u64 = undefined; var x90: u1 = undefined; - p256AddcarryxU64(&x89, &x90, x88, x80, x77); + addcarryxU64(&x89, &x90, x88, x80, x77); var x91: u64 = undefined; var x92: u1 = undefined; - p256AddcarryxU64(&x91, &x92, 0x0, x69, x83); + addcarryxU64(&x91, &x92, 0x0, x69, x83); var x93: u64 = undefined; var x94: u1 = undefined; - p256AddcarryxU64(&x93, &x94, x92, x71, x85); + addcarryxU64(&x93, &x94, x92, x71, x85); var x95: u64 = undefined; var x96: u1 = undefined; - p256AddcarryxU64(&x95, &x96, x94, x73, x87); + addcarryxU64(&x95, &x96, x94, x73, x87); var x97: u64 = undefined; var x98: u1 = undefined; - p256AddcarryxU64(&x97, &x98, x96, x75, x89); + addcarryxU64(&x97, &x98, x96, x75, x89); var x99: u64 = undefined; var x100: u64 = undefined; - p256MulxU64(&x99, &x100, x91, 0xffffffff00000001); + mulxU64(&x99, &x100, x91, 0xffffffff00000001); var x101: u64 = undefined; var x102: u64 = undefined; - p256MulxU64(&x101, &x102, x91, 0xffffffff); + mulxU64(&x101, &x102, x91, 0xffffffff); var x103: u64 = undefined; var x104: u64 = undefined; - p256MulxU64(&x103, &x104, x91, 0xffffffffffffffff); + mulxU64(&x103, &x104, x91, 0xffffffffffffffff); var x105: u64 = undefined; var x106: u1 = undefined; - p256AddcarryxU64(&x105, &x106, 0x0, x104, x101); + addcarryxU64(&x105, &x106, 0x0, x104, x101); var x107: u64 = undefined; var x108: u1 = undefined; - p256AddcarryxU64(&x107, &x108, 0x0, x91, x103); + addcarryxU64(&x107, &x108, 0x0, x91, x103); var x109: u64 = undefined; var x110: u1 = undefined; - p256AddcarryxU64(&x109, &x110, x108, x93, x105); + addcarryxU64(&x109, &x110, x108, x93, x105); var x111: u64 = undefined; var x112: u1 = undefined; - p256AddcarryxU64(&x111, &x112, x110, x95, (@intCast(u64, x106) + x102)); + addcarryxU64(&x111, &x112, x110, x95, (cast(u64, x106) + x102)); var x113: u64 = undefined; var x114: u1 = undefined; - p256AddcarryxU64(&x113, &x114, x112, x97, x99); + addcarryxU64(&x113, &x114, x112, x97, x99); var x115: u64 = undefined; var x116: u1 = undefined; - p256AddcarryxU64(&x115, &x116, x114, ((@intCast(u64, x98) + @intCast(u64, x76)) + (@intCast(u64, x90) + x78)), x100); + addcarryxU64(&x115, &x116, x114, ((cast(u64, x98) + cast(u64, x76)) + (cast(u64, x90) + x78)), x100); var x117: u64 = undefined; var x118: u64 = undefined; - p256MulxU64(&x117, &x118, x3, 0x4fffffffd); + mulxU64(&x117, &x118, x3, 0x4fffffffd); var x119: u64 = undefined; var x120: u64 = undefined; - p256MulxU64(&x119, &x120, x3, 0xfffffffffffffffe); + mulxU64(&x119, &x120, x3, 0xfffffffffffffffe); var x121: u64 = undefined; var x122: u64 = undefined; - p256MulxU64(&x121, &x122, x3, 0xfffffffbffffffff); + mulxU64(&x121, &x122, x3, 0xfffffffbffffffff); var x123: u64 = undefined; var x124: u64 = undefined; - p256MulxU64(&x123, &x124, x3, 0x3); + mulxU64(&x123, &x124, x3, 0x3); var x125: u64 = undefined; var x126: u1 = undefined; - p256AddcarryxU64(&x125, &x126, 0x0, x124, x121); + addcarryxU64(&x125, &x126, 0x0, x124, x121); var x127: u64 = undefined; var x128: u1 = undefined; - p256AddcarryxU64(&x127, &x128, x126, x122, x119); + addcarryxU64(&x127, &x128, x126, x122, x119); var x129: u64 = undefined; var x130: u1 = undefined; - p256AddcarryxU64(&x129, &x130, x128, x120, x117); + addcarryxU64(&x129, &x130, x128, x120, x117); var x131: u64 = undefined; var x132: u1 = undefined; - p256AddcarryxU64(&x131, &x132, 0x0, x109, x123); + addcarryxU64(&x131, &x132, 0x0, x109, x123); var x133: u64 = undefined; var x134: u1 = undefined; - p256AddcarryxU64(&x133, &x134, x132, x111, x125); + addcarryxU64(&x133, &x134, x132, x111, x125); var x135: u64 = undefined; var x136: u1 = undefined; - p256AddcarryxU64(&x135, &x136, x134, x113, x127); + addcarryxU64(&x135, &x136, x134, x113, x127); var x137: u64 = undefined; var x138: u1 = undefined; - p256AddcarryxU64(&x137, &x138, x136, x115, x129); + addcarryxU64(&x137, &x138, x136, x115, x129); var x139: u64 = undefined; var x140: u64 = undefined; - p256MulxU64(&x139, &x140, x131, 0xffffffff00000001); + mulxU64(&x139, &x140, x131, 0xffffffff00000001); var x141: u64 = undefined; var x142: u64 = undefined; - p256MulxU64(&x141, &x142, x131, 0xffffffff); + mulxU64(&x141, &x142, x131, 0xffffffff); var x143: u64 = undefined; var x144: u64 = undefined; - p256MulxU64(&x143, &x144, x131, 0xffffffffffffffff); + mulxU64(&x143, &x144, x131, 0xffffffffffffffff); var x145: u64 = undefined; var x146: u1 = undefined; - p256AddcarryxU64(&x145, &x146, 0x0, x144, x141); + addcarryxU64(&x145, &x146, 0x0, x144, x141); var x147: u64 = undefined; var x148: u1 = undefined; - p256AddcarryxU64(&x147, &x148, 0x0, x131, x143); + addcarryxU64(&x147, &x148, 0x0, x131, x143); var x149: u64 = undefined; var x150: u1 = undefined; - p256AddcarryxU64(&x149, &x150, x148, x133, x145); + addcarryxU64(&x149, &x150, x148, x133, x145); var x151: u64 = undefined; var x152: u1 = undefined; - p256AddcarryxU64(&x151, &x152, x150, x135, (@intCast(u64, x146) + x142)); + addcarryxU64(&x151, &x152, x150, x135, (cast(u64, x146) + x142)); var x153: u64 = undefined; var x154: u1 = undefined; - p256AddcarryxU64(&x153, &x154, x152, x137, x139); + addcarryxU64(&x153, &x154, x152, x137, x139); var x155: u64 = undefined; var x156: u1 = undefined; - p256AddcarryxU64(&x155, &x156, x154, ((@intCast(u64, x138) + @intCast(u64, x116)) + (@intCast(u64, x130) + x118)), x140); + addcarryxU64(&x155, &x156, x154, ((cast(u64, x138) + cast(u64, x116)) + (cast(u64, x130) + x118)), x140); var x157: u64 = undefined; var x158: u1 = undefined; - p256SubborrowxU64(&x157, &x158, 0x0, x149, 0xffffffffffffffff); + subborrowxU64(&x157, &x158, 0x0, x149, 0xffffffffffffffff); var x159: u64 = undefined; var x160: u1 = undefined; - p256SubborrowxU64(&x159, &x160, x158, x151, 0xffffffff); + subborrowxU64(&x159, &x160, x158, x151, 0xffffffff); var x161: u64 = undefined; var x162: u1 = undefined; - p256SubborrowxU64(&x161, &x162, x160, x153, @intCast(u64, 0x0)); + subborrowxU64(&x161, &x162, x160, x153, cast(u64, 0x0)); var x163: u64 = undefined; var x164: u1 = undefined; - p256SubborrowxU64(&x163, &x164, x162, x155, 0xffffffff00000001); + subborrowxU64(&x163, &x164, x162, x155, 0xffffffff00000001); var x165: u64 = undefined; var x166: u1 = undefined; - p256SubborrowxU64(&x165, &x166, x164, @intCast(u64, x156), @intCast(u64, 0x0)); + subborrowxU64(&x165, &x166, x164, cast(u64, x156), cast(u64, 0x0)); var x167: u64 = undefined; - p256CmovznzU64(&x167, x166, x157, x149); + cmovznzU64(&x167, x166, x157, x149); var x168: u64 = undefined; - p256CmovznzU64(&x168, x166, x159, x151); + cmovznzU64(&x168, x166, x159, x151); var x169: u64 = undefined; - p256CmovznzU64(&x169, x166, x161, x153); + cmovznzU64(&x169, x166, x161, x153); var x170: u64 = undefined; - p256CmovznzU64(&x170, x166, x163, x155); + cmovznzU64(&x170, x166, x163, x155); out1[0] = x167; out1[1] = x168; out1[2] = x169; out1[3] = x170; } -/// The function p256Nonzero outputs a single non-zero word if the input is non-zero and zero otherwise. +/// The function nonzero outputs a single non-zero word if the input is non-zero and zero otherwise. /// Preconditions: /// 0 ≤ eval arg1 < m /// Postconditions: @@ -1263,12 +1285,14 @@ pub fn p256ToMontgomery(out1: *Limbs, arg1: Limbs) void { /// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] -pub fn p256Nonzero(out1: *u64, arg1: Limbs) void { - const x1: u64 = ((arg1[0]) | ((arg1[1]) | ((arg1[2]) | (arg1[3])))); +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 p256Selectznz is a multi-limb conditional select. +/// The function selectznz is a multi-limb conditional select. /// Postconditions: /// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3) /// @@ -1278,22 +1302,24 @@ pub fn p256Nonzero(out1: *u64, arg1: Limbs) void { /// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] -pub fn p256Selectznz(out1: *Limbs, arg1: u1, arg2: Limbs, arg3: Limbs) void { +pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void { + @setRuntimeSafety(mode == .Debug); + var x1: u64 = undefined; - p256CmovznzU64(&x1, arg1, (arg2[0]), (arg3[0])); + cmovznzU64(&x1, arg1, (arg2[0]), (arg3[0])); var x2: u64 = undefined; - p256CmovznzU64(&x2, arg1, (arg2[1]), (arg3[1])); + cmovznzU64(&x2, arg1, (arg2[1]), (arg3[1])); var x3: u64 = undefined; - p256CmovznzU64(&x3, arg1, (arg2[2]), (arg3[2])); + cmovznzU64(&x3, arg1, (arg2[2]), (arg3[2])); var x4: u64 = undefined; - p256CmovznzU64(&x4, arg1, (arg2[3]), (arg3[3])); + cmovznzU64(&x4, arg1, (arg2[3]), (arg3[3])); out1[0] = x1; out1[1] = x2; out1[2] = x3; out1[3] = x4; } -/// The function p256ToBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order. +/// The function toBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order. /// Preconditions: /// 0 ≤ eval arg1 < m /// Postconditions: @@ -1303,67 +1329,69 @@ pub fn p256Selectznz(out1: *Limbs, arg1: u1, arg2: Limbs, arg3: Limbs) void { /// 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 p256ToBytes(out1: *[32]u8, arg1: Limbs) void { - const x1: u64 = (arg1[3]); - const x2: u64 = (arg1[2]); - const x3: u64 = (arg1[1]); - const x4: u64 = (arg1[0]); - const x5: u8 = @intCast(u8, (x4 & @intCast(u64, 0xff))); - const x6: u64 = (x4 >> 8); - const x7: u8 = @intCast(u8, (x6 & @intCast(u64, 0xff))); - const x8: u64 = (x6 >> 8); - const x9: u8 = @intCast(u8, (x8 & @intCast(u64, 0xff))); - const x10: u64 = (x8 >> 8); - const x11: u8 = @intCast(u8, (x10 & @intCast(u64, 0xff))); - const x12: u64 = (x10 >> 8); - const x13: u8 = @intCast(u8, (x12 & @intCast(u64, 0xff))); - const x14: u64 = (x12 >> 8); - const x15: u8 = @intCast(u8, (x14 & @intCast(u64, 0xff))); - const x16: u64 = (x14 >> 8); - const x17: u8 = @intCast(u8, (x16 & @intCast(u64, 0xff))); - const x18: u8 = @intCast(u8, (x16 >> 8)); - const x19: u8 = @intCast(u8, (x3 & @intCast(u64, 0xff))); - const x20: u64 = (x3 >> 8); - const x21: u8 = @intCast(u8, (x20 & @intCast(u64, 0xff))); - const x22: u64 = (x20 >> 8); - const x23: u8 = @intCast(u8, (x22 & @intCast(u64, 0xff))); - const x24: u64 = (x22 >> 8); - const x25: u8 = @intCast(u8, (x24 & @intCast(u64, 0xff))); - const x26: u64 = (x24 >> 8); - const x27: u8 = @intCast(u8, (x26 & @intCast(u64, 0xff))); - const x28: u64 = (x26 >> 8); - const x29: u8 = @intCast(u8, (x28 & @intCast(u64, 0xff))); - const x30: u64 = (x28 >> 8); - const x31: u8 = @intCast(u8, (x30 & @intCast(u64, 0xff))); - const x32: u8 = @intCast(u8, (x30 >> 8)); - const x33: u8 = @intCast(u8, (x2 & @intCast(u64, 0xff))); - const x34: u64 = (x2 >> 8); - const x35: u8 = @intCast(u8, (x34 & @intCast(u64, 0xff))); - const x36: u64 = (x34 >> 8); - const x37: u8 = @intCast(u8, (x36 & @intCast(u64, 0xff))); - const x38: u64 = (x36 >> 8); - const x39: u8 = @intCast(u8, (x38 & @intCast(u64, 0xff))); - const x40: u64 = (x38 >> 8); - const x41: u8 = @intCast(u8, (x40 & @intCast(u64, 0xff))); - const x42: u64 = (x40 >> 8); - const x43: u8 = @intCast(u8, (x42 & @intCast(u64, 0xff))); - const x44: u64 = (x42 >> 8); - const x45: u8 = @intCast(u8, (x44 & @intCast(u64, 0xff))); - const x46: u8 = @intCast(u8, (x44 >> 8)); - const x47: u8 = @intCast(u8, (x1 & @intCast(u64, 0xff))); - const x48: u64 = (x1 >> 8); - const x49: u8 = @intCast(u8, (x48 & @intCast(u64, 0xff))); - const x50: u64 = (x48 >> 8); - const x51: u8 = @intCast(u8, (x50 & @intCast(u64, 0xff))); - const x52: u64 = (x50 >> 8); - const x53: u8 = @intCast(u8, (x52 & @intCast(u64, 0xff))); - const x54: u64 = (x52 >> 8); - const x55: u8 = @intCast(u8, (x54 & @intCast(u64, 0xff))); - const x56: u64 = (x54 >> 8); - const x57: u8 = @intCast(u8, (x56 & @intCast(u64, 0xff))); - const x58: u64 = (x56 >> 8); - const x59: u8 = @intCast(u8, (x58 & @intCast(u64, 0xff))); - const x60: u8 = @intCast(u8, (x58 >> 8)); +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; @@ -1398,7 +1426,7 @@ pub fn p256ToBytes(out1: *[32]u8, arg1: Limbs) void { out1[31] = x60; } -/// The function p256FromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order. +/// 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: @@ -1409,74 +1437,76 @@ pub fn p256ToBytes(out1: *[32]u8, arg1: Limbs) void { /// 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 p256FromBytes(out1: *Limbs, arg1: [32]u8) void { - const x1: u64 = (@intCast(u64, (arg1[31])) << 56); - const x2: u64 = (@intCast(u64, (arg1[30])) << 48); - const x3: u64 = (@intCast(u64, (arg1[29])) << 40); - const x4: u64 = (@intCast(u64, (arg1[28])) << 32); - const x5: u64 = (@intCast(u64, (arg1[27])) << 24); - const x6: u64 = (@intCast(u64, (arg1[26])) << 16); - const x7: u64 = (@intCast(u64, (arg1[25])) << 8); - const x8: u8 = (arg1[24]); - const x9: u64 = (@intCast(u64, (arg1[23])) << 56); - const x10: u64 = (@intCast(u64, (arg1[22])) << 48); - const x11: u64 = (@intCast(u64, (arg1[21])) << 40); - const x12: u64 = (@intCast(u64, (arg1[20])) << 32); - const x13: u64 = (@intCast(u64, (arg1[19])) << 24); - const x14: u64 = (@intCast(u64, (arg1[18])) << 16); - const x15: u64 = (@intCast(u64, (arg1[17])) << 8); - const x16: u8 = (arg1[16]); - const x17: u64 = (@intCast(u64, (arg1[15])) << 56); - const x18: u64 = (@intCast(u64, (arg1[14])) << 48); - const x19: u64 = (@intCast(u64, (arg1[13])) << 40); - const x20: u64 = (@intCast(u64, (arg1[12])) << 32); - const x21: u64 = (@intCast(u64, (arg1[11])) << 24); - const x22: u64 = (@intCast(u64, (arg1[10])) << 16); - const x23: u64 = (@intCast(u64, (arg1[9])) << 8); - const x24: u8 = (arg1[8]); - const x25: u64 = (@intCast(u64, (arg1[7])) << 56); - const x26: u64 = (@intCast(u64, (arg1[6])) << 48); - const x27: u64 = (@intCast(u64, (arg1[5])) << 40); - const x28: u64 = (@intCast(u64, (arg1[4])) << 32); - const x29: u64 = (@intCast(u64, (arg1[3])) << 24); - const x30: u64 = (@intCast(u64, (arg1[2])) << 16); - const x31: u64 = (@intCast(u64, (arg1[1])) << 8); - const x32: u8 = (arg1[0]); - const x33: u64 = (x31 + @intCast(u64, x32)); - const x34: u64 = (x30 + x33); - const x35: u64 = (x29 + x34); - const x36: u64 = (x28 + x35); - const x37: u64 = (x27 + x36); - const x38: u64 = (x26 + x37); - const x39: u64 = (x25 + x38); - const x40: u64 = (x23 + @intCast(u64, x24)); - const x41: u64 = (x22 + x40); - const x42: u64 = (x21 + x41); - const x43: u64 = (x20 + x42); - const x44: u64 = (x19 + x43); - const x45: u64 = (x18 + x44); - const x46: u64 = (x17 + x45); - const x47: u64 = (x15 + @intCast(u64, x16)); - const x48: u64 = (x14 + x47); - const x49: u64 = (x13 + x48); - const x50: u64 = (x12 + x49); - const x51: u64 = (x11 + x50); - const x52: u64 = (x10 + x51); - const x53: u64 = (x9 + x52); - const x54: u64 = (x7 + @intCast(u64, x8)); - const x55: u64 = (x6 + x54); - const x56: u64 = (x5 + x55); - const x57: u64 = (x4 + x56); - const x58: u64 = (x3 + x57); - const x59: u64 = (x2 + x58); - const x60: u64 = (x1 + x59); +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 p256SetOne returns the field element one in the Montgomery domain. +/// 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 @@ -1484,14 +1514,16 @@ pub fn p256FromBytes(out1: *Limbs, arg1: [32]u8) void { /// Input Bounds: /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] -pub fn p256SetOne(out1: *Limbs) void { - out1[0] = @intCast(u64, 0x1); +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 p256Msat returns the saturated representation of the prime modulus. +/// The function msat returns the saturated representation of the prime modulus. /// Postconditions: /// twos_complement_eval out1 = m /// 0 ≤ eval out1 < m @@ -1499,15 +1531,17 @@ pub fn p256SetOne(out1: *Limbs) void { /// Input Bounds: /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] -pub fn p256Msat(out1: *[5]u64) void { +pub fn msat(out1: *[5]u64) void { + @setRuntimeSafety(mode == .Debug); + out1[0] = 0xffffffffffffffff; out1[1] = 0xffffffff; - out1[2] = @intCast(u64, 0x0); + out1[2] = cast(u64, 0x0); out1[3] = 0xffffffff00000001; - out1[4] = @intCast(u64, 0x0); + out1[4] = cast(u64, 0x0); } -/// The function p256Divstep computes a divstep. +/// The function divstep computes a divstep. /// Preconditions: /// 0 ≤ eval arg4 < m /// 0 ≤ eval arg5 < m @@ -1534,209 +1568,211 @@ pub fn p256Msat(out1: *[5]u64) void { /// 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 p256Divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *Limbs, out5: *Limbs, arg1: u64, arg2: [5]u64, arg3: [5]u64, arg4: Limbs, arg5: Limbs) void { +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; - p256AddcarryxU64(&x1, &x2, 0x0, (~arg1), @intCast(u64, 0x1)); - const x3: u1 = (@intCast(u1, (x1 >> 63)) & @intCast(u1, ((arg3[0]) & @intCast(u64, 0x1)))); + 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; - p256AddcarryxU64(&x4, &x5, 0x0, (~arg1), @intCast(u64, 0x1)); + addcarryxU64(&x4, &x5, 0x0, (~arg1), cast(u64, 0x1)); var x6: u64 = undefined; - p256CmovznzU64(&x6, x3, arg1, x4); + cmovznzU64(&x6, x3, arg1, x4); var x7: u64 = undefined; - p256CmovznzU64(&x7, x3, (arg2[0]), (arg3[0])); + cmovznzU64(&x7, x3, (arg2[0]), (arg3[0])); var x8: u64 = undefined; - p256CmovznzU64(&x8, x3, (arg2[1]), (arg3[1])); + cmovznzU64(&x8, x3, (arg2[1]), (arg3[1])); var x9: u64 = undefined; - p256CmovznzU64(&x9, x3, (arg2[2]), (arg3[2])); + cmovznzU64(&x9, x3, (arg2[2]), (arg3[2])); var x10: u64 = undefined; - p256CmovznzU64(&x10, x3, (arg2[3]), (arg3[3])); + cmovznzU64(&x10, x3, (arg2[3]), (arg3[3])); var x11: u64 = undefined; - p256CmovznzU64(&x11, x3, (arg2[4]), (arg3[4])); + cmovznzU64(&x11, x3, (arg2[4]), (arg3[4])); var x12: u64 = undefined; var x13: u1 = undefined; - p256AddcarryxU64(&x12, &x13, 0x0, @intCast(u64, 0x1), (~(arg2[0]))); + addcarryxU64(&x12, &x13, 0x0, cast(u64, 0x1), (~(arg2[0]))); var x14: u64 = undefined; var x15: u1 = undefined; - p256AddcarryxU64(&x14, &x15, x13, @intCast(u64, 0x0), (~(arg2[1]))); + addcarryxU64(&x14, &x15, x13, cast(u64, 0x0), (~(arg2[1]))); var x16: u64 = undefined; var x17: u1 = undefined; - p256AddcarryxU64(&x16, &x17, x15, @intCast(u64, 0x0), (~(arg2[2]))); + addcarryxU64(&x16, &x17, x15, cast(u64, 0x0), (~(arg2[2]))); var x18: u64 = undefined; var x19: u1 = undefined; - p256AddcarryxU64(&x18, &x19, x17, @intCast(u64, 0x0), (~(arg2[3]))); + addcarryxU64(&x18, &x19, x17, cast(u64, 0x0), (~(arg2[3]))); var x20: u64 = undefined; var x21: u1 = undefined; - p256AddcarryxU64(&x20, &x21, x19, @intCast(u64, 0x0), (~(arg2[4]))); + addcarryxU64(&x20, &x21, x19, cast(u64, 0x0), (~(arg2[4]))); var x22: u64 = undefined; - p256CmovznzU64(&x22, x3, (arg3[0]), x12); + cmovznzU64(&x22, x3, (arg3[0]), x12); var x23: u64 = undefined; - p256CmovznzU64(&x23, x3, (arg3[1]), x14); + cmovznzU64(&x23, x3, (arg3[1]), x14); var x24: u64 = undefined; - p256CmovznzU64(&x24, x3, (arg3[2]), x16); + cmovznzU64(&x24, x3, (arg3[2]), x16); var x25: u64 = undefined; - p256CmovznzU64(&x25, x3, (arg3[3]), x18); + cmovznzU64(&x25, x3, (arg3[3]), x18); var x26: u64 = undefined; - p256CmovznzU64(&x26, x3, (arg3[4]), x20); + cmovznzU64(&x26, x3, (arg3[4]), x20); var x27: u64 = undefined; - p256CmovznzU64(&x27, x3, (arg4[0]), (arg5[0])); + cmovznzU64(&x27, x3, (arg4[0]), (arg5[0])); var x28: u64 = undefined; - p256CmovznzU64(&x28, x3, (arg4[1]), (arg5[1])); + cmovznzU64(&x28, x3, (arg4[1]), (arg5[1])); var x29: u64 = undefined; - p256CmovznzU64(&x29, x3, (arg4[2]), (arg5[2])); + cmovznzU64(&x29, x3, (arg4[2]), (arg5[2])); var x30: u64 = undefined; - p256CmovznzU64(&x30, x3, (arg4[3]), (arg5[3])); + cmovznzU64(&x30, x3, (arg4[3]), (arg5[3])); var x31: u64 = undefined; var x32: u1 = undefined; - p256AddcarryxU64(&x31, &x32, 0x0, x27, x27); + addcarryxU64(&x31, &x32, 0x0, x27, x27); var x33: u64 = undefined; var x34: u1 = undefined; - p256AddcarryxU64(&x33, &x34, x32, x28, x28); + addcarryxU64(&x33, &x34, x32, x28, x28); var x35: u64 = undefined; var x36: u1 = undefined; - p256AddcarryxU64(&x35, &x36, x34, x29, x29); + addcarryxU64(&x35, &x36, x34, x29, x29); var x37: u64 = undefined; var x38: u1 = undefined; - p256AddcarryxU64(&x37, &x38, x36, x30, x30); + addcarryxU64(&x37, &x38, x36, x30, x30); var x39: u64 = undefined; var x40: u1 = undefined; - p256SubborrowxU64(&x39, &x40, 0x0, x31, 0xffffffffffffffff); + subborrowxU64(&x39, &x40, 0x0, x31, 0xffffffffffffffff); var x41: u64 = undefined; var x42: u1 = undefined; - p256SubborrowxU64(&x41, &x42, x40, x33, 0xffffffff); + subborrowxU64(&x41, &x42, x40, x33, 0xffffffff); var x43: u64 = undefined; var x44: u1 = undefined; - p256SubborrowxU64(&x43, &x44, x42, x35, @intCast(u64, 0x0)); + subborrowxU64(&x43, &x44, x42, x35, cast(u64, 0x0)); var x45: u64 = undefined; var x46: u1 = undefined; - p256SubborrowxU64(&x45, &x46, x44, x37, 0xffffffff00000001); + subborrowxU64(&x45, &x46, x44, x37, 0xffffffff00000001); var x47: u64 = undefined; var x48: u1 = undefined; - p256SubborrowxU64(&x47, &x48, x46, @intCast(u64, x38), @intCast(u64, 0x0)); - const x49: u64 = (arg4[3]); - const x50: u64 = (arg4[2]); - const x51: u64 = (arg4[1]); - const x52: u64 = (arg4[0]); + 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; - p256SubborrowxU64(&x53, &x54, 0x0, @intCast(u64, 0x0), x52); + subborrowxU64(&x53, &x54, 0x0, cast(u64, 0x0), x52); var x55: u64 = undefined; var x56: u1 = undefined; - p256SubborrowxU64(&x55, &x56, x54, @intCast(u64, 0x0), x51); + subborrowxU64(&x55, &x56, x54, cast(u64, 0x0), x51); var x57: u64 = undefined; var x58: u1 = undefined; - p256SubborrowxU64(&x57, &x58, x56, @intCast(u64, 0x0), x50); + subborrowxU64(&x57, &x58, x56, cast(u64, 0x0), x50); var x59: u64 = undefined; var x60: u1 = undefined; - p256SubborrowxU64(&x59, &x60, x58, @intCast(u64, 0x0), x49); + subborrowxU64(&x59, &x60, x58, cast(u64, 0x0), x49); var x61: u64 = undefined; - p256CmovznzU64(&x61, x60, @intCast(u64, 0x0), 0xffffffffffffffff); + cmovznzU64(&x61, x60, cast(u64, 0x0), 0xffffffffffffffff); var x62: u64 = undefined; var x63: u1 = undefined; - p256AddcarryxU64(&x62, &x63, 0x0, x53, x61); + addcarryxU64(&x62, &x63, 0x0, x53, x61); var x64: u64 = undefined; var x65: u1 = undefined; - p256AddcarryxU64(&x64, &x65, x63, x55, (x61 & 0xffffffff)); + addcarryxU64(&x64, &x65, x63, x55, (x61 & 0xffffffff)); var x66: u64 = undefined; var x67: u1 = undefined; - p256AddcarryxU64(&x66, &x67, x65, x57, @intCast(u64, 0x0)); + addcarryxU64(&x66, &x67, x65, x57, cast(u64, 0x0)); var x68: u64 = undefined; var x69: u1 = undefined; - p256AddcarryxU64(&x68, &x69, x67, x59, (x61 & 0xffffffff00000001)); + addcarryxU64(&x68, &x69, x67, x59, (x61 & 0xffffffff00000001)); var x70: u64 = undefined; - p256CmovznzU64(&x70, x3, (arg5[0]), x62); + cmovznzU64(&x70, x3, (arg5[0]), x62); var x71: u64 = undefined; - p256CmovznzU64(&x71, x3, (arg5[1]), x64); + cmovznzU64(&x71, x3, (arg5[1]), x64); var x72: u64 = undefined; - p256CmovznzU64(&x72, x3, (arg5[2]), x66); + cmovznzU64(&x72, x3, (arg5[2]), x66); var x73: u64 = undefined; - p256CmovznzU64(&x73, x3, (arg5[3]), x68); - const x74: u1 = @intCast(u1, (x22 & @intCast(u64, 0x1))); + cmovznzU64(&x73, x3, (arg5[3]), x68); + const x74 = cast(u1, (x22 & cast(u64, 0x1))); var x75: u64 = undefined; - p256CmovznzU64(&x75, x74, @intCast(u64, 0x0), x7); + cmovznzU64(&x75, x74, cast(u64, 0x0), x7); var x76: u64 = undefined; - p256CmovznzU64(&x76, x74, @intCast(u64, 0x0), x8); + cmovznzU64(&x76, x74, cast(u64, 0x0), x8); var x77: u64 = undefined; - p256CmovznzU64(&x77, x74, @intCast(u64, 0x0), x9); + cmovznzU64(&x77, x74, cast(u64, 0x0), x9); var x78: u64 = undefined; - p256CmovznzU64(&x78, x74, @intCast(u64, 0x0), x10); + cmovznzU64(&x78, x74, cast(u64, 0x0), x10); var x79: u64 = undefined; - p256CmovznzU64(&x79, x74, @intCast(u64, 0x0), x11); + cmovznzU64(&x79, x74, cast(u64, 0x0), x11); var x80: u64 = undefined; var x81: u1 = undefined; - p256AddcarryxU64(&x80, &x81, 0x0, x22, x75); + addcarryxU64(&x80, &x81, 0x0, x22, x75); var x82: u64 = undefined; var x83: u1 = undefined; - p256AddcarryxU64(&x82, &x83, x81, x23, x76); + addcarryxU64(&x82, &x83, x81, x23, x76); var x84: u64 = undefined; var x85: u1 = undefined; - p256AddcarryxU64(&x84, &x85, x83, x24, x77); + addcarryxU64(&x84, &x85, x83, x24, x77); var x86: u64 = undefined; var x87: u1 = undefined; - p256AddcarryxU64(&x86, &x87, x85, x25, x78); + addcarryxU64(&x86, &x87, x85, x25, x78); var x88: u64 = undefined; var x89: u1 = undefined; - p256AddcarryxU64(&x88, &x89, x87, x26, x79); + addcarryxU64(&x88, &x89, x87, x26, x79); var x90: u64 = undefined; - p256CmovznzU64(&x90, x74, @intCast(u64, 0x0), x27); + cmovznzU64(&x90, x74, cast(u64, 0x0), x27); var x91: u64 = undefined; - p256CmovznzU64(&x91, x74, @intCast(u64, 0x0), x28); + cmovznzU64(&x91, x74, cast(u64, 0x0), x28); var x92: u64 = undefined; - p256CmovznzU64(&x92, x74, @intCast(u64, 0x0), x29); + cmovznzU64(&x92, x74, cast(u64, 0x0), x29); var x93: u64 = undefined; - p256CmovznzU64(&x93, x74, @intCast(u64, 0x0), x30); + cmovznzU64(&x93, x74, cast(u64, 0x0), x30); var x94: u64 = undefined; var x95: u1 = undefined; - p256AddcarryxU64(&x94, &x95, 0x0, x70, x90); + addcarryxU64(&x94, &x95, 0x0, x70, x90); var x96: u64 = undefined; var x97: u1 = undefined; - p256AddcarryxU64(&x96, &x97, x95, x71, x91); + addcarryxU64(&x96, &x97, x95, x71, x91); var x98: u64 = undefined; var x99: u1 = undefined; - p256AddcarryxU64(&x98, &x99, x97, x72, x92); + addcarryxU64(&x98, &x99, x97, x72, x92); var x100: u64 = undefined; var x101: u1 = undefined; - p256AddcarryxU64(&x100, &x101, x99, x73, x93); + addcarryxU64(&x100, &x101, x99, x73, x93); var x102: u64 = undefined; var x103: u1 = undefined; - p256SubborrowxU64(&x102, &x103, 0x0, x94, 0xffffffffffffffff); + subborrowxU64(&x102, &x103, 0x0, x94, 0xffffffffffffffff); var x104: u64 = undefined; var x105: u1 = undefined; - p256SubborrowxU64(&x104, &x105, x103, x96, 0xffffffff); + subborrowxU64(&x104, &x105, x103, x96, 0xffffffff); var x106: u64 = undefined; var x107: u1 = undefined; - p256SubborrowxU64(&x106, &x107, x105, x98, @intCast(u64, 0x0)); + subborrowxU64(&x106, &x107, x105, x98, cast(u64, 0x0)); var x108: u64 = undefined; var x109: u1 = undefined; - p256SubborrowxU64(&x108, &x109, x107, x100, 0xffffffff00000001); + subborrowxU64(&x108, &x109, x107, x100, 0xffffffff00000001); var x110: u64 = undefined; var x111: u1 = undefined; - p256SubborrowxU64(&x110, &x111, x109, @intCast(u64, x101), @intCast(u64, 0x0)); + subborrowxU64(&x110, &x111, x109, cast(u64, x101), cast(u64, 0x0)); var x112: u64 = undefined; var x113: u1 = undefined; - p256AddcarryxU64(&x112, &x113, 0x0, x6, @intCast(u64, 0x1)); - const x114: u64 = ((x80 >> 1) | ((x82 << 63) & 0xffffffffffffffff)); - const x115: u64 = ((x82 >> 1) | ((x84 << 63) & 0xffffffffffffffff)); - const x116: u64 = ((x84 >> 1) | ((x86 << 63) & 0xffffffffffffffff)); - const x117: u64 = ((x86 >> 1) | ((x88 << 63) & 0xffffffffffffffff)); - const x118: u64 = ((x88 & 0x8000000000000000) | (x88 >> 1)); + 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; - p256CmovznzU64(&x119, x48, x39, x31); + cmovznzU64(&x119, x48, x39, x31); var x120: u64 = undefined; - p256CmovznzU64(&x120, x48, x41, x33); + cmovznzU64(&x120, x48, x41, x33); var x121: u64 = undefined; - p256CmovznzU64(&x121, x48, x43, x35); + cmovznzU64(&x121, x48, x43, x35); var x122: u64 = undefined; - p256CmovznzU64(&x122, x48, x45, x37); + cmovznzU64(&x122, x48, x45, x37); var x123: u64 = undefined; - p256CmovznzU64(&x123, x111, x102, x94); + cmovznzU64(&x123, x111, x102, x94); var x124: u64 = undefined; - p256CmovznzU64(&x124, x111, x104, x96); + cmovznzU64(&x124, x111, x104, x96); var x125: u64 = undefined; - p256CmovznzU64(&x125, x111, x106, x98); + cmovznzU64(&x125, x111, x106, x98); var x126: u64 = undefined; - p256CmovznzU64(&x126, x111, x108, x100); + cmovznzU64(&x126, x111, x108, x100); out1.* = x112; out2[0] = x7; out2[1] = x8; @@ -1758,7 +1794,7 @@ pub fn p256Divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *Limbs, out5: out5[3] = x126; } -/// The function p256DivstepPrecomp returns the precomputed value for Bernstein-Yang-inversion (in montgomery form). +/// 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 @@ -1766,7 +1802,9 @@ pub fn p256Divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *Limbs, out5: /// Input Bounds: /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] -pub fn p256DivstepPrecomp(out1: *Limbs) void { +pub fn divstepPrecomp(out1: *[4]u64) void { + @setRuntimeSafety(mode == .Debug); + out1[0] = 0x67ffffffb8000000; out1[1] = 0xc000000038000000; out1[2] = 0xd80000007fffffff; diff --git a/lib/std/crypto/pcurves/p256/p256_scalar_64.zig b/lib/std/crypto/pcurves/p256/p256_scalar_64.zig new file mode 100644 index 0000000000..7e3cc211f5 --- /dev/null +++ b/lib/std/crypto/pcurves/p256/p256_scalar_64.zig @@ -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; +} diff --git a/lib/std/crypto/pcurves/p256/scalar.zig b/lib/std/crypto/pcurves/p256/scalar.zig index e047f6a8d6..3cd6689897 100644 --- a/lib/std/crypto/pcurves/p256/scalar.zig +++ b/lib/std/crypto/pcurves/p256/scalar.zig @@ -6,32 +6,44 @@ 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 Fe = @import("field.zig").Fe; +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 = [32]u8; +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) NonCanonicalError!void { - return Fe.rejectNonCanonical(s); +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) CompressedScalar { - return Scalar.fromBytes48(s).toBytes(); +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) CompressedScalar { - return ScalarDouble.fromBytes64(s).toBytes(); +pub fn reduce64(s: [64]u8, endian: builtin.Endian) CompressedScalar { + return ScalarDouble.fromBytes64(s, endian).toBytes(endian); } /// Return a*b (mod L) @@ -183,19 +195,19 @@ const ScalarDouble = struct { } var t = ScalarDouble{ .x1 = undefined, .x2 = Fe.zero, .x3 = Fe.zero }; { - var b = [_]u8{0} ** 32; + 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} ** 32; + 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} ** 32; + 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; From b10d40b89bca0f70944434a1e0ffbfb984b4eae5 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 2 May 2021 12:48:58 +0200 Subject: [PATCH 29/47] stage2: Implement CPU host detection for ARM/AArch64 targets --- lib/std/zig/system/linux.zig | 226 +++++++++++++++++++++++++++++++++-- 1 file changed, 219 insertions(+), 7 deletions(-) diff --git a/lib/std/zig/system/linux.zig b/lib/std/zig/system/linux.zig index dc0d3c7f6a..8353b87566 100644 --- a/lib/std/zig/system/linux.zig +++ b/lib/std/zig/system/linux.zig @@ -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,218 @@ 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; + + // implementer = 0x41 + const ARM = .{ + .{ 0x926, &A32.arm926ej_s, null }, + .{ 0xb02, &A32.mpcore, null }, + .{ 0xb36, &A32.arm1136j_s, null }, + .{ 0xb56, &A32.arm1156t2_s, null }, + .{ 0xb76, &A32.arm1176jz_s, null }, + .{ 0xc05, &A32.cortex_a5, null }, + .{ 0xc07, &A32.cortex_a7, null }, + .{ 0xc08, &A32.cortex_a8, null }, + .{ 0xc09, &A32.cortex_a9, null }, + .{ 0xc0d, &A32.cortex_a17, null }, + .{ 0xc0f, &A32.cortex_a15, null }, + .{ 0xc0e, &A32.cortex_a17, null }, + .{ 0xc14, &A32.cortex_r4, null }, + .{ 0xc15, &A32.cortex_r5, null }, + .{ 0xc17, &A32.cortex_r7, null }, + .{ 0xc18, &A32.cortex_r8, null }, + .{ 0xc20, &A32.cortex_m0, null }, + .{ 0xc21, &A32.cortex_m1, null }, + .{ 0xc23, &A32.cortex_m3, null }, + .{ 0xc24, &A32.cortex_m4, null }, + .{ 0xc27, &A32.cortex_m7, null }, + .{ 0xc60, &A32.cortex_m0plus, null }, + .{ 0xd01, &A32.cortex_a32, null }, + .{ 0xd03, &A32.cortex_a53, &A64.cortex_a53 }, + .{ 0xd04, &A32.cortex_a35, &A64.cortex_a35 }, + .{ 0xd05, &A32.cortex_a55, &A64.cortex_a55 }, + .{ 0xd07, &A32.cortex_a57, &A64.cortex_a57 }, + .{ 0xd08, &A32.cortex_a72, &A64.cortex_a72 }, + .{ 0xd09, &A32.cortex_a73, &A64.cortex_a73 }, + .{ 0xd0a, &A32.cortex_a75, &A64.cortex_a75 }, + .{ 0xd0b, &A32.cortex_a76, &A64.cortex_a76 }, + .{ 0xd0c, &A32.neoverse_n1, null }, + .{ 0xd0d, &A32.cortex_a77, &A64.cortex_a77 }, + .{ 0xd13, &A32.cortex_r52, null }, + .{ 0xd20, &A32.cortex_m23, null }, + .{ 0xd21, &A32.cortex_m33, null }, + .{ 0xd41, &A32.cortex_a78, &A64.cortex_a78 }, + .{ 0xd4b, &A32.cortex_a78c, &A64.cortex_a78c }, + .{ 0xd44, &A32.cortex_x1, &A64.cortex_x1 }, + .{ 0xd02, null, &A64.cortex_a34 }, + .{ 0xd06, null, &A64.cortex_a65 }, + .{ 0xd43, null, &A64.cortex_a65ae }, + }; + + fn isKnown(implementer: u8, part: u16, is_64bit: bool) ?*const Target.Cpu.Model { + const models = switch (implementer) { + 0x41 => ARM, + else => return null, + }; + + inline for (models) |model| { + if (model[0] == part) + return if (is_64bit) model[2] else model[1]; + } + + 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.implementer, core.part, 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 +395,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; }, From 792cf925ec170ddcb42a2d78ab8f464642e92b17 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 2 May 2021 12:49:43 +0200 Subject: [PATCH 30/47] std: Fix missing CPU feature check We need both the v6k and the v6m checks. --- lib/std/Thread.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig index 39d37f2e5f..84b91b2de3 100644 --- a/lib/std/Thread.zig +++ b/lib/std/Thread.zig @@ -75,7 +75,7 @@ pub fn spinLoopHint() callconv(.Inline) void { }, .arm, .armeb, .thumb, .thumbeb => { // `yield` was introduced in v6k but are also available on v6m. - const can_yield = comptime std.Target.arm.featureSetHas(std.Target.current.cpu.features, .has_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"); }, .aarch64, .aarch64_be, .aarch64_32 => { From a7f3e12d23aa59ef3a6d78b1eb10a2a0d688906a Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 2 May 2021 18:52:08 +0200 Subject: [PATCH 31/47] std: Add fallback on pre-v6 ARM targets Thanks xackus for noticing the missing else branch. --- lib/std/Thread.zig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig index 84b91b2de3..a85219a458 100644 --- a/lib/std/Thread.zig +++ b/lib/std/Thread.zig @@ -76,7 +76,9 @@ pub fn spinLoopHint() callconv(.Inline) void { .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"); + if (can_yield) asm volatile ("yield" ::: "memory") + // Fallback. + else asm volatile ("" ::: "memory"); }, .aarch64, .aarch64_be, .aarch64_32 => { asm volatile ("isb" ::: "memory"); From e2d2295382164776d32997d5806b9829525d7875 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 2 May 2021 19:35:06 +0200 Subject: [PATCH 32/47] std: Add many more vendors and cpus to the ARM detection list Hand-picked from GCC and LLVM lists. --- lib/std/zig/system/linux.zig | 155 +++++++++++++++++++++++------------ 1 file changed, 103 insertions(+), 52 deletions(-) diff --git a/lib/std/zig/system/linux.zig b/lib/std/zig/system/linux.zig index 8353b87566..a755a0de91 100644 --- a/lib/std/zig/system/linux.zig +++ b/lib/std/zig/system/linux.zig @@ -163,61 +163,113 @@ const ArmCpuinfoImpl = struct { const A32 = Target.arm.cpu; const A64 = Target.aarch64.cpu; - // implementer = 0x41 - const ARM = .{ - .{ 0x926, &A32.arm926ej_s, null }, - .{ 0xb02, &A32.mpcore, null }, - .{ 0xb36, &A32.arm1136j_s, null }, - .{ 0xb56, &A32.arm1156t2_s, null }, - .{ 0xb76, &A32.arm1176jz_s, null }, - .{ 0xc05, &A32.cortex_a5, null }, - .{ 0xc07, &A32.cortex_a7, null }, - .{ 0xc08, &A32.cortex_a8, null }, - .{ 0xc09, &A32.cortex_a9, null }, - .{ 0xc0d, &A32.cortex_a17, null }, - .{ 0xc0f, &A32.cortex_a15, null }, - .{ 0xc0e, &A32.cortex_a17, null }, - .{ 0xc14, &A32.cortex_r4, null }, - .{ 0xc15, &A32.cortex_r5, null }, - .{ 0xc17, &A32.cortex_r7, null }, - .{ 0xc18, &A32.cortex_r8, null }, - .{ 0xc20, &A32.cortex_m0, null }, - .{ 0xc21, &A32.cortex_m1, null }, - .{ 0xc23, &A32.cortex_m3, null }, - .{ 0xc24, &A32.cortex_m4, null }, - .{ 0xc27, &A32.cortex_m7, null }, - .{ 0xc60, &A32.cortex_m0plus, null }, - .{ 0xd01, &A32.cortex_a32, null }, - .{ 0xd03, &A32.cortex_a53, &A64.cortex_a53 }, - .{ 0xd04, &A32.cortex_a35, &A64.cortex_a35 }, - .{ 0xd05, &A32.cortex_a55, &A64.cortex_a55 }, - .{ 0xd07, &A32.cortex_a57, &A64.cortex_a57 }, - .{ 0xd08, &A32.cortex_a72, &A64.cortex_a72 }, - .{ 0xd09, &A32.cortex_a73, &A64.cortex_a73 }, - .{ 0xd0a, &A32.cortex_a75, &A64.cortex_a75 }, - .{ 0xd0b, &A32.cortex_a76, &A64.cortex_a76 }, - .{ 0xd0c, &A32.neoverse_n1, null }, - .{ 0xd0d, &A32.cortex_a77, &A64.cortex_a77 }, - .{ 0xd13, &A32.cortex_r52, null }, - .{ 0xd20, &A32.cortex_m23, null }, - .{ 0xd21, &A32.cortex_m33, null }, - .{ 0xd41, &A32.cortex_a78, &A64.cortex_a78 }, - .{ 0xd4b, &A32.cortex_a78c, &A64.cortex_a78c }, - .{ 0xd44, &A32.cortex_x1, &A64.cortex_x1 }, - .{ 0xd02, null, &A64.cortex_a34 }, - .{ 0xd06, null, &A64.cortex_a65 }, - .{ 0xd43, null, &A64.cortex_a65ae }, + 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, }; - fn isKnown(implementer: u8, part: u16, is_64bit: bool) ?*const Target.Cpu.Model { - const models = switch (implementer) { - 0x41 => ARM, + // 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 = 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, + 0x51 => &Qualcomm, else => return null, }; - inline for (models) |model| { - if (model[0] == part) - return if (is_64bit) model[2] else model[1]; + 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; @@ -287,8 +339,7 @@ const ArmCpuinfoImpl = struct { 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.implementer, core.part, is_64bit); + known_models[i] = cpu_models.isKnown(core, is_64bit); } // XXX We pick the first core on big.LITTLE systems, hopefully the From 3eed61340784af95a92e2035712eeaeab7cf0ad3 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 3 May 2021 12:30:18 +0200 Subject: [PATCH 33/47] std: Add two more ARM CPUs to the known CPU list Modeled after GCC's description. --- lib/std/target/aarch64.zig | 18 ++++++++++++++++++ lib/std/zig/system/linux.zig | 6 ++++++ tools/update_cpu_features.zig | 22 ++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/lib/std/target/aarch64.zig b/lib/std/target/aarch64.zig index 03c2031207..a331d8a874 100644 --- a/lib/std/target/aarch64.zig +++ b/lib/std/target/aarch64.zig @@ -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, + }), + }; }; diff --git a/lib/std/zig/system/linux.zig b/lib/std/zig/system/linux.zig index a755a0de91..c2cf7b009d 100644 --- a/lib/std/zig/system/linux.zig +++ b/lib/std/zig/system/linux.zig @@ -239,6 +239,11 @@ const ArmCpuinfoImpl = struct { 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 }, @@ -262,6 +267,7 @@ const ArmCpuinfoImpl = struct { 0x43 => &Cavium, 0x46 => &Fujitsu, 0x48 => &HiSilicon, + 0x50 => &Ampere, 0x51 => &Qualcomm, else => return null, }; diff --git a/tools/update_cpu_features.zig b/tools/update_cpu_features.zig index 15143dfca4..c2ddd87f7c 100644 --- a/tools/update_cpu_features.zig +++ b/tools/update_cpu_features.zig @@ -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", + }, + }, }, }, .{ From b6be28ddcc50bd4bf085294ffcb696e31a7a1de5 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 4 May 2021 09:30:06 +0200 Subject: [PATCH 34/47] std: Accept unaligned slice in several ArrayListAligned ops Do not impose the internal alignment requirements to the user-supplied parameters. Closes #8647 --- lib/std/array_list.zig | 84 +++++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig index f30a86d8f7..7825d36ac3 100644 --- a/lib/std/array_list.zig +++ b/lib/std/array_list.zig @@ -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.ensureCapacity(self.items.len + 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.ensureCapacity(self.items.len + 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; @@ -429,7 +428,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`. @@ -483,7 +481,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.ensureCapacity(allocator, self.items.len + items.len); self.items.len += items.len; @@ -495,7 +493,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(); @@ -543,14 +541,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.ensureCapacity(allocator, self.items.len + 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; @@ -1128,15 +1126,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" { @@ -1167,18 +1181,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; { @@ -1226,3 +1228,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 }); + } +} From 86ab6ca56c4e6d115b017eed40dc62815a6a8e3d Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sun, 2 May 2021 23:40:08 +0200 Subject: [PATCH 35/47] zld: rewrite Object to include pointers to Symbols --- src/link/MachO/Object.zig | 178 ++++++++++++++----------------- src/link/MachO/Symbol.zig | 111 +++++++++++++------ src/link/MachO/reloc.zig | 10 +- src/link/MachO/reloc/aarch64.zig | 16 +-- src/link/MachO/reloc/x86_64.zig | 16 +-- 5 files changed, 186 insertions(+), 145 deletions(-) diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 6703a5bfb7..d599a6edbe 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -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 = .translation_unit, + .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; diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index 9e6c2bf68a..a907146e25 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -2,31 +2,93 @@ 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, +pub const Regular = struct { + base: Symbol, -/// Index of this symbol within the file's symbol table. -index: ?u32 = null, + /// Linkage type. + linkage: Linkage, -pub fn deinit(self: *Symbol, allocator: *Allocator) void { - allocator.free(self.name); + /// 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 const Proxy = struct { + base: Symbol, + + /// Dylib ordinal. + dylib: u16, + + pub const base_type: Symbol.Type = .proxy; +}; + +pub const Unresolved = struct { + base: Symbol, + + /// Alias of. + alias: ?*Symbol = null, + + /// 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 isStab(sym: macho.nlist_64) bool { @@ -55,17 +117,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; } diff --git a/src/link/MachO/reloc.zig b/src/link/MachO/reloc.zig index 57825149d1..1ce9fa2c2d 100644 --- a/src/link/MachO/reloc.zig +++ b/src/link/MachO/reloc.zig @@ -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(); diff --git a/src/link/MachO/reloc/aarch64.zig b/src/link/MachO/reloc/aarch64.zig index d8e7cebddd..dbc233b3a5 100644 --- a/src/link/MachO/reloc/aarch64.zig +++ b/src/link/MachO/reloc/aarch64.zig @@ -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, diff --git a/src/link/MachO/reloc/x86_64.zig b/src/link/MachO/reloc/x86_64.zig index cdc90aac90..32f83924e8 100644 --- a/src/link/MachO/reloc/x86_64.zig +++ b/src/link/MachO/reloc/x86_64.zig @@ -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, From 68ebc7cba0cb6089be3eb4511a05615830f132ae Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 3 May 2021 14:11:07 +0200 Subject: [PATCH 36/47] zld: rewrite symbol resolution --- src/link/MachO/Object.zig | 2 +- src/link/MachO/Symbol.zig | 12 +- src/link/MachO/Zld.zig | 295 +++++++++++++++++++++----------------- 3 files changed, 173 insertions(+), 136 deletions(-) diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index d599a6edbe..31cc63cfe0 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -365,7 +365,7 @@ pub fn parseSymbols(self: *Object) !void { .@"type" = .regular, .name = name, }, - .linkage = .translation_unit, + .linkage = linkage, .address = sym.n_value, .section = sym.n_sect - 1, .weak_ref = Symbol.isWeakRef(sym), diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index a907146e25..72ef25587d 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -19,6 +19,15 @@ pub const Type = enum { /// Symbol name. Owned slice. name: []u8, +/// Alias of. +alias: ?*Symbol = null, + +/// Index in GOT table for indirection. +got_index: ?u32 = null, + +/// Index in stubs table for late binding. +stubs_index: ?u32 = null, + pub const Regular = struct { base: Symbol, @@ -71,9 +80,6 @@ pub const Proxy = struct { pub const Unresolved = struct { base: Symbol, - /// Alias of. - alias: ?*Symbol = null, - /// File where this symbol was referenced. file: *Object, diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index a585b1fd1e..75b483c9a4 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -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) = .{}, @@ -74,30 +74,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.StringArrayHashMapUnmanaged(*Symbol) = .{}, +got_entries: std.StringArrayHashMapUnmanaged(*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 +117,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 +125,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); { @@ -216,19 +200,21 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { try self.populateMetadata(); try self.parseInputFiles(files); try self.resolveSymbols(); - try self.resolveStubsAndGotEntries(); - try self.updateMetadata(); - try self.sortSections(); - try self.allocateTextSegment(); - try self.allocateDataConstSegment(); - try self.allocateDataSegment(); - self.allocateLinkeditSegment(); - try self.allocateSymbols(); - try self.allocateStubsAndGotEntries(); - try self.allocateCppStatics(); - try self.writeStubHelperCommon(); - try self.resolveRelocsAndWriteSections(); - try self.flush(); + self.printSymbols(); + return error.Unfinished; + // try self.resolveStubsAndGotEntries(); + // try self.updateMetadata(); + // try self.sortSections(); + // try self.allocateTextSegment(); + // try self.allocateDataConstSegment(); + // try self.allocateDataSegment(); + // self.allocateLinkeditSegment(); + // try self.allocateSymbols(); + // try self.allocateStubsAndGotEntries(); + // try self.allocateCppStatics(); + // try self.writeStubHelperCommon(); + // try self.resolveRelocsAndWriteSections(); + // try self.flush(); } fn parseInputFiles(self: *Zld, files: []const []const u8) !void { @@ -291,7 +277,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 +288,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; @@ -1274,141 +1266,150 @@ 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]; - log.debug("resolving symbols in '{s}'", .{object.name}); +fn resolveSymbolsInObject(self: *Zld, object: *Object) !void { + log.warn("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.warn("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 { @@ -2979,3 +2980,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.warn("globals", .{}); + for (self.globals.items()) |entry| { + const sym = entry.value.cast(Symbol.Regular) orelse unreachable; + log.warn(" | {s} @ {*}", .{ sym.base.name, entry.value }); + log.warn(" => alias of {*}", .{sym.base.alias}); + log.warn(" => linkage {s}", .{sym.linkage}); + log.warn(" => defined in {s}", .{sym.file.name.?}); + } + for (self.objects.items) |object| { + log.warn("locals in {s}", .{object.name.?}); + for (object.symbols.items) |sym| { + log.warn(" | {s} @ {*}", .{ sym.name, sym }); + log.warn(" => alias of {*}", .{sym.alias}); + if (sym.cast(Symbol.Regular)) |reg| { + log.warn(" => linkage {s}", .{reg.linkage}); + } else { + log.warn(" => unresolved", .{}); + } + } + } + log.warn("proxies", .{}); + for (self.imports.items()) |entry| { + const sym = entry.value.cast(Symbol.Proxy) orelse unreachable; + log.warn(" | {s} @ {*}", .{ sym.base.name, entry.value }); + log.warn(" => alias of {*}", .{sym.base.alias}); + log.warn(" => defined in libSystem.B.dylib", .{}); + } +} From fcd57f08574fd89cf68080f2de6a1300375c83e5 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 3 May 2021 14:33:13 +0200 Subject: [PATCH 37/47] zld: resolve GOT loads and stubs --- src/link/MachO/Symbol.zig | 7 ++++ src/link/MachO/Zld.zig | 69 +++++++++++++++------------------------ 2 files changed, 34 insertions(+), 42 deletions(-) diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index 72ef25587d..1475c96383 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -97,6 +97,13 @@ pub fn cast(base: *Symbol, comptime T: type) ?*T { 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 { return (macho.N_STAB & sym.n_type) != 0; } diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 75b483c9a4..cac756772f 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -83,8 +83,8 @@ strtab_dir: std.StringHashMapUnmanaged(u32) = .{}, threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{}, local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, -stubs: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, -got_entries: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, +stubs: std.ArrayListUnmanaged(*Symbol) = .{}, +got_entries: std.ArrayListUnmanaged(*Symbol) = .{}, stub_helper_stubs_start_off: ?u64 = null, @@ -200,9 +200,9 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { try self.populateMetadata(); try self.parseInputFiles(files); try self.resolveSymbols(); - self.printSymbols(); + // self.printSymbols(); + try self.resolveStubsAndGotEntries(); return error.Unfinished; - // try self.resolveStubsAndGotEntries(); // try self.updateMetadata(); // try self.sortSections(); // try self.allocateTextSegment(); @@ -1413,8 +1413,8 @@ fn resolveSymbols(self: *Zld) !void { } fn resolveStubsAndGotEntries(self: *Zld) !void { - for (self.objects.items) |object, object_id| { - log.debug("resolving stubs and got entries from {s}", .{object.name}); + for (self.objects.items) |object| { + log.warn("resolving stubs and got entries from {s}", .{object.name}); for (object.sections.items) |sect| { const relocs = sect.relocs orelse continue; @@ -1422,42 +1422,31 @@ 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.warn(" | 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.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.warn(" | found stub {s}: {*}", .{ sym.name, sym }); }, } } @@ -1465,16 +1454,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.warn(" | found GOT entry {s}: {*}", .{ sym.name, sym }); } fn resolveRelocsAndWriteSections(self: *Zld) !void { From 00c3d57a51d963e078e8f4dfc090bd2a0d0d6a30 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 3 May 2021 14:56:45 +0200 Subject: [PATCH 38/47] zld: rewrite symbol allocations --- src/link/MachO/Zld.zig | 99 ++++++++++-------------------------------- 1 file changed, 24 insertions(+), 75 deletions(-) diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index cac756772f..b5fbda2ed2 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -202,16 +202,14 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { try self.resolveSymbols(); // self.printSymbols(); try self.resolveStubsAndGotEntries(); + try self.updateMetadata(); + try self.sortSections(); + try self.allocateTextSegment(); + try self.allocateDataConstSegment(); + try self.allocateDataSegment(); + self.allocateLinkeditSegment(); + try self.allocateSymbols(); return error.Unfinished; - // try self.updateMetadata(); - // try self.sortSections(); - // try self.allocateTextSegment(); - // try self.allocateDataConstSegment(); - // try self.allocateDataSegment(); - // self.allocateLinkeditSegment(); - // try self.allocateSymbols(); - // try self.allocateStubsAndGotEntries(); - // try self.allocateCppStatics(); // try self.writeStubHelperCommon(); // try self.resolveRelocsAndWriteSections(); // try self.flush(); @@ -797,7 +795,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; @@ -848,7 +846,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; @@ -863,7 +861,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; @@ -906,95 +904,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.warn("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; } } } From 9e11f27c4134b885786f703f0c340392644a39db Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 3 May 2021 16:00:50 +0200 Subject: [PATCH 39/47] zld: build updated macho backend --- src/link/MachO/Symbol.zig | 7 + src/link/MachO/Zld.zig | 405 ++++++++++++++++---------------------- 2 files changed, 177 insertions(+), 235 deletions(-) diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index 1475c96383..4b8ee3c77c 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -66,6 +66,13 @@ pub const Regular = struct { 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 { diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index b5fbda2ed2..2dd4223559 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -209,10 +209,9 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { try self.allocateDataSegment(); self.allocateLinkeditSegment(); try self.allocateSymbols(); - return error.Unfinished; - // try self.writeStubHelperCommon(); - // try self.resolveRelocsAndWriteSections(); - // try self.flush(); + try self.writeStubHelperCommon(); + try self.resolveRelocsAndWriteSections(); + try self.flush(); } fn parseInputFiles(self: *Zld, files: []const []const u8) !void { @@ -268,7 +267,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { continue; } - log.debug("unexpected input file of unknown type '{s}'", .{file_name}); + log.warn("unexpected input file of unknown type '{s}'", .{file_name}); } // Based on our classification, proceed with parsing. @@ -326,7 +325,7 @@ fn mapAndUpdateSections( .target_sect_id = target_sect_id, .offset = @intCast(u32, offset), }); - log.debug("{s}: {s},{s} mapped to {s},{s} from 0x{x} to 0x{x}", .{ + log.warn("{s}: {s},{s} mapped to {s},{s} from 0x{x} to 0x{x}", .{ object.name, parseName(&source_sect.segname), parseName(&source_sect.sectname), @@ -556,7 +555,7 @@ fn updateMetadata(self: *Zld) !void { }); }, else => { - log.debug("unhandled section type 0x{x} for '{s}/{s}'", .{ flags, segname, sectname }); + log.warn("unhandled section type 0x{x} for '{s}/{s}'", .{ flags, segname, sectname }); }, } } @@ -581,7 +580,7 @@ fn updateMetadata(self: *Zld) !void { const segname = parseName(&source_sect.segname); const sectname = parseName(&source_sect.sectname); - log.debug("section '{s}/{s}' will be unmapped", .{ segname, sectname }); + log.warn("section '{s}/{s}' will be unmapped", .{ segname, sectname }); try self.unhandled_sections.putNoClobber(self.allocator, .{ .object_id = object_id, @@ -978,8 +977,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); } @@ -1022,9 +1021,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; @@ -1075,8 +1074,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); @@ -1099,7 +1099,7 @@ fn writeLazySymbolPointer(self: *Zld, index: u32) !void { var buf: [@sizeOf(u64)]u8 = undefined; mem.writeIntLittle(u64, &buf, end); const off = la_symbol_ptr.offset + index * @sizeOf(u64); - log.debug("writing lazy symbol pointer entry 0x{x} at 0x{x}", .{ end, off }); + log.warn("writing lazy symbol pointer entry 0x{x} at 0x{x}", .{ end, off }); try self.file.?.pwriteAll(&buf, off); } @@ -1112,7 +1112,7 @@ fn writeStub(self: *Zld, index: u32) !void { const stub_off = stubs.offset + index * stubs.reserved2; const stub_addr = stubs.addr + index * stubs.reserved2; const la_ptr_addr = la_symbol_ptr.addr + index * @sizeOf(u64); - log.debug("writing stub at 0x{x}", .{stub_off}); + log.warn("writing stub at 0x{x}", .{stub_off}); var code = try self.allocator.alloc(u8, stubs.reserved2); defer self.allocator.free(code); switch (self.arch.?) { @@ -1413,7 +1413,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { fn resolveRelocsAndWriteSections(self: *Zld) !void { for (self.objects.items) |object, object_id| { - log.debug("relocating object {s}", .{object.name}); + log.warn("relocating object {s}", .{object.name}); for (object.sections.items) |sect, source_sect_id| { if (sect.inner.flags == macho.S_MOD_INIT_FUNC_POINTERS or @@ -1422,14 +1422,14 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { const segname = parseName(§.inner.segname); const sectname = parseName(§.inner.sectname); - log.debug("relocating section '{s},{s}'", .{ segname, sectname }); + log.warn("relocating section '{s},{s}'", .{ segname, sectname }); // Get mapping const target_mapping = self.mappings.get(.{ .object_id = @intCast(u16, object_id), .source_sect_id = @intCast(u16, source_sect_id), }) orelse { - log.debug("no mapping for {s},{s}; skipping", .{ segname, sectname }); + log.warn("no mapping for {s},{s}; skipping", .{ segname, sectname }); continue; }; const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment; @@ -1482,11 +1482,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| { @@ -1505,10 +1502,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) { @@ -1523,7 +1518,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { } } - log.debug("writing contents of '{s},{s}' section from '{s}' from 0x{x} to 0x{x}", .{ + log.warn("writing contents of '{s},{s}' section from '{s}' from 0x{x} to 0x{x}", .{ segname, sectname, object.name, @@ -1535,7 +1530,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { target_sect.flags == macho.S_THREAD_LOCAL_ZEROFILL or target_sect.flags == macho.S_THREAD_LOCAL_VARIABLES) { - log.debug("zeroing out '{s},{s}' from 0x{x} to 0x{x}", .{ + log.warn("zeroing out '{s},{s}' from 0x{x} to 0x{x}", .{ parseName(&target_sect.segname), parseName(&target_sect.sectname), target_sect_off, @@ -1555,58 +1550,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.warn(" | regular '{s}'", .{sym.name}); + break :blk reg.address; + } else if (final.cast(Symbol.Proxy)) |proxy| { + if (mem.eql(u8, sym.name, "__tlv_bootstrap")) { + log.warn(" | 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.warn(" | 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; } }, @@ -2071,10 +2035,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); } } @@ -2128,17 +2092,18 @@ 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 }); + log.warn("writing GOT pointers at 0x{x} to 0x{x}", .{ sect.offset, sect.offset + buffer.len }); try self.file.?.pwriteAll(buffer, sect.offset); } @@ -2148,7 +2113,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); } @@ -2161,24 +2127,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; @@ -2202,10 +2165,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, }); } @@ -2226,7 +2189,7 @@ fn writeRebaseInfoTable(self: *Zld) !void { dyld_info.rebase_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @sizeOf(u64))); seg.inner.filesize += dyld_info.rebase_size; - log.debug("writing rebase info from 0x{x} to 0x{x}", .{ dyld_info.rebase_off, dyld_info.rebase_off + dyld_info.rebase_size }); + log.warn("writing rebase info from 0x{x} to 0x{x}", .{ dyld_info.rebase_off, dyld_info.rebase_off + dyld_info.rebase_size }); try self.file.?.pwriteAll(buffer, dyld_info.rebase_off); } @@ -2241,21 +2204,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, + }); + } } } @@ -2265,14 +2223,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, }); } @@ -2289,7 +2248,7 @@ fn writeBindInfoTable(self: *Zld) !void { dyld_info.bind_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64))); seg.inner.filesize += dyld_info.bind_size; - log.debug("writing binding info from 0x{x} to 0x{x}", .{ dyld_info.bind_off, dyld_info.bind_off + dyld_info.bind_size }); + log.warn("writing binding info from 0x{x} to 0x{x}", .{ dyld_info.bind_off, dyld_info.bind_off + dyld_info.bind_size }); try self.file.?.pwriteAll(buffer, dyld_info.bind_off); } @@ -2304,20 +2263,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, }); } } @@ -2335,7 +2290,7 @@ fn writeLazyBindInfoTable(self: *Zld) !void { dyld_info.lazy_bind_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64))); seg.inner.filesize += dyld_info.lazy_bind_size; - log.debug("writing lazy binding info from 0x{x} to 0x{x}", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size }); + log.warn("writing lazy binding info from 0x{x} to 0x{x}", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size }); try self.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off); try self.populateLazyBindOffsetsInStubHelper(buffer); @@ -2386,7 +2341,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, @@ -2399,9 +2354,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); } } @@ -2413,12 +2369,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, }); @@ -2437,7 +2394,7 @@ fn writeExportInfo(self: *Zld) !void { dyld_info.export_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64))); seg.inner.filesize += dyld_info.export_size; - log.debug("writing export info from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size }); + log.warn("writing export info from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size }); try self.file.?.pwriteAll(buffer, dyld_info.export_off); } @@ -2446,7 +2403,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 "./"; @@ -2475,39 +2432,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 => { @@ -2523,9 +2483,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, }); }, } @@ -2551,7 +2511,7 @@ fn writeDebugInfo(self: *Zld) !void { const stabs_off = symtab.symoff; const stabs_size = symtab.nsyms * @sizeOf(macho.nlist_64); - log.debug("writing symbol stabs from 0x{x} to 0x{x}", .{ stabs_off, stabs_size + stabs_off }); + log.warn("writing symbol stabs from 0x{x} to 0x{x}", .{ stabs_off, stabs_size + stabs_off }); try self.file.?.pwriteAll(mem.sliceAsBytes(stabs.items), stabs_off); linkedit.inner.filesize += stabs_size; @@ -2561,27 +2521,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; @@ -2589,56 +2528,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; @@ -2647,17 +2582,17 @@ fn writeSymbolTable(self: *Zld) !void { const locals_off = symtab.symoff + symtab.nsyms * @sizeOf(macho.nlist_64); const locals_size = nlocals * @sizeOf(macho.nlist_64); - log.debug("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off }); + log.warn("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off }); try self.file.?.pwriteAll(mem.sliceAsBytes(locals.items), locals_off); const exports_off = locals_off + locals_size; const exports_size = nexports * @sizeOf(macho.nlist_64); - log.debug("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off }); + log.warn("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off }); try self.file.?.pwriteAll(mem.sliceAsBytes(exports.items), exports_off); const undefs_off = exports_off + exports_size; const undefs_size = nundefs * @sizeOf(macho.nlist_64); - log.debug("writing undefined symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off }); + log.warn("writing undefined symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off }); try self.file.?.pwriteAll(mem.sliceAsBytes(undefs.items), undefs_off); symtab.nsyms += @intCast(u32, nlocals + nexports + nundefs); @@ -2678,8 +2613,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; @@ -2687,7 +2622,7 @@ fn writeSymbolTable(self: *Zld) !void { const needed_size = dysymtab.nindirectsyms * @sizeOf(u32); seg.inner.filesize += needed_size; - log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{ + log.warn("writing indirect symbol table from 0x{x} to 0x{x}", .{ dysymtab.indirectsymoff, dysymtab.indirectsymoff + needed_size, }); @@ -2699,25 +2634,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); @@ -2730,7 +2665,7 @@ fn writeStringTable(self: *Zld) !void { symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64))); seg.inner.filesize += symtab.strsize; - log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize }); + log.warn("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize }); try self.file.?.pwriteAll(self.strtab.items, symtab.stroff); @@ -2776,7 +2711,7 @@ fn writeDataInCode(self: *Zld) !void { dice_cmd.datasize = datasize; seg.inner.filesize += datasize; - log.debug("writing data-in-code from 0x{x} to 0x{x}", .{ fileoff, fileoff + datasize }); + log.warn("writing data-in-code from 0x{x} to 0x{x}", .{ fileoff, fileoff + datasize }); try self.file.?.pwriteAll(buf.items, fileoff); } @@ -2797,7 +2732,7 @@ fn writeCodeSignaturePadding(self: *Zld) !void { seg.inner.filesize += needed_size; seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size.?); - log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size }); + log.warn("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size }); // Pad out the space. We need to do this to calculate valid hashes for everything in the file // except for code signature data. @@ -2823,7 +2758,7 @@ fn writeCodeSignature(self: *Zld) !void { var stream = std.io.fixedBufferStream(buffer); try code_sig.write(stream.writer()); - log.debug("writing code signature from 0x{x} to 0x{x}", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len }); + log.warn("writing code signature from 0x{x} to 0x{x}", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len }); try self.file.?.pwriteAll(buffer, code_sig_cmd.dataoff); } @@ -2841,7 +2776,7 @@ fn writeLoadCommands(self: *Zld) !void { } const off = @sizeOf(macho.mach_header_64); - log.debug("writing {} load commands from 0x{x} to 0x{x}", .{ self.load_commands.items.len, off, off + sizeofcmds }); + log.warn("writing {} load commands from 0x{x} to 0x{x}", .{ self.load_commands.items.len, off, off + sizeofcmds }); try self.file.?.pwriteAll(buffer, off); } @@ -2879,7 +2814,7 @@ fn writeHeader(self: *Zld) !void { for (self.load_commands.items) |cmd| { header.sizeofcmds += cmd.cmdsize(); } - log.debug("writing Mach-O header {}", .{header}); + log.warn("writing Mach-O header {}", .{header}); try self.file.?.pwriteAll(mem.asBytes(&header), 0); } @@ -2892,13 +2827,13 @@ pub fn makeStaticString(bytes: []const u8) [16]u8 { fn makeString(self: *Zld, bytes: []const u8) !u32 { if (self.strtab_dir.get(bytes)) |offset| { - log.debug("reusing '{s}' from string table at offset 0x{x}", .{ bytes, offset }); + log.warn("reusing '{s}' from string table at offset 0x{x}", .{ bytes, offset }); return offset; } try self.strtab.ensureCapacity(self.allocator, self.strtab.items.len + bytes.len + 1); const offset = @intCast(u32, self.strtab.items.len); - log.debug("writing new string '{s}' into string table at offset 0x{x}", .{ bytes, offset }); + log.warn("writing new string '{s}' into string table at offset 0x{x}", .{ bytes, offset }); self.strtab.appendSliceAssumeCapacity(bytes); self.strtab.appendAssumeCapacity(0); try self.strtab_dir.putNoClobber(self.allocator, try self.allocator.dupe(u8, bytes), offset); From 1867c3c34c10312a742041e6525aea8abe32f48d Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 3 May 2021 16:56:46 +0200 Subject: [PATCH 40/47] zld: disable most logs --- src/link/MachO/Zld.zig | 113 +++++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 56 deletions(-) diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 2dd4223559..c6f85da3c1 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -267,7 +267,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { continue; } - log.warn("unexpected input file of unknown type '{s}'", .{file_name}); + log.debug("unexpected input file of unknown type '{s}'", .{file_name}); } // Based on our classification, proceed with parsing. @@ -325,7 +325,7 @@ fn mapAndUpdateSections( .target_sect_id = target_sect_id, .offset = @intCast(u32, offset), }); - log.warn("{s}: {s},{s} mapped to {s},{s} from 0x{x} to 0x{x}", .{ + log.debug("{s}: {s},{s} mapped to {s},{s} from 0x{x} to 0x{x}", .{ object.name, parseName(&source_sect.segname), parseName(&source_sect.sectname), @@ -555,7 +555,7 @@ fn updateMetadata(self: *Zld) !void { }); }, else => { - log.warn("unhandled section type 0x{x} for '{s}/{s}'", .{ flags, segname, sectname }); + log.debug("unhandled section type 0x{x} for '{s}/{s}'", .{ flags, segname, sectname }); }, } } @@ -580,7 +580,7 @@ fn updateMetadata(self: *Zld) !void { const segname = parseName(&source_sect.segname); const sectname = parseName(&source_sect.sectname); - log.warn("section '{s}/{s}' will be unmapped", .{ segname, sectname }); + log.debug("section '{s}/{s}' will be unmapped", .{ segname, sectname }); try self.unhandled_sections.putNoClobber(self.allocator, .{ .object_id = object_id, @@ -928,7 +928,7 @@ fn allocateSymbols(self: *Zld) !void { const target_addr = target_sect.addr + target_mapping.offset; const address = reg.address - source_sect.addr + target_addr; - log.warn("resolving symbol '{s}' at 0x{x}", .{ sym.name, address }); + log.debug("resolving symbol '{s}' at 0x{x}", .{ sym.name, address }); // TODO there might be a more generic way of doing this. var section: u8 = 0; @@ -1099,7 +1099,7 @@ fn writeLazySymbolPointer(self: *Zld, index: u32) !void { var buf: [@sizeOf(u64)]u8 = undefined; mem.writeIntLittle(u64, &buf, end); const off = la_symbol_ptr.offset + index * @sizeOf(u64); - log.warn("writing lazy symbol pointer entry 0x{x} at 0x{x}", .{ end, off }); + log.debug("writing lazy symbol pointer entry 0x{x} at 0x{x}", .{ end, off }); try self.file.?.pwriteAll(&buf, off); } @@ -1112,7 +1112,7 @@ fn writeStub(self: *Zld, index: u32) !void { const stub_off = stubs.offset + index * stubs.reserved2; const stub_addr = stubs.addr + index * stubs.reserved2; const la_ptr_addr = la_symbol_ptr.addr + index * @sizeOf(u64); - log.warn("writing stub at 0x{x}", .{stub_off}); + log.debug("writing stub at 0x{x}", .{stub_off}); var code = try self.allocator.alloc(u8, stubs.reserved2); defer self.allocator.free(code); switch (self.arch.?) { @@ -1216,7 +1216,7 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void { } fn resolveSymbolsInObject(self: *Zld, object: *Object) !void { - log.warn("resolving symbols in '{s}'", .{object.name}); + log.debug("resolving symbols in '{s}'", .{object.name}); for (object.symbols.items) |sym| { if (sym.cast(Symbol.Regular)) |reg| { @@ -1245,7 +1245,7 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void { }, .global => { if (reg.linkage == .global) { - log.warn("symbol '{s}' defined multiple times", .{reg.base.name}); + log.debug("symbol '{s}' defined multiple times", .{reg.base.name}); return error.MultipleSymbolDefinitions; } sym.alias = g_sym; @@ -1363,7 +1363,7 @@ fn resolveSymbols(self: *Zld) !void { fn resolveStubsAndGotEntries(self: *Zld) !void { for (self.objects.items) |object| { - log.warn("resolving stubs and got entries from {s}", .{object.name}); + log.debug("resolving stubs and got entries from {s}", .{object.name}); for (object.sections.items) |sect| { const relocs = sect.relocs orelse continue; @@ -1378,7 +1378,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { sym.got_index = index; try self.got_entries.append(self.allocator, sym); - log.warn(" | found GOT entry {s}: {*}", .{ sym.name, sym }); + log.debug(" | found GOT entry {s}: {*}", .{ sym.name, sym }); }, else => { if (rel.target != .symbol) continue; @@ -1387,15 +1387,16 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { assert(sym.@"type" != .unresolved); if (sym.stubs_index != null) continue; - if (sym.cast(Symbol.Regular)) |reg| { - if (!reg.weak_ref) continue; - } + if (sym.@"type" != .proxy) continue; + // if (sym.cast(Symbol.Regular)) |reg| { + // if (!reg.weak_ref) continue; + // } const index = @intCast(u32, self.stubs.items.len); sym.stubs_index = index; try self.stubs.append(self.allocator, sym); - log.warn(" | found stub {s}: {*}", .{ sym.name, sym }); + log.debug(" | found stub {s}: {*}", .{ sym.name, sym }); }, } } @@ -1408,12 +1409,12 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { sym.got_index = index; try self.got_entries.append(self.allocator, sym); - log.warn(" | found GOT entry {s}: {*}", .{ sym.name, sym }); + log.debug(" | found GOT entry {s}: {*}", .{ sym.name, sym }); } fn resolveRelocsAndWriteSections(self: *Zld) !void { for (self.objects.items) |object, object_id| { - log.warn("relocating object {s}", .{object.name}); + log.debug("relocating object {s}", .{object.name}); for (object.sections.items) |sect, source_sect_id| { if (sect.inner.flags == macho.S_MOD_INIT_FUNC_POINTERS or @@ -1422,14 +1423,14 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { const segname = parseName(§.inner.segname); const sectname = parseName(§.inner.sectname); - log.warn("relocating section '{s},{s}'", .{ segname, sectname }); + log.debug("relocating section '{s},{s}'", .{ segname, sectname }); // Get mapping const target_mapping = self.mappings.get(.{ .object_id = @intCast(u16, object_id), .source_sect_id = @intCast(u16, source_sect_id), }) orelse { - log.warn("no mapping for {s},{s}; skipping", .{ segname, sectname }); + log.debug("no mapping for {s},{s}; skipping", .{ segname, sectname }); continue; }; const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment; @@ -1518,7 +1519,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { } } - log.warn("writing contents of '{s},{s}' section from '{s}' from 0x{x} to 0x{x}", .{ + log.debug("writing contents of '{s},{s}' section from '{s}' from 0x{x} to 0x{x}", .{ segname, sectname, object.name, @@ -1530,7 +1531,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { target_sect.flags == macho.S_THREAD_LOCAL_ZEROFILL or target_sect.flags == macho.S_THREAD_LOCAL_VARIABLES) { - log.warn("zeroing out '{s},{s}' from 0x{x} to 0x{x}", .{ + log.debug("zeroing out '{s},{s}' from 0x{x} to 0x{x}", .{ parseName(&target_sect.segname), parseName(&target_sect.sectname), target_sect_off, @@ -1555,17 +1556,17 @@ fn relocTargetAddr(self: *Zld, object_id: u16, target: reloc.Relocation.Target) .symbol => |sym| { const final = sym.getTopmostAlias(); if (final.cast(Symbol.Regular)) |reg| { - log.warn(" | regular '{s}'", .{sym.name}); + 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.warn(" | symbol '__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; } - log.warn(" | symbol stub '{s}'", .{sym.name}); + 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; @@ -2103,7 +2104,7 @@ fn writeGotEntries(self: *Zld) !void { try writer.writeIntLittle(u64, address); } - log.warn("writing GOT pointers at 0x{x} to 0x{x}", .{ sect.offset, sect.offset + buffer.len }); + log.debug("writing GOT pointers at 0x{x} to 0x{x}", .{ sect.offset, sect.offset + buffer.len }); try self.file.?.pwriteAll(buffer, sect.offset); } @@ -2189,7 +2190,7 @@ fn writeRebaseInfoTable(self: *Zld) !void { dyld_info.rebase_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @sizeOf(u64))); seg.inner.filesize += dyld_info.rebase_size; - log.warn("writing rebase info from 0x{x} to 0x{x}", .{ dyld_info.rebase_off, dyld_info.rebase_off + dyld_info.rebase_size }); + log.debug("writing rebase info from 0x{x} to 0x{x}", .{ dyld_info.rebase_off, dyld_info.rebase_off + dyld_info.rebase_size }); try self.file.?.pwriteAll(buffer, dyld_info.rebase_off); } @@ -2248,7 +2249,7 @@ fn writeBindInfoTable(self: *Zld) !void { dyld_info.bind_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64))); seg.inner.filesize += dyld_info.bind_size; - log.warn("writing binding info from 0x{x} to 0x{x}", .{ dyld_info.bind_off, dyld_info.bind_off + dyld_info.bind_size }); + log.debug("writing binding info from 0x{x} to 0x{x}", .{ dyld_info.bind_off, dyld_info.bind_off + dyld_info.bind_size }); try self.file.?.pwriteAll(buffer, dyld_info.bind_off); } @@ -2290,7 +2291,7 @@ fn writeLazyBindInfoTable(self: *Zld) !void { dyld_info.lazy_bind_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64))); seg.inner.filesize += dyld_info.lazy_bind_size; - log.warn("writing lazy binding info from 0x{x} to 0x{x}", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size }); + log.debug("writing lazy binding info from 0x{x} to 0x{x}", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size }); try self.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off); try self.populateLazyBindOffsetsInStubHelper(buffer); @@ -2394,7 +2395,7 @@ fn writeExportInfo(self: *Zld) !void { dyld_info.export_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64))); seg.inner.filesize += dyld_info.export_size; - log.warn("writing export info from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size }); + log.debug("writing export info from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size }); try self.file.?.pwriteAll(buffer, dyld_info.export_off); } @@ -2511,7 +2512,7 @@ fn writeDebugInfo(self: *Zld) !void { const stabs_off = symtab.symoff; const stabs_size = symtab.nsyms * @sizeOf(macho.nlist_64); - log.warn("writing symbol stabs from 0x{x} to 0x{x}", .{ stabs_off, stabs_size + stabs_off }); + log.debug("writing symbol stabs from 0x{x} to 0x{x}", .{ stabs_off, stabs_size + stabs_off }); try self.file.?.pwriteAll(mem.sliceAsBytes(stabs.items), stabs_off); linkedit.inner.filesize += stabs_size; @@ -2582,17 +2583,17 @@ fn writeSymbolTable(self: *Zld) !void { const locals_off = symtab.symoff + symtab.nsyms * @sizeOf(macho.nlist_64); const locals_size = nlocals * @sizeOf(macho.nlist_64); - log.warn("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off }); + log.debug("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off }); try self.file.?.pwriteAll(mem.sliceAsBytes(locals.items), locals_off); const exports_off = locals_off + locals_size; const exports_size = nexports * @sizeOf(macho.nlist_64); - log.warn("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off }); + log.debug("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off }); try self.file.?.pwriteAll(mem.sliceAsBytes(exports.items), exports_off); const undefs_off = exports_off + exports_size; const undefs_size = nundefs * @sizeOf(macho.nlist_64); - log.warn("writing undefined symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off }); + log.debug("writing undefined symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off }); try self.file.?.pwriteAll(mem.sliceAsBytes(undefs.items), undefs_off); symtab.nsyms += @intCast(u32, nlocals + nexports + nundefs); @@ -2622,7 +2623,7 @@ fn writeSymbolTable(self: *Zld) !void { const needed_size = dysymtab.nindirectsyms * @sizeOf(u32); seg.inner.filesize += needed_size; - log.warn("writing indirect symbol table from 0x{x} to 0x{x}", .{ + log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{ dysymtab.indirectsymoff, dysymtab.indirectsymoff + needed_size, }); @@ -2665,7 +2666,7 @@ fn writeStringTable(self: *Zld) !void { symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64))); seg.inner.filesize += symtab.strsize; - log.warn("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize }); + log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize }); try self.file.?.pwriteAll(self.strtab.items, symtab.stroff); @@ -2711,7 +2712,7 @@ fn writeDataInCode(self: *Zld) !void { dice_cmd.datasize = datasize; seg.inner.filesize += datasize; - log.warn("writing data-in-code from 0x{x} to 0x{x}", .{ fileoff, fileoff + datasize }); + log.debug("writing data-in-code from 0x{x} to 0x{x}", .{ fileoff, fileoff + datasize }); try self.file.?.pwriteAll(buf.items, fileoff); } @@ -2732,7 +2733,7 @@ fn writeCodeSignaturePadding(self: *Zld) !void { seg.inner.filesize += needed_size; seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size.?); - log.warn("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size }); + log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size }); // Pad out the space. We need to do this to calculate valid hashes for everything in the file // except for code signature data. @@ -2758,7 +2759,7 @@ fn writeCodeSignature(self: *Zld) !void { var stream = std.io.fixedBufferStream(buffer); try code_sig.write(stream.writer()); - log.warn("writing code signature from 0x{x} to 0x{x}", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len }); + log.debug("writing code signature from 0x{x} to 0x{x}", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len }); try self.file.?.pwriteAll(buffer, code_sig_cmd.dataoff); } @@ -2776,7 +2777,7 @@ fn writeLoadCommands(self: *Zld) !void { } const off = @sizeOf(macho.mach_header_64); - log.warn("writing {} load commands from 0x{x} to 0x{x}", .{ self.load_commands.items.len, off, off + sizeofcmds }); + log.debug("writing {} load commands from 0x{x} to 0x{x}", .{ self.load_commands.items.len, off, off + sizeofcmds }); try self.file.?.pwriteAll(buffer, off); } @@ -2814,7 +2815,7 @@ fn writeHeader(self: *Zld) !void { for (self.load_commands.items) |cmd| { header.sizeofcmds += cmd.cmdsize(); } - log.warn("writing Mach-O header {}", .{header}); + log.debug("writing Mach-O header {}", .{header}); try self.file.?.pwriteAll(mem.asBytes(&header), 0); } @@ -2827,13 +2828,13 @@ pub fn makeStaticString(bytes: []const u8) [16]u8 { fn makeString(self: *Zld, bytes: []const u8) !u32 { if (self.strtab_dir.get(bytes)) |offset| { - log.warn("reusing '{s}' from string table at offset 0x{x}", .{ bytes, offset }); + log.debug("reusing '{s}' from string table at offset 0x{x}", .{ bytes, offset }); return offset; } try self.strtab.ensureCapacity(self.allocator, self.strtab.items.len + bytes.len + 1); const offset = @intCast(u32, self.strtab.items.len); - log.warn("writing new string '{s}' into string table at offset 0x{x}", .{ bytes, offset }); + log.debug("writing new string '{s}' into string table at offset 0x{x}", .{ bytes, offset }); self.strtab.appendSliceAssumeCapacity(bytes); self.strtab.appendAssumeCapacity(0); try self.strtab_dir.putNoClobber(self.allocator, try self.allocator.dupe(u8, bytes), offset); @@ -2851,31 +2852,31 @@ pub fn parseName(name: *const [16]u8) []const u8 { } fn printSymbols(self: *Zld) void { - log.warn("globals", .{}); + log.debug("globals", .{}); for (self.globals.items()) |entry| { const sym = entry.value.cast(Symbol.Regular) orelse unreachable; - log.warn(" | {s} @ {*}", .{ sym.base.name, entry.value }); - log.warn(" => alias of {*}", .{sym.base.alias}); - log.warn(" => linkage {s}", .{sym.linkage}); - log.warn(" => defined in {s}", .{sym.file.name.?}); + 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.warn("locals in {s}", .{object.name.?}); + log.debug("locals in {s}", .{object.name.?}); for (object.symbols.items) |sym| { - log.warn(" | {s} @ {*}", .{ sym.name, sym }); - log.warn(" => alias of {*}", .{sym.alias}); + log.debug(" | {s} @ {*}", .{ sym.name, sym }); + log.debug(" => alias of {*}", .{sym.alias}); if (sym.cast(Symbol.Regular)) |reg| { - log.warn(" => linkage {s}", .{reg.linkage}); + log.debug(" => linkage {s}", .{reg.linkage}); } else { - log.warn(" => unresolved", .{}); + log.debug(" => unresolved", .{}); } } } - log.warn("proxies", .{}); + log.debug("proxies", .{}); for (self.imports.items()) |entry| { const sym = entry.value.cast(Symbol.Proxy) orelse unreachable; - log.warn(" | {s} @ {*}", .{ sym.base.name, entry.value }); - log.warn(" => alias of {*}", .{sym.base.alias}); - log.warn(" => defined in libSystem.B.dylib", .{}); + log.debug(" | {s} @ {*}", .{ sym.base.name, entry.value }); + log.debug(" => alias of {*}", .{sym.base.alias}); + log.debug(" => defined in libSystem.B.dylib", .{}); } } From 96556ce8b885c9c56e24f26a65b6234eb8b102be Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 4 May 2021 10:59:33 +0200 Subject: [PATCH 41/47] zld: port over a few more bits from ld64 * UTF16 gets its own section, `__TEXT,__ustring` * TLV data and bss sections have to aligned to the same max alignment according to Apple rdar comment in the latest ld64 --- src/link/MachO/Zld.zig | 119 +++++++++++++++++++++++++++++++++-------- 1 file changed, 96 insertions(+), 23 deletions(-) diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index c6f85da3c1..1b343fad3f 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -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, @@ -200,7 +201,6 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { try self.populateMetadata(); try self.parseInputFiles(files); try self.resolveSymbols(); - // self.printSymbols(); try self.resolveStubsAndGotEntries(); try self.updateMetadata(); try self.sortSections(); @@ -209,8 +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.writeStubHelperCommon(); - try self.resolveRelocsAndWriteSections(); try self.flush(); } @@ -356,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; @@ -588,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. + // 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 { @@ -663,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 .{ @@ -712,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: { @@ -1991,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]; From 785a6c1aa9a7979a962db9d741a53897c423cb92 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 4 May 2021 10:26:01 -0700 Subject: [PATCH 42/47] std: remove dead and rotting C parsing code --- lib/std/c.zig | 2 - lib/std/c/ast.zig | 681 -------------------- lib/std/c/parse.zig | 1434 ------------------------------------------- 3 files changed, 2117 deletions(-) delete mode 100644 lib/std/c/ast.zig delete mode 100644 lib/std/c/parse.zig diff --git a/lib/std/c.zig b/lib/std/c.zig index 01247ffc00..f66376f812 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -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 { diff --git a/lib/std/c/ast.zig b/lib/std/c/ast.zig deleted file mode 100644 index 71455c0ea3..0000000000 --- a/lib/std/c/ast.zig +++ /dev/null @@ -1,681 +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, - op: Op, - rhs: *Expr, - - pub const Op = enum {}; - }; -}; diff --git a/lib/std/c/parse.zig b/lib/std/c/parse.zig deleted file mode 100644 index 29d4ba2fe1..0000000000 --- a/lib/std/c/parse.zig +++ /dev/null @@ -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| blk: { - if (e.name) |some| - if (!parser.tree.tokenEql(some, tok)) - break :blk; - return parser.err(.{ - .MustUseKwToRefer = .{ .kw = e.tok, .name = tok }, - }); - }, - .Record => |r| blk: { - if (r.name) |some| - if (!parser.tree.tokenEql(some, tok)) - break :blk; - 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, - }); - } -}; From c75ae8b66d57d9e7c195121e1d8d8ff5ca98e73d Mon Sep 17 00:00:00 2001 From: lithdew Date: Wed, 5 May 2021 16:09:08 +0900 Subject: [PATCH 43/47] x/net: fix tcp tests for openbsd and add missing `fmt` import On OpenBSD, connecting to a newly-allocated port on an unspecified IPv4 host address causes EINVAL. This was found by @mikdusan when running TCP tests on OpenBSD. This commit fixes TCP tests on OpenBSD by having all tests that allocate a new host-port pair to have the host IPv4/IPv6 address point to the host's loopback adapter (on localhost). --- lib/std/x/net/ip.zig | 2 ++ lib/std/x/net/tcp.zig | 12 ++++++++++-- lib/std/x/os/Socket.zig | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/std/x/net/ip.zig b/lib/std/x/net/ip.zig index 6d1632a50d..7f2d82d208 100644 --- a/lib/std/x/net/ip.zig +++ b/lib/std/x/net/ip.zig @@ -6,6 +6,8 @@ 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; diff --git a/lib/std/x/net/tcp.zig b/lib/std/x/net/tcp.zig index 8d6254fd0d..a4cc4a288c 100644 --- a/lib/std/x/net/tcp.zig +++ b/lib/std/x/net/tcp.zig @@ -282,7 +282,11 @@ test "tcp: create client/listener pair" { try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0)); try listener.listen(128); - const binded_address = try listener.getLocalAddress(); + 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(); @@ -302,7 +306,11 @@ test "tcp/client: set read timeout of 1 millisecond on blocking client" { try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0)); try listener.listen(128); - const binded_address = try listener.getLocalAddress(); + 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(); diff --git a/lib/std/x/os/Socket.zig b/lib/std/x/os/Socket.zig index bb984af97a..3656899aea 100644 --- a/lib/std/x/os/Socket.zig +++ b/lib/std/x/os/Socket.zig @@ -8,6 +8,7 @@ const std = @import("../../std.zig"); const net = @import("net.zig"); const os = std.os; +const fmt = std.fmt; const mem = std.mem; const time = std.time; From 70a9a3a562582173c140a064762b674e3c761a41 Mon Sep 17 00:00:00 2001 From: Jay Petacat Date: Wed, 5 May 2021 00:02:16 -0400 Subject: [PATCH 44/47] stage1: Fix other OS target PR #7827 added some new `std.Target.Os.Tag` before `other`. The corresponding enum in stage1.h was not updated, which caused a mismatch in the underlying integer values. While attempting to target `other`, I encountered crashes. This PR updates the stage1.h enum to include the added OS tags. The new tags also had to be added to various switch cases to fix compiler warnings, but have not been tested in any way. --- src/stage1/stage1.h | 5 ++++- src/stage1/target.cpp | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/stage1/stage1.h b/src/stage1/stage1.h index 59632b9877..6413914f6e 100644 --- a/src/stage1/stage1.h +++ b/src/stage1/stage1.h @@ -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, }; diff --git a/src/stage1/target.cpp b/src/stage1/target.cpp index 6aa3cfcbd0..5a1e18e152 100644 --- a/src/stage1/target.cpp +++ b/src/stage1/target.cpp @@ -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(); } From e863204c47eb89bfefd762739943f6b2f99f2c16 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 4 May 2021 19:29:25 +0200 Subject: [PATCH 45/47] zig fmt: Fix edge case in inline asm parsing The presence of a trailing comma in the single and only input/output declaration confused the parser and made zig fmt discard any element placed after the comma. --- lib/std/zig/ast.zig | 20 +++++++++++++------- lib/std/zig/parser_test.zig | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index a0e7754896..cab7749691 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -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; } } diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 2fa8baa185..fe119a5d27 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -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 { From 18b46485bcb6ad6b4be31c87659ffd78a311c904 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Wed, 5 May 2021 10:46:21 +0200 Subject: [PATCH 46/47] stage2: Fix UAF in ErrorMsg destructor After calling gpa.destroy the object is gone for good, setting the contents to undefined is a bug and may crash the compiler. --- src/Compilation.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 7ff7ef1374..58d6f41858 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -232,7 +232,6 @@ pub const CObject = struct { pub fn destroy(em: *ErrorMsg, gpa: *Allocator) void { gpa.free(em.msg); gpa.destroy(em); - em.* = undefined; } }; From 9d409233b2c62e1d24635165ac6b3b7686ffd5e4 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 23 Mar 2021 10:08:34 +0100 Subject: [PATCH 47/47] std: Implement hex float printing The results have been cross-checked with LLVM's APFloat implementation by randomly sampling the f32/f64 space, while the f16 one was completely checked given the small size. --- lib/std/fmt.zig | 159 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 491a1d0726..878969b88a 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -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( @@ -1900,6 +2011,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)});