From 73b96ebacf2a23eb052b7d13848ffe7f28c9cc3b Mon Sep 17 00:00:00 2001 From: Mihai Preda Date: Fri, 25 Oct 2024 10:12:26 +0300 Subject: [PATCH] Add CERT from George Woltman --- src/Gpu.cpp | 68 +++++++++++++++++++++++++++++++++++++++++++++++- src/Gpu.h | 3 +++ src/Task.cpp | 20 ++++++++++++++ src/Task.h | 4 ++- src/Worktodo.cpp | 27 ++++++++++++++++++- 5 files changed, 119 insertions(+), 3 deletions(-) diff --git a/src/Gpu.cpp b/src/Gpu.cpp index 21688d16..81569ff1 100644 --- a/src/Gpu.cpp +++ b/src/Gpu.cpp @@ -1,4 +1,4 @@ -// Copyright Mihai Preda and George Woltman. +// Copyright (C) Mihai Preda and George Woltman. #include "Gpu.h" #include "Proof.h" @@ -15,6 +15,7 @@ #include "timeutil.h" #include "TrigBufCache.h" #include "fs.h" +#include "Sha3Hash.h" #include #include @@ -1616,6 +1617,71 @@ LLResult Gpu::isPrimeLL(const Task& task) { } } +array Gpu::isCERT(const Task& task) { + assert(E == task.exponent); + wantROE = 0; + + // Get CERT start value + char fname[32]; + sprintf(fname, "M%u.cert", E); + File fi = File::openReadThrow(fname); + +//We need to gracefully handle the CERT file missing. There is a window in primenet.py between worktodo.txt entry and starting value download. + + u32 nBytes = (E - 1) / 8 + 1; + Words B = fi.readBytesLE(nBytes); + + writeIn(bufData, std::move(B)); + + Timer elapsedTimer; + + elapsedTimer.reset(); + + u32 startK = 0; + + IterationTimer iterationTimer{startK}; + + u32 k = 0; + u32 kEnd = task.squarings; + bool leadIn = true; + + while (true) { + ++k; + bool doStop = (k >= kEnd); + + if (Signal::stopRequested()) { + doStop = true; + log("Stopping, please wait..\n"); + } + + bool doLog = (k % 100'000 == 0) || doStop; + bool leadOut = doLog || useLongCarry; + + squareCERT(bufData, leadIn, leadOut); + leadIn = leadOut; + + if (!doLog) { + if (k % args.flushStep == 0) { queue->finish(); } // Periodically flush the queue + continue; + } + + Words data = readData(); + assert(data.size() >= 2); + u64 res64 = (u64(data[1]) << 32) | data[0]; + + float secsPerIt = iterationTimer.reset(k); + log("%9u %016" PRIx64 " %4.0f\n", k, res64, secsPerIt * 1'000'000); + + if (k >= kEnd) { + fs::remove (fname); + return std::move(SHA3{}.update(data.data(), (E-1)/8+1)).finish(); + } + + if (doStop) { throw "stop requested"; } + } +} + + void Gpu::clear(bool isPRP) { if (isPRP) { Saver::clear(E); diff --git a/src/Gpu.h b/src/Gpu.h index cb796faf..d4041ce2 100644 --- a/src/Gpu.h +++ b/src/Gpu.h @@ -201,6 +201,7 @@ class Gpu { void writeIn(Buffer& buf, vector&& words); void square(Buffer& out, Buffer& in, bool leadIn, bool leadOut, bool doMul3 = false, bool doLL = false); + void squareCERT(Buffer& io, bool leadIn, bool leadOut) { square(io, io, leadIn, leadOut, false, false); } void squareLL(Buffer& io, bool leadIn, bool leadOut) { square(io, io, leadIn, leadOut, false, true); } void square(Buffer& io); @@ -252,6 +253,8 @@ class Gpu { PRPResult isPrimePRP(const Task& task); LLResult isPrimeLL(const Task& task); + array isCERT(const Task& task); + double timePRP(); tuple measureROE(bool quick); diff --git a/src/Task.cpp b/src/Task.cpp index 37ea63d1..6056c7e0 100644 --- a/src/Task.cpp +++ b/src/Task.cpp @@ -178,6 +178,22 @@ void Task::writeResultLL(const Args &args, bool isPrime, u64 res64, u32 fftSize) writeResult(exponent, "LL", isPrime ? "P" : "C", AID, args, fields); } +void Task::writeResultCERT(const Args &args, array hash, u32 squarings, u32 fftSize) const { + string hexhash = hex(hash[3]) + hex(hash[2]) + hex(hash[1]) + hex(hash[0]); + vector fields{json("worktype", "Cert"), + json("exponent", exponent), + json("sha3-hash", hexhash.c_str()), + json("squarings", squarings), + json("fft-length", fftSize), + json("shift-count", 0), + json("error-code", "00000000"), // I don't know the meaning of this + }; + fields += tailFields(AID, args); + string s = json(std::move(fields)); + log("%s\n", s.c_str()); + File::append(args.resultsFile, s + '\n'); +} + void Task::execute(GpuCommon shared, Queue *q, u32 instance) { if (kind == VERIFY) { exponent = proof::getInfo(verifyPath).exp; } @@ -214,6 +230,10 @@ void Task::execute(GpuCommon shared, Queue *q, u32 instance) { } else { gpu->clear(kind == PRP); } + } else if (kind == CERT) { + auto sha256 = gpu->isCERT(*this); + writeResultCERT(*shared.args, sha256, squarings, fft.size()); + Worktodo::deleteTask(*this, instance); } else { throw "Unexpected task kind " + to_string(kind); } diff --git a/src/Task.h b/src/Task.h index f43e16bc..914e364c 100644 --- a/src/Task.h +++ b/src/Task.h @@ -16,16 +16,18 @@ class TrigBufCache; class Task { public: - enum Kind {PRP, VERIFY, LL}; + enum Kind {PRP, VERIFY, LL, CERT}; Kind kind; u32 exponent; string AID; // Assignment ID string line; // the verbatim worktodo line, used in deleteTask(). + u32 squarings; // For CERTs string verifyPath; // For Verify void execute(GpuCommon shared, Queue* q, u32 instance); void writeResultPRP(const Args&, bool isPrime, u64 res64, const std::string& res2048, u32 fftSize, u32 nErrors, const fs::path& proofPath) const; void writeResultLL(const Args&, bool isPrime, u64 res64, u32 fftSize) const; + void writeResultCERT(const Args&, array hash, u32 squarings, u32 fftSize) const; }; diff --git a/src/Worktodo.cpp b/src/Worktodo.cpp index a6e68218..bba33809 100644 --- a/src/Worktodo.cpp +++ b/src/Worktodo.cpp @@ -25,6 +25,7 @@ bool isHex(const string& s) { // Examples: // PRP=FEEE9DCD59A0855711265C1165C4C693,1,2,124647911,-1,77,0 // DoubleCheck=E0F583710728343C61643028FBDBA0FB,70198703,75,1 +// Cert=B2EE67DC0A514753E488794C9DD6F6BD,1,2,82997591,-1,162105 std::optional parse(const std::string& line) { if (line.empty() || line[0] == '#') { return {}; } @@ -32,6 +33,7 @@ std::optional parse(const std::string& line) { bool isPRP = false; bool isLL = false; + bool isCERT = false; if (topParts.size() == 2) { string kind = topParts.front(); @@ -39,6 +41,8 @@ std::optional parse(const std::string& line) { isPRP = true; } else if (kind == "Test" || kind == "DoubleCheck") { isLL = true; + } else if (kind == "Cert") { + isCERT = true; } } @@ -61,7 +65,28 @@ std::optional parse(const std::string& line) { u64 exp{}; auto [ptr, _] = from_chars(s.c_str(), end, exp, 10); if (ptr != end) { exp = 0; } - if (exp > 1000) { return {{isPRP ? Task::PRP : Task::LL, u32(exp), AID, line}}; } + if (exp > 1000) { return {{isPRP ? Task::PRP : Task::LL, u32(exp), AID, line, 0}}; } + } + if (isCERT) { + vector parts = split(topParts.back(), ','); + if (!parts.empty() && parts.front().size() == 32 && isHex(parts.front())) { + string AID; + AID = parts.front(); + parts.erase(parts.begin()); + + if (parts.size() == 5 && parts[0] == "1" && parts[1] == "2" && parts[3] == "-1") { + string s = parts[2]; + const char *end = s.c_str() + s.size(); + u64 exp{0}; + from_chars(s.c_str(), end, exp, 10); + s = parts[4]; + end = s.c_str() + s.size(); + u64 squarings{0}; + from_chars(s.c_str(), end, squarings, 10); +//printf ("Exec cert %d %d \n", (int) exp, (int) squarings); + if (exp > 1000 && squarings > 100) { return {{Task::CERT, u32(exp), AID, line, u32(squarings) }}; } + } + } } log("worktodo.txt line ignored: \"%s\"\n", rstripNewline(line).c_str()); return {};