system: [SYSTEM]

user: 3. 方案主要算法的设计及智能合约的交互细节 3.1. 密封出价方案中keccak算法的设计 为了保密密封出价中出价方的真实出价，本方案使用了单向密码体制中的keccak256算法，只有加密过程，没有解密过程。 keccak256算法是SHA3标准下提出的一种可扩展输出函数SHAKE128的核心算法，而完整的keccak算法描述比较复杂，由于篇幅有限，本文只介绍keccak256加密算法的应用与实现。 keccak算法 [ 8 ] 采用了海绵结构，基本公式为： b = r + c z = S P O N G E [ f ( b ) ， p a d ， r ] ( M ， l ) (1) 其中z为最终加密输出的密文； f ( b ) 为混乱函数，用作置换；b为计算的内存状态，以矩阵形式存储和运算；r为会与输入消息和输出摘要发生关系的比特，所有的消息根据r长度进行分块，不够分块的就填充pad；c为容量，与起始输入消息M无关，规定为输出摘要l的两倍，l为消息串M的摘要长度。 在本方案中，具体应用的公式如下： M = a m o u n t + s e c r e t T e x t k e c c a k [ c ] ( M ， l ) = S P O N G E [ f ( b ) ， p a d ( 10 ∗ 1 ) ， r ] ( M ， l ) s e a l e d B i d = k e c c a k [ c ] ( M ， l ) . t o S t r i n g ( h e x ) (2) 其中amount是出价方输入的真实出价，secretText是出价方输入的密文，sealedBid是传输到合约的密封出价，为方便合约存储和判断，需要将加密之后的字符串转化成16进制。具体实施步骤为：先在竞价过程中将出价方的真实出价和出价方自己定义的密文进行绑定，然后使用keccak256算法对该组合消息进行加密后传给合约进行存储，出价效果图如图4所示。 图4. 密封出价效果图 在揭价阶段再由出价方输入之前出价的金额和密文，交由合约进行比对。合约比对无误后则视为成功揭价一次，揭价的效果图如图5所示。 图5. 揭价效果图 3.2. 交易数据的确认——数字签名 本文为了测试需要，引用数字钱包MetaMask作为用户资金存放的工具，图6是利用MetaMask进行交易的详细数据图。 图6. 资金交易数据图 虽然在一定程度上使用MetaMask钱包保证了账户数据信息的安全，但仍然存在敌手伪造成用户对拍卖交易过程进行破坏的可能性，如敌手可以伪造成出价方身份进行恶意出价，导致出价方无法按理想价格出价。为了降低敌手带来这样类似的风险，在交易逻辑上还需要进一步的改进。 数字签名自1976年 [ 9 ] 被提出以来，就作为保障网络信息安全的手段之一，用来解决伪造、抵赖、冒充和篡改问题。本文根据方案设计中的不同情形实现数字签名，对出价方身份及交易数据做进一步确认。 3.2.1. 椭圆曲线数字签名算法ECDSA应用与优势分析 椭圆曲线数字签名算法ECDSA [ 10 ] 是使用椭圆曲线密码ECC对数字签名算法DSA的模拟。ECDSA并不直接对消息进行加解密，而是使用另外安全的散列算法生成数字签名，将公钥经过hash运算之后与传入的消息做异或运算。 由于ECDSA签名速度快，且密钥存储空间小，在密封出价、揭价这种签名和验签较为频繁的场景下非常适用，另外根据以太坊黄皮书 [ 11 ]，以太坊已经实现了ECDSA算法并进行了封装，配合本文方案适用场景可以直接进行调用。 本文在密封出价和揭价公示时的签名流程和验签流程分别如下： 1) 签名流程： 先选择一条椭圆曲线 E p ( a ， b ) 和基点G，对应从中产生的公私钥对为 ( e ， d ) ；然后选择临时私有密钥 k ( k < n ) ，n为G的阶，利用基点G计算点 ( x ， y ) = k G ；接着产生一个随机整数 r ≡ x mod n ( r < n ) ，并将消息M作为参数，计算 k e c c a k 256 ( M ) ，把得到的比特串化为整数z后，计算 s ≡ k − 1 ( z + r d ) mod n ，r和s便作为签名值参与验签，如果r和s其中一个为0，重新产生 和 。 2) 验签流程： 接收方在收到消息 M ′ 和签名值 ( r ， s ) 后，计算 k e c c a k 256 ( M ′ ) ，得到的比特串化为整数 z ′ ；然后计算： s G + z ′ e = ( x 1 ， y 1 ) ， r 1 ≡ x 1 mod n ；接着验证等式： r 1 ≡ r mod n ，如果等式成立，接受签名，否则签名无效。 因为消息仍然为keccak256加密的消息摘要，并不更改之前的交易逻辑，所以此算法的改进加强了出价、揭价过程中的安全。 3.2.2. 资金托管中多重签名逻辑的改进与优化 在资金托管合约中引入多重签名是为了保证资金流转的安全性。因为采用多重签名可以做到防欺诈保护，解决交易双方的信任问题。就相对于“单签名交易”而言，多重签名引入了仲裁人机制，产生纠纷时可由可信第三方做出仲裁，做到交易的不抵赖、付款和出货的保证，从而保障交易的公正性。 多重签名中最常见的就是2/3多重签名，然而以太坊外部账户只由一个独立私钥创建，无法进行多签。但是合约具有可编程性，所以可在合约上编写符合多重签名的逻辑代码，实现多个以太坊账户共签交易资金，从而控制资金流向。 如果将用户资金流向选择的消息未经加密而直接传给合约，敌手便可以在传输过程中截取用户的资金流向选择的消息，进而在签名时间内更改用户的选择，最终更改资金流向破坏交易，所以这种方法不可取。因为用户签名之后，合约验签的时候需要对各个用户传过来的资金流向选择的消息加以判断，虽然之前在出价、揭价过程中使用的ECDSA签名算法，有签名速度快，密钥存储空间小的特点，但其无法直接对消息加解密 [ 12 ]，所以本文在这种多重签名的设计逻辑中，选择即可用于签名也可用于加密的RSA数字签名算法。 基于RSA数字签名体制，使用用户的私钥对资金流向选择的消息进行签名，然后传到合约之后使用用户的公钥进行验签，得到用户对资金流向的判断。RSA数字签名体制如下： 设 n = p q ，其中p、q为素数，设 p = q = z n ，且定义 K = { ( n ， p ， q ， e ， d ) : e d = 1 mod φ ( n ) } 。 对于一个密码体制五元组 k = ( n ， p ， q ， e ， d ) ，定义： s i g k ( x ) = x d mod n v e r k ( x ， y ) = t r u e   O R   f a l s e (3) 其中 ( x ， y ∈ z n ) ， ( n ， e ) 为公钥， ( n ， d ) 为私钥。因为RSA签名的验证过程与RSA加解密过程的格式相同，其有效签名验证一致性的成立可以通过RSA加解密过程的一致性得到，即： d k ( e k ( y ) ) = x e d = x mod n (4) 但是如果这样直接照搬RSA数字签名的设计，仍然存在伪造他人签名y，对应的消息是 e k ( y ) = y e ，一般这种消息是无意义的，但要防止攻击者计算大量的 e k ( y ) ，从而找出有意义的值进行签名伪造。这里给出两种解决的方案，一种是按照密封出价时的逻辑，使用hash函数对消息摘要后再签名；另一种是给消息增加可识别的冗余信息后再签名。 对于第一种方案，首先将用户对交易资金流向选择的消息M进行hash得到消息摘要 M 1 = H A S H ( M ) ，然后使用用户私钥对 M 1 进行签名 s i g k ( M 1 ) ，再传输至资金托管合约进行验签 v e r k ( s i g k ( M 1 ) ) ，解密得到 M 1 。因为用户资金流向选择只有两种，要么释放资金给卖家，要么返回资金给买家，所以合约验签得到用户资金选择的消息摘要 M 1 后，还要分别对释放资金给卖家的消息 a 和返还资金给买家的消息 b 进行摘要，即 M 2 = H A S H ( a ) (4) M 3 = H A S H ( b ) (5) 然后将 M 1 与 M 2 和 M 3 进行比对，如果 M 1 = = M 2 ，那么表示该用户同意释放资金给卖家；如果 M 1 = = M 3 ，那么表示该用户同意返还资金给买家。显然，这样资金流转的效率并不高，因为在这种三方参与的多重签名逻辑中，每次资金交易都需要进行至少6次hash才能决定资金流向(率先签名的两方都同意释放资金或者返还资金的情况)，这样就增加了验签运算过程的时间，从而降低资金流转效率。 对于第二种方案，给消息增加可识别的冗余信息，采用用户对资金流转的消息M与当前用户进行签名的时间戳T进行标识，然后转成字节码形式后使用用户私钥签名，即： M ′ = b y t e s ( M + T ) s i g k ( M ′ ) = M ′ d mod n v e r k ( M ′ ) = t r u e   O R   f a l s e (7) 对 M ′ 进行签名，然后再传给合约使用用户公钥解密后，将拆分开成M和T两部分，根据M判断用户的选择，根据T判断用户签名时间的合法性。相比第一种方案，减少了资金流转过程中过多的运算提高了效率，同时依赖时间戳在一定程度上可以防重放攻击，加强了交易的安全性。本文基于第二种方案投票的多签效果如图7。 图7. 资金托管投票效果图 3.3. 智能合约交互的业务细节 本节将描述方案中与智能合约交互的具体细节，图8是方案中的业务交互图。 图8. 拍卖方案业务交互图 如图8所示，完整合约交互过程首先应该编写符合规范的合约逻辑，然后将其编译成字节码文件。编译好的字节码文件会提供一些可供远程调用的API，通过这些API创建交易数据暂存到以太坊交易池的入队列中，等待节点上的用户(矿工)利用以太坊共识算法Ethash进行工作量证明后，产生一个新区块 [ 13 ]。最后交由其他节点检验区块的合法性，再部署添加到以太坊区块链上。 方案中通过在以太坊节点上可供远程调用的接口，向区块链请求数据，区块链则会根据不同请求进行响应，接着与浏览器直接进行通信，返回相关数据。当然，也可以通过这些接口先与业务服务器先通信，然后利用HTTP请求返回业务数据供前端使用。 3.4. 智能合约交互的技术细节 关于方案中智能合约交互的技术细节，根据3.3节描述的业务交互图来看，业务服务器、浏览器在与合约进行交互的过程中，是通过RPC API接口读取、写入有关数据的，并没有为了与合约交互而每次都向以太坊网络进行直接请求。当然，编写直接访问以太坊网络的请求逻辑也是可行的，但比较麻烦，管理也很困难。 本文将以拍卖方上架商品与查询拍卖商品信息为例来对合约交互的技术细节进行详细的描述，也就是本方案中通过合约逻辑对区块链数据的读和写的操作。我们通过合约抽象对合约代码进行封装，这样方便在以太坊网络上执行合约函数。图9是拍卖方进行商品上架、查询商品数据时的合约的交互逻辑： 图9. 商品上架的合约交互逻辑 图中拍卖方往合约传输商品数据的执行过程就是一个写数据的过程，数据从合约那边返回的过程就是一个读数据的过程。为进一步展示合约被调用的过程，这里给出以太坊私有链客户端Ganache上商品上架时生成某个区块里的交易数据内容。 如图10所示，在商品上架时调用了eshop合约里的addProductToStore()函数传输商品数据的内容，将数据内容转成hash串放入区块，同时触发了NewProduct的合约事件，以便交给业务服务器做数据返回的处理。 图10. 交易区块内容详情