日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

可信計算應用開發

TAPP 可信應用是運行在可信執行環境中,持有密鑰的 WebAssembly 智能合約。TAPP 提供了一套基于 C99/C++14 標準的 C++ 語言子集作為合約語言。TAPP 開發者在開發可信計算應用程序時,需要先下載、安裝 TAPP 編譯工具 mytf.mycdt, 通過編譯工具將編寫的 TAPP 代碼編譯成 WASM 字節碼。之后,將TAPP 字節碼安裝到 MYTF 可信計算引擎中,由 MYTF 對 WASM 字節碼進行解釋并執行。

編寫 TAPP

TAPP 代碼基本框架如下(sample.cpp):

// 基本庫,包含了全部MYTF庫函數
#include <mychainlib/contract.h>
// 三方庫,本示例引入JSON庫
#include <third_party/rapidjson/document.h>
#include <third_party/rapidjson/stringbuffer.h>
#include <third_party/rapidjson/writer.h>
// 基本MYTF庫函數的命名空間
using namespace mychain;
// TAPP主類,與C++類定義相同,區別在于繼承Contract
class MyTapp : public Contract {
public:
    // TAPP函數,與C++函數定義相同。區別在于,如果是外部可調用接口,使用INTERFACE宏
    INTERFACE std::string Encode(const std::string& data) {
        std::string out;
        // 調用MYTF庫函數提供的接口(API):Base64Encode
        CryptoErrorCode err = Base64Encode(data, out);
        if (err != CryptoErrorCode::kSuccess) {
            // 目前打印至MYTF日志
            print("failed to base64encode: %d", err);
            return std::to_string(err);
        }
        return out;
    }

    // TAPP函數,與C++函數定義相同。區別在于,如果是外部可調用接口,使用INTERFACE宏
    INTERFACE int Add(int a, int b) {
        return a + b;
    }
};
// 通過宏定義外部可調用函數
INTERFACE_EXPORT(MyTapp, (Encode) (Add))

下載編譯工具

目前,編譯工具支持 Linux、macOS 系統,版本信息及對應下載地址如下:

名稱

版本

下載地址

mytf.mycdt

0.2.2.1

點擊下載 macOS 版本

點擊下載 Linux 版本

該編譯工具鏈基于 Clang。開發者可以通過 mytf.mycdt 將可信計算應用代碼編譯成 WASM 字節碼,然后用 MYTF SDK 將 TAPP 安裝到 C3S MYTF 中。MYTF 可信計算引擎會對 WASM 字節碼進行解釋執行。

安裝編譯工具

下載編譯工具后,將工具包解壓到指定目錄,如 $HOME/mycdt,并設置 PATH 環境變量。

注意my++ --version 取決于安裝的版本。

$ export PATH=$PATH:$HOME/mycdt/bin
$ my++ --version
my++ version mytf-0.2.2.1

編譯應用

下面以可信應用 sample.cpp 為例編譯應用。

$ my++ sample.cpp -o sample.wasm

編譯完成后,生成 WASM 字節碼 sample.wasm。可以通過 MYTF SDK 將該字節碼 安裝至 MYTF 可信計算引擎中進行解釋執行,具體操作參見 SDK 使用指南

API 詳解

除 C++ 標準庫之外,MYTF 提供了若干庫函數和 API 接口,可以在 TAPP 中使用,提高易用性和性能。API 分類介紹如下:

基礎設施接口

MyAssert & Require

// 函數原型
// 如果(not expression),則終止程序,將msg信息寫入Output中
// (每次tapp調用會得到return_val和Output,其中output是系統級別信息,詳見SDK文檔)
// (以下不再贅述Output)
void MyAssert(int expression, const std::string& msg);

// 如果(not condition),則終止程序,將exception信息寫入Output中
// 返回值為0,無意義
int Require(bool condition, const std::string& exception);

// 兩個接口自Mychain智能合約就存在,差異不大

// 使用示例
INTERFACE std::string Encode(const std::string& data) {
    std::string out;
    // 調用MYTF庫函數提供的接口(API):Base64Encode
    CryptoErrorCode err = Base64Encode(data, out);
    MyAssert(err == CryptoErrorCode::kSuccess, "failed to base64encode");
    return out;
}

LOG_*

包括 LOG_DEBUGLOG_INFO 和 LOG_ERROR。打印調試信息。每次輸出信息作為一行,如 LOG_DEBUG("%d", INT32_MAX);將會輸出 “[DEBUG] 2147483647\n”。每行最大長度為512,超出此長度則會進行截斷。

