“Fidelius开发教程”的版本间差异

来自典枢
跳到导航 跳到搜索
→‎HPDA
 
(未显示4个用户的119个中间版本)
第4行: 第4行:
Fidelius 提供了自定义算法的能力。此处的算法用于分析数据,并将分析结果交付给用户。
Fidelius 提供了自定义算法的能力。此处的算法用于分析数据,并将分析结果交付给用户。


Fidelius 的算法实现基于 C/C++1。一个算法是指一个运行在可信执行环境(TEE)中的代码,由于目前主要的支持硬件为 Intel SGX,因此编程方式符合
Fidelius 的算法实现基于 C/C++11。一个算法是指一个运行在可信执行环境(TEE)中的代码,由于目前主要的支持硬件为 Intel SGX,因此编程方式符合
Intel SGX 的编程规范。
Intel SGX 的编程规范。


第10行: 第10行:


== Hello World ==
== Hello World ==
就像其他开发教程一样,我们先从写一个最简单的“Hello World”程序开始。
详见以下章节《如何基于Fidelius开发算法》进行简单开发和运行程序。


需要 git clone example,然后软链接到 example 目录下,需要解释编译的步骤,release 版本签名的步骤,执行的步骤需要解释各个文件的作用和意义
下面来看一个完整的 hello world 程序。
下面来看一个完整的 hello world 程序。


#include ”corecommon/ crypto / stdeth . h”
  #include ”corecommon/crypto/stdeth.h”
  #include ”stbox/tsgx/log.h”
  #include ”ypc_t/analyzer/algo_wrapper.h”
  #include ”ypc_t/analyzer/macro.h”
  class hello_world {
  public:
    inline stbox::bytes do_parse(const stbox::bytes &param) {
      LOG(INFO) << ”hello world”;
      return param;
    }
  };
 
  ypc::algo_wrapper<ypc::crypto::eth_sgx_crypto, ypc::noinput_data_stream,
                    hello_world,
                    ypc::local_result> pw;
  YPC_PARSER_IMPL(pw);
 
== algo_wrapper ==
 
  template<typename Crypto, typename DataSession, typename ParserT,
          typename Result, typename ModelT = void,
          template<typename> class DataAllowancePolicy = ignore_data_allowance,
          template<typename> class ModelAllowancePolicy = ignore_model_allowance>
  class algo_warpper ;
 
代码来源<code>core/include/ypc_t/analyzer/algo_wrapper.h‎</code>
 
:* Crypto:密码协议簇,目前支持<code>ypc::crypto::eth_sgx_crypto</code>,兼容以太坊。


#include ” stbox / tsgx / log . h”
:* DataSession:数据源方式,支持<code>noinput_data_stream, raw_data_stream, sealed_data_stream, multi_data_stream</code>。


#include ”ypc_t/ a n a l y z e r / algo_wrapper . h”
:* ParserT:表示自定义的算法类。


#include ”ypc_t/ a n a l y z e r /macro . h”
:* Result:表示结果的类型,支持<code>local_result, onchain_result, offchain_result, forward_result</code>。


class  hello_world {
:* ModelT:表示模型的类型,是<code>ff::util::ntobject<...></code>。


public :
:* DataAllowancePolicy:表示数据源的许可验证策略,支持<code>ignore_data_allowance, check_data_allowance</code>。
 
:* ModelAllowancePolicy:表示模型的许可验证策略,支持<code>ignore_model_allowance, check_model_allowance</code>。
 
通过对上述参数的选择和组合,可以支持不同的场景。
 
= HPDA =
 
算法的主体通常使用 HPDA(High Performance Data Analysis)完成。HPDA 算法由输入(input)、处理单元(processor)、输出(output)三种不同的功能单元
组成,其中输入、处理有一个或多个,输出仅有一个。


i n l i n e stbox : : bytes do_parse ( const stbox : : bytes &param ) {
一个 HPDA 算法可以表示一个如下的有向图,其中节点表示功能单元,即输入、处理单元或输出,边表示数据。自然地,输入只有出边,输出只有入边,
处理单元有一个或多个入边,且有一个或多个出边。


LOG(INFO) << ” h e l l o ␣ world ” ;
算法的执行过程一般分为连个阶段:1)构造 HPDA 的图;2)运行算法。算法一旦开始运行,则会开始读取输入、产生输出,直到所有的输入读取完成。


