/* $Id: t_dibigdDSA.cpp $ */
/*
* Copyright (C) 2026 David Ireland, D.I. Management Services Pty Limited
* <https://di-mgt.com.au/contact/> <https://di-mgt.com.au/bigdigits.html>
* SPDX-License-Identifier: MPL-2.0
*
* Last updated:
* $Date: 2026-05-05 02:02 $
* $Revision: 1.0.1 $
* $Author: dai $
*/
/* EXAMPLE OF THE DSA from APPENDIX 5 FIPS PUB 186-2
"DIGITAL SIGNATURE STANDARD (DSS)", 27 January 2000 */
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <iostream>
//#include <string>
#include <stdexcept>
#include <assert.h>
#include "dibigd.hpp"
using std::cout;
using std::endl;
using namespace dibigd;
void do_test() {
cout << "EXAMPLE OF THE DSA from APPENDIX 5 FIPS PUB 186-2 'DIGITAL SIGNATURE STANDARD'" << endl;
cout << "==============================================================================" << endl;
// Initialize parameters from hex (NB no spaces permitted)
BigDigit p("0x8df2a494492276aa3d25759bb06869cbeac0d83afb8d0cf7"
"cbb8324f0d7882e5d0762fc5b7210eafc2e9adac32ab7aac"
"49693dfbf83724c2ec0736ee31c80291");
BigDigit q("0xc773218c737ec8ee993b4f2ded30f48edace915f");
BigDigit g("0x626d027839ea0a13413163a55b4cb500299d5522956cefcb"
"3bff10f399ce2c2e71cb9de5fa24babf58e5b79521925c9c"
"c42e9f6f464b088cc572af53e6d78802");
BigDigit x("0x2070b3223dba372fde1c0ffc7b2e3b498b260614");
BigDigit k("0x358dad571462710f50e254cf1a376b2bdeaadfbf");
/* M = ASCII form of "abc" (See FIPS PUB 180-1, Appendix A)
(SHA-1)(M) = <pre-computed value> */
BigDigit hashm("0xa9993e364706816aba3e25717850c26c9cd0d89d");
p.printhex("p=");
//cout << "p is " << (p.isprime() ? "prime" : "NOT PRIME") << endl;
/* Compute public key y = g^x mod p */
BigDigit y = g.mod_exp(x, p);
y.printhex("public key, y=\n");
/* COMPUTATION BY SIGNER */
/* (p, q, g) are public, common values
x is signer's private key
k is a random integer 0 < k < q
Keep (x, k) secret
*/
cout << "Signing message 'abc' using private key x..." << endl;
/* Compute k' = k^-1 mod q */
BigDigit k1 = k.mod_inv(q);
k1.printhex("k^-1=");
/* Compute y = g^x mod p */
BigDigit r = g.mod_exp(k, p) % q;
r.printhex("r=");
/* Compute s = (k^-1(SHA-1(M) + xr)) mod q */
BigDigit s = k1.mod_mult(x.mod_mult(r, q) + hashm, q);
s.printhex("s=");
assert(r == from_str("0x8bac1ab66410435cb7181f95b16ab97c92b341c0"));
assert(s == from_str("0x41e2345f1f56df2458f426d155b4ba2db6dcd8c8"));
cout << "signature is (r,s)." << endl;
/* VERIFICATION BY RECEIVER */
/* (p, q, g) are public, common values
y is signer's public key
(r,s) = signature(M)
Receiver receives (M', r', s').
Receiver recomputes SHA-1(M') for received message M'
*/
cout << "Verifying signature using public key y..." << endl;
/* Check 0 < r' < q and 0 < s' < q */
assert(q > r);
assert(q > s);
/* Compute w = s^-1 mod q */
BigDigit w = s.mod_inv(q);
w.printhex("w=");
/* Compute u1 = ((SHA-1(M'))w) mod q */
BigDigit u1 = hashm.mod_mult(w, q);
u1.printhex("u1=");
/* Compute u2 = ((r')w) mod q */
BigDigit u2 = r.mod_mult(w, q);
u2.printhex("u2=");
/* Compute g^u1 mod p */
BigDigit gg = g.mod_exp(u1, p);
gg.printhex("g^u1 mod p=\n");
/* Compute y^u2 mod p */
BigDigit yy = y.mod_exp(u2, p);
yy.printhex("y^u2 mod p=\n");
/* Compute v = (((g^u1)(y^u2)) mod p) mod q */
BigDigit v = gg.mod_mult(yy, p) % q;
v.printhex("v=");
cout << "Signature is verified if v == r" << endl;
if (v == r) {
cout << "Signature verified OK." << endl;
}
else {
cout << "Signature verification FAILED!" << endl;
}
}
int main() {
/* MSVC memory leak checking stuff */
#if _MSC_VER >= 1100
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
#endif
/* Catch any exceptions */
try {
do_test();
}
catch (const std::exception& e) {
// Handle standard exceptions with a specific message
std::cerr << "Standard exception: " << e.what() << std::endl;
}
catch (...) {
std::cerr << "Caught unknown exception." << std::endl;
}
cout << endl << "ALL DONE." << endl << endl;
return 0;
}