// 原型
// 格式與 C99 中 printf 相仿
int LOG_DEBUG(const char* format, ...);
// 示例
INTERFACE void TestPrint() {
    LOG_DEBUG("%d", INT32_MAX); // 2147483647
    LOG_DEBUG("%d", -1);        // -1
    LOG_DEBUG("%u", -1);        // 4294967295
    LOG_DEBUG("%o", 16);        // 20
    LOG_DEBUG("%x", 16);        // 10
    LOG_DEBUG("%f", -1.01);     // -1.010000
    LOG_DEBUG("%c", 'a');       // a
    LOG_INFO("%p", 0);          // 00000000
    LOG_INFO("%s", "hello");    // hello
    LOG_INFO("%%");             // %
    LOG_ERROR("hello");         // hello
    LOG_ERROR("");              // 
}

一次 tapp 調用期間,LOG 信息會保存在一個 rotate log buffer 內,調用結束之后將返回給調用者(ExecuteRes.log)。log buffer 大小目前設定為200k, 超出限制也會滾動寫入。如通過 LOG_DEBUG 寫入30k 行,每行20 個字節,則只有最后 10k 行會保留下來,返回給調用者。tapp 安裝時可以指定日志級別:

enum TappLogLevel {
    kTappLogDebug = 0,
    kTappLogInfo  = 1,
    kTappLogError = 2,
    kTappLogDisable = 3,
};

默認為kTappLogDisable,即不輸出任何日志。低于設定日志級別的 LOG 操作將不會生效。如安裝 tapp 時指定日志級別為 kTappLogError,則 tapp 中的 LOG_DEBUG 和 LOG_INFO 將不會打印信息。

Bin2Hex & Hex2Bin

// 函數原型
// 每個字節轉化為兩個字節(hex模式)。如"\0\255" => "00ff" 或 "00FF" (uppercase = true)
std::string Bin2Hex(const std::string& input, bool uppercase = false);
// 上述函數的逆操作,允許0x或0X開頭
std::string Hex2Bin(const std::string& input);

信封接口

EnvelopeOpen & EnvelopeBuild

TAPP 內部可以使用該函數進行基于 ECIES-SECP256K1 或國密算法的加密解密。支持多方用戶數據加密后,由第三方服務平臺融合多方加密數據并請求執行 TAPP,服務平臺無法獲取用戶隱私數據。

envelope
// 函數原型
// 解密信封envelope,得到其中的plain_data。信封構造參考SDK文檔
CryptoErrorCode EnvelopeOpen(const std::string& envelope, std::string& plain_data);
// 構造信封,使用pk使用algo算法對plain_data進行加密,得到加密后的信封
CryptoErrorCode EnvelopeBuild(const std::string& pk, const std::string& plain_data, std::string& output_envelope, KEY_ALGO_TYPE algo = KEY_ALGO_TYPE::ECIES_SECP256K1_KEY);

// 實例
INTERFACE std::string TestEnvelopeBuild(std::string plain_data, std::string pk) {
    print("plain_data %s are ready to be encrypt", plain_data.c_str());
    std::string ret_envelope = "";
    CryptoErrorCode ret = EnvelopeBuild(pk, plain_data, ret_envelope);
    if(CryptoErrorCode::kSuccess != ret) {
        print("Failed to encrypt envelope");
        return std::to_string(ret);
    }
    return ret_envelope;
}
INTERFACE std::string TestEnvelopeOpen(std::string envelope_data) {
    std::string plain_data = "";
    CryptoErrorCode ret = EnvelopeOpen(envelope_data, plain_data);
    if(CryptoErrorCode::kSuccess != ret) {
        print("Failed to decrypt envelope");
        return std::to_string(ret);
    }
    print("Decrypted data: %s", plain_data.c_str());
    return plain_data;
}

ECElgamalEnvelopeDecrypt

TAPP 內部可以使用該函數進行基于 ECElgamal-SECP256K1 算法的解密。支持數據一方加密后多方解密。

ecenvelope
// 原型
// 指定curve_type與prikey,對cipher解密得到output
CryptoErrorCode ECElgamalEnvelopeOpen(uint32_t curve_type, const std::string& prikey, const std::string& cipher, std::string& output);
// 示例
INTERFACE std::string TestECElgamalEnvelopeDecrypt(uint32_t pk_num, std::string prikey, std::string cipher_data) {
    uint32_t curve_type = 0;
    std::string plain_data = "";
    CryptoErrorCode ret = ECElgamalEnvelopeOpen(curve_type, prikey, cipher_data, plain_data);
    if (CryptoErrorCode::kSuccess != ret) {
        print("Failed to decrypt envelope");
        return std::to_string(ret);
    }
    return plain_data;
}

AuthEnvelopeDecrypt

