Skip to content

Version 0.6.2: ECDSA/ ECDH interface and Workflow enhancements #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Nov 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: CI Test Workflow

on:
push:
branches:
- main
- release/*
pull_request:
branches:
- main
- release/*

jobs:
build-and-test:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Install dependencies
run: sudo apt-get install -y cmake g++ libgmp-dev

- name: Set up Google Test
run: |
mkdir -p build
cd build
cmake -DGESTALT_BUILD_TESTS=ON -DGESTALT_FETCH_GOOGLETEST=ON ..
make

- name: Run Tests
run: |
cd build
ctest --output-on-failure
7 changes: 3 additions & 4 deletions AUTHORS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Gestalt was designed and developed by Hunter RIchardson.
Gestalt was designed and developed by Hunter Richardson.

### Current Maintainers

Expand All @@ -10,7 +10,6 @@ Gestalt was designed and developed by Hunter RIchardson.

## Thanks

Special thanks to the following extraordinary individuals, without whom
Gestalt would not be possible:
Special thanks to the following extraordinary individuals, without whom Gestalt would not be possible:

*
* Morteza Mirzaei | mirzaim
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,18 +135,19 @@ int main() {

```cpp
#include <gestalt/ecdsa.h>
#include <gestalt/sha2.h>
#include <iostream>

int main() {
std::string privateKey = "0xC9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721";
ECDSA ecdsa(StandardCurve::P256, privateKey);

std::string message = "Hello, Gestalt!";
std::string messageHash = hashSHA256(message);

Signature signature = ecdsa.signMessage(messageHash);
bool signatureStatus = ecdsa.verifySignature(messageHash, signature);
Signature signature = ecdsa.signMessage(message, HashAlgorithm::SHA256);

ECDSAPublicKey peerPublicKey("0x60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
"0x7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299");
bool signatureStatus = ecdsa.verifySignature(message, peerPublicKey, signature, HashAlgorithm::SHA256);

if (signatureStatus) std::cout << "Valid!" << std::endl;

Expand Down
9 changes: 2 additions & 7 deletions include/gestalt/ecdh.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@

class ECDH : public ECC {
private:

Point peerPublicKey;

std::string keyToString(const Point& point) const;

friend class ECDH_Test;
Expand All @@ -44,8 +41,6 @@ class ECDH : public ECC {

~ECDH() {}

Point givePublicKey() const;
void getPublicKey(const Point& givenPublicKey);
std::string computeSharedSecret();
std::string computeSharedSecret(const Point& peerPublicKey);
ECDHPublicKey getPublicKey() const { return keyPair.getPublicKey(); };
std::string computeSharedSecret(const ECDHPublicKey& peerPublicKey);
};
21 changes: 17 additions & 4 deletions include/gestalt/ecdsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,26 @@

#pragma once

#include <functional>
#include "../src/ecc/ecc.h"

enum class HashAlgorithm {
None, // No hash function
SHA1,
SHA224,
SHA256,
SHA384,
SHA512
};

class ECDSA : public ECC {
private:

void prepareMessage(const std::string& messageHash, mpz_t& result);
bool isInvalidSignature(Signature S);

Signature generateSignature(const mpz_t& e, mpz_t& k);
std::function<std::string(const std::string&)> getHashFunction(HashAlgorithm hashAlg);

friend class ECDSA_Test;
public:
Expand All @@ -47,7 +58,9 @@ class ECDSA : public ECC {

~ECDSA() {}

Signature signMessage(const std::string& messageHash);
Signature signMessage(const std::string& messageHash, BigInt& K);
bool verifySignature(const std::string& messageHash, const Signature signature);
};
ECDSAPublicKey getPublicKey() const { return keyPair.publicKey; };

Signature signMessage(const std::string& message, HashAlgorithm hashAlg = HashAlgorithm::None);
Signature signMessage(const std::string& message, BigInt& K, HashAlgorithm hashAlg = HashAlgorithm::None);
bool verifySignature(const std::string& message, const ECDSAPublicKey& peerPublicKey, const Signature& signature, HashAlgorithm hashAlg = HashAlgorithm::None);
};
1 change: 1 addition & 0 deletions src/aes/aes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
*/

#include <string>
#include <cstring>
#include <iostream>

#include <gestalt/aes.h>
Expand Down
1 change: 1 addition & 0 deletions src/aes/aesCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
*/