return param ;
== Iris 为例 ==
  class enclave_iris_means_parser {
  public:
    enclave_iris_means_parser(ypc::data_source ∗source):m_source(source){};
    inline stbox::bytes do_parse(const stbox::bytes &param) {
      ypc::to_type<extra_nt_t> converter(m_source);
      transform_format trans(&converter);
      typedef hpda::algorithm::kmeans::kmeans_processor<
        hpda::ntobject<iris_data, species>,
        iris_data, double, iid> kmeans_t;
      kmeans_t km(&trans, 3, 0.001);
      hpda::output::memory_output<iid, kmeans_t::mean_point, kmeans_t::average_distance> mo(km.means_stream());
      mo.get_engine()−>run();
      ...
    }
  protected:
    ypc::data_source ∗m_source;
  };


}
该算法可以表示为如下的图


};
[[文件:Iris例图1.png|600px|center]]


ypc : : algo_wrapper<ypc : : crypto : : eth_sgx_crypto ,
== 图中的边—数据类型 ==


ypc : : noinput_data_stream ,
在 HPDA 所表示的有向图中,一条边可以表示为 (A, B),我们称 A 是 B 的输入源,A 的输出数据类型和 B 的输入数据类型必须一致,否则会产生编译错误。我们将 A 的输出数据类型(或 B 的输入数据类型)称为边 (A, B) 上的数据类型。


hello_world , ypc : : l o c a l _ r e s u l t >
边的数据类型为


pw ;
<code>
template<typename ...ARGS> ff::util::ntobject;
</code>


YPC_PARSER_IMPL(pw ) ;
[[文件:开发者教程-图2.png|600PX|center]]


== algo_wrapper ==
== data_source ==


template<typename Crypto , typename DataSession , typename ParserT ,
data_source 是一个表示输入的虚基类,其输出为 bytes 类型。一般后面会跟一个 converter,用于将 bytes 转换为自定义的结构。


typename Result , typename ModelT = void ,
== 处理单元(processor) ==
处理单元用于完成对数据的转换、处理等。目前系统已有的处理单元包括:


template <typename> c l a s s DataAllowancePolicy = ignore_data_allowance ,
:* filter 用于过滤,仅输出满足条件的数据。


template <typename> c l a s s ModelAllowancePolicy = ignore_model_allowance>
:* concat 用于连接不同的数据,在一个输入源结束后,输出另一个输入源。


class algo_warpper ;
:* group 用于在指定的域相同的数据上完成相应的操作,这些操作包括取平均 (avg),求最大 (max),求最小(min),求和(sum),求数量(count)。


代码来源core/include/ypc_t/analyzer/algo_wrapper.h
:* split 用于将一个输入复制为多个输出。


Crypto:密码协议簇,目前支持 ypc::crypto::eth_sgx_crypto,兼容以太坊。
:* kmeans_processor 用于在指定的数据上完成 kmeans 聚类算法。


DataSession:数据源方式,支持 noinput_data_stream, raw_data_stream,
== memory_output ==


sealed_data_stream, multi_data_stream。
memory_output是一个将结果存放在内存的输出单元。可以使用如下方式遍历


ParserT:表示自定义的算法类。
所有的输出


Result:表示结果的类型,支持 local_result, onchain_result, offchain_result,forward_result。
  for(auto it : mo.values()) {
    ...
  }


ModelT:表示模型的类型,是 ff::util::ntobject<...>。
== 自定义处理单元 ==


DataAllowancePolicy,表示数据源的许可验证策略,支持 ignore_data_allowance,check_data_allowance。
通常,系统内置的处理单元并不能满足特定的数据处理需求,因此,需要自定义处理单元。此时需要继承hpda中的处理单元基类,如下:


ModelAllowancePolicy,表示模型的许可验证策略,支持 ignore_model_allowance,check_model_allowance。
  typedef ff::util::ntobject<sepal_len,sepal_wid,petal_len,petal_wid,species> extra_nt_t;
  class transform_format
    : public hpda::processor::processor_base_t<extra_nt_t, user_item_t> {
  public:
    transform_format(::hpda::processor_with_output_t<extra_nt_t> *t)
        : hpda::processor::processor_base_t<extra_nt_t, user_item_t>(t) {}
    virtual bool process() {
      if (!has_input_value()) {
        return false;
      }
      auto t = base::input_value();
      m_data.get<iris_data>().set<sepal_len, sepal_wid, petal_len, petal_wid>(
          t.get<sepal_len>(), t.get<sepal_wid>(), t.get<petal_len>(),
          t.get<petal_wid>());
      m_data.set<species>(t.get<species>());
      base::consume_input_value();
      return true;
    }
    virtual user_item_t output_value() { return m_data; }
  protected:
    user_item_t m_data;
  };


通过对上述参数的选择和组合,可以支持不同的场景。
= 高级 =


= HPDA =
== 直接访问上下文 ==
上下文是指算法在执行过程中的信息,包括该算法的 hash,与 keymgr 的会话等。可以在算法类中添加如下方法以获得上下文的指针


算法的主体通常使用 HPDA(High Performance Data Analysis)完成。HPDA 算法由输入(input)、处理单元(processor)、输出(output)三种不同的功能单元
  void set_context(ypc::analyzer_context ∗context){
组成,其中输入、处理有一个或多个,输出仅有一个。
    m_context = context;
  }


一个 HPDA 算法可以表示一个如下的有向图,其中节点表示功能单元,即输入、处理单元或输出,边表示数据。自然地,输入只有出边,输出只有入边,
algo_wrapper会自动检测到该方法的存在,并编译生成相应的代码。
处理单元有一个或多个入边,且有一个或多个出边。


算法的执行过程一般分为连个阶段:1)构造 HPDA 的图;2)运行算法。算法一旦开始运行,则会开始读取输入、产生输出,直到所有的输入读取完成。
== 自定义输入数据格式 ==


== Iris 为例 ==
Fidelius 内置了对于 CSV,mysql 的支持,可以通过定义一个简单的 JSON 描述文件完成文件的加密、读取。然而,对于自定义的文件格式,开发者需要额外的开发工作。
c l a s s enclave_iris_means_parser {


public :
首先,该数据必须可以描述为一个 bytes 的数组,这在大多数场景下是适用的。例如,视频可以描述为一个数组,数组的每一个元素为一帧图像;一个图片可以表示为一个数组,数组的每一个元素为图片中的一个像素点。Fidelius 的算法每次读如数组中的一个或多个元素。受限于 Intel SGX 的内存限制,一个元素的大小通常不超过 128KB。


enclave_iris_means_parser ( ypc : : data_source ∗ source )
其次,对于自定义的数据格式,需要实现如下的方法,并编译为.so 的插件库。


: m_source ( source ){};
  void ∗create_item_reader(const char ∗extra_param, int len);
  int reset_for_read(void ∗handle);
  int read_item_data(void ∗handle, char ∗buf, int ∗len);
  int close_item_reader(void ∗handle);
  uint64_t get_item_number();


i n l i n e stbox : : bytes do_parse ( const stbox : : bytes &param ) {
= 如何基于Fidelius开发算法 =
== 下载 Fidelius 源码 ==


ypc : : to_type<extra_nt_t> c o n v e r t e r ( m_source ) ;
  $ git clone https://github.com/YeeZTech/YeeZ-Privacy-Computing.git


transform_format t r a n s (& c o n v e r t e r ) ;
== 编译 Fidelius ==


typedef hpda : : algorithm : : kmeans : : kmeans_processor<
  $ cd YeeZ-Privacy-Computing
  $ ./build.sh compile-project prerelease


hpda : : ntobject <i r i s _ d a t a , s p e c i e s >,
'''注意''': 开发者可以根据需求修改编译选项,支持的编译模式有 Debug、PreRelease、Release。


i r i s _ d a t a , double , i i d >
Debug、Prelease 模式下会自动对一些 Enclave 进行签名。


kmeans_t ;
但是,在 Release 编译选项下还需要手动地对一些 Enclave 签名,这些 Enclave 包括密钥管理的 Enclave libkeymgr.so 和算法样例的 Enclave libiris_parser.so。


kmeans_t km(&trans , 3 , 0 . 0 0 1 ) ;
手动签名操作需要依赖 openssl 工具,需事先安装 openssl ,签名步骤如下:


hpda : : output : : memory_output<i i d , kmeans_t : : mean_point ,
=== 生成 RSA-3072 的私钥和公钥(仅 Release 模式下需要)===


kmeans_t : : average_distance >
  $ cd YeeZ-Privacy-Computing/lib
  $ openssl genrsa -out private_key.pem -3 3072
  $ openssl rsa -in private_key.pem -pubout -out public_key.pem


mo(km. means_stream ( ) ) ;
生成的私钥文件为 private_key.pem,公钥文件为 public_key.pem,私钥文件用于对 Enclave 签名,公钥文件会 append 到 签名后的 Enclave 中。


mo. get_engine()−>run ( ) ;
=== 签名两个 Enclave(仅 Release 模式下需要)===


. . .
  $ openssl dgst -sha256 -out keymgr_sig.hex -sign private_key.pem -keyform PEM keymgr_hash.hex
  $ openssl dgst -sha256 -out iris_parser_sig.hex -sign private_key.pem -keyform PEM iris_parser_hash.hex


}
文件 keymgr_sig.hex 与 iris_parser_sig.hex 为私钥签名后的文件。


protected :
=== 生成签名后的 Enclave(仅 Release 模式下需要)===


ypc : : data_source ∗m_source ;
  $ /opt/intel/sgxsdk/bin/x64/sgx_sign catsig -enclave libkeymgr.so -config ../keymgr/default/enclave/ekeymgr.config.xml -out keymgr.signed.so -key public_key.pem -sig keymgr_sig.hex -unsigned keymgr_hash.hex
  $ /opt/intel/sgxsdk/bin/x64/sgx_sign catsig -enclave libiris_parser.so -config ../example/iris/analyzer/enclave/enclave.config.xml -out iris_parser.signed.so -key public_key.pem -sig iris_parser_sig.hex -unsigned iris_parser_hash.hex


};
签名后的 Enclave 实际上包括:算法原始文件、Enclave 配置文件、RSA-3072公钥、签名文件、算法哈希文件。


