Skip to content

Commit

Permalink
Webauthn public key support (#3145)
Browse files Browse the repository at this point in the history
* Webauthn public key support

* Update Webauthn.h

* Update Webauthn.cpp

* Code review fixes

* make public key optional

* rename files

* Counterfactual address computation for ERC-4337 (#3150)

Added to your initial branch you can follow up the fixes in the other branch

* Move Barz to separate files

* update tests

* update tests

* Update EIP4337Tests.cpp

* Update TWEthereum.cpp

* Update TestBarz.kt

* Update TWEthereum.cpp

* Create TWBarz.yaml

* Update WalletCore.h

* Update TestBarz.kt

* Update TestBarz.kt

* Update TestBarz.kt

* Update TWBarz.yaml

* feat(barz): fix barz

---------

Co-authored-by: Milerius <[email protected]>
  • Loading branch information
rsrbk and Milerius authored May 12, 2023
1 parent 0f70467 commit 34f2c7f
Show file tree
Hide file tree
Showing 13 changed files with 525 additions and 0 deletions.

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions codegen-v2/manifest/TWBarz.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: TWBarz
structs:
- name: TWBarz
is_public: true
is_class: false
functions:
- name: TWBarzGetCounterfactualAddress
is_public: true
is_static: true
params:
- name: input
type:
variant: data
is_constant: true
is_nullable: false
is_pointer: true
return_type:
variant: string
is_constant: true
is_nullable: false
is_pointer: true
1 change: 1 addition & 0 deletions codegen-v2/src/codegen/swift/templates/WalletCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ FOUNDATION_EXPORT const unsigned char WalletCoreVersionString[];
#include "TWAESPaddingMode.h"
#include "TWAccount.h"
#include "TWAnyAddress.h"
#include "TWBarz.h"
#include "TWBase32.h"
#include "TWBase58.h"
#include "TWBase64.h"
Expand Down
25 changes: 25 additions & 0 deletions include/TrustWalletCore/TWBarz.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright © 2017-2023 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.
#pragma once

#include "TWBase.h"
#include "TWData.h"
#include "TWString.h"

TW_EXTERN_C_BEGIN

/// Barz functions
TW_EXPORT_STRUCT
struct TWBarz;

/// Calculate a counterfactual address for the smart contract wallet
///
/// \param input The serialized data of ContractAddressInput.
/// \return The address.
TW_EXPORT_STATIC_METHOD
TWString *_Nonnull TWBarzGetCounterfactualAddress(TWData *_Nonnull input);

TW_EXTERN_C_END
54 changes: 54 additions & 0 deletions src/Ethereum/Barz.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright © 2017-2023 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

#include "ABI.h"
#include "AddressChecksum.h"
#include "EIP1014.h"
#include "Hash.h"
#include "HexCoding.h"
#include <WebAuthn.h>
#include "../proto/Barz.pb.h"

namespace TW::Barz {

using ParamBasePtr = std::shared_ptr<TW::Ethereum::ABI::ParamBase>;
using ParamCollection = std::vector<ParamBasePtr>;

std::string getCounterfactualAddress(const TW::Barz::Proto::ContractAddressInput input) {
auto params = TW::Ethereum::ABI::ParamTuple();
params.addParam(std::make_shared<TW::Ethereum::ABI::ParamAddress>(parse_hex(input.diamond_cut_facet())));
params.addParam(std::make_shared<TW::Ethereum::ABI::ParamAddress>(parse_hex(input.account_facet())));
params.addParam(std::make_shared<TW::Ethereum::ABI::ParamAddress>(parse_hex(input.verification_facet())));
params.addParam(std::make_shared<TW::Ethereum::ABI::ParamAddress>(parse_hex(input.entry_point())));
params.addParam(std::make_shared<TW::Ethereum::ABI::ParamAddress>(parse_hex(input.security_manager())));
params.addParam(std::make_shared<TW::Ethereum::ABI::ParamAddress>(parse_hex(input.facet_registry())));

Data publicKey;
switch (input.owner().kind_case()) {
case TW::Barz::Proto::ContractOwner::KindCase::KIND_NOT_SET:
return "";
case TW::Barz::Proto::ContractOwner::KindCase::kPublicKey:
publicKey = parse_hex(input.owner().public_key());
break;
case TW::Barz::Proto::ContractOwner::KindCase::kAttestationObject:
const auto attestationObject = parse_hex(input.owner().attestation_object());
publicKey = subData(TW::WebAuthn::getPublicKey(attestationObject)->bytes, 1); // Drop the first byte which corresponds to the public key type
break;
}
params.addParam(std::make_shared<TW::Ethereum::ABI::ParamByteArray>(publicKey));

Data encoded;
params.encode(encoded);

Data initCode = parse_hex(input.bytecode());
append(initCode, encoded);

const Data initCodeHash = Hash::keccak256(initCode);
const Data salt(32, 0);
return Ethereum::checksumed(TW::Ethereum::Address(hexEncoded(TW::Ethereum::create2Address(input.factory(), salt, initCodeHash))));
}

} // namespace TW::Barz
17 changes: 17 additions & 0 deletions src/Ethereum/Barz.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright © 2017-2023 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

#pragma once

#include "Data.h"
#include "uint256.h"
#include "../proto/Barz.pb.h"

namespace TW::Barz {

std::string getCounterfactualAddress(const TW::Barz::Proto::ContractAddressInput input);

}
115 changes: 115 additions & 0 deletions src/WebAuthn.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Copyright © 2017-2023 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.


#include "Cbor.h"
#include "PublicKey.h"

#include <iostream>
#include <utility>
#include <algorithm>

namespace TW::WebAuthn {

// https://www.w3.org/TR/webauthn-2/#authenticator-data
struct AuthData {
Data rpIdHash;
std::array<std::uint8_t, 1> flagsBuf;
struct {
bool up;
bool uv;
bool at;
bool ed;
std::uint8_t flagsInt;
} flags;
std::uint32_t counter;
Data counterBuf;
Data aaguid;
Data credID;
Data COSEPublicKey;
};

AuthData parseAuthData(const Data& buffer) {
AuthData authData;

authData.rpIdHash = subData(buffer, 0, 32);

auto it = buffer.begin() + 32;
authData.flagsBuf = { *it };
++it;
std::uint8_t flagsInt = authData.flagsBuf[0];
authData.flags.up = !!(flagsInt & 0x01);
authData.flags.uv = !!(flagsInt & 0x04);
authData.flags.at = !!(flagsInt & 0x40);
authData.flags.ed = !!(flagsInt & 0x80);
authData.flags.flagsInt = flagsInt;

authData.counterBuf = Data(it, it + 4);
authData.counter = static_cast<std::uint32_t>((authData.counterBuf[0] << 24) |
(authData.counterBuf[1] << 16) |
(authData.counterBuf[2] << 8) |
authData.counterBuf[3]);
it += 4;

if (authData.flags.at) {
authData.aaguid = Data(it, it + 16);
it += 16;

std::array<std::uint8_t, 2> credIDLenBuf = { *(it), *(it + 1) };
std::uint16_t credIDLen = static_cast<std::uint16_t>((credIDLenBuf[0] << 8) |
credIDLenBuf[1]);
it += 2;

authData.credID = Data(it, it + credIDLen);
it += credIDLen;

authData.COSEPublicKey = Data(it, buffer.end());
}

return authData;
}

auto findIntKey = [](const auto& map, const auto& key) {
return std::find_if(map.begin(), map.end(), [&](const auto& p) {
return p.first.dumpToString() == key;
});
};

auto findStringKey = [](const auto& map, const auto& key) {
return std::find_if(map.begin(), map.end(), [&](const auto& p) {
return p.first.getString() == key;
});
};

std::optional<PublicKey> getPublicKey(const Data& attestationObject) {
const Data authData = findStringKey(TW::Cbor::Decode(attestationObject).getMapElements(), "authData")->second.getBytes();
if (authData.empty()) {
return std::nullopt;
}

const AuthData authDataParsed = parseAuthData(authData);
const auto COSEPublicKey = TW::Cbor::Decode(authDataParsed.COSEPublicKey).getMapElements();

if (COSEPublicKey.empty()) {
return std::nullopt;
}

// https://www.w3.org/TR/webauthn-2/#sctn-encoded-credPubKey-examples
const std::string xKey = "-2";
const std::string yKey = "-3";

const auto x = findIntKey(COSEPublicKey, xKey);
const auto y = findIntKey(COSEPublicKey, yKey);

Data publicKey;
append(publicKey, 0x04);
append(publicKey, x->second.getBytes());
append(publicKey, y->second.getBytes());

return PublicKey(publicKey, TWPublicKeyTypeNIST256p1Extended);
}

} // namespace TW::Webauthn
17 changes: 17 additions & 0 deletions src/WebAuthn.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright © 2017-2023 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

#pragma once

#include "Data.h"
#include "PublicKey.h"
#include <optional>

namespace TW::WebAuthn {

std::optional<PublicKey> getPublicKey(const Data& attestationObject);

}
21 changes: 21 additions & 0 deletions src/interface/TWBarz.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright © 2017-2023 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

#include <TrustWalletCore/TWBarz.h>
#include <string>
#include "Ethereum/Barz.h"

TWString *_Nonnull TWBarzGetCounterfactualAddress(TWData *_Nonnull input) {
TW::Barz::Proto::ContractAddressInput inputProto;

const auto bytes = TWDataBytes(input);
const auto size = static_cast<int>(TWDataSize(input));
if (!inputProto.ParseFromArray(bytes, size)) {
return "";
}

return TWStringCreateWithUTF8Bytes(TW::Barz::getCounterfactualAddress(inputProto).c_str());
}
46 changes: 46 additions & 0 deletions src/proto/Barz.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright © 2017-2023 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

syntax = "proto3";

package TW.Barz.Proto;
option java_package = "wallet.core.jni.proto";

import "Common.proto";

// Represents the access control to the wallet
message ContractOwner {
oneof kind {
string public_key = 1;
string attestation_object = 2;
}
}

// Input parameters for calculating a counterfactual address for ERC-4337 based smart contract wallet
message ContractAddressInput {
// Address of the contract factory
string factory = 1;

// Diamond proxy facets required for the contract setup
string diamond_cut_facet = 2;
string account_facet = 3;
string verification_facet = 4;

// ERC-4337 entry point
string entry_point = 5;

// Address of the contract that defines security constraints
string security_manager = 6;

// Address of the contract that defines if a facet is secure
string facet_registry = 7;

// Bytecode of the smart contract to deploy
string bytecode = 8;

// Owner of the wallet
ContractOwner owner = 9;
}
Loading

0 comments on commit 34f2c7f

Please sign in to comment.