在 MYTF 中,每個計算 TAPP 擁有加密公私鑰。數據所有者需要使用 TAPP 的公鑰加密,對隱私構造 AuthEnvelope 數據權屬信封結構,對數據的使用權限進行把控,保證了只有該 TAPP 才能解密此數據。當數據所有者需要將隱私數據使用權授信給其他人時,需要簽發 VC 給數據使用者,明確誰可以使用此數據執行 TAPP 的哪些函數。當 TAPP 收到數據使用者的計算請求時,會校驗使用者是否具有隱私數據的使用權限。

authenvelope
// 原型
// 數據擁有者的加密數據envelope,調用者提供擁有者的授權authorization和自身身份證明id_proof。調用此接口得到原文數據plain
CryptoErrorCode AuthEnvelopeOpen(const std::string& envelope, const std::string& authorization, const std::string& id_proof, std::string& plain /* out */);
// 示例
INTERFACE std::string TestAuthEnvelopeDecrypt(std::string envelope_data, std::string auth, std::string id_proof) {
    std::string plain_data = "";
    CryptoErrorCode res_code = AuthEnvelopeOpen(envelope_data, auth, id_proof, plain_data);
    if (CryptoErrorCode::kSuccess != res_code) {
        print("Failed to decrypt authenvelope: %u", res_code);
        return std::to_string(res_code);
    }
    print("Decrypted auth data: %s", plain_data.c_str());
    return plain_data;
}

密碼接口

RsaSign & RsaVerify

// 原型
// 使用pri_key,采用digest_name摘要方式,對data簽名得到sign
CryptoErrorCode RsaSign(const std::string& pri_key, const std::string& digest_name, const std::string& data, std::string& sign);
// 使用pub_key,采用digest_name摘要方式,驗證data的簽名sign
CryptoErrorCode RsaVerify(const std::string& pub_key, const std::string& digest_name, const std::string& data, const std::string& sign);

// 示例
INTERFACE std::vector<std::string> OrderVerify() {
    std::vector<std::string> ret;
    // 密碼配置
    const std::string digest_name = "SHA1";
    const std::string pri_key = "-----BEGIN RSA PRIVATE KEY-----\nXXBase64XX\n-----END RSA PRIVATE KEY-----";
    const std::string pub_key = "XXBase64XX";
    // 獲取簽名
    std::string encode_params = "some data";
    std::string sign;
    CryptoErrorCode sign_err = RsaSign(pri_key, digest_name, encode_params, sign);
    if (sign_err != CryptoErrorCode::kSuccess) {
        print("failed to sign: %u", sign_err);
        ret.push_back("FAIL"); ret.push_back("failed to sign"); ret.push_back(std::to_string(sign_err));
        return ret;
    }
    std::string encode_resp = "some data";
    std::string resp_sign = "XXBase64XX";

    // 驗證簽名
    CryptoErrorCode verify_err = RsaVerify(pub_key, digest_name, encode_resp, resp_sign);
    if (verify_err != CryptoErrorCode::kSuccess) {
        print("failed to verify sig: %u", verify_err);
        ret.push_back("FAIL"); ret.push_back("failed to verify signature"); ret.push_back(std::to_string(verify_err));
    }
    return ret;
}

TappEcdsaSign

TAPP函數:使用TAPP的私鑰對 data 進行簽名,簽名算法為 SECP256K1 ,內部實現使用bitcoin優化過的 secp256k1 算法。驗簽端注意對此算法對齊。

  • 函數原型

/*
功能:使用當前 TAPP 的簽名私鑰,對 data 進行簽名。摘要算法為 SHA256,簽名算法曲線為 curve_name,默認為 SECP256K1
返回值:執行結果,int 型枚舉類型。具體錯誤碼解釋見后文
參數:
  data: 入參,需要簽名的數據
  sign: 出參,得到簽名的結果。
  curve_name: 缺省入參,簽名算法使用的曲線,可選 ECDSA_RAW_SECP256K1_KEY或ECDSA_SM2P256V1_KEY
*/
CryptoErrorCode TappEcdsaSign(const std::string& data, std::string& sign, KEY_ALGO_TYPE curve_name = KEY_ALGO_TYPE::ECDSA_RAW_SECP256K1_KEY);

Sha256

// 原型
// 計算msg的SHA256摘要,得到hash
CryptoErrorCode Sha256(const std::string& msg, std::string& hash);

Hmac

/* 原型
 * 計算Hmac, 使用md_type摘要算法,使用key對msg計算hmac,得到結果mac
 * 其中摘要算法類型
    enum MdType: int {
        kSha1 = 0,
        kSha256 = 1,
    }; 
*/
CryptoErrorCode Hmac(const MdType& md_type, const std::string& msg, const std::string& key, std::string& mac);

