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

Hash x #1097

Closed
wants to merge 12 commits into from
3 changes: 2 additions & 1 deletion src/crypto/KeyUtils.cpp
Expand Up @@ -17,7 +17,8 @@ KeyUtils::getKeyVersionSize(strKey::StrKeyVersionByte keyVersion)
case strKey::STRKEY_PUBKEY_ED25519:
case strKey::STRKEY_SEED_ED25519:
return crypto_sign_PUBLICKEYBYTES;
case strKey::STRKEY_PUBKEY_HASH_TX:
case strKey::STRKEY_HASH_TX:
case strKey::STRKEY_HASH_X:
return 32U;
default:
throw std::invalid_argument("invalid key version: " + std::to_string(keyVersion));
Expand Down
16 changes: 13 additions & 3 deletions src/crypto/SignerKey.cpp
Expand Up @@ -25,7 +25,9 @@ KeyFunctions<SignerKey>::getKeyVersionIsSupported(strKey::StrKeyVersionByte keyV
{
case strKey::STRKEY_PUBKEY_ED25519:
return true;
case strKey::STRKEY_PUBKEY_HASH_TX:
case strKey::STRKEY_HASH_TX:
return true;
case strKey::STRKEY_HASH_X:
return true;
default:
return false;
Expand All @@ -39,8 +41,10 @@ KeyFunctions<SignerKey>::toKeyType(strKey::StrKeyVersionByte keyVersion)
{
case strKey::STRKEY_PUBKEY_ED25519:
return SignerKeyType::SIGNER_KEY_TYPE_ED25519;
case strKey::STRKEY_PUBKEY_HASH_TX:
case strKey::STRKEY_HASH_TX:
return SignerKeyType::SIGNER_KEY_TYPE_HASH_TX;
case strKey::STRKEY_HASH_X:
return SignerKeyType::SIGNER_KEY_TYPE_HASH_X;
default:
throw std::invalid_argument("invalid signer key type");
}
Expand All @@ -54,7 +58,9 @@ KeyFunctions<SignerKey>::toKeyVersion(SignerKeyType keyType)
case SignerKeyType::SIGNER_KEY_TYPE_ED25519:
return strKey::STRKEY_PUBKEY_ED25519;
case SignerKeyType::SIGNER_KEY_TYPE_HASH_TX:
return strKey::STRKEY_PUBKEY_HASH_TX;
return strKey::STRKEY_HASH_TX;
case SignerKeyType::SIGNER_KEY_TYPE_HASH_X:
return strKey::STRKEY_HASH_X;
default:
throw std::invalid_argument("invalid signer key type");
}
Expand All @@ -69,6 +75,8 @@ KeyFunctions<SignerKey>::getKeyValue(SignerKey &key)
return key.ed25519();
case SIGNER_KEY_TYPE_HASH_TX:
return key.hashTx();
case SIGNER_KEY_TYPE_HASH_X:
return key.hashX();
default:
throw std::invalid_argument("invalid signer key type");
}
Expand All @@ -83,6 +91,8 @@ KeyFunctions<SignerKey>::getKeyValue(SignerKey const &key)
return key.ed25519();
case SIGNER_KEY_TYPE_HASH_TX:
return key.hashTx();
case SIGNER_KEY_TYPE_HASH_X:
return key.hashX();
default:
throw std::invalid_argument("invalid signer key type");
}
Expand Down
3 changes: 2 additions & 1 deletion src/crypto/StrKey.h
Expand Up @@ -17,7 +17,8 @@ typedef enum
// version bytes - 5 bits only
STRKEY_PUBKEY_ED25519 = 6, // 'G'
STRKEY_SEED_ED25519 = 18, // 'S'
STRKEY_PUBKEY_HASH_TX = 19 // 'T'
STRKEY_HASH_TX = 19, // 'T',
STRKEY_HASH_X = 23 // 'X'
} StrKeyVersionByte;