Y
== 运行算法示例 ==
  $ cd YeeZ-Privacy-Computing/test/integrate
  $ cd js && npm install && cd ..
  $ python3 test_iris.py


该算法可以表示为如下的图
= Q&A =

2023年3月8日 (三) 07:33的最新版本

介绍

简介

Fidelius 提供了自定义算法的能力。此处的算法用于分析数据,并将分析结果交付给用户。

Fidelius 的算法实现基于 C/C++11。一个算法是指一个运行在可信执行环境(TEE)中的代码,由于目前主要的支持硬件为 Intel SGX,因此编程方式符合 Intel SGX 的编程规范。

本文介绍的算法开发基于 Fidelius 的最新版本,请检查自己的版本。

Hello World

就像其他开发教程一样,我们先从写一个最简单的“Hello World”程序开始。

详见以下章节《如何基于Fidelius开发算法》进行简单开发和运行程序。

下面来看一个完整的 hello world 程序。

 #include ”corecommon/crypto/stdeth.h”
 #include ”stbox/tsgx/log.h”
 #include ”ypc_t/analyzer/algo_wrapper.h”
 #include ”ypc_t/analyzer/macro.h” 
 class hello_world {
 public:
   inline stbox::bytes do_parse(const stbox::bytes &param) {
     LOG(INFO) << ”hello world”;
     return param;
   }
 };
 ypc::algo_wrapper<ypc::crypto::eth_sgx_crypto, ypc::noinput_data_stream,
                   hello_world,
                   ypc::local_result> pw;
 YPC_PARSER_IMPL(pw);

algo_wrapper

 template<typename Crypto, typename DataSession, typename ParserT,
          typename Result, typename ModelT = void,
          template<typename> class DataAllowancePolicy = ignore_data_allowance,
          template<typename> class ModelAllowancePolicy = ignore_model_allowance>
 class algo_warpper ;