// 示例
String hmac_key = "abcd";
String hmac_data = "hello";
String hmac_out;
CryptoErrorCode ret = Hmac(MdType::kSha1, hmac_data, hmac_key, hmac_out);
MyAssert(CryptoErrorCode::kSuccess == ret, "hmac errcode");
MyAssert(Bin2Hex(hmac_out) == "5126823fdb3f4ee3f970f8274929a50bbd5c8d0c", "hmac result");

國密接口

支持 Sm3_256Sm2Sm3SignSm2Sm3VerifySm2Sm3EncryptSm2Sm3DecryptSm4GcmEncryptSm4GcmDecrypt,示例如下:

// 函數原型
// const參數msg為入參,非const參數hash為結果出參。使用SM3 256算法,對msg計算摘要hash
// 如無特殊說明,以下const參數均為入參,非const參數均為結果出參。函數和參數名清晰,不再贅述具體含義
CryptoErrorCode Sm3_256(const std::string& msg, std::string& hash);

CryptoErrorCode Sm2Sm3Sign(const std::string& msg, const std::string& prikey, std::string& signature);

CryptoErrorCode Sm2Sm3Verify(const std::string& msg, const std::string& pubkey, const std::string& signature);

CryptoErrorCode Sm2Sm3Encrypt(const std::string& plain, const std::string& pubkey, std::string& cipher);

CryptoErrorCode Sm2Sm3Decrypt(const std::string& cipher, const std::string& prikey, std::string& plain);

CryptoErrorCode Sm4GcmEncrypt(const std::string& plain, const std::string& secret_key, std::string& cipher);

CryptoErrorCode Sm4GcmDecrypt(const std::string& cipher, const std::string& secret_key, std::string& plain);

// 示例
// 綜合測試SM所有接口
INTERFACE int TestSM(String plain, String expected_hash, String pubkey, String prikey, String secret_key) {
    // Sm3 hash
    String hash;
    CryptoErrorCode ret = Sm3_256(plain, hash);
    MyAssert(CryptoErrorCode::kSuccess == ret, "sm3 256");
    MyAssert(hash == expected_hash, "test sm3_256");

    // Sm2Sm3 sign
    String signature;
    ret = Sm2Sm3Sign(plain, prikey, signature);
    MyAssert(CryptoErrorCode::kSuccess == ret, "sm2 sm3 sign");

    ret = Sm2Sm3Verify(plain, pubkey, signature);
    MyAssert(CryptoErrorCode::kSuccess == ret, "sm2 sm3 verify");

    // Sm2Sm3 encrypt
    String cipher;
    ret = Sm2Sm3Encrypt(plain, pubkey, cipher);
    MyAssert(CryptoErrorCode::kSuccess == ret, "sm2 sm3 encrypt");

    String plain_decrypted;
    ret = Sm2Sm3Decrypt(cipher, prikey, plain_decrypted);
    MyAssert(CryptoErrorCode::kSuccess == ret, "sm2 sm3 decrypt");
    MyAssert(plain == plain_decrypted, "test sm2 sm3 encrypt");

    // Sm4 encrypt
    ret = Sm4GcmEncrypt(plain, secret_key, cipher);
    MyAssert(CryptoErrorCode::kSuccess == ret, "sm4 gcm encrypt");

    ret = Sm4GcmDecrypt(cipher, secret_key, plain_decrypted);
    MyAssert(CryptoErrorCode::kSuccess == ret, "sm4 gcm decrypt");
    MyAssert(plain == plain_decrypted, "test sm4 gcm encrypt");
    return 0;
}

對稱加解密接口

支持 AesGcmDecrypt(”AES/GCM/NoPadding”解密算法,支持密鑰長度128/192/256 bit)、AesEcbDecrypt (”AES/ECB/PKCS5Padding”解密算法,支持密鑰長度128/192/256 bit)、AesGcmEncrypt(”AES/GCM/NoPadding”加密算法,支持密鑰長度128/192/256 bit)、AesEcbEncrypt(”AES/ECB/PKCS5Padding”加密算法,支持密鑰長度128/192/256 bit),參考代碼見下:

/**
    函數原型:AesGcmDecrypt
    參數說明:
           key: 加密密鑰,合法長度16/24/32字節
           iv: Initialization_Vector, 12字節
           aad: Additional Authenticated Data
           cipher: 密文
           plain[out]: 解密后明文
    返回值:
           CryptoErrorCode 錯誤碼
*/           
CryptoErrorCode AesGcmDecrypt(const std::string& key, const std::string& iv, const std::string& aad, const std::string& cipher, std::string& plain);

