本文介绍了Sirrah,一个结合了机密计算和区块链的极简示范,利用受信执行环境(TEE)扩展智能合约的功能。文章详细阐述了TEE的工作原理,包括如何通过Solidity编程实现安全拍卖过程,并介绍了实施过程中的设计与技术细节。此项目展示了如何在保留可见性的同时,实现数据的机密性与安全性。
这篇文章介绍了Sirrah,一个使用可信执行环境(TEEs)扩展区块链的简约演示。我们将涵盖从头到尾的开发过程:从Gramine-SGX和普通的REVM开始,到最终的MEV-aware拍卖应用程序……以及一个你可以立即尝试的定时加密演示。
作者:Andrew Miller, Mateusz Morusiewicz, Frieder Paape。特别感谢Brock Smedley提供的Timelock Demo webapp,以及Hasu和Jonathan Passerat-Palmbach的编辑工作。
在我们这里,TEE协处理器是一个运行在普通区块链旁的系统,并通过TEE基础的安全计算扩展该区块链的智能合约环境。
在这篇文章结束时,我们实现的功能与Secret Network及其他基于TEE的智能合约(如Oasis、Phala、Obscuro)以及早期的研究论文(如Ekiden和State for the Stateless)类似。所有这些共享相同的高层设计:采用普通区块链,但使智能合约虚拟机运行在TEE内部。现在你有了某种保密性的智能合约系统。实际上,学术界和工业界有一篇知识系统化论文,包括20多种这种设计的变体。
然而,我们在智能合约中添加TEE的方法与所有这些相关项目不同。具体来说,我们的代码基更加简单,因为尽可能多的内容是在Solidity中实现的,并且我们附加到一个完全未修改的现存区块链上。
我们采用的设计方法是优化了可观察性。几乎所有代码都是用Solidity编写的。你会看到我们只修改了REVM crate中的一小段Rust代码,其余全是智能合约。我们希望尽可能使受信计算基于Solidity以促进可见性。实际上,这些预编译函数向Solidity开发者暴露了整个SGX框架,并提供本地私有存储和远程证明。
我们将要做的是添加一些额外的预编译函数来扩展普通的EVM。这些预编译函数实际上不会被底层区块链的验证者和客户端识别。它看起来就像一个包含一堆无用查看函数的合约,这些函数会失败。然而,这些预编译函数对运行SGX enclave的TEE节点是有意义的,称为Kettles……这些是确实执行“协处理器”系统计算的计算节点。
这篇文章的趣味回报将是编写一个优雅的应用演示,运行在协处理器上。在开始主要挑战构建协处理器之前,让我们先看看我们希望最终达成的编程模型。
在我们的应用中,智能合约实例将与一个公钥相关联,并且以明文形式在链上进行追踪:
bytes public xPub;
用户可以使用这个密钥为协处理器加密机密数据。我们在TEE协处理器中运行的应用方法需要能够访问相应的私钥以解密:
// 仅对离链的TEE协处理器可用函数 function xPriv() internal coprocessor returns(bytes32);
在普通EVM上运行时,xPriv()
会简单地回滚。但在TEE coprocessor
中运行时,它将返回适当的密钥。通过这些密钥,用户可以传输机密数据,以便只有应用程序能够从TEE协处理器中访问它们。
让我们介绍一下TEE协处理器解决的问题的促动示例。我们从使用Solidity编写的第二价格拍卖开始。投标可以在硬编码的截止时间之前提交。在截止时间过后,任何人都可以完成拍卖,基于所有可用的投标计算第二价格。简单吧?
contract LeakyAuction is AuctionBase {
mapping (address => uint) public balance; uint public constant auctionEndTime = /* 截止时间 */; uint public secondPrice; mapping (address => uint) public bids; address[] public bidders;
// 接受明文投标 event BidPlaced(address sender, uint bid); function submitBid(uint bid) public virtual { require(block.number <= auctionEndTime); require(bids[msg.sender] == 0); bids[msg.sender] = bid; bidders.push(msg.sender); emit BidPlaced(msg.sender, bid); }
// 完成拍卖并计算第二价格 event Concluded(uint secondPrice); function conclude() public { require(block.number > auctionEndTime); require(secondPrice == 0); // 计算第二价格 uint best = 0; for (uint i = 0; i < bidders.length; i++) { uint bid = bids[bidders[i]]; if (bid > best) { secondPrice = best; best = bid; } else if (bid > secondPrice) { secondPrice = bid; } } emit Concluded(secondPrice); }}
主要问题是交易前隐私。投标是明文的,因此“第二价格”这一环节完全不能抵御抢跑。最后出价的人可以影响结果价格,让赢家心烦。换句话说,第二价格拍卖中隐私的要点是防止虚假竞标……我们不希望拍卖师窥探赢家的出价并将价格提高到他们出价的$1以下。
现在,如果我们有一个TEE协处理器,我们可以扩展我们的智能合约以使用一些额外特性。客户端可以向xPub
公钥提交加密订单,而不是使用明文订单:
contract SealedBidAuction is AuctionBase, ... { ... mapping(address => bytes) encBids; function submitEncrypted(bytes memory ciphertext) public { require(block.number <= auctionEndTime); require(encBids[msg.sender].length == 0); encBids[msg.sender] = ciphertext; bidders.push(msg.sender); }}
在代码库中,我们包含一个示例加密函数,主要是为了使我们可以使用类似cast
的找到工具调用它。但不要困惑,这个函数的点是由客户端在本地评估。参数r
必须由客户端随机生成。
function encryptBid(uint bid, bytes32 r) public view returns(bytes memory ciphertext) { return PKE.encrypt(xPub, r, abi.encodePacked(bid)); }
为了完成我们的拍卖应用程序的草图,我们必须实现finalize()
例程。这个公共方法仅在TEE协处理器中运行,因此使用coprocessor
注解。协处理器解密每个加密的投标,并计算第二价格拍卖的结果。
function finalize() public coprocessor { require(block.number > auctionEndTime); uint secondPrice_; for (uint i = 0; i < ciphertexts.length; i++) { uint bid = PKE.decrypt(xPriv(), ciphertexts[i]); ... // 计算第二价格_ applyOnchain(secondPrice_) { secondPrice = secondPrice_; emit Concluded(secondPrice); }}
最奇妙的功能是applyOnchain
代码块。想法是协处理器中的finalize
方法会在链上最终更新拍卖的状态。我们将在几个方法中实现这一点。
我们已经看到了足够的协处理器编程模型,了解我们的目标。现在,让我们深入研究如何使用TEE实现这个目标。
以下是我们将采取的步骤概要,以实现上述描述的拍卖应用:
在enclave中运行REVM。基本实现是REVM的一个分支,可以在SGX enclave中运行。我们使用Gramine框架,但其他框架如Oclum或Fortanix也能很好地工作。我们将包含构建协处理器所需的一些额外的预编译函数。具体来说,我们需要生成和存储私钥xPriv
的能力。
在enclave中包含一个轻节点。我们必须确保TEE协处理器仅在与实际区块链状态相对应的有效环境中执行EVM。我们在Gramine中运行Helios轻客户端,并调整以处理权威证明(而不是权益证明)。
向Solidity添加远程证明。我们需要使用TEE的远程证明功能,以便我们的智能合约能够验证消息来自于TEE。为此,我们添加一个新的预编译,使Solidity代码能够生成远程证明。这有点像Gramine为Solidity提供的支持,因为我们直接向智能合约环境暴露一个相对低级的接口。生成证明需要SGX处理器,而验证证明则完全发生在链上。远程证明仅是一个证书链,验证器是用Solidity编写的。我们特别使用了Automata-V3-DCAP库,这是一个用于验证的开源Solidity库。
完成拍卖应用程序。我们将通过编写Solidity代码完成应用程序,以在TEE协处理器上完成解密,并将响应写入链上。
接下来,我们将更详细地讨论这些步骤。
TEE是一个隔离的进程环境。它是许多英特尔和AMD处理器支持的一个特性。基本上,它定义了一种新的进程类型,即enclave进程,运行在额外的隔离级别中。甚至操作系统内核或虚拟机监控器也无法检查或篡改enclave进程。这是使用TEE进行安全计算的基础。了解有关enclave的更多信息(a) (forum)
我们使用的最重要的TEE特性是远程证明。这意味着TEE可以生成由信任根(制造商,如英特尔)签名的证书链。你可以验证该证书,以检查一条特定消息是否确实是由TEE生成的。稍后我们将再讨论这一点。
Gramine是我们用来调整现有代码以在SGX enclave中运行的框架。它实际上做了两件事。第一件是它可以将所有依赖项的二进制文件打包成一个根哈希。具体来说,这是一个“清单文件”,有了Gramine,你基本上是指向它复制任何已经构建的依赖项和系统库。它伴随着Rust的示例。 从实际角度来看,这涉及到一个Gramine脚本,它遍历系统依赖项,锁定它们的版本和二进制哈希,类似于Cargo.lock所达到的效果。 理想情况下,我们会为整个堆栈提供可重复的构建,但目前的瓶颈是依赖于Gramine发布的“dockerhub”镜像,同时预先建立所有系统库。
Gramine的第二件事是提供libOS
。这意味着enclave中的每个系统调用都用Gramine定义替换,通常必须将控制权移交给不受信任的操作系统。稍后我们主要将使用Gramine通过文件系统提供的功能。
REVM很简单,因为没有太多依赖项。我们看到乔治奥斯(Georgios)的REVM在enclave中运行的简约示例,以及几封随后的推特线程。在我们能做任何有趣的事情之前,我们必须启用访问随机源。我们通过向我们的EVM分支中添加额外的操作码,称为“预编译函数”,来实现这一目的。
为了生成密钥,我们的协处理器需要在Solidity中执行以下操作:
function Suave.localRandom() internal coprocessor returns (bytes32);
扩展REVM以包含额外的预编译函数并不是很困难。以下是sgx_attest.rs中实施的一个摘录。请注意硬编码的地址(没有真正的约定,但我们应该尽量避免冲突)和硬编码的Gas费用。
pub const RANDOM: PrecompileWithAddress = PrecompileWithAddress( u64_to_address(0x40703), Precompile::Standard(sgxattest_random as StandardPrecompileFn),);fn sgxattest_random(input: &[u8], gas_limit: u64) -> PrecompileResult { let gas_used = 10000 as u64; if gas_used > gas_limit { return Err(Error::OutOfGas); } else { let mut file = std::fs::File::open("/dev/urandom").unwrap(); let mut buffer = [0; 32]; file.read(&mut buffer[..]).unwrap(); return Ok((gas_used, buffer.to_vec())) }}
我们还需要存储密钥,将其持久化在本地。
function Suave.volatileSet(bytes32 tag, bytes32 value) external coprocessor; function Suave.volatileGet(bytes32 tag) external coprocessor returns(bytes32);
为了做到这一点,我们可以直接使用静态引用变量包含Hashmap在RAM中。调用此预编译函数的合约的地址caller
用作域分隔符。通过这种方式,每个合约获取其在协处理器中的独立存储。我们将仅显示sgxattesta_volatile_set
的主要摘录。
fn sgxattest_volatile_set(input: &[u8], gas_limit: u64, env: &Env) -> PrecompileResult { ... let mut vol = volatile.lock().unwrap(); let domain_sep = env.msg.caller; let mut key : [u8;52] = [0; 52]; key[ 0..20].copy_from_slice(&domain_sep.0.0); key[20..52].copy_from_slice(&input[0..32]); let mut val: [u8; 32] = [0; 32]; val.copy_from_slice(&input[32..64]); vol.insert(key, val); return Ok((gas_used, vec![]))}
请注意,这意味着该预编译函数在协处理器上有一个副作用。尽管coprocessor
区块类似于“视图”,即不会对链上状态产生副作用,但它们仍然会修改协处理器的本地存储。这种挥发性存储是指在调用间持久存在,但仅限于此进程的生命周期。
我们公开的最后一种机制是密封密钥。这是持久密钥,即使TEE进程重新启动也会持续存在。密封的密钥将是相同的。它绑定到特定的CPU和特定的enclave。在我们的实现中,为每个调用者衍生出一个唯一的密封密钥。
确保TEE协处理器仅在与当前区块链状态对齐的有效上下文中执行EVM是十分重要的。这确保了执行的完整性,并防止潜在的攻击,例如水壶操作者试图通过修改此状态来提取机密数据。 虽然在SGX中运行一个完整节点是可行的,但它需要大量的存储,这与我们希望最小化TCB(受信任计算基地)的目标相矛盾。作为这种方法的替代,我们希望使用以太坊轻客户端协议的实现,以获得验证状态,同时只需较小的TCB占用和无需存储。 轻客户端不需要下载每个区块,而只下载区块头。这些头部包含有关区块内容的摘要信息。任何其他信息轻客户端需要的可以从一个完整节点请求。轻客户端可以独立地对它们所接收的数据进行验证,以与区块头中的状态根进行比较。
Helios如何为TEE协处理器提供有效状态? Helios是一个完全无信任、高效、便携的以太坊轻客户端,使用Rust编写,并且建立在REVM之上。它将不受信任的中心化RPC提供者转换为可验证安全的本地RPC。在SGX中使用Gramine运行Helios使我们能够通过RPC访问受信任的状态来源。 然而,我们希望进一步降低TCB,方法是将Helios嵌入为Kettle中的客户端库。在我们的实现中,执行层通过远程状态数据库向REVM提供状态信息。该数据库实现连接到Helios方法,以实时获取必要的执行状态并使用Merkle证明进行验证。 与Helios共识不同,Sirrah是为Clique权威证明共识协议而设计的,而不是权益证明协议。虽然执行层构建在Helios之上,但对于PoA,我们提供了一个简化的轻客户端共识层实现,消除了投票和签名者限制。这导致共识过程,我们对生成的PoA区块做出激进的假设,意味着只有区块签名会进行验证,并且每个验证者必须完全信任。在这种假设下,检查区块头历史没有增加价值。为了同步,我们只需从不受信任的RPC中获取最新的区块头。 虽然将Helios执行层验证方法导入到水壶中,以实时验证状态变得容易,但这也意味着我们仍然依赖于Helios的大部分部分,而这并不是在SGX中运行所必需的,即使用(异步)网络通信的所有代码。为了使这些代码在Gramine中工作,我们不得不启用“非安全的”eventfd系统,并切换到多线程执行。这样做可能会暴露额外的攻击面,这就是为什么在未来的版本中我们希望限制水壶对Helios的暴露仅限于验证逻辑,提供为每个事务预先获取的状态和验证证明。
我们已经使用enclave生成了解密密钥。我们如何确保我们拥有以这种方式生成的公钥?
这就是远程证明发挥作用的地方。
function Suave.attestSgx(bytes32 appData) external coprocessor returns (bytes memory att); function Suave.verifySgx(address caller, bytes32 appData, bytes memory att) public view returns (bool);
在TEE环境中运行时,它将输出一个证书att
,可以由对应的验证函数进行验证。
具体来说,如果使用地址addr
的合约调用Suave.attestSgx(appData)
,我们可以将其传递给Suave.verifySgx(addr, appData, att)
,它将通过……不过,只有通过在适当的SGX配置上运行相应的enclave进程,才能生成通过的证明。
我们基本上是在很低的级别向智能合约环境公开远程证明。我们设计的几乎唯一的限制是将调用者的智能合约地址用作域分隔符。这意味着合约只能生成在其自己的地址下验证的证明。通过这种方式,合约之间相互隔离,防止互相伪造证明。
所有新的预编译函数的实现均在不到200行的Rust代码中完成。
以下是远程证明预编译的完整实现:
fn sgxattest_run(input: &[u8], gas_limit: u64, env: &Env) -> PrecompileResult { let gas_used = 10000 as u64; if gas_used > gas_limit { return Err(Error::OutOfGas); } else { // 写入一些用户报告数据 let mut f = match File::create("/dev/attestation/user_report_data")?; // 用户报告数据 = Hash( Caller || Application input) let domain_sep = env.msg.caller; let message : &[u8] = ðers_core::abi::encode(&[Token::Address(H160(domain_sep.0.0)), Token::Bytes(input.to_vec())]); let hash = sha2::Sha256::digest(message).to_vec(); f.write_all(&hash)?; let quote = fs::read("/dev/attestation/quote")?; return Ok((gas_used, quote)) }}
这个示例使用Gramine,因此我们将在这里解释远程证明是如何工作的。在底层,这涉及使用扩展x86中的SGX操作码,以激活一个称为引用enclave的固定SGX进程,该进程检查我们的enclave并返回签名报告。Gramine通过方便的接口暴露这些:伪设备文件,具体为/dev/attestation/quote
和/dev/attestation/user_report_data
。从Gramine应用程序的角度来看,写入user_report_data
是我们设置应用程序定义数据的方式,而从/dev/attestation/quote
读取则提供结果。Fortanix提供库函数以实现类似的效果。
我们现在可以将这些组件组合在一起,并初始化合约,在Kettle中生成私钥。
function offchain_Bootstrap() public returns(bytes memory _xPub, bytes memory att) { bytes32 xPriv_ = Sirrah.localRandom(); _xPub = PKE.derivePubKey(xPriv_); Sirrah.volatileSet("xPriv", xPriv_); att = Sirrah.attestSgx("xPub", keccak256(_xPub)); }
在下一步中,我们必须在链上验证这一点。
到目前为止,我们已经描述了如何启动密钥并离链生成密钥。验证证明是接下来的任务。这不需要EVM的任何特殊内容,只需一些老派的Solidity编码。这是一个关于两个项目的(论坛帖子),来自Puffer Finance的RAVE和Automata-DCAP-v3-Attestation以演示其工作原理。这里还有一个竞赛,以说明EPID事务的验证如何工作。
// 我们做的主要事情是建立一个开发环境,将“验证”证明与创建它们隔离。基本上,我们运行一个网络服务,即按需验证证明,允许你将64字节用户数据配置为你想要的任何内容。基本上这是为验证者生成现实测试案例的方便方法,而无需实际运行自己的SGX节点。
以下是密钥管理器代码中用于安装公钥的摘录:
function onchain_Bootstrap(bytes memory _xPub, bytes memory att) public { require(xPub.length == 0); // 仅安装一次 Suave.verifySgx(address(this), keccak256(abi.encodePacked("xPub", _xPub)), att); xPub = _xPub; }
最后,我们可以完成拍卖应用。而实际上,这也不比我们所讨论的内容多。在此时,我们的合约有一个公钥,TEE协处理器本地保存其私钥。我们已经描述了用户可以如何基于公钥加密记录,并且我们已经定义了计算结果的函数。因此,我们的拍卖只需要一个额外的离链函数来解密结果,并将响应写入链上。
由于我们之前没有指定,对于密钥派生和解密,我们特定使用alt_bn128
椭圆曲线,EVM已通过ecMul
和ecAdd
预编译支持。
// 任何水壶调用以计算第二价格 function offline_Finalize() public returns (uint256 secondPrice_, bytes memory att) { require(block.number > auctionEndTime); bytes32 xPriv = xPriv();
// 解密每个投标并计算第二价格 uint256 best = 0; for (uint256 i = 0; i < bidders.length; i++) { bytes memory ciphertext = encBids[bidders[i]]; uint256 bid = abi.decode(PKE.decrypt(xPriv, ciphertext), (uint256)); if (bid > best) { secondPrice_ = best; best = bid; } else if (bid > secondPrice_) { secondPrice_ = bid; } }
// 使用密钥管理器进行证明 att = Suave.attestSgx(keccak256(abi.encodePacked("2ndprice", secondPrice_))); }
最后,这是验证拍卖结果的证明并存储结果的应用方法。
function onchain_Finalize(uint256 secondPrice_, bytes memory att) public { require(block.number > auctionEndTime); Suave.verifySgx(address(this), keccak256(abi.encodePacked("2ndprice", secondPrice_)), att); secondPrice = secondPrice_; emit Concluded(secondPrice);}
这结束了快速演示! 一个完整的通过TEE实现隐私的拍卖演示。
让我们统计一下代码行数:
SpeedrunAuction.sol
:139行
你能相信吗?这几乎是整个应用程序,包括启动拍卖逻辑本身。Andromeda.sol
:61行,仅用于围绕预编译“STATICCALL”的类型注释suave-andromeda-revm/src/precompiles/sgxattest.rs
185行,预编译函数实现的代码Encryption.sol
:87行,仅用于围绕alt_bn128库进行加密的包装DcapVerifier.sol
:32行,以适应automata(不包括Automata依赖项)suave-andromeda-revm/src/consensus.rs
128行以适应该测试网的PoS到PoAsuave-andromeda-revm/src/*.rs
:大约1000行,用于处理来自不受信任主机的RPC,在验证Merkle存储证明后,将存储从轻客户端传递到EVM执行环境。我们完成了MVP演示,但代码库中包含了一些额外的内容,演示我们在Solidity中为如此多系统做出的努力的“回报”。我们可以通过修改Solidity代码来改进密钥管理过程。基本上,我们提供一个模块,类似于Secret Network如何处理跨多个SGX计算节点的不同合约的密钥。它有以下功能: 一个密钥由一个单独的节点初始启动,但随后它与加入网络的其他SGX节点共享。 远程证明在链上很昂贵,因此我们仅在新节点注册时执行一次。来自该节点的后续“签名消息”可以只使用便宜的数字签名,链上的注册基本上将地址映射到以前收集的证明。 此外,许多应用程序可以共享相同的密钥分配。每个应用程序都获得访问自己强制推导密钥的权限,就像比特币钱包导出一样。 以下是高层次的描绘:
这个改进的密钥管理器仅作为一个起始点进行说明。下一个SUAVE里程碑将有更合适的设计。
我们没有详细讨论安全模型。首先我们可以说一下有关保密性的保证。我们还可以关注当SGX发生故障时的备份保证。最后,我们可以尝试限制人们的合作造成的损害。
我们还必须覆盖一些问题,例如密钥轮换,定义和实施对可接受mrenclaves的治理政策等等。 这可能听起来是一个艰巨的任务,但Solidity实际上对此涉及的一切都相当高效-验证证书以及表达/执行访问控制政策非常适合solidity。而EVM是一个相当便携的实现。此外,由于智能合约吸引审计人员的关注,这也是将关键代码放在审计人员会仔细查看的地方的好方法。
我们的威胁模型是一个分析导向的Kettle操作者,它运行除enclave之外的所有内容的修改版本,并试图从观察MEVM执行中泄漏尽可能多的alpha。我们提到我们示例的要点是保持投标密封。但在EVM执行过程中实际上还有其他什么被泄漏出来?
实际上,许多操作(例如SHA3)处理的数据量是根本可变的……这尤其是在读取的“内存”中操作了一种可变长度字符串。处理它的Gas费用也是对应的,Gas费用为30气+ 6气每字(向上取整)。我们可以遮蔽使用的气体计数器……但更重要的是实际数据的大小仅受交易的最大Gas参数限制。我们无法“填充”每个SHA3到其最大可能的大小。
另一个问题是访问模式泄漏。实际上,许多操作(例如SLOAD和SSTORE)引入潜在的危险。这是因为合约的总存储大小可能超过处理器本身的存储(例如,USDT代币上的“余额”映射大约有500万个账户。这是一个由仅有20字节地址和32字节余额组成的160兆字节映射)。这需要使用内存分页,而在SGX中,这仍然在不受信任的操作系统控制下。实际上,要了解SGX中这如何工作,你应该学习如何运行SGX-Step,例如一个专业的侧信道黑客是如何在分析工具中运行水壶的。
与其试图缓解这一点,目前我们将首先明确标记我们认为泄漏的内容。我们的方法如下:我们提供MEVM的扩展,提供“泄漏模型轨迹”,或“删除的调试轨迹”。这是通过REVM中的“检查器”抽象实现的。这是将“访问者”附加到每个操作码执行过程的便利方式。这个工作正在进行中。下面提供该输出样本:
...depth:1, PC:3513, gas:XXX(XXX), OPCODE: "SWAP1"(144) refund:XXX(XXX) Stack Size:6, Data size:96depth:1, PC:3514, gas:XXX(XXX), OPCODE: "SWAP2"(145) refund:XXX(XXX) Stack Size:6, Data size:96depth:1, PC:3515, gas:XXX(XXX), OPCODE: "AND"(22) refund:XXX(XXX) Stack Size:6, Data size:96depth:1, PC:3516, gas:XXX(XXX), OPCODE: "SWAP2"(145) refund:XXX(XXX) Stack Size:5, Data size:96depth:1, PC:3517, gas:XXX(XXX), OPCODE: "PUSH29"(124) refund:XXX(XXX) Stack Size:5, Data size:96...
你可以看到它提供了程序计数器和每个步骤正在执行的操作码的详细跟踪,以及部分删除/清理的堆栈和内存。当类似SHA3的操作码运行时,这表明了参数的长度!而每当发生MLOAD/MSTORE/SLOAD/SSTORE时,我们看到正在提取的密钥。
这个计划是,这代表了我们认为的保守估计,如果侧信道分析师能够充分利用SGX-Step,他们能够确定的内容。这是作为文档呈现的,类似于密码学家或精明的安全审计员所期望的形式,以泄漏函数的形式应用于任何MEVM运行的地方。
你可以在自己的forge环境中运行拍卖代码,或者如果你勇敢的话,部署自己的TEE。 但为了给大家提供一个大家可以立即玩的额外演示,这里有一个额外的定时加密应用。
这个应用受到了Oasis上的"Vigil.sol"应用的启发(这并非巧合,因为它很好地说明了相同的编程模型)。
基本上流程与拍卖相似,但不再是上传加密出价,而是将加密消息发布到与此Timelock.sol
智能合约相关联的公钥上。
该合约位于Rigil测试网上https://explorer.rigil.suave.flashbots.net/address/0x685816...26dDD6。
加密消息只有在加密消息在链上被时间戳且经过固定的持续时间后(大约一分钟)才能被TEE kettle解密。
你可以通过演示的前端Web应用尝试一下。
请注意,你需要一个像Metamask这样的web3提供者,并将其指向the Rigil testnet,并可能访问Rigil faucet。
- 原文链接: writings.flashbots.net/s...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!