Commit 5dc742f4 authored by Bernard van Gastel's avatar Bernard van Gastel
Browse files

Converted remaining tabs to spaces.

parent fc764dfd
......@@ -9,14 +9,14 @@
#include "sodium/crypto_hash_sha512.h"
#ifndef NDEBUG
#define EXPECT(e) ((e) ? (void)0 : CrashAssert(__func__, __FILE__, __LINE__, #e))
#define EXPECT_TEXT(e, text) ((e) ? (void)0 : CrashAssert(__func__, __FILE__, __LINE__, #e, text))
#define EXPECT(e) ((e) ? (void)0 : CrashAssert(__func__, __FILE__, __LINE__, #e))
#define EXPECT_TEXT(e, text) ((e) ? (void)0 : CrashAssert(__func__, __FILE__, __LINE__, #e, text))
#else
#define EXPECT(e) ((void)0)
#define EXPECT_TEXT(e, text) ((void)0)
#define EXPECT(e) ((void)0)
#define EXPECT_TEXT(e, text) ((void)0)
#endif
#define ENSURE(e) ((e) ? (void)0 : CrashAssert(__func__, __FILE__, __LINE__, #e))
#define ENSURE_TEXT(e, text) ((e) ? (void)0 : CrashAssert(__func__, __FILE__, __LINE__, #e, text))
#define ENSURE(e) ((e) ? (void)0 : CrashAssert(__func__, __FILE__, __LINE__, #e))
#define ENSURE_TEXT(e, text) ((e) ? (void)0 : CrashAssert(__func__, __FILE__, __LINE__, #e, text))
extern "C" [[noreturn]] void CrashAssert(const char* func, const char* file, int line, const char* condition, const char* explanation = nullptr);
namespace radboud {
......@@ -26,29 +26,29 @@ struct GroupElement;
struct Scalar {
static const constexpr size_t BYTES = 32;
uint8_t value[BYTES];
Scalar() {
memset(value, 0, sizeof(value));
}
Scalar(const Scalar& rhs) {
*this = rhs;
}
Scalar& operator=(const Scalar& rhs) {
memcpy(value, rhs.value, sizeof(value));
return *this;
}
std::string_view raw() const {
return {reinterpret_cast<const char*>(value), sizeof(value)};
}
GroupElement base() const;
Scalar invert() const ; // s * s^-1 = 1
Scalar complement() const ; // s + comp = 1 (mod L)
Scalar operator-() const; // negate
bool zero() const;
bool valid() const;
// returns a scalar != 0
static Scalar Random();
static Scalar FromHash(uint8_t (&value)[64]);
uint8_t value[BYTES];
Scalar() {
memset(value, 0, sizeof(value));
}
Scalar(const Scalar& rhs) {
*this = rhs;
}
Scalar& operator=(const Scalar& rhs) {
memcpy(value, rhs.value, sizeof(value));
return *this;
}
std::string_view raw() const {
return {reinterpret_cast<const char*>(value), sizeof(value)};
}
GroupElement base() const;
Scalar invert() const ; // s * s^-1 = 1
Scalar complement() const ; // s + comp = 1 (mod L)
Scalar operator-() const; // negate
bool zero() const;
bool valid() const;
// returns a scalar != 0
static Scalar Random();
static Scalar FromHash(uint8_t (&value)[64]);
};
bool operator==(const Scalar& lhs, const Scalar& rhs);
......@@ -56,24 +56,24 @@ bool operator!=(const Scalar& lhs, const Scalar& rhs);
struct GroupElement {
static const constexpr size_t BYTES = 32;
uint8_t value[BYTES];
GroupElement() {
memset(value, 0, sizeof(value));
}
GroupElement(const GroupElement& rhs) {
*this = rhs;
}
GroupElement& operator=(const GroupElement& rhs) {
memcpy(value, rhs.value, sizeof(value));
return *this;
}
uint8_t value[BYTES];
GroupElement() {
memset(value, 0, sizeof(value));
}
GroupElement(const GroupElement& rhs) {
*this = rhs;
}
GroupElement& operator=(const GroupElement& rhs) {
memcpy(value, rhs.value, sizeof(value));
return *this;
}
std::string_view raw() const {
return {reinterpret_cast<const char*>(value), sizeof(value)};
}
bool zero() const;
bool valid() const;
static GroupElement Random();
static GroupElement FromHash(uint8_t (&value)[64]);
return {reinterpret_cast<const char*>(value), sizeof(value)};
}
bool zero() const;
bool valid() const;
static GroupElement Random();
static GroupElement FromHash(uint8_t (&value)[64]);
};
bool operator==(const GroupElement& lhs, const GroupElement& rhs);
......@@ -106,22 +106,22 @@ inline void _SHA512Update(crypto_hash_sha512_state*) {
template <typename... Args>
void _SHA512Update(crypto_hash_sha512_state* cxt, std::string in, const Args& ... args) {
crypto_hash_sha512_update(cxt, reinterpret_cast<const unsigned char*>(in.data()), in.length());
_SHA512Update(cxt, args...);
crypto_hash_sha512_update(cxt, reinterpret_cast<const unsigned char*>(in.data()), in.length());
_SHA512Update(cxt, args...);
}
template <typename... Args>
void _SHA512Update(crypto_hash_sha512_state* cxt, std::string_view in, const Args& ... args) {
crypto_hash_sha512_update(cxt, reinterpret_cast<const unsigned char*>(in.data()), in.length());
_SHA512Update(cxt, args...);
crypto_hash_sha512_update(cxt, reinterpret_cast<const unsigned char*>(in.data()), in.length());
_SHA512Update(cxt, args...);
}
template <typename... Args>
void SHA512(HashSHA512& hash, const Args& ... args) {
crypto_hash_sha512_state context;
crypto_hash_sha512_init(&context);
_SHA512Update(&context, args...);
crypto_hash_sha512_final(&context, &hash[0]);
crypto_hash_sha512_state context;
crypto_hash_sha512_init(&context);
_SHA512Update(&context, args...);
crypto_hash_sha512_final(&context, &hash[0]);
// see http://www.daemonology.net/blog/2014-09-06-zeroing-buffers-is-insufficient.html and is slow
}
......@@ -129,15 +129,15 @@ void RandomBytes(void* ptr, std::size_t length);
template <size_t N>
void RandomBytes(char (&buffer)[N]) {
RandomBytes(buffer, N);
RandomBytes(buffer, N);
}
template <size_t N>
void RandomBytes(uint8_t (&buffer)[N]) {
RandomBytes(buffer, N);
RandomBytes(buffer, N);
}
template <typename T>
void RandomBytes(T & t, typename std::enable_if<std::is_integral<T>::value, void*>::type = nullptr) {
RandomBytes(&t, sizeof(T));
RandomBytes(&t, sizeof(T));
}
// KDF = Blake2b
......
......@@ -8,13 +8,13 @@ namespace radboud {
namespace pep {
struct ElGamal {
GroupElement B;
GroupElement C;
GroupElement Y;
ElGamal() { }
ElGamal(GroupElement _B, const GroupElement& _C, const GroupElement& _Y);
bool operator==(const ElGamal& rhs) const;
bool operator!=(const ElGamal& rhs) const;
GroupElement B;
GroupElement C;
GroupElement Y;
ElGamal() { }
ElGamal(GroupElement _B, const GroupElement& _C, const GroupElement& _Y);
bool operator==(const ElGamal& rhs) const;
bool operator!=(const ElGamal& rhs) const;
};
// encrypt message M using public key Y
......
......@@ -33,16 +33,16 @@ extern "C" {
#if defined(WIN32)
inline int strncasecmp(const char* s1, const char* s2, size_t n) {
return _strnicmp(s1, s2, n);
return _strnicmp(s1, s2, n);
}
inline int link(const char* oldPlace, const char *newPlace) {
if (CreateHardLinkA(newPlace, oldPlace, NULL))
return 0;
return -1;
if (CreateHardLinkA(newPlace, oldPlace, NULL))
return 0;
return -1;
}
inline void bzero(void* b, size_t len) {
memset(b, '\0', len);
memset(b, '\0', len);
}
#endif
......
......@@ -20,32 +20,32 @@ static_assert(crypto_core_ristretto255_BYTES == GroupElement::BYTES);
// documentation of libsodium primitives: https://libsodium.gitbook.io/doc/advanced/point-arithmetic/ristretto
GroupElement Scalar::base() const {
GroupElement r;
ENSURE(crypto_scalarmult_ristretto255_base(r.value, value) == 0);
return r;
GroupElement r;
ENSURE(crypto_scalarmult_ristretto255_base(r.value, value) == 0);
return r;
}
Scalar Scalar::invert() const {
Scalar r;
crypto_core_ristretto255_scalar_invert(r.value, value);
return r;
Scalar r;
crypto_core_ristretto255_scalar_invert(r.value, value);
return r;
};
Scalar Scalar::operator-() const {
Scalar r;
crypto_core_ristretto255_scalar_negate(r.value, value);
return r;
Scalar r;
crypto_core_ristretto255_scalar_negate(r.value, value);
return r;
}
Scalar Scalar::complement() const {
Scalar r;
crypto_core_ristretto255_scalar_complement(r.value, value);
return r;
Scalar r;
crypto_core_ristretto255_scalar_complement(r.value, value);
return r;
}
[[maybe_unused]] bool Scalar::zero() const {
return sodium_is_zero(value, sizeof(value));
}
bool Scalar::valid() const {
// sc25519_is_canonical() from ed25519_ref10.c
// sc25519_is_canonical() from ed25519_ref10.c
/* 2^252+27742317777372353535851937790883648493 */
/* 2^252+27742317777372353535851937790883648493 */
static const unsigned char L[32] = {
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7,
0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
......@@ -65,15 +65,15 @@ bool Scalar::valid() const {
}
Scalar Scalar::Random() {
Scalar r;
// does random bytes, and check if it is canonical and != zero
crypto_core_ristretto255_scalar_random(r.value);
return r;
Scalar r;
// does random bytes, and check if it is canonical and != zero
crypto_core_ristretto255_scalar_random(r.value);
return r;
}
Scalar Scalar::FromHash(uint8_t (&value)[64]) {
Scalar r;
crypto_core_ristretto255_scalar_reduce(r.value, value);
return r;
Scalar r;
crypto_core_ristretto255_scalar_reduce(r.value, value);
return r;
}
[[maybe_unused]] bool GroupElement::zero() const {
return sodium_is_zero(value, sizeof(value));
......@@ -82,76 +82,76 @@ bool GroupElement::valid() const {
return crypto_core_ristretto255_is_valid_point(value);
}
GroupElement GroupElement::FromHash(uint8_t (&value)[64]) {
GroupElement r;
crypto_core_ristretto255_from_hash(r.value, value);
return r;
GroupElement r;
crypto_core_ristretto255_from_hash(r.value, value);
return r;
}
GroupElement GroupElement::Random() {
GroupElement r;
// random bytes and calls *_from_hash(...)
crypto_core_ristretto255_random(r.value);
return r;
GroupElement r;
// random bytes and calls *_from_hash(...)
crypto_core_ristretto255_random(r.value);
return r;
}
namespace radboud {
namespace pep {
GroupElement operator+(const GroupElement& lhs, const GroupElement& rhs) {
GroupElement r;
crypto_core_ristretto255_add(r.value, lhs.value, rhs.value);
return r;
GroupElement r;
crypto_core_ristretto255_add(r.value, lhs.value, rhs.value);
return r;
}
GroupElement operator-(const GroupElement& lhs, const GroupElement& rhs) {
GroupElement r;
crypto_core_ristretto255_sub(r.value, lhs.value, rhs.value);
return r;
GroupElement r;
crypto_core_ristretto255_sub(r.value, lhs.value, rhs.value);
return r;
}
Scalar operator+(const Scalar& lhs, const Scalar& rhs) {
Scalar r;
crypto_core_ristretto255_scalar_add(r.value, lhs.value, rhs.value);
return r;
Scalar r;
crypto_core_ristretto255_scalar_add(r.value, lhs.value, rhs.value);
return r;
}
[[maybe_unused]] Scalar operator-(const Scalar& lhs, const Scalar& rhs) {
Scalar r;
crypto_core_ristretto255_scalar_sub(r.value, lhs.value, rhs.value);
return r;
Scalar r;
crypto_core_ristretto255_scalar_sub(r.value, lhs.value, rhs.value);
return r;
}
Scalar operator*(const Scalar& lhs, const Scalar& rhs) {
Scalar r;
crypto_core_ristretto255_scalar_mul(r.value, lhs.value, rhs.value);
return r;
Scalar r;
crypto_core_ristretto255_scalar_mul(r.value, lhs.value, rhs.value);
return r;
}
Scalar operator/(const Scalar& lhs, const Scalar& rhs) {
Scalar r = rhs.invert();
crypto_core_ristretto255_scalar_mul(r.value, lhs.value, r.value);
return r;
Scalar r = rhs.invert();
crypto_core_ristretto255_scalar_mul(r.value, lhs.value, r.value);
return r;
}
[[maybe_unused]] bool operator==(const Scalar& lhs, const Scalar& rhs) {
for (size_t i = 0; i < sizeof(lhs.value); ++i)
if (lhs.value[i] != rhs.value[i])
return false;
return true;
for (size_t i = 0; i < sizeof(lhs.value); ++i)
if (lhs.value[i] != rhs.value[i])
return false;
return true;
}
[[maybe_unused]] bool operator!=(const Scalar& lhs, const Scalar& rhs) {
return !operator==(lhs, rhs);
return !operator==(lhs, rhs);
}
GroupElement operator*(const Scalar& lhs, const GroupElement& rhs) {
GroupElement r;
ENSURE(0 == crypto_scalarmult_ristretto255(r.value, lhs.value, rhs.value));
return r;
GroupElement r;
ENSURE(0 == crypto_scalarmult_ristretto255(r.value, lhs.value, rhs.value));
return r;
}
GroupElement operator/(const GroupElement& lhs, const Scalar& rhs) {
GroupElement r;
ENSURE(0 == crypto_scalarmult_ristretto255(r.value, rhs.invert().value, lhs.value));
return r;
GroupElement r;
ENSURE(0 == crypto_scalarmult_ristretto255(r.value, rhs.invert().value, lhs.value));
return r;
}
bool operator==(const GroupElement& lhs, const GroupElement& rhs) {
for (size_t i = 0; i < sizeof(lhs.value); ++i)
if (lhs.value[i] != rhs.value[i])
return false;
return true;
for (size_t i = 0; i < sizeof(lhs.value); ++i)
if (lhs.value[i] != rhs.value[i])
return false;
return true;
}
bool operator!=(const GroupElement& lhs, const GroupElement& rhs) {
return !operator==(lhs, rhs);
return !operator==(lhs, rhs);
}
GroupElement operator*(const Scalar& lhs, const _G&) {
......@@ -166,11 +166,11 @@ static_assert(crypto_kdf_KEYBYTES == KDF_SEEDKEYBYTES);
static_assert(crypto_kdf_blake2b_CONTEXTBYTES == KDF_CONTEXTBYTES);
void KDFGenerateSeedKey(KDFSeedKey& seedKey) {
crypto_kdf_keygen(seedKey);
crypto_kdf_keygen(seedKey);
}
void KDF(unsigned char *output, size_t outputLength, uint64_t subkey_id, const KDFContext& context, const KDFSeedKey& seedKey) {
ENSURE(0 == crypto_kdf_derive_from_key(output, outputLength, subkey_id, context, seedKey));
ENSURE(0 == crypto_kdf_derive_from_key(output, outputLength, subkey_id, context, seedKey));
}
}
......
......@@ -17,37 +17,37 @@ bool radboud::pep::ElGamal::operator!=(const ElGamal& rhs) const {
// encrypt message M using public key Y
ElGamal radboud::pep::Encrypt(const GroupElement& M, const GroupElement& Y) {
auto r = Scalar::Random();
auto r = Scalar::Random();
EXPECT(!r.zero()); // Random() does never return a zero scalar
ENSURE(!Y.zero()); // we should not encrypt anything with an empty public key, as this will result in plain text send over the line
return {r * G, M + r*Y, Y};
return {r * G, M + r*Y, Y};
}
// decrypt encrypted ElGamal tuple with secret key y
GroupElement radboud::pep::Decrypt(const ElGamal& in, const Scalar& y) {
return in.C - y * in.B;
return in.C - y * in.B;
}
ElGamal RerandomizeY(const ElGamal& in, const Scalar& s) {
return {in.B - s*G, in.C, in.Y + s*G};
return {in.B - s*G, in.C, in.Y + s*G};
}
// randomize the encryption
ElGamal radboud::pep::Rerandomize(const ElGamal& in, const Scalar& s) {
return {s * G + in.B, s * in.Y + in.C, in.Y};
return {s * G + in.B, s * in.Y + in.C, in.Y};
}
// make it decryptable with another key k*y (with y the original private key)
ElGamal radboud::pep::Rekey(const ElGamal& in, const Scalar& k) {
return {in.B / k, in.C, k * in.Y};
return {in.B / k, in.C, k * in.Y};
}
// adjust the encrypted cypher text to be n*M (with M the original text being encrypted)
ElGamal radboud::pep::Reshuffle(const ElGamal& in, const Scalar& n) {
return {n * in.B, n * in.C, in.Y};
return {n * in.B, n * in.C, in.Y};
}
// combination of Rekey(k) and Reshuffle(n)
ElGamal radboud::pep::RKS(const ElGamal& in, const Scalar& k, const Scalar& n) {
return {(n / k) * in.B, n * in.C, k * in.Y};
return {(n / k) * in.B, n * in.C, k * in.Y};
}
......@@ -5,115 +5,115 @@
using namespace radboud::pep;
std::tuple<GroupElement,Proof> radboud::pep::CreateProof(const Scalar& a /*secret*/, const GroupElement& M /*public*/) {
Scalar r = Scalar::Random();
Scalar r = Scalar::Random();
GroupElement A = a * G;
GroupElement N = a * M;
GroupElement C1 = r * G;
GroupElement C2 = r * M;
GroupElement A = a * G;
GroupElement N = a * M;
GroupElement C1 = r * G;
GroupElement C2 = r * M;
HashSHA512 hash;
SHA512(hash,
A.raw(),
M.raw(),
N.raw(),
C1.raw(),
C2.raw());
Scalar e = Scalar::FromHash(hash);
Scalar s = a*e + r;
return {A, {N, C1, C2, s}};
HashSHA512 hash;
SHA512(hash,
A.raw(),
M.raw(),
N.raw(),
C1.raw(),
C2.raw());
Scalar e = Scalar::FromHash(hash);
Scalar s = a*e + r;
return {A, {N, C1, C2, s}};
}
[[nodiscard]] bool radboud::pep::VerifyProof(const GroupElement& A, const GroupElement& M, const GroupElement& N, const GroupElement& C1, const GroupElement& C2, const Scalar& s) {
if (!A.valid() || !M.valid() || !N.valid() || !C1.valid() || !C2.valid() || !s.valid())
return false;
HashSHA512 hash;
SHA512(hash,
A.raw(),
M.raw(),
N.raw(),
C1.raw(),
C2.raw());
Scalar e = Scalar::FromHash(hash);
if (!A.valid() || !M.valid() || !N.valid() || !C1.valid() || !C2.valid() || !s.valid())
return false;
HashSHA512 hash;
SHA512(hash,
A.raw(),
M.raw(),
N.raw(),
C1.raw(),
C2.raw());
Scalar e = Scalar::FromHash(hash);
return s * G == e*A + C1
&& s * M == e*N + C2;
return s * G == e*A + C1
&& s * M == e*N + C2;
}
[[nodiscard]] bool radboud::pep::VerifyProof(const GroupElement& A, const GroupElement& M, const Proof& p) {
return VerifyProof(A, M, p.N, p.C1, p.C2, p.s);
return VerifyProof(A, M, p.N, p.C1, p.C2, p.s);
}
Signature radboud::pep::Sign(const GroupElement& message, const Scalar& secretKey) {
auto p = CreateProof(secretKey, message);
return std::get<1>(p);
auto p = CreateProof(secretKey, message);
return std::get<1>(p);
}
[[nodiscard]] bool radboud::pep::Verify(const GroupElement& message, const Signature& p, const GroupElement& publicKey) {
return VerifyProof(publicKey, message, p.N, p.C1, p.C2, p.s);
return VerifyProof(publicKey, message, p.N, p.C1, p.C2, p.s);
}
ProvedRerandomize radboud::pep::ProveRerandomize(const ElGamal& in, const Scalar& s) {
// Rerandomize is normally {s * G + in.b, s*in.y + in.c, in.y};
return CreateProof(s, in.Y);
// Rerandomize is normally {s * G + in.b, s*in.y + in.c, in.y};
return CreateProof(s, in.Y);
}
[[nodiscard]] std::optional<ElGamal> radboud::pep::VerifyRerandomize(const GroupElement& B, const GroupElement& C, const GroupElement& Y, const GroupElement& S, const Proof& py) {
// slightly different than the others, as we reuse the structure of a standard proof to reconstruct the Rerandomize operation after sending
return B.valid() && C.valid() && VerifyProof(S, Y, py) ?
ElGamal{S + B, py.value() + C, Y} : std::optional<ElGamal>();
// slightly different than the others, as we reuse the structure of a standard proof to reconstruct the Rerandomize operation after sending
return B.valid() && C.valid() && VerifyProof(S, Y, py) ?
ElGamal{S + B, py.value() + C, Y} : std::optional<ElGamal>();
}
[[nodiscard]] std::optional<ElGamal> radboud::pep::VerifyRerandomize(const ElGamal& in, const ProvedRerandomize& p) {
return VerifyRerandomize(in.B, in.C, in.Y, std::get<0>(p), std::get<1>(p));
return VerifyRerandomize(in.B, in.C, in.Y, std::get<0>(p), std::get<1>(p));
}
// adjust the encrypted cypher text to be n*M (with M the original text being encrypted)
ProvedReshuffle radboud::pep::ProveReshuffle(const ElGamal& in, const Scalar& n) {
// Reshuffle is normally {n * in.b, n * in.c, in.y};
// NOTE: can be optimised a bit, by fusing the two CreateProofs (because same n is used)
// Reshuffle is normally {n * in.b, n * in.c, in.y};
// NOTE: can be optimised a bit, by fusing the two CreateProofs (because same n is used)
auto [AB, pb] = CreateProof(n, in.B);
auto [AC, pc] = CreateProof(n, in.C);
return {AB, pb, AC, pc};
return {AB, pb, AC, pc};
}
[[nodiscard]] std::optional<ElGamal> radboud::pep::VerifyReshuffle(const GroupElement& B, const GroupElement& C, const GroupElement& Y, const GroupElement& AB, const Proof& pb, const GroupElement& AC, const Proof& pc) {
return VerifyProof(AB, B, pb) && VerifyProof(AC, C, pc) && Y.valid() ?
ElGamal{pb.value(), pc.value(), Y} : std::optional<ElGamal>();
return VerifyProof(AB, B, pb) && VerifyProof(AC, C, pc) && Y.valid() ?
ElGamal{pb.value(), pc.value(), Y} : std::optional<ElGamal>();
}
[[nodiscard]] std::optional<ElGamal> radboud::pep::VerifyReshuffle(const ElGamal& in, const ProvedReshuffle& p) {
return VerifyReshuffle(in.B, in.C, in.Y, std::get<0>(p), std::get<1>(p), std::get<2>(p), std::get<3>(p));
return VerifyReshuffle(in.B, in.C, in.Y, std::get<0>(p), std::get<1>(p), std::get<2>(p), std::get<3>(p));
}
// adjust the encrypted cypher text to be n*M (with M the original text being encrypted)
ProvedRekey radboud::pep::ProveRekey(const ElGamal& in, const Scalar& k) {
// Rekey is normmaly {in.b/k, in.c, k*in.y};
auto [AB, pb] = CreateProof(k.invert(), in.B);
// Rekey is normmaly {in.b/k, in.c, k*in.y};
auto [AB, pb] = CreateProof(k.invert(), in.B);
auto [AY, py] = CreateProof(k, in.Y);
return {AB, pb, AY, py};
}
[[nodiscard]] std::optional<ElGamal> radboud::pep::VerifyRekey(const GroupElement& B, const GroupElement& C, const GroupElement& Y, const GroupElement& AB, const Proof& pb, const GroupElement& AY, const Proof& py) {