// 代碼示例
INTERFACE String TestAesGcmDecrypt(String key, String iv, String aad, String cipher) {
        String out;
        CryptoErrorCode err = AesGcmDecrypt(key, iv, aad, cipher, out);
        if (err != CryptoErrorCode::kSuccess) {
            print("failed to AesGcmDecrypt: %d", err);
            return std::to_string(err);
        }
        print("TestAesGcmDecrypt, out size %d, %s", out.size(), out.c_str());
        return out;
    }

/**
    函數原型:AesGcmEncrypt
    參數說明:
           key: 加密密鑰,合法長度16/24/32字節
           iv: Initialization_Vector, 12字節
           aad: Additional Authenticated Data
           plain: 明文
           cipher[out]: 加密后密文
    返回值:
           CryptoErrorCode 錯誤碼
*/ 
CryptoErrorCode AesGcmEncrypt(const std::string& key, const std::string& iv, const std::string& aad, const std::string& plain, std::string& cipher);

// 示例代碼
    INTERFACE String TestAesGcmEncrypt(String key, String iv, String aad, String plain) {
        String out;
        CryptoErrorCode err = AesGcmEncrypt(key, iv, aad, plain, out);
        if (err != CryptoErrorCode::kSuccess) {
            print("failed to AesGcmEncrypt: %d", err);
            return std::to_string(err);
        }
        print("TestAesGcmEncrypt, out size %d, %s", out.size(), out.c_str());
        return out;
    }

/**
    函數原型:AesEcbDecrypt
    參數說明:
           key: 加密密鑰,合法長度16/24/32字節
           cipher: 密文
           plain[out]: 解密后明文
    返回值:
           CryptoErrorCode 錯誤碼
*/  
CryptoErrorCode AesEcbDecrypt(const std::string& key, const std::string& cipher, std::string& plain);

// 示例代碼
    INTERFACE String TestAesEcbDecrypt(String key, String cipher) {
        String out;
        CryptoErrorCode err = AesEcbDecrypt(key, cipher, out);
        if (err != CryptoErrorCode::kSuccess) {
            print("failed to AesEcbDecrypt: %d", err);
            return std::to_string(err);
        }
        print("TestAesEcbDecrypt, out %s", out.c_str());
        return out;
    }

/**
    函數原型:AesEcbEncrypt
    參數說明:
           key: 加密密鑰,合法長度16/24/32字節
           plain: 明文
           cipher: 加密后密文
    返回值:
           CryptoErrorCode 錯誤碼
*/ 
CryptoErrorCode AesEcbEncrypt(const std::string& key, const std::string& plain, std::string& cipher);

// 示例代碼
    INTERFACE String TestAesEcbEncrypt(String key, String plain) {
        String out;
        CryptoErrorCode err = AesEcbEncrypt(key, plain, out);
        if (err != CryptoErrorCode::kSuccess) {
            print("failed to AesEcbEncrypt: %d", err);
            return std::to_string(err);
        }
        print("TestAesEcbEncrypt, out %s", out.c_str());
        return out;
    }

Tools

Base64EncodeBase64Decode 的示例如下:

// 原型
CryptoErrorCode Base64Encode(const std::string& input, std::string& output);
CryptoErrorCode Base64Decode(const std::string& input, std::string& output);

時間處理接口

SDK版本要求:0.2.2.2+。

  • 時間字符串轉UNIX時間戳:strptime

    說明

    要引用 <time.h> 頭文件

    INTERFACE long StrptimeEval(String time_string, String fmt, int utc_offset) {
        struct tm tm;
        memset(&tm, 0, sizeof(struct tm));
        // char *strptime_tz(const char *restrict s, const char *restrict f, int utc_hour_off, struct tm *restrict tm)
        // 按給定時區(UTC偏移)將本地時間字符串轉換為本地時間tm結構
        // 目前支持時區:CHINA_STANDARD_TIME_TZ_OFFSET
        //             GREENWICH_MEAN_TIME_TZ_OFFSET
        // 或者 直接提供本地時區與UTC之間差距
        char* s = strptime_tz(time_string.c_str(), fmt.c_str(), utc_offset, &tm);
        MyAssert(s != NULL, "strptime");
        // 轉為時間戳
        time_t t = timegm(&tm);
        return (long)t;
    }

SDK示例代碼:

testReqMethod = "StrptimeEval";
        tappExecuteRequest = TappExecuteRequest.builder()
                .defaultRequest(tappId, tappVersion, testReqMethod)
                .addString("2001-11-12 18:31:01")
                .addString("%Y-%m-%d %H:%M:%S")
                .addInt32(BigInteger.valueOf(8))
                .build();
        tappExecuteResponse = client.executeTappPrivately(tappExecuteRequest);
        Assert.assertNotNull(tappExecuteResponse);
        Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
        Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
        Assert.assertEquals(1005561061, tappExecuteResponse.getReturnValue().toInt());
  • UNIX時間戳轉時間字符串:strftime

    說明

    要引用 <time.h> 頭文件。

#include <time.h>

INTERFACE String StrftimeEval(long ts, String fmt, int utc_offset) {

      //長度128,此處是示例值。請設置為實際格式化后字符串的長度。
      //此處指定長度可以大于實際長度
      //如果小于實際長度,則會發生截斷
      const size_t buffer_size = 128;
      char buffer[buffer_size];

      struct tm *pt;

      // UNIX時間戳
      time_t mytime = (time_t)(ts);

      // struct tm *localtime(const time_t *t, int utc_hour_off)
      // 時間戳轉本地時區tm結構
      // 目前支持時區:CHINA_STANDARD_TIME_TZ_OFFSET (+8)
      //             GREENWICH_MEAN_TIME_TZ_OFFSET (0)
      // 或者 直接提供本地時區與UTC之間差距,[-12, 12]
      // 轉換失敗返回NULL。
      pt = localtime(&mytime, utc_offset);
      MyAssert(NULL != pt, "localtime");

      // size_t strftime(char *s, size_t n, const char *f, const struct tm *tm);
      // 轉換成格式化字符串
      // fmt可以為 "%Y-%m-%d %H:%M:%S"
      // 更多格式化參考:https://www.man7.org/linux/man-pages/man3/strftime.3.html 
      // 轉換失敗返回0  
      size_t len = strftime(buffer, buffer_size, fmt.c_str(), pt);
      MyAssert(len != 0, "strftime");

      return String{buffer, len};
    }

SDK使用代碼:

// 發送端到端加密請求
        testReqMethod = "StrftimeEval";
        tappExecuteRequest = TappExecuteRequest.builder()
                .defaultRequest(tappId, tappVersion, testReqMethod)
                .addInt32(BigInteger.valueOf(1005561061))
                .addString("%Y-%m-%d %H:%M:%S")
                .addInt32(BigInteger.valueOf(8))
                .build();
        tappExecuteResponse = client.executeTappPrivately(tappExecuteRequest);
        Assert.assertNotNull(tappExecuteResponse);
        Assert.assertTrue(tappExecuteResponse.isRequestSuccess());
        Assert.assertTrue(tappExecuteResponse.isExecuteSuccess());
        Assert.assertEquals("2001-11-12 18:31:01", tappExecuteResponse.getReturnValue().toUtf8String());

三方庫

目前從MYCDT編譯器層面集成了若干三方庫。注意,三方庫是以編譯器庫函數的形式提供,因此函數會被編譯成WASM字節碼,增加了WASM的體積,運行速度也受到解釋執行的限制。而上述接口使用WASM外部集成的方式,在SGX內部原生實現,不參與WASM的編譯過程。

目前支持的三方庫如下:

返回值定義

ApiErrorCode

調用tapp庫接口的返回碼,我們會將所有接口返回碼統一到此。

enum ApiErrorCode: int {
    kApiSuccess               = 1,
    kApiFail                  = 0,
    kApiInternalError         = -0x0001,

    // ------------------------------------------
    //  COMMON ERROR CODE: [-0x2000, -0x2fff]
    // ------------------------------------------
    kApiDoNotUseSyncInterface       = -0x2000,

    // ------------------------------------------
    //  CRYPTO RELATED ERROR CODE: [-0x0002, -0x1fff]
    // ------------------------------------------
    // Crypto ErrorCode
    // 輸入錯誤
    kApiPrivateKeyBufferError = -0x0002,
    kApiPublicKeyBufferError  = -0x0003,
    kApiDigestBufferError     = -0x0004,
    kApiDataBufferError       = -0x0005,
    kApiSignatureBufferError  = -0x0006,
    kApiInputDataError        = -0x0007,
    // 過程錯誤
    kApiUnknownDigestName     = -0x0008,
    kApiPrivateKeyError       = -0x0009,
    kApiPublicKeyError        = -0x000a,
    // 輸出錯誤
    kApiOutputBufferError     = -0x000b,
    // 授權信封錯誤
    kApiEnvelopeFieldError      = -0x000c,
    kApiEnvelopeProofFieldError = -0x000d,
    kApiUnsupportType           = -0x000e,
    kApiInvalidDid              = -0x000f,
    kApiInvalidVC               = -0x0010,
    kApiInvalidAuth             = -0x0011,
    kApiSubjectNotMatch         = -0x0012,
    kApiAuthNotMatch            = -0x0013,
    kApiInvalidSignature        = -0x0014,
    kApiInvalidDidProof         = -0x0015,
    kApiInvalidCallerSig        = -0x0016,
    // 其他
    kApiGasExhausted            = -0x0017,
    // 傳入參數 md type 錯誤
    kApiInvalidMdType           = -0x0018,
    kApiDecryptFail             = -0x0019,