#include <sstream>
#include <cstring>

#include "aesCore.h"
#include "aesConstants.h"
Expand Down
12 changes: 6 additions & 6 deletions src/ecc/ecc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,12 @@ bool ECC::isPointOnCurve(Point P) {
return (isInDomainRange(P.x)) && (isInDomainRange(P.y));
}

std::string ECC::isValidPublicKey(const Point P) {
if (!isPointOnCurve(P)) return "Error: Given Public Key is not on the curve.";
if (isIdentityPoint(P)) return "Error: Given Public Key is the Identity element.";
std::string ECC::isValidPublicKey(const ECDSAPublicKey P) {
if (!isPointOnCurve(P.getPublicKey())) return "Error: Given Public Key is not on the curve.";
if (isIdentityPoint(P.getPublicKey())) return "Error: Given Public Key is the Identity element.";

// Check n*P = identity
Point result = scalarMultiplyPoints(ellipticCurve.n, P);
Point result = scalarMultiplyPoints(ellipticCurve.n, P.getPublicKey());
if (!isIdentityPoint(result)) {
return "Error: Given Public key multiplied by curve modulus is not Identity Element.";
}
Expand All @@ -202,7 +202,7 @@ std::string ECC::isValidKeyPair(const KeyPair& K) {

// Check d*G = pubKey
Point result = scalarMultiplyPoints(K.privateKey, ellipticCurve.generator);
if (mpz_cmp(result.x, K.publicKey.x) != 0 || mpz_cmp(result.y, K.publicKey.y) != 0) {
if (mpz_cmp(result.x, K.publicKey.getPublicKey().x) != 0 || mpz_cmp(result.y, K.publicKey.getPublicKey().y) != 0) {
return "Error: Pair-wise consistency check failed.";
}

Expand Down Expand Up @@ -246,7 +246,7 @@ void ECC::setKeyPair(const std::string& givenKey) {
stringToGMP(givenKey, n);

KeyPair result(n, scalarMultiplyPoints(n, ellipticCurve.generator));
if(isIdentityPoint(result.publicKey)) throw
if(isIdentityPoint(result.publicKey.getPublicKey())) throw
std::invalid_argument("Error: Given Private Key derives identity public key.");

mpz_clear(n);
Expand Down
12 changes: 8 additions & 4 deletions src/ecc/ecc.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
#pragma once

#include "eccObjects.h"
#include "standardCurves.h"

class ECC {
private:
Expand All @@ -41,22 +40,27 @@ class ECC {
bool isInDomainRange(const mpz_t k);
bool isIdentityPoint(Point P);
bool isPointOnCurve(Point P);
std::string isValidPublicKey(const Point P);
std::string isValidPublicKey(const ECDSAPublicKey P);
std::string isValidKeyPair(const KeyPair& K);

friend class ECDSA;
friend class ECDH;
friend class ECC_Test;
public:

ECC(StandardCurve curve = StandardCurve::secp256k1) : ellipticCurve(getCurveParams(curve)) {}
ECC(StandardCurve curve = StandardCurve::secp256k1) : ellipticCurve(getCurveParams(curve)) {
keyPair.publicKey.setCurve(curve);
}

~ECC() {}

KeyPair generateKeyPair();

void setKeyPair(const KeyPair& newKeyPair);
void setKeyPair(const std::string& strKey);
void setCurve(StandardCurve curveType) { ellipticCurve = getCurveParams(curveType); }
void setCurve(StandardCurve curveType) {
ellipticCurve = getCurveParams(curveType);
keyPair.publicKey.setCurve(curveType);
}
KeyPair getKeyPair() const { return keyPair; }
};
64 changes: 61 additions & 3 deletions src/ecc/eccObjects.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*/
#pragma once

//#include "standardCurves.h"

#include <string>
#include <gmp.h>

Expand Down Expand Up @@ -94,19 +96,73 @@ class Point {
Point setPoint(const std::string& strX, const std::string& strY) { return Point(strX, strY); };
};

#include "standardCurves.h"

class PublicKey {
private:
Point point;
StandardCurve curve;

StandardCurve guessCurve(const Point& point) {
size_t sizeInBytes = (mpz_sizeinbase(point.x, 2) + 7) / 8;
if (sizeInBytes == 32) {
return StandardCurve::P256;
} else if (sizeInBytes == 48) {
return StandardCurve::P384;
} else if (sizeInBytes == 66) {
return StandardCurve::P521;
} else {
return StandardCurve::secp256k1;
}
}

public:
// Constructors
PublicKey() : curve(StandardCurve::P256) {}
PublicKey(const std::string& strX, const std::string& strY) : point(Point(strX, strY)) {
curve = guessCurve(point);
}
PublicKey(const Point& publicKey) : point(publicKey) {
curve = guessCurve(publicKey);
}
PublicKey(const Point& publicKey, const StandardCurve& curve) : point(publicKey), curve(curve) {}

// Accessors
Point getPublicKey() const { return point; }
StandardCurve getPublicKeyCurve() const { return curve; }

void setCurve(const StandardCurve& givenCurve) { curve = givenCurve; }
};

class ECDSAPublicKey : public PublicKey{
public:
ECDSAPublicKey() : PublicKey() {}
ECDSAPublicKey(const std::string& strX, const std::string& strY) : PublicKey(strX, strY) {}
ECDSAPublicKey(const Point& point) : PublicKey(point) {}
ECDSAPublicKey(const Point& point, const StandardCurve& curve) : PublicKey(point, curve) {}
};

class ECDHPublicKey : public PublicKey{
public:
ECDHPublicKey() : PublicKey() {}
ECDHPublicKey(const std::string& strX, const std::string& strY) : PublicKey(strX, strY) {}
ECDHPublicKey(const Point& point) : PublicKey(point) {}
ECDHPublicKey(const Point& point, const StandardCurve& curve) : PublicKey(point, curve) {}
};

class KeyPair {
public:
mpz_t privateKey;
Point publicKey;
ECDSAPublicKey publicKey;

KeyPair() { mpz_init(privateKey); }
KeyPair(const mpz_t& gmpPriv, const Point& strPub) {
KeyPair(const mpz_t& gmpPriv, const ECDSAPublicKey& strPub) {
mpz_init(privateKey);
mpz_set(privateKey, gmpPriv);
publicKey = strPub;
}

KeyPair(const std::string& strPriv, const Point& strPub) {
KeyPair(const std::string& strPriv, const ECDSAPublicKey& strPub) {
mpz_init(privateKey);
stringToGMP(strPriv, privateKey);
publicKey = strPub;
Expand All @@ -123,6 +179,8 @@ class KeyPair {
}

~KeyPair() { mpz_clear(privateKey); }

Point getPublicKey() const { return publicKey.getPublicKey(); };
};

class Signature {
Expand Down
25 changes: 3 additions & 22 deletions src/ecc/ecdh/ecdh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,13 @@

#include <gestalt/ecdh.h>

Point ECDH::givePublicKey() const {
return keyPair.publicKey;
}

void ECDH::getPublicKey(const Point& givenPublicKey) {
std::string validationError = isValidPublicKey(givenPublicKey);
if (!validationError.empty()) {
throw std::invalid_argument(validationError);
}
peerPublicKey = givenPublicKey;
}

std::string ECDH::computeSharedSecret() {
Point sharedPoint = scalarMultiplyPoints(keyPair.privateKey, peerPublicKey);
if(isIdentityPoint(sharedPoint)) throw std::invalid_argument("Error: Computed shared value is Identity element.");
fieldElementToInteger(sharedPoint.x, sharedPoint.x);
return keyToString(sharedPoint);
}

std::string ECDH::computeSharedSecret(const Point& givenPeerPublicKey) {
std::string validationError = isValidPublicKey(givenPeerPublicKey);
std::string ECDH::computeSharedSecret(const ECDHPublicKey& givenPeerPublicKey) {
std::string validationError = isValidPublicKey(givenPeerPublicKey.getPublicKey());
if (!validationError.empty()) {
throw std::invalid_argument(validationError);
}

Point sharedPoint = scalarMultiplyPoints(keyPair.privateKey, givenPeerPublicKey);
Point sharedPoint = scalarMultiplyPoints(keyPair.privateKey, givenPeerPublicKey.getPublicKey());
if(isIdentityPoint(sharedPoint)) throw std::invalid_argument("Error: Computed shared value is Identity element.");
fieldElementToInteger(sharedPoint.x, sharedPoint.x);
return keyToString(sharedPoint);
Expand Down
Loading
Loading