// Encode a version byte and ByteSlice into StrKey
Expand Down
13 changes: 6 additions & 7 deletions src/transactions/OperationFrame.cpp
Expand Up @@ -76,10 +76,10 @@ OperationFrame::OperationFrame(Operation const& op, OperationResult& res,
}

bool
OperationFrame::apply(LedgerDelta& delta, Application& app)
OperationFrame::apply(SignatureChecker& signatureChecker, LedgerDelta& delta, Application& app)
{
bool res;
res = checkValid(app, &delta);
res = checkValid(signatureChecker, app, &delta);
if (res)
{
res = doApply(app, delta, app.getLedgerManager());
Expand All @@ -95,9 +95,9 @@ OperationFrame::getNeededThreshold() const
}

bool
OperationFrame::checkSignature() const
OperationFrame::checkSignature(SignatureChecker& signatureChecker) const
{
return mParentTx.checkSignature(*mSourceAccount, getNeededThreshold());
return mParentTx.checkSignature(signatureChecker, *mSourceAccount, getNeededThreshold());
}

AccountID const&
Expand Down Expand Up @@ -125,9 +125,8 @@ OperationFrame::getResultCode() const
// make sure sig is correct
// verifies that the operation is well formed (operation specific)
bool
OperationFrame::checkValid(Application& app, LedgerDelta* delta)
OperationFrame::checkValid(SignatureChecker& signatureChecker, Application& app, LedgerDelta* delta)
{

bool forApply = (delta != nullptr);
if (!loadAccount(delta, app.getDatabase()))
{
Expand All @@ -146,7 +145,7 @@ OperationFrame::checkValid(Application& app, LedgerDelta* delta)
}
}

if (!checkSignature())
if (!checkSignature(signatureChecker))
{
app.getMetrics()
.NewMeter({"operation", "invalid", "bad-auth"}, "operation")
Expand Down
7 changes: 4 additions & 3 deletions src/transactions/OperationFrame.h
Expand Up @@ -21,6 +21,7 @@ class Application;
class LedgerManager;
class LedgerDelta;

class SignatureChecker;
class TransactionFrame;

class OperationFrame
Expand All @@ -31,7 +32,7 @@ class OperationFrame
AccountFrame::pointer mSourceAccount;
OperationResult& mResult;

bool checkSignature() const;
bool checkSignature(SignatureChecker& signatureChecker) const;

virtual bool doCheckValid(Application& app) = 0;
virtual bool doApply(Application& app, LedgerDelta& delta,
Expand Down Expand Up @@ -75,9 +76,9 @@ class OperationFrame
}
OperationResultCode getResultCode() const;

bool checkValid(Application& app, LedgerDelta* delta = nullptr);
bool checkValid(SignatureChecker& signatureChecker, Application& app, LedgerDelta* delta = nullptr);

bool apply(LedgerDelta& delta, Application& app);
bool apply(SignatureChecker& signatureChecker, LedgerDelta& delta, Application& app);

Operation const&
getOperation() const
Expand Down
115 changes: 115 additions & 0 deletions src/transactions/SignatureChecker.cpp
@@ -0,0 +1,115 @@
// Copyright 2016 Stellar Development Foundation and contributors. Licensed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's talk about this.

// under the Apache License, Version 2.0. See the COPYING file at the root
// of this distribution or at http://www.apache.org/licenses/LICENSE-2.0

#include "SignatureChecker.h"

#include "crypto/KeyUtils.h"
#include "crypto/SecretKey.h"
#include "crypto/SHA.h"
#include "crypto/SignerKey.h"
#include "util/Algoritm.h"

namespace stellar
{

using xdr::operator < ;
using xdr::operator == ;

SignatureChecker::SignatureChecker(Hash const &contentsHash, xdr::xvector<DecoratedSignature,20> const &signatures) :
mContentsHash(contentsHash),
mSignatures(signatures)
{
mUsedSignatures.resize(mSignatures.size());
}

bool SignatureChecker::checkSignature(AccountID const &accountID, std::vector<Signer> const &signersV, int neededWeight)
{
auto signers = split(signersV, [](const Signer &s){ return s.key.type(); });

// calculate the weight of the signatures
int totalWeight = 0;

// compare all available SIGNER_KEY_TYPE_HASH_TX with current transaction hash
// current transaction hash is not stored in getEnvelope().signatures - it is
// computed with getContentsHash() method
for (auto const &signerKey : signers[SIGNER_KEY_TYPE_HASH_TX])
{
if (signerKey.key.hashTx() == mContentsHash)
{
mUsedOneTimeSignerKeys[accountID].insert(signerKey.key);
totalWeight += signerKey.weight;
if (totalWeight >= neededWeight)
return true;
}
}

auto &hashXKeyWeights = signers[SIGNER_KEY_TYPE_HASH_X];
for (size_t i = 0; i < mSignatures.size(); i++)
{
auto x = std::string{mSignatures[i].signature.begin(), mSignatures[i].signature.end()};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the preimage a string?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using just mSignatures[i].signature now

auto hash = sha256(x);

for (auto it = hashXKeyWeights.begin(); it != hashXKeyWeights.end(); ++it)
{
auto &signerKey = *it;
if (signerKey.key.hashX() == hash)
{
mUsedSignatures[i] = true;
totalWeight += signerKey.weight;
if (totalWeight >= neededWeight)
return true;

hashXKeyWeights.erase(it);
break;
}
}
}

auto &accountKeyWeights = signers[SIGNER_KEY_TYPE_ED25519];
for (size_t i = 0; i < mSignatures.size(); i++)
{
auto const& sig = mSignatures[i];

for (auto it = accountKeyWeights.begin(); it != accountKeyWeights.end(); ++it)
{
auto &signerKey = *it;
auto pubKey = KeyUtils::convertKey<PublicKey>(signerKey.key);
if (PubKeyUtils::hasHint(pubKey, sig.hint) &&
PubKeyUtils::verifySig(pubKey, sig.signature,
mContentsHash))
{
mUsedSignatures[i] = true;
totalWeight += signerKey.weight;
if (totalWeight >= neededWeight)
return true;

accountKeyWeights.erase(it);
break;
}
}
}

return false;
}

bool
SignatureChecker::checkAllSignaturesUsed() const
{
for (auto sigb : mUsedSignatures)
{
if (!sigb)
{
return false;
}
}
return true;
}

const UsedOneTimeSignerKeys &
SignatureChecker::usedOneTimeSignerKeys() const
{
return mUsedOneTimeSignerKeys;
}

};
39 changes: 39 additions & 0 deletions src/transactions/SignatureChecker.h
@@ -0,0 +1,39 @@
#pragma once

// Copyright 2016 Stellar Development Foundation and contributors. Licensed
// under the Apache License, Version 2.0. See the COPYING file at the root
// of this distribution or at http://www.apache.org/licenses/LICENSE-2.0

#include "xdr/Stellar-ledger-entries.h"
#include "xdr/Stellar-transaction.h"
#include "xdr/Stellar-types.h"

#include <map>
#include <set>
#include <stdint.h>
#include <vector>

namespace stellar
{

using UsedOneTimeSignerKeys = std::map<AccountID, std::set<SignerKey>>;

class SignatureChecker
{
public:
explicit SignatureChecker(Hash const &contentsHash, xdr::xvector<DecoratedSignature,20> const &signatures);

bool checkSignature(AccountID const &accountID, std::vector<Signer> const &signersV, int32_t neededWeight);
bool checkAllSignaturesUsed() const;

const UsedOneTimeSignerKeys & usedOneTimeSignerKeys() const;

private:
Hash const &mContentsHash;
xdr::xvector<DecoratedSignature,20> const &mSignatures;

std::vector<bool> mUsedSignatures;
UsedOneTimeSignerKeys mUsedOneTimeSignerKeys;
};

};