    // reserve for more CryptoErrorCode
    // [-0x0019, -0x00FF]

    // mychain crypto lib errorcode
    // [-0x0100, -0x1FFF]
    // reserve for more MychainCrypto

    // ------------------------------------------
    //  FILE RELATED ERROR CODE: [-0x4000, -0x4fff]
    // ------------------------------------------
    // 權限
    kApiFilePermissionInvalid = -0x4000,

    // 文件句柄
    kApiFileNotOpened = -0x4100,   // tfile 句柄未打開
    kApiFileOpenedExceedTotalLimit = -0x4101,
    kApiFileOpenedExceedRequestLimit = -0x4102,

    // data address
    kApiFileNonSupportedFileSourceType = -0x4200, // file meta 地址格式錯誤,合法應該為 xx.meta.hash
    kApiFileMetaAddressFormatError = -0x4201, // file meta 地址格式錯誤,合法應該為 xx.meta.hash
    // data limit
    kApiFileLineExceedLimit = -0x4300,
    kApiFileSliceExceedLimit = -0x4301,
    kApiFileSliceCountExceedLimit = -0x4302,
    kApiFileMetaExceedLimit = -0x4303,
    kApiFileChunkExceedLimit = -0x4304,
    kApiFileMalformedChunk = -0x4305,
    kApiFileMalformedFileMeta = -0x4306,
    kApiFileMalformedSlice = -0x4307,
    kApiFileIsEmpty = -0x4308,
    kApiJoinFileExceedLimit = -0x4309,   // 求交算法join文件太大
    kApiResultLineExceedLimit = -0x430a, // 求交算法結果行超出限制

    // data IO
    kApiFileOssObjectUploadFailed = -0x4400,
    kApiFileOssObjectDownloadFailed = -0x4401,
    kApiFileOssObjectNotFound = -0x4402,
    kApiFileOssObjectTooLarge = -0x4403,

    // data read & write
    kApiFileNonSupportedDecoder = -0x4500,
    kApiFileNonSupportedEncoder = -0x4501,
    kApiFileEndOfTfile = -0x4502,   // tfile文件已讀到結束

    // auxiliary
    kApiFileMalformedAuxiliary = -0x4600,
    kApiFileAuxiliaryCheckFailed = -0x4601,
    kApiFileNonSupportFileType = -0x4602,

    // runtime
    kApiFileStatusInvalid = -0x4700,

    // integrity
    kApiFileSliceRootHashError = -0x4800, // slice root hash 完整新校驗失敗
    kApiFileMetaHashError = -0x4801, // slice root hash 完整新校驗失敗

};

CryptoErrorCode

我們會將所有接口返回碼統一到 ApiErrorCode,此返回碼會保留。

// MYTF 密碼操作相關接口返回值
enum CryptoErrorCode: int {
   kSuccess               = 1,
   kFail                  = 0,
   kInternalError         = -0x0001,
   // 輸入錯誤
   kPrivateKeyBufferError = -0x0002,
   kPublicKeyBufferError  = -0x0003,
   kDigestBufferError     = -0x0004,
   kDataBufferError       = -0x0005,
   kSignatureBufferError  = -0x0006,
   kInputDataError        = -0x0007,
   // 過程錯誤
   kUnknownDigestName     = -0x0008,
   kPrivateKeyError       = -0x0009,
   kPublicKeyError        = -0x000a,
   // 輸出錯誤
   kOutputBufferError     = -0x000b,
   // 授權信封錯誤
   kEnvelopeFieldError      = -0x000c,
   kEnvelopeProofFieldError = -0x000d,
   kUnsupportType           = -0x000e,
   kInvalidDid              = -0x000f,
   kInvalidVC               = -0x0010,
   kInvalidAuth             = -0x0011,
   kSubjectNotMatch         = -0x0012,
   kAuthNotMatch            = -0x0013,
   kInvalidSignature        = -0x0014,
   kInvalidDidProof         = -0x0015,
   kInvalidCallerSig        = -0x0016,
   // 其他
   kGasExhausted            = -0x0017,
};

常見問題

C++ 標準支持情況