代码来源core/include/ypc_t/analyzer/algo_wrapper.h‎

  • Crypto:密码协议簇,目前支持ypc::crypto::eth_sgx_crypto,兼容以太坊。
  • DataSession:数据源方式,支持noinput_data_stream, raw_data_stream, sealed_data_stream, multi_data_stream
  • ParserT:表示自定义的算法类。
  • Result:表示结果的类型,支持local_result, onchain_result, offchain_result, forward_result
  • ModelT:表示模型的类型,是ff::util::ntobject<...>
  • DataAllowancePolicy:表示数据源的许可验证策略,支持ignore_data_allowance, check_data_allowance
  • ModelAllowancePolicy:表示模型的许可验证策略,支持ignore_model_allowance, check_model_allowance

通过对上述参数的选择和组合,可以支持不同的场景。

HPDA

算法的主体通常使用 HPDA(High Performance Data Analysis)完成。HPDA 算法由输入(input)、处理单元(processor)、输出(output)三种不同的功能单元 组成,其中输入、处理有一个或多个,输出仅有一个。

一个 HPDA 算法可以表示一个如下的有向图,其中节点表示功能单元,即输入、处理单元或输出,边表示数据。自然地,输入只有出边,输出只有入边, 处理单元有一个或多个入边,且有一个或多个出边。

算法的执行过程一般分为连个阶段:1)构造 HPDA 的图;2)运行算法。算法一旦开始运行,则会开始读取输入、产生输出,直到所有的输入读取完成。

Iris 为例

 class enclave_iris_means_parser {
 public:
   enclave_iris_means_parser(ypc::data_source ∗source):m_source(source){};
   inline stbox::bytes do_parse(const stbox::bytes &param) {
     ypc::to_type<extra_nt_t> converter(m_source);
     transform_format trans(&converter);
     typedef hpda::algorithm::kmeans::kmeans_processor<
       hpda::ntobject<iris_data, species>,
       iris_data, double, iid> kmeans_t;
     kmeans_t km(&trans, 3, 0.001);
     hpda::output::memory_output<iid, kmeans_t::mean_point, kmeans_t::average_distance> mo(km.means_stream());
     mo.get_engine()−>run();
     ...
   }
 protected:
   ypc::data_source ∗m_source;
 };

该算法可以表示为如下的图

Iris例图1.png

图中的边—数据类型

在 HPDA 所表示的有向图中,一条边可以表示为 (A, B),我们称 A 是 B 的输入源,A 的输出数据类型和 B 的输入数据类型必须一致,否则会产生编译错误。我们将 A 的输出数据类型(或 B 的输入数据类型)称为边 (A, B) 上的数据类型。

边的数据类型为

template<typename ...ARGS> ff::util::ntobject;

600PX

data_source

data_source 是一个表示输入的虚基类,其输出为 bytes 类型。一般后面会跟一个 converter,用于将 bytes 转换为自定义的结构。

处理单元(processor)

处理单元用于完成对数据的转换、处理等。目前系统已有的处理单元包括:

  • filter 用于过滤,仅输出满足条件的数据。
  • concat 用于连接不同的数据,在一个输入源结束后,输出另一个输入源。
  • group 用于在指定的域相同的数据上完成相应的操作,这些操作包括取平均 (avg),求最大 (max),求最小(min),求和(sum),求数量(count)。
  • split 用于将一个输入复制为多个输出。
  • kmeans_processor 用于在指定的数据上完成 kmeans 聚类算法。

memory_output

memory_output是一个将结果存放在内存的输出单元。可以使用如下方式遍历

所有的输出

 for(auto it : mo.values()) {
   ...
 }

自定义处理单元

通常,系统内置的处理单元并不能满足特定的数据处理需求,因此,需要自定义处理单元。此时需要继承hpda中的处理单元基类,如下:

 typedef ff::util::ntobject<sepal_len,sepal_wid,petal_len,petal_wid,species> extra_nt_t;
 class transform_format
   : public hpda::processor::processor_base_t<extra_nt_t, user_item_t> {
 public:
   transform_format(::hpda::processor_with_output_t<extra_nt_t> *t)
       : hpda::processor::processor_base_t<extra_nt_t, user_item_t>(t) {}
   virtual bool process() {
     if (!has_input_value()) {
       return false;
     }
     auto t = base::input_value();
     m_data.get<iris_data>().set<sepal_len, sepal_wid, petal_len, petal_wid>(
         t.get<sepal_len>(), t.get<sepal_wid>(), t.get<petal_len>(),
         t.get<petal_wid>());
     m_data.set<species>(t.get<species>());
     base::consume_input_value();
     return true;
   }
   virtual user_item_t output_value() { return m_data; }
 protected:
   user_item_t m_data;
 };

