“Fidelius开发教程”的版本间差异
(→高级) |
|||
第213行: | 第213行: | ||
. . . | . . . | ||
m_data . set <s p e c i e s >(t . get<s p e c i e s >()); | m_data . set <nowiki> <s p e c i e s > </nowiki> (t . get<s p e c i e s >()); | ||
base : : consume_input_value ( ) ; | base : : consume_input_value ( ) ; |
2022年4月26日 (二) 03:40的版本
介绍
简介
Fidelius 提供了自定义算法的能力。此处的算法用于分析数据,并将分析结果交付给用户。
Fidelius 的算法实现基于 C/C++1。一个算法是指一个运行在可信执行环境(TEE)中的代码,由于目前主要的支持硬件为 Intel SGX,因此编程方式符合 Intel SGX 的编程规范。
本文介绍的算法开发基于 Fidelius 的最新版本,请检查自己的版本。
Hello World
需要 git clone example,然后软链接到 example 目录下,需要解释编译的步骤,release 版本签名的步骤,执行的步骤需要解释各个文件的作用和意义 下面来看一个完整的 hello world 程序。
- include ”corecommon/ crypto / stdeth . h”
- include ” stbox / tsgx / log . h”
- include ”ypc_t/ a n a l y z e r / algo_wrapper . h”
- include ”ypc_t/ a n a l y z e r /macro . h”
class hello_world {
public :
i n l i n e stbox : : bytes do_parse ( const stbox : : bytes ¶m ) {
LOG(INFO) << ” h e l l o ␣ world ” ;
return param ;
}
};
ypc : : algo_wrapper<ypc : : crypto : : eth_sgx_crypto ,
ypc : : noinput_data_stream ,
hello_world , ypc : : l o c a l _ r e s u l t >
pw ;
YPC_PARSER_IMPL(pw ) ;
algo_wrapper
template<typename Crypto , typename DataSession , typename ParserT ,
typename Result , typename ModelT = void ,
template <typename> c l a s s DataAllowancePolicy = ignore_data_allowance ,
template <typename> c l a s s 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 为例
c l a s s enclave_iris_means_parser {
public :
enclave_iris_means_parser ( ypc : : data_source ∗ source )
- m_source ( source ){};
i n l i n e stbox : : bytes do_parse ( const stbox : : bytes ¶m ) {
ypc : : to_type<extra_nt_t> c o n v e r t e r ( m_source ) ;
transform_format t r a n s (& c o n v e r t e r ) ;
typedef hpda : : algorithm : : kmeans : : kmeans_processor<
hpda : : ntobject ,
i r i s _ d a t a , double , i i d >
kmeans_t ;
kmeans_t km(&trans , 3 , 0 . 0 0 1 ) ;
hpda : : output : : memory_output
mo(km. means_stream ( ) ) ;
mo. get_engine()−>run ( ) ;
. . .
}
protected :
ypc : : data_source ∗m_source ;
};
Y
该算法可以表示为如下的图
图中的边—数据类型
在 HPDA 所表示的有向图中,一条边可以表示为 (A, B),我们称 A 是 B 的输入源,A 的输出数据类型和 B 的输入数据类型必须一致,否则会产生编译错误。我们将 A 的输出数据类型(或 B 的输入数据类型)称为边 (A, B) 上的数据类型。
边的数据类型为
template<typename . . . ARGS>
f f : : u t i l : : n t o b j e c t ;
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 i t : mo. v a l u e s ( ) ) {
. . .
}
自定义处理单元
通常,系统内置的处理单元并不能满足特定的数据处理需求,因此,需要自定义处理单元。此时需要继承 hpda 中的处理单元基类,如下:
typedef f f : : u t i l : : ntobject <sepal_len , sepal_wid ,
petal_len , petal_wid , s p e c i e s > extra_nt_t ;
c l a s s transform_format
- public hpda : : p r o c e s s o r : : processor_base_t<
extra_nt_t , user_item_t> {
public :
transform_format (
- : hpda : : processor_with_output_t<extra_nt_t> ∗ t )
- hpda : : p r o c e s s o r : : processor_base_t<
extra_nt_t , user_item_t >(t )
{}
v i r t u a l bool process () {
i f ( ! has_input_value ( ) ) { return f a l s e ;}
auto t = base : : input_value ( ) ;
. . .
m_data . set <s p e c i e s > (t . get());
base : : consume_input_value ( ) ;
return true ; }
v i r t u a l 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 , i n t l e n ) ;
i n t reset_for_read ( void ∗ handle ) ;
i n t read_item_data ( void ∗ handle , char ∗ buf , i n t ∗ l e n ) ;
i n t close_item_reader ( void ∗ handle ) ;
uint64_t get_item_number ( ) ;