從安全與審計角度考慮,不推薦使用以下基礎設施:

  • 指針/引用。指針的越界行為是 C99/C++14 中最難以捉摸的行為,因此審計時需要格外小心。

  • 數組。數組的越界是 C++ 中的常見錯誤且很難排查。TAPP語言從正交化的角度考慮提供 std::vector 來替代。

  • enum/enum class/union。enum(作為弱類型枚舉)、enum class(作為強類型枚舉)及 union 的內存布局與標準 C++ 一致,但和數組一樣,類型檢查與越界檢測很難發揮效力。

  • 包括重載、模板與繼承,TAPP語言對這些基礎設施支持良好,且允許組合使用。

標準庫支持

  • malloc/free、new/delete 等內存管理類操作。已改寫以保證安全性。

  • abort/exit 等進程控制類操作。已改寫以保證安全性,不應在TAPP 中使用。

  • iostream/cstdio 中所包含的 IO 操作。TAPP語言不允許進行類似操作,同時提供了與 C++ 中 printf 行為相仿的 print 接口供TAPP開發者本地調試與輸出使用。

  • 對 std::vector 與 std::string 以外的 C++14 標準庫所支持類型與 可序列化數據類型 中所描述的可序列化類型的序列化行為未作嚴格定義,因此無法作為函數參數傳遞。

系統調用支持

不支持調用分類及細分說明:

  • 網絡:DNS、TCP、UDP、IPv6、以太網、socket、epoll、poll、select 等。

  • IO:文件、設備 ioctl、多緩沖區讀寫、內存映射。

  • 系統內核信息:進程分析 ptrace、磁盤使用信息、系統文件使用情況統計、Linux 文件系統操作。

  • 系統調度:動態加載、cache 控制、重啟。

  • 進程間通信:消息機制、信號量、共享內存、信號處理、IPC。

  • 線程調度:線程、鎖、用戶層進程內多線程上下文切換、定時器 sleep、wait。

  • 系統權限控制:賬戶體系、文件權限。

  • 其他:歸檔、復數、正則表達式、終端仿真 mount、系統調用入口 syscall、時間、隨機數、編碼轉換。 iconv、系統日志、“long double”相關運算與函數。

編譯選項支持

編譯工具使用以下編譯參數對某些 C++ 特性做了限制。注意,編寫 TAPP 時不要使用被禁止的特性:

  • -fno-cfl-aa 禁用 CFL 別名分析。

  • -fno-elide-constructors 禁用復制構造函數的 復制消除行為。

  • -fno-lto 禁用鏈接時優化。

  • -fno-rtti 禁用 RTTI。

  • -fno-exceptions 禁用異常。

  • -fno-threadsafe-statics 禁用靜態局部變量的線程安全特性。

編譯器安裝或使用失敗

目前在 Ubuntu、CentOS、AliOS 和 Mac OS 均進行了測試,其中 Ubuntu 某些環境會出現編譯問題。解決途徑:? 編譯器 my++ 和mychain的編譯器 my++ 重名,請檢查路徑中是否有其他 my++ (which my++)。運行 my++ --verison 應該返回 “my++ version mytf-VERSION(commitid)”。? 將需要編譯的文件 xx.cpp 移入 $MYCDT_INSTALL_HOME/bin/ 文件夾,在此文件夾直接運行my++ xx.cpp -o xx.wasm

結果返回“abort called”?

一般是tapp程序調用 abort() 導致,如JSON庫在面對非法字段訪問的時候,會調用abort 。產生此錯誤請仔細檢查tapp程序

結果返回“res[8450]: out of bounds memory access”?

Tapp目前支持最大16MB內存,超出此內存限制則會返回此錯誤。出現此錯誤,請仔細檢查Tapp的內存使用量,及時釋放不需要的內存。優化示例如下:

// 此處s占用10M空間,s2再次申請10M空間,則會內存超限
std::string s(10 * 1024 * 1024, 'a');
DoSomething(s);
std::string s2(10 * 1024 * 1024, 'a');


// 優化方式1: 我們使用{}將s的作用域限制一下,那么在}處,s就會被釋放。s2就能正常申請內存
{
    std::string s(10 * 1024 * 1024, 'a');
    DoSomething(s);
}
std::string s2(10 * 1024 * 1024, 'a');


// 優化方式2:我們在s使用結束后及時清空s的內存。s2就能正常申請內存
// 使用下面第3行所示的swap()方式清空s內存。注意,調用s.clear()并不會立即清空內存,推薦使用swap方式
std::string s(10 * 1024 * 1024, 'a');
DoSomething(s);
std::string().swap(s);
std::string s2(10 * 1024 * 1024, 'a');