高级

直接访问上下文

上下文是指算法在执行过程中的信息,包括该算法的 hash,与 keymgr 的会话等。可以在算法类中添加如下方法以获得上下文的指针

 void set_context(ypc::analyzer_context ∗context){
   m_context = context;
 }

algo_wrapper会自动检测到该方法的存在,并编译生成相应的代码。

自定义输入数据格式

Fidelius 内置了对于 CSV,mysql 的支持,可以通过定义一个简单的 JSON 描述文件完成文件的加密、读取。然而,对于自定义的文件格式,开发者需要额外的开发工作。

首先,该数据必须可以描述为一个 bytes 的数组,这在大多数场景下是适用的。例如,视频可以描述为一个数组,数组的每一个元素为一帧图像;一个图片可以表示为一个数组,数组的每一个元素为图片中的一个像素点。Fidelius 的算法每次读如数组中的一个或多个元素。受限于 Intel SGX 的内存限制,一个元素的大小通常不超过 128KB。

其次,对于自定义的数据格式,需要实现如下的方法,并编译为.so 的插件库。

 void ∗create_item_reader(const char ∗extra_param, int len);
 int reset_for_read(void ∗handle);
 int read_item_data(void ∗handle, char ∗buf, int ∗len);
 int close_item_reader(void ∗handle);
 uint64_t get_item_number();

如何基于Fidelius开发算法

下载 Fidelius 源码

 $ git clone https://github.com/YeeZTech/YeeZ-Privacy-Computing.git

编译 Fidelius

 $ cd YeeZ-Privacy-Computing
 $ ./build.sh compile-project prerelease

注意: 开发者可以根据需求修改编译选项,支持的编译模式有 Debug、PreRelease、Release。

Debug、Prelease 模式下会自动对一些 Enclave 进行签名。

但是,在 Release 编译选项下还需要手动地对一些 Enclave 签名,这些 Enclave 包括密钥管理的 Enclave libkeymgr.so 和算法样例的 Enclave libiris_parser.so。

手动签名操作需要依赖 openssl 工具,需事先安装 openssl ,签名步骤如下:

生成 RSA-3072 的私钥和公钥(仅 Release 模式下需要)

 $ cd YeeZ-Privacy-Computing/lib
 $ openssl genrsa -out private_key.pem -3 3072
 $ openssl rsa -in private_key.pem -pubout -out public_key.pem

生成的私钥文件为 private_key.pem,公钥文件为 public_key.pem,私钥文件用于对 Enclave 签名,公钥文件会 append 到 签名后的 Enclave 中。

签名两个 Enclave(仅 Release 模式下需要)

 $ openssl dgst -sha256 -out keymgr_sig.hex -sign private_key.pem -keyform PEM keymgr_hash.hex
 $ openssl dgst -sha256 -out iris_parser_sig.hex -sign private_key.pem -keyform PEM iris_parser_hash.hex

文件 keymgr_sig.hex 与 iris_parser_sig.hex 为私钥签名后的文件。

生成签名后的 Enclave(仅 Release 模式下需要)

 $ /opt/intel/sgxsdk/bin/x64/sgx_sign catsig -enclave libkeymgr.so -config ../keymgr/default/enclave/ekeymgr.config.xml -out keymgr.signed.so -key public_key.pem -sig keymgr_sig.hex -unsigned keymgr_hash.hex
 $ /opt/intel/sgxsdk/bin/x64/sgx_sign catsig -enclave libiris_parser.so -config ../example/iris/analyzer/enclave/enclave.config.xml -out iris_parser.signed.so -key public_key.pem -sig iris_parser_sig.hex -unsigned iris_parser_hash.hex

签名后的 Enclave 实际上包括:算法原始文件、Enclave 配置文件、RSA-3072公钥、签名文件、算法哈希文件。

运行算法示例

 $ cd YeeZ-Privacy-Computing/test/integrate
 $ cd js && npm install && cd ..
 $ python3 test_iris.py

Q&A