Skip to content
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

chore: add elliptic curve #795

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions services/util/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ target_sources(services.util PRIVATE
EchoOnMessageCommunication.hpp
EchoOnSesame.cpp
EchoOnSesame.hpp
EllipticCurve.hpp
EllipticCurveDiffieHellman.cpp
EllipticCurveDiffieHellman.hpp
FlashAlign.cpp
FlashAlign.hpp
FlashMultipleAccess.cpp
Expand All @@ -44,6 +47,8 @@ target_sources(services.util PRIVATE
FlashRegion.hpp
GpioPinInverted.cpp
GpioPinInverted.hpp
KeyGenerator.cpp
KeyGenerator.hpp
I2cMultipleAccess.cpp
I2cMultipleAccess.hpp
LowPowerSerialCommunication.cpp
Expand All @@ -57,6 +62,8 @@ target_sources(services.util PRIVATE
MessageCommunicationWindowed.hpp
RepeatingButton.cpp
RepeatingButton.hpp
Secp256r1.cpp
Secp256r1.hpp
SerialCommunicationLoopback.cpp
SerialCommunicationLoopback.hpp
Sesame.hpp
Expand Down
55 changes: 55 additions & 0 deletions services/util/EllipticCurve.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#ifndef SERVICES_ELLIPTIC_CURVE_HPP
#define SERVICES_ELLIPTIC_CURVE_HPP

#include "infra/util/ByteRange.hpp"
#include "infra/util/Function.hpp"

namespace services
{
// Parameters of a curve E: y^2 = x^3 + ax + b over a finite field F_p
struct EllipticCurveParameters
{
public:
infra::ConstByteRange p; // Finite field modulus
infra::ConstByteRange a; // Curve parameter a
infra::ConstByteRange b; // Curve parameter b
infra::ConstByteRange gX; // x-coordinate of the base point G
infra::ConstByteRange gY; // y-coordinate of the base point G
infra::ConstByteRange n; // Order of the base point G
uint32_t h; // Cofactor of the base point G
};

struct EllipticCurveExtendedParameters
: EllipticCurveParameters
{
public:
infra::ConstByteRange absA; // Curve parameter |a|
bool isAPositive; // True if a > 0
infra::ConstByteRange montgomeryR2; // Montgomery parameter R^2 mod n
};

class EllipticCurveOperations
{
public:
enum class PointOnCurveResult : uint8_t
{
pointOnCurve,
pointNotOnCurve,
};

enum class ComparisonResult : uint8_t
{
aEqualsB,
aGreaterThanB,
aLessThanB
};

using MultiplicationResult = infra::Function<void(infra::ConstByteRange x, infra::ConstByteRange y)>;

virtual void ScalarMultiplication(const EllipticCurveExtendedParameters& curve, infra::ConstByteRange scalar, infra::ConstByteRange x, infra::ConstByteRange y, const MultiplicationResult& onDone) const = 0;
virtual void CheckPointOnCurve(const EllipticCurveExtendedParameters& curve, infra::ConstByteRange x, infra::ConstByteRange y, const infra::Function<void(PointOnCurveResult)>& onDone) const = 0;
virtual void Comparison(infra::ConstByteRange a, infra::ConstByteRange b, const infra::Function<void(ComparisonResult)>& onDone) const = 0;
};
}

#endif
87 changes: 87 additions & 0 deletions services/util/EllipticCurveDiffieHellman.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include "services/util/EllipticCurveDiffieHellman.hpp"

namespace services
{
EllipticCurveDiffieHellman::EllipticCurveDiffieHellman(EllipticCurveOperations& ecc)
: ecc(ecc)
, states(infra::InPlaceType<Idle>(), *this)
{}

void EllipticCurveDiffieHellman::CalculateSharedSecretKey(const EllipticCurveExtendedParameters& ellipticCurve, infra::ConstByteRange privateKey, infra::ConstByteRange peerPublicKey, infra::ByteRange sharedSecretKey, const infra::Function<void(bool)>& onDone)
{
really_assert(privateKey.size() * 2 == peerPublicKey.size() && privateKey.size() == sharedSecretKey.size());

this->privateKey = privateKey;
this->publicKeyX = infra::Head(peerPublicKey, peerPublicKey.size() / 2);
this->publicKeyY = infra::Tail(peerPublicKey, peerPublicKey.size() / 2);
this->sharedKey = sharedSecretKey;
this->onDone = onDone;

states.Emplace<CheckPublicKeyX>(*this, ellipticCurve);
}

EllipticCurveDiffieHellman::State::State(EllipticCurveDiffieHellman& ecdh, const EllipticCurveExtendedParameters* ellipticCurve)
: ecdh(ecdh)
, ellipticCurve(ellipticCurve)
{}

EllipticCurveDiffieHellman& EllipticCurveDiffieHellman::State::Ecdh() const
{
return ecdh;
}

const EllipticCurveExtendedParameters* EllipticCurveDiffieHellman::State::EllipticCurve() const
{
return ellipticCurve;
}

EllipticCurveDiffieHellman::Idle::Idle(EllipticCurveDiffieHellman& ecdh)
: State(ecdh, nullptr)
{}

EllipticCurveDiffieHellman::CheckPublicKeyX::CheckPublicKeyX(EllipticCurveDiffieHellman& ecdh, const EllipticCurveExtendedParameters& ellipticCurve)
: State(ecdh, &ellipticCurve)
{
ecdh.ecc.Comparison(ecdh.publicKeyX, ellipticCurve.p, [this](auto result)
{
if (result == EllipticCurveOperations::ComparisonResult::aLessThanB)
this->Ecdh().states.Emplace<CheckPublicKeyY>(this->Ecdh(), *this->EllipticCurve());
else
this->Ecdh().onDone(false);
});
}

EllipticCurveDiffieHellman::CheckPublicKeyY::CheckPublicKeyY(EllipticCurveDiffieHellman& ecdh, const EllipticCurveExtendedParameters& ellipticCurve)
: State(ecdh, &ellipticCurve)
{
ecdh.ecc.Comparison(ecdh.publicKeyY, ellipticCurve.p, [this](auto result)
{
if (result == EllipticCurveOperations::ComparisonResult::aLessThanB)
this->Ecdh().states.Emplace<CheckPublicKeyOnCurve>(this->Ecdh(), *this->EllipticCurve());
else
this->Ecdh().onDone(false);
});
}

EllipticCurveDiffieHellman::CheckPublicKeyOnCurve::CheckPublicKeyOnCurve(EllipticCurveDiffieHellman& ecdh, const EllipticCurveExtendedParameters& ellipticCurve)
: State(ecdh, &ellipticCurve)
{
ecdh.ecc.CheckPointOnCurve(ellipticCurve, ecdh.publicKeyX, ecdh.publicKeyY, [this](auto result)
{
if (result == EllipticCurveOperations::PointOnCurveResult::pointOnCurve)
this->Ecdh().states.Emplace<CalculateSharedKey>(this->Ecdh(), *this->EllipticCurve());
else
this->Ecdh().onDone(false);
});
}

EllipticCurveDiffieHellman::CalculateSharedKey::CalculateSharedKey(EllipticCurveDiffieHellman& ecdh, const EllipticCurveExtendedParameters& ellipticCurve)
: State(ecdh, &ellipticCurve)
{
ecdh.ecc.ScalarMultiplication(ellipticCurve, ecdh.privateKey, ecdh.publicKeyX, ecdh.publicKeyY, [this](auto x, auto)
{
infra::Copy(x, this->Ecdh().sharedKey);
this->Ecdh().onDone(true);
});
}
}
79 changes: 79 additions & 0 deletions services/util/EllipticCurveDiffieHellman.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#ifndef SERVICES_ELLIPTIC_CURVE_DIFFIE_HELLMAN_HPP
#define SERVICES_ELLIPTIC_CURVE_DIFFIE_HELLMAN_HPP

#include "infra/util/ByteRange.hpp"
#include "infra/util/PolymorphicVariant.hpp"
#include "services/util/EllipticCurve.hpp"

namespace services
{
class EllipticCurveDiffieHellman
{
public:
explicit EllipticCurveDiffieHellman(EllipticCurveOperations& ecc);

void CalculateSharedSecretKey(const EllipticCurveExtendedParameters& ellipticCurve, infra::ConstByteRange privateKey, infra::ConstByteRange peerPublicKey, infra::ByteRange sharedSecretKey, const infra::Function<void(bool)>& onDone);

private:
class State
{
public:
State(EllipticCurveDiffieHellman& ecdh, const EllipticCurveExtendedParameters* ellipticCurve);
virtual ~State() = default;

protected:
EllipticCurveDiffieHellman& Ecdh() const;
const EllipticCurveExtendedParameters* EllipticCurve() const;

private:
EllipticCurveDiffieHellman& ecdh;
const EllipticCurveExtendedParameters* ellipticCurve;
};

class Idle
: public State
{
public:
explicit Idle(EllipticCurveDiffieHellman& ecdh);
};

class CheckPublicKeyX
: public State
{
public:
CheckPublicKeyX(EllipticCurveDiffieHellman& ecdh, const EllipticCurveExtendedParameters& ellipticCurve);
};

class CheckPublicKeyY
: public State
{
public:
CheckPublicKeyY(EllipticCurveDiffieHellman& ecdh, const EllipticCurveExtendedParameters& ellipticCurve);
};

class CheckPublicKeyOnCurve
: public State
{
public:
CheckPublicKeyOnCurve(EllipticCurveDiffieHellman& ecdh, const EllipticCurveExtendedParameters& ellipticCurve);
};

class CalculateSharedKey
: public State
{
public:
CalculateSharedKey(EllipticCurveDiffieHellman& ecdh, const EllipticCurveExtendedParameters& ellipticCurve);
};

private:
EllipticCurveOperations& ecc;
infra::ConstByteRange privateKey;
infra::ConstByteRange publicKeyX;
infra::ConstByteRange publicKeyY;
infra::ByteRange sharedKey;
infra::Function<void(bool)> onDone;
infra::PolymorphicVariant<State, Idle, CheckPublicKeyX, CheckPublicKeyY, CheckPublicKeyOnCurve, CalculateSharedKey> states;
};
}

#endif
23 changes: 23 additions & 0 deletions services/util/KeyGenerator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "services/util/KeyGenerator.hpp"

namespace services
{
KeyGenerator::KeyGenerator(EllipticCurveOperations& ecc)
: ecc(ecc)
{}

void KeyGenerator::GeneratePublicKeyFromPrivateKey(const EllipticCurveExtendedParameters& ellipticCurve, infra::ConstByteRange privateKey, infra::ByteRange publicKey, const infra::Function<void()>& onDone)
{
really_assert(privateKey.size() * 2 == publicKey.size());

this->publicKey = publicKey;
this->onDone = onDone;

ecc.ScalarMultiplication(ellipticCurve, privateKey, infra::ConstByteRange(), infra::ConstByteRange(), [this](auto x, auto y)
{
infra::Copy(x, infra::Head(this->publicKey, this->publicKey.size() / 2));
infra::Copy(y, infra::Tail(this->publicKey, this->publicKey.size() / 2));
this->onDone();
});
}
}
23 changes: 23 additions & 0 deletions services/util/KeyGenerator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef SERVICES_KEY_GENERATOR_HPP
#define SERVICES_KEY_GENERATOR_HPP

#include "infra/util/ByteRange.hpp"
#include "services/util/EllipticCurve.hpp"

namespace services
{
class KeyGenerator
{
public:
explicit KeyGenerator(EllipticCurveOperations& ecc);

void GeneratePublicKeyFromPrivateKey(const EllipticCurveExtendedParameters& ellipticCurve, infra::ConstByteRange privateKey, infra::ByteRange publicKey, const infra::Function<void()>& onDone);

private:
EllipticCurveOperations& ecc;
infra::ByteRange publicKey;
infra::Function<void()> onDone;
};
}

#endif
Loading
Loading