Skip to content

Commit

Permalink
Sync dev with master (#3308)
Browse files Browse the repository at this point in the history
  • Loading branch information
satoshiotomakan committed Oct 6, 2023
1 parent cef220b commit 9b50c29
Show file tree
Hide file tree
Showing 19 changed files with 303 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class CoinAddressDerivationTests {
ETHEREUM, SMARTCHAIN, POLYGON, OPTIMISM, ZKSYNC, ARBITRUM, ECOCHAIN, AVALANCHECCHAIN, XDAI,
FANTOM, CELO, CRONOSCHAIN, SMARTBITCOINCASH, KUCOINCOMMUNITYCHAIN, BOBA, METIS,
AURORA, EVMOS, MOONRIVER, MOONBEAM, KAVAEVM, KLAYTN, METER, OKXCHAIN, POLYGONZKEVM, SCROLL,
CONFLUXESPACE, ACALAEVM -> assertEquals("0x8f348F300873Fd5DA36950B2aC75a26584584feE", address)
CONFLUXESPACE, ACALAEVM, OPBNBTESTNET -> assertEquals("0x8f348F300873Fd5DA36950B2aC75a26584584feE", address)
RONIN -> assertEquals("ronin:8f348F300873Fd5DA36950B2aC75a26584584feE", address)
ETHEREUMCLASSIC -> assertEquals("0x078bA3228F3E6C08bEEac9A005de0b7e7089aD1c", address)
GOCHAIN -> assertEquals("0x5940ce4A14210d4Ccd0ac206CE92F21828016aC2", address)
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,19 @@ class TestWebAuthn {
val result = WebAuthn.getPublicKey(attestationObject).data()
assertEquals(Numeric.toHexString(result), "0x04a620a8cfc88fd062b11eab31663e56cad95278bef612959be214d98779f645b84e7b905b42917570148b0432f99ba21f2e7eebe018cbf837247e38150a89f771")
}

@Test
fun testGetRSValues() {
val signature = Numeric.hexStringToByteArray("0x30440220766589b461a838748708cdf88444b21b1fa52b57d70671b4f9bf60ad14b372ec022020cc439c9c20661bfa39bbea24a900ec1484b2395eb065ead8ef4e273144a57d")
val result = WebAuthn.getRSValues(signature)
assertEquals(Numeric.toHexString(result), "0x766589b461a838748708cdf88444b21b1fa52b57d70671b4f9bf60ad14b372ec20cc439c9c20661bfa39bbea24a900ec1484b2395eb065ead8ef4e273144a57d")
}

@Test
fun testReconstructOriginalMessage() {
val authenticatorData = Numeric.hexStringToByteArray("0x1a70842af8c1feb7133b81e6a160a6a2be45ee057f0eb6d3f7f5126daa202e071d00000000")
val clientDataJSON = Numeric.hexStringToByteArray("0x7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a224e5549794f5545774d6b45744e554535517930304d6b5a424c546847516a4174517a52474f4441794d3045304f546b30222c226f726967696e223a2268747470733a2f2f747275737477616c6c65742e636f6d227d")
val result = WebAuthn.reconstructOriginalMessage(authenticatorData, clientDataJSON)
assertEquals(Numeric.toHexString(result), "0x3254cdbd677e6e31e75d2135bad0cf56440d7c6b108c141a3509d76ce45c6731")
}
}
1 change: 1 addition & 0 deletions docs/registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ This list is generated from [./registry.json](../registry.json)
| 2301 | Qtum | QTUM | <img src="https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/qtum/info/logo.png" width="32" /> | <https://qtum.org> |
| 2718 | Nebulas | NAS | <img src="https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/nebulas/info/logo.png" width="32" /> | <https://nebulas.io> |
| 3030 | Hedera | HBAR | <img src="https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/hedera/info/logo.png" width="32" /> | <https://hedera.com/> |
| 5611 | OpBNB testnet | tBNB | <img src="https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/opbnb/info/logo.png" width="32" /> | <https://opbnb.bnbchain.org/en> |
| 6060 | GoChain | GO | <img src="https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/gochain/info/logo.png" width="32" /> | <https://gochain.io> |
| 8964 | NULS | NULS | <img src="https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/nuls/info/logo.png" width="32" /> | <https://nuls.io> |
| 14001 | WAX | WAXP | <img src="https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/wax/info/logo.png" width="32" /> | <http://wax.io> |
Expand Down
1 change: 1 addition & 0 deletions include/TrustWalletCore/TWCoinType.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ enum TWCoinType {
TWCoinTypeConfluxeSpace = 1030,
TWCoinTypeAcala = 787,
TWCoinTypeAcalaEVM = 10000787,
TWCoinTypeOpBNBtestnet = 5611,
};

/// Returns the blockchain for a coin type.
Expand Down
15 changes: 15 additions & 0 deletions include/TrustWalletCore/TWWebAuthn.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,19 @@ struct TWWebAuthn;
/// \return Public key.
TW_EXPORT_STATIC_METHOD
struct TWPublicKey *_Nullable TWWebAuthnGetPublicKey(TWData *_Nonnull attestationObject);

/// Uses ASN parser to extract r and s values from a webauthn signature
///
/// \param signature ASN encoded webauthn signature: https://www.w3.org/TR/webauthn-2/#sctn-signature-attestation-types
/// \return Concatenated r and s values.
TW_EXPORT_STATIC_METHOD
TWData *_Nonnull TWWebAuthnGetRSValues(TWData *_Nonnull signature);

/// Reconstructs the original message that was signed via P256 curve. Can be used for signature validation.
///
/// \param authenticatorData Authenticator Data: https://www.w3.org/TR/webauthn-2/#authenticator-data
/// \param clientDataJSON clientDataJSON: https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson
/// \return original messages.
TW_EXPORT_STATIC_METHOD
TWData *_Nonnull TWWebAuthnReconstructOriginalMessage(TWData* _Nonnull authenticatorData, TWData* _Nonnull clientDataJSON);
TW_EXTERN_C_END
30 changes: 30 additions & 0 deletions registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -3960,6 +3960,36 @@
"documentation": "https://doc.confluxnetwork.org/docs/espace"
}
},
{
"id": "opbnb",
"name": "OpBNB testnet",
"coinId": 5611,
"chainId": "5611",
"symbol": "tBNB",
"decimals": 18,
"blockchain": "Ethereum",
"derivation": [
{
"path": "m/44'/60'/0'/0/0"
}
],
"curve": "secp256k1",
"publicKeyType": "secp256k1Extended",
"addressHasher": "keccak256",
"explorer": {
"url": "https://opbnbscan.com",
"txPath": "/tx/",
"accountPath": "/address/",
"sampleTx": "0x788ea8fb4a82dae957f1d3b18af3cd0bbde55a276e66bd17af8c869f24c03a0f",
"sampleAccount": "0x4eaf936c172b5e5511959167e8ab4f7031113ca3"
},
"info": {
"url": "https://opbnb.bnbchain.org/en",
"source": "https://github.com/bnb-chain/opbnb",
"rpc": "https://opbnb-testnet-rpc.bnbchain.org",
"documentation": "https://docs.bnbchain.org/opbnb-docs"
}
},
{
"id": "stratis",
"name": "Stratis",
Expand Down
75 changes: 59 additions & 16 deletions src/Cardano/Signer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ Common::Proto::SigningError Signer::assembleSignatures(std::vector<std::pair<Dat
const auto address = AddressV3(publicKey);
privateKeys[address.string()] = privateKeyData;

const auto legacyAddress = AddressV2(publicKey);
privateKeys[legacyAddress.string()] = privateKeyData;

// Also add the derived staking private key (the 2nd half) and associated address; because staking keys also need signature
const auto stakingPrivKeyData = deriveStakingPrivateKey(privateKeyData);
if (!stakingPrivKeyData.empty()) {
Expand All @@ -131,7 +134,7 @@ Common::Proto::SigningError Signer::assembleSignatures(std::vector<std::pair<Dat
// collect every unique input UTXO address, preserving order
std::vector<std::string> addresses;
for (auto& u : plan.utxos) {
if (!AddressV3::isValid(u.address)) {
if (!AddressV3::isValidLegacy(u.address)) {
return Common::Proto::Error_invalid_address;
}
addresses.emplace_back(u.address);
Expand Down Expand Up @@ -174,31 +177,53 @@ Common::Proto::SigningError Signer::assembleSignatures(std::vector<std::pair<Dat
const auto privateKey = PrivateKey(privateKeyData);
const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Cardano);
const auto signature = privateKey.sign(txId, TWCurveED25519ExtendedCardano);
// public key (first 32 bytes) and signature (64 bytes)
signatures.emplace_back(subData(publicKey.bytes, 0, 32), signature);
signatures.emplace_back(publicKey.bytes, signature);
}

return Common::Proto::OK;
}

Cbor::Encode cborizeSignatures(const std::vector<std::pair<Data, Data>>& signatures) {
Cbor::Encode cborizeSignatures(const std::vector<std::pair<Data, Data>>& signatures, const bool addByronSignatures) {
std::map<Cbor::Encode, Cbor::Encode> cborizeSigs;
// signatures as Cbor
// clang-format off
std::vector<Cbor::Encode> sigsCbor;
std::vector<Cbor::Encode> sigsShelly;
std::vector<Cbor::Encode> sigsByron;

for (auto& s : signatures) {
sigsCbor.emplace_back(Cbor::Encode::array({
Cbor::Encode::bytes(s.first),
sigsShelly.emplace_back(Cbor::Encode::array({
// public key (first 32 bytes)
Cbor::Encode::bytes(subData(s.first, 0, 32)),
Cbor::Encode::bytes(s.second)
}));

if (addByronSignatures) {
sigsByron.emplace_back(Cbor::Encode::array({
// skey - public key (first 32 bytes)
Cbor::Encode::bytes(subData(s.first, 0, 32)),
Cbor::Encode::bytes(s.second),
// vkey - public key (second 32 bytes started from 32)
Cbor::Encode::bytes(subData(s.first, 32, 32)),
// payload
Cbor::Encode::bytes(parse_hex("A0"))
}));
}
}

cborizeSigs.emplace(
Cbor::Encode::uint(0),
Cbor::Encode::array(sigsShelly)
);

if (!sigsByron.empty()) {
cborizeSigs.emplace(
Cbor::Encode::uint(2),
Cbor::Encode::array(sigsByron)
);
}

// Cbor-encode txAux & signatures
return Cbor::Encode::map({
std::make_pair(
Cbor::Encode::uint(0),
Cbor::Encode::array(sigsCbor)
)
});
return Cbor::Encode::map(cborizeSigs);
// clang-format on
}

Expand Down Expand Up @@ -242,7 +267,16 @@ Common::Proto::SigningError Signer::encodeTransaction(Data& encoded, Data& txId,
if (sigError != Common::Proto::OK) {
return sigError;
}
const auto sigsCbor = cborizeSignatures(signatures);

bool hasLegacyUtxos = false;
for (const auto& utxo : input.utxos()) {
if (AddressV2::isValid(utxo.address())) {
hasLegacyUtxos = true;
break;
}
}

const auto sigsCbor = cborizeSignatures(signatures, hasLegacyUtxos);

// Cbor-encode txAux & signatures
const auto cbor = Cbor::Encode::array({
Expand Down Expand Up @@ -557,8 +591,17 @@ Data Signer::encodeTransactionWithSig(const Proto::SigningInput &input, const Pu
}

std::vector<std::pair<Data, Data>> signatures;
signatures.emplace_back(subData(publicKey.bytes, 0, 32), signature);
const auto sigsCbor = cborizeSignatures(signatures);
signatures.emplace_back(publicKey.bytes, signature);

bool hasLegacyUtxos = false;
for (const auto& utxo : input.utxos()) {
if (AddressV2::isValid(utxo.address())) {
hasLegacyUtxos = true;
break;
}
}

const auto sigsCbor = cborizeSignatures(signatures, hasLegacyUtxos);

// Cbor-encode txAux & signatures
const auto cbor = Cbor::Encode::array({
Expand Down
5 changes: 1 addition & 4 deletions src/Ethereum/Barz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,11 @@ using ParamCollection = std::vector<ParamBasePtr>;

std::string getCounterfactualAddress(const Proto::ContractAddressInput input) {
auto params = Ethereum::ABI::ParamTuple();
params.addParam(std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(input.diamond_cut_facet())));
params.addParam(std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(input.account_facet())));
params.addParam(std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(input.verification_facet())));
params.addParam(std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(input.token_receiver_facet())));
params.addParam(std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(input.diamond_loupe_facet())));
params.addParam(std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(input.entry_point())));
params.addParam(std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(input.diamond_init())));
params.addParam(std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(input.facet_registry())));
params.addParam(std::make_shared<Ethereum::ABI::ParamAddress>(parse_hex(input.default_fallback())));
params.addParam(std::make_shared<Ethereum::ABI::ParamByteArray>(parse_hex(input.public_key())));

Data encoded;
Expand Down
6 changes: 4 additions & 2 deletions src/Polkadot/Extrinsic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,15 @@ Data Extrinsic::encodeStakingCall(const Proto::Staking& staking) const {
Data data;
switch (staking.message_oneof_case()) {
case Proto::Staking::kBond: {
auto address = SS58Address(staking.bond().controller(), network);
auto value = load(staking.bond().value());
auto reward = byte(staking.bond().reward_destination());
// call index
append(data, getCallIndex(staking.bond().call_indices(), network, stakingBond));
// controller
append(data, encodeAccountId(address.keyBytes(), encodeRawAccount()));
if (!staking.bond().controller().empty()) {
auto controller = SS58Address(staking.bond().controller(), network);
append(data, encodeAccountId(controller.keyBytes(), encodeRawAccount()));
}
// value
append(data, encodeCompact(value));
// reward destination
Expand Down
14 changes: 14 additions & 0 deletions src/interface/TWWebAuthn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <TrustWalletCore/TWWebAuthn.h>
#include <string>
#include "WebAuthn.h"
#include "AsnParser.h"

struct TWPublicKey *_Nullable TWWebAuthnGetPublicKey(TWData *_Nonnull attestationObject) {
const auto& attestationObjectData = *reinterpret_cast<const TW::Data*>(attestationObject);
Expand All @@ -17,3 +18,16 @@ struct TWPublicKey *_Nullable TWWebAuthnGetPublicKey(TWData *_Nonnull attestatio
return nullptr;
}
}

TWData *_Nonnull TWWebAuthnGetRSValues(TWData *_Nonnull signature) {
const auto& signatureData = *reinterpret_cast<const TW::Data*>(signature);
const auto& rsValues = TW::ASN::AsnParser::ecdsa_signature_from_der(signatureData);
return TWDataCreateWithData(&rsValues);
}

TWData *_Nonnull TWWebAuthnReconstructOriginalMessage(TWData* _Nonnull authenticatorData, TWData* _Nonnull clientDataJSON) {
const auto& authenticatorDataConverted = *reinterpret_cast<const TW::Data*>(authenticatorData);
const auto& clientDataJSONConverted = *reinterpret_cast<const TW::Data*>(clientDataJSON);
const auto& message = TW::WebAuthn::reconstructSignedMessage(authenticatorDataConverted, clientDataJSONConverted);
return TWDataCreateWithData(&message);
}
19 changes: 7 additions & 12 deletions src/proto/Barz.proto
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,19 @@ option java_package = "wallet.core.jni.proto";

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

// Diamond proxy facets required for the contract setup
string diamond_cut_facet = 2;
string account_facet = 3;
string verification_facet = 4;
string token_receiver_facet= 5;
string diamond_loupe_facet = 6;
string diamond_init = 7;
string facet_registry = 8;

// ERC-4337 entry point
string entry_point = 9;
string facet_registry = 5;
string default_fallback = 6;

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

string bytecode = 7;
// PublicKey of the wallet
string public_key = 11;
string public_key = 8;
}
17 changes: 6 additions & 11 deletions swift/Tests/BarzTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,19 @@ class BarzTests: XCTestCase {
XCTAssertEqual(result.hexString, "3fc708630d85a3b5ec217e53100ec2b735d4f800296601cd0000000000000000000000006bf22ff186cc97d88ecfba47d1473a234cebefdf00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004104e6f4e0351e2f556fd7284a9a033832bae046ac31fd529ad02ab6220870624b79eb760e718fdaed7a037dd1d77a561759cee9f2706eb55a729dc953e0d5719b0200000000000000000000000000000000000000000000000000000000000000")
}

// https://testnet.bscscan.com/address/0x5d51930e0ce5cc08a67a1763fadb66892c0994d1
func testCounterfactualAddress() {
let verificationFacet = "0xDcfbDE24847FdF29E6d0311f4bAEb2b49ae8B5a3"
let input = BarzContractAddressInput.with {
$0.factory = factory
$0.diamondCutFacet = diamondCutFacet
$0.accountFacet = accountFacet
$0.verificationFacet = verificationFacet
$0.tokenReceiverFacet = tokenReceiverFacet
$0.diamondLoupeFacet = diamondLoupeFacet
$0.factory = "0x2c97f4a366Dd5D91178ec9E36c5C1fcA393A538C"
$0.accountFacet = "0x3322C04EAe11B9b14c6c289f2668b6f07071b591"
$0.verificationFacet = "0x90A6fE0A938B0d4188e9013C99A0d7D9ca6bFB63"
$0.entryPoint = entryPoint
$0.diamondInit = diamondInit
$0.facetRegistry = facetRegistry
$0.facetRegistry = "0xFd1A8170c12747060324D9079a386BD4290e6f93"
$0.defaultFallback = "0x22eB0720d9Fc4bC90BB812B309e939880B71c20d"
$0.bytecode = bytecode
$0.publicKey = "0xB5547FBdC56DCE45e1B8ef75569916D438e09c46"
}

XCTAssertEqual(Barz.getCounterfactualAddress(input: try! input.serializedData()), "0x42138448be17503df67546CEE92470BF130e5611");
XCTAssertEqual(Barz.getCounterfactualAddress(input: try! input.serializedData()), "0x77F62bb3E43190253D4E198199356CD2b25063cA");
}

func testFormatSignature() {
Expand Down
1 change: 1 addition & 0 deletions swift/Tests/CoinAddressDerivationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class CoinAddressDerivationTests: XCTestCase {
.meter,
.okxchain,
.confluxeSpace,
.opBNBtestnet,
.acalaEVM:
let expectedResult = "0x8f348F300873Fd5DA36950B2aC75a26584584feE"
assertCoinDerivation(coin, expectedResult, derivedAddress, address)
Expand Down
13 changes: 13 additions & 0 deletions swift/Tests/WebAuthnTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,17 @@ class WebAuthnTests: XCTestCase {
let result = WebAuthn.getPublicKey(attestationObject: attestationObject)!.data
XCTAssertEqual(result.hexString, "04a620a8cfc88fd062b11eab31663e56cad95278bef612959be214d98779f645b84e7b905b42917570148b0432f99ba21f2e7eebe018cbf837247e38150a89f771")
}

func testGetRSValues() {
let signature = Data(hexString: "0x30440220766589b461a838748708cdf88444b21b1fa52b57d70671b4f9bf60ad14b372ec022020cc439c9c20661bfa39bbea24a900ec1484b2395eb065ead8ef4e273144a57d")!
let result = WebAuthn.getRSValues(signature: signature)
XCTAssertEqual(result.hexString, "766589b461a838748708cdf88444b21b1fa52b57d70671b4f9bf60ad14b372ec20cc439c9c20661bfa39bbea24a900ec1484b2395eb065ead8ef4e273144a57d")
}

func testReconstructOriginalMessage() {
let authenticatorData = Data(hexString: "0x1a70842af8c1feb7133b81e6a160a6a2be45ee057f0eb6d3f7f5126daa202e071d00000000")!
let clientDataJSON = Data(hexString: "0x7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a224e5549794f5545774d6b45744e554535517930304d6b5a424c546847516a4174517a52474f4441794d3045304f546b30222c226f726967696e223a2268747470733a2f2f747275737477616c6c65742e636f6d227d")!
let result = WebAuthn.reconstructOriginalMessage(authenticatorData: authenticatorData, clientDataJSON: clientDataJSON)
XCTAssertEqual(result.hexString, "3254cdbd677e6e31e75d2135bad0cf56440d7c6b108c141a3509d76ce45c6731")
}
}
Loading

0 comments on commit 9b50c29

Please sign in to comment.