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

IOS-3384 Cosmos — add external signer to wallet core #6

Merged
merged 5 commits into from
Apr 13, 2023
Merged
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
8 changes: 8 additions & 0 deletions src/Cosmos/Entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) con
dataOut.insert(dataOut.end(), serializedOut.begin(), serializedOut.end());
}

// TANGEM
void Entry::signExternally([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut, const Data& publicKey, const std::function<Data(Data)> externalSigner) const {
auto input = Proto::SigningInput();
input.ParseFromArray(dataIn.data(), (int)dataIn.size());
auto serializedOut = Signer::sign(input, coin, publicKey, externalSigner).SerializeAsString();
dataOut.insert(dataOut.end(), serializedOut.begin(), serializedOut.end());
}

string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const {
return Signer::signJSON(json, key, coin);
}
Expand Down
2 changes: 2 additions & 0 deletions src/Cosmos/Entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class Entry : public CoinEntry {
std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const override;
Data addressToData(TWCoinType coin, const std::string& address) const final;
void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const override;
// TANGEM
void signExternally(TWCoinType coin, const Data& dataIn, Data& dataOut, const Data& publicKey, const std::function<Data(Data)> externalSigner) const override;
bool supportsJSONSigning() const final { return true; }
std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const override;
};
Expand Down
20 changes: 14 additions & 6 deletions src/Cosmos/ProtobufSerialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

#include <future>

#include "ProtobufSerialization.h"
#include "JsonSerialization.h"
#include "../proto/Cosmos.pb.h"
Expand Down Expand Up @@ -316,14 +318,13 @@ std::string buildProtoTxBody(const Proto::SigningInput& input) {
return txBody.SerializeAsString();
}

std::string buildAuthInfo(const Proto::SigningInput& input, TWCoinType coin) {
std::string buildAuthInfo(const Proto::SigningInput& input, TWCoinType coin, const Data& publicKeyData) {
if (input.messages_size() >= 1 && input.messages(0).has_sign_direct_message()) {
return input.messages(0).sign_direct_message().auth_info_bytes();
}

// AuthInfo
const auto privateKey = PrivateKey(input.private_key());
const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1);
const PublicKey publicKey(publicKeyData, TWPublicKeyTypeSECP256k1);
auto authInfo = cosmos::AuthInfo();
auto* signerInfo = authInfo.add_signer_infos();

Expand Down Expand Up @@ -361,7 +362,7 @@ std::string buildAuthInfo(const Proto::SigningInput& input, TWCoinType coin) {
return authInfo.SerializeAsString();
}

Data buildSignature(const Proto::SigningInput& input, const std::string& serializedTxBody, const std::string& serializedAuthInfo, TWCoinType coin) {
Data buildSignature(const Proto::SigningInput& input, const std::string& serializedTxBody, const std::string& serializedAuthInfo, TWCoinType coin, const std::function<Data(Data)> externalSigner) {
// SignDoc Preimage
auto signDoc = cosmos::SignDoc();
signDoc.set_body_bytes(serializedTxBody);
Expand All @@ -382,8 +383,15 @@ Data buildSignature(const Proto::SigningInput& input, const std::string& seriali
}
}

const auto privateKey = PrivateKey(input.private_key());
auto signedHash = privateKey.sign(hashToSign, TWCurveSECP256k1);
auto signedHash = Data();
if(externalSigner) {
std::future<Data> signedHashFuture = std::async(externalSigner, hashToSign);
signedHash = signedHashFuture.get();
} else {
const auto privateKey = PrivateKey(input.private_key());
signedHash = privateKey.sign(hashToSign, TWCurveSECP256k1);
}

auto signature = Data(signedHash.begin(), signedHash.end() - 1);
return signature;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Cosmos/ProtobufSerialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ namespace TW::Cosmos::Protobuf {

std::string buildProtoTxBody(const Proto::SigningInput& input);

std::string buildAuthInfo(const Proto::SigningInput& input, TWCoinType coin);
std::string buildAuthInfo(const Proto::SigningInput& input, TWCoinType coin, const Data& publicKeyData);

Data buildSignature(const Proto::SigningInput& input, const std::string& serializedTxBody, const std::string& serializedAuthInfo, TWCoinType coin);
Data buildSignature(const Proto::SigningInput& input, const std::string& serializedTxBody, const std::string& serializedAuthInfo, TWCoinType coin, const std::function<Data(Data)> externalSigner);

std::string buildProtoTxRaw(const std::string& serializedTxBody, const std::string& serializedAuthInfo, const Data& signature);

Expand Down
15 changes: 11 additions & 4 deletions src/Cosmos/Signer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,20 @@
namespace TW::Cosmos {

Proto::SigningOutput Signer::sign(const Proto::SigningInput& input, TWCoinType coin) noexcept {
const auto& privateKey = PrivateKey(input.private_key());
const auto& publicKey = privateKey.getPublicKey(TWCoinTypePublicKeyType(coin));
return sign(input, coin, publicKey.bytes, nullptr);
}

//// TANGEM
Proto::SigningOutput Signer::sign(const Proto::SigningInput& input, TWCoinType coin, const Data& publicKeyData, const std::function<Data(Data)> externalSigner) noexcept {
switch (input.signing_mode()) {
case Proto::JSON:
return signJsonSerialized(input, coin);

case Proto::Protobuf:
default:
return signProtobuf(input, coin);
return signProtobuf(input, coin, publicKeyData, externalSigner);
}
}

Expand All @@ -42,13 +49,13 @@ Proto::SigningOutput Signer::signJsonSerialized(const Proto::SigningInput& input
return output;
}

Proto::SigningOutput Signer::signProtobuf(const Proto::SigningInput& input, TWCoinType coin) noexcept {
Proto::SigningOutput Signer::signProtobuf(const Proto::SigningInput& input, TWCoinType coin, const Data& publicKeyData, const std::function<Data(Data)> externalSigner) noexcept {
using namespace Protobuf;
using namespace Json;
try {
const auto serializedTxBody = buildProtoTxBody(input);
const auto serializedAuthInfo = buildAuthInfo(input, coin);
const auto signature = buildSignature(input, serializedTxBody, serializedAuthInfo, coin);
const auto serializedAuthInfo = buildAuthInfo(input, coin, publicKeyData);
const auto signature = buildSignature(input, serializedTxBody, serializedAuthInfo, coin, externalSigner);
auto serializedTxRaw = buildProtoTxRaw(serializedTxBody, serializedAuthInfo, signature);

auto output = Proto::SigningOutput();
Expand Down
5 changes: 4 additions & 1 deletion src/Cosmos/Signer.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ class Signer {
public:
/// Signs a Proto::SigningInput transaction
static Proto::SigningOutput sign(const Proto::SigningInput& input, TWCoinType coin) noexcept;

// TANGEM
static Proto::SigningOutput sign(const Proto::SigningInput& input, TWCoinType coin, const Data& publicKey, const std::function<Data(Data)> externalSigner) noexcept;

/// Signs a Proto::SigningInput transaction, using Json serialization
static Proto::SigningOutput signJsonSerialized(const Proto::SigningInput& input, TWCoinType coin) noexcept;

/// Signs a Proto::SigningInput transaction, using binary Protobuf serialization
static Proto::SigningOutput signProtobuf(const Proto::SigningInput& input, TWCoinType coin) noexcept;
static Proto::SigningOutput signProtobuf(const Proto::SigningInput& input, TWCoinType coin, const Data& publicKeyData, const std::function<Data(Data)> externalSigner) noexcept;

/// Signs a json Proto::SigningInput with private key
static std::string signJSON(const std::string& json, const Data& key, TWCoinType coin);
Expand Down
9 changes: 8 additions & 1 deletion swift/Tests/Blockchains/CosmosTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class CosmosSignerTests: XCTestCase {
}]
}

let input = CosmosSigningInput.with {
var input = CosmosSigningInput.with {
$0.signingMode = .protobuf;
$0.accountNumber = 1037
$0.chainID = "gaia-13003"
Expand All @@ -66,6 +66,13 @@ class CosmosSignerTests: XCTestCase {

XCTAssertJSONEqual(output.serialized, "{\"tx_bytes\": \"CowBCokBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmkKLWNvc21vczFoc2s2anJ5eXFqZmhwNWRoYzU1dGM5anRja3lneDBlcGg2ZGQwMhItY29zbW9zMXp0NTBhenVwYW5xbGZhbTVhZmh2M2hleHd5dXRudWtlaDRjNTczGgkKBG11b24SATESZQpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAlcobsPzfTNVe7uqAAsndErJAjqplnyudaGB0f+R+p3FEgQKAggBGAgSEQoLCgRtdW9uEgMyMDAQwJoMGkD54fQAFlekIAnE62hZYl0uQelh/HLv0oQpCciY5Dn8H1SZFuTsrGdu41PH1Uxa4woptCELi/8Ov9yzdeEFAC9H\", \"mode\": \"BROADCAST_MODE_BLOCK\"}")
XCTAssertEqual(output.error, "")

// TANGEM
let signer = PrivateKeySigner(privateKey: PrivateKey(data: input.privateKey)!, coin: .cosmos)
input.privateKey = Data(repeating: 1, count: 32)
let outputExternal: CosmosSigningOutput = AnySigner.signExternally(input: input, coin: .cosmos, signer: signer)
XCTAssertJSONEqual(outputExternal.serialized, "{\"tx_bytes\": \"CowBCokBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmkKLWNvc21vczFoc2s2anJ5eXFqZmhwNWRoYzU1dGM5anRja3lneDBlcGg2ZGQwMhItY29zbW9zMXp0NTBhenVwYW5xbGZhbTVhZmh2M2hleHd5dXRudWtlaDRjNTczGgkKBG11b24SATESZQpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAlcobsPzfTNVe7uqAAsndErJAjqplnyudaGB0f+R+p3FEgQKAggBGAgSEQoLCgRtdW9uEgMyMDAQwJoMGkD54fQAFlekIAnE62hZYl0uQelh/HLv0oQpCciY5Dn8H1SZFuTsrGdu41PH1Uxa4woptCELi/8Ov9yzdeEFAC9H\", \"mode\": \"BROADCAST_MODE_BLOCK\"}")
XCTAssertEqual(outputExternal.error, "")
}

func testAuthCompounding() {
Expand Down