PoET 1.0 Specification

简介

时间消逝证明(PoET)共识方法为拜占庭将军问题提供了一种解决方案,该方案利用“可信的执行环境”来提高现有解决方案(如工作证明PoW)的效率.最初发布到Hyperledger的PoET参考实现是为一个抽象的TEE编写的,以保持它对任何TEE实现的灵活性。本规范定义了SGX的具体实现。下面的演示假设使用Intel SGX作为可信的执行环境.

在高层次上,PoET随机选择单个对等节点,以给定的目标速率执行请求。个体节点对指数分布的随机变量进行抽样,然后等待由抽样决定的一段时间。抽样最小的节点赢得选举.通过使用可信的执行环境、身份验证和基于非对称密钥加密的黑名单,以及一组额外的选举策略,可以防止作弊.

为了有效地实现分布式共识,好的抽彩函数具有以下几个特点:

  • 公平:该函数应在尽可能广泛的参与者中分配领导者选举.
  • 投资:控制领导者选举过程的成本应与从中获得的价值成正比.
  • 验证:对于所有参与者来说,验证领导者是否被合法选择应该相对简单.

PoET是为实现这些目标而设计的,它使用了在消费者和企业处理器中广泛可用的新的安全CPU指令.PoET使用这些特性来确保领导者选举过程的安全性和随机性,而不需要在大多数“证明”算法中高昂能源花费和专门硬件投资.

Sawtooth包含一个模拟安全指令的实现.这将使社区更容易使用该软件,但同时也放弃了拜占庭式的容错能力.

PoET的基本工作如下:
1.每个验证节点都从enclave(可信函数)请求等待时间.
2.对于特定交易区块,等待时间最短的验证节点被选为leader.
3.一个函数(如“CreateTimer”)为交易区块创建一个计时器,该计时器保证由enclave创建.
4.另一个函数(如“CheckTimer”)验证计时器是由enclave创建的.如果计时器已经过期,该函数将创建一个证明,该证明可用于证实验证节点的确等待了分配的时间后才声明领导者角色.

PoET领导者选举算法符合良好抽彩算法的标准。它将领导者选举随机分布在所有验证节点中,其分布类似于其他彩票算法.选择的概率与所提供的资源成正比(在本例中,资源是具有可信执行环境的通用处理器).执行证明提供了用于验证证书是在enclave中创建的(和验证节点已经等待了分配的时间).此外,较低的参与成本增加了验证节点总数将会很大的可能性,提高了一致性算法的鲁棒性.

定义

以下术语在PoET spec中使用,并在此定义以供参考.

  • Enclave
    应用程序地址空间中的一个受保护区域,即使存在特权恶意软件,该区域也提供机密性和完整性.
    这个术语还可以用来指用特定代码和数据初始化的特定enclave.
  • Basename
    服务提供者的基本名称。在我们的文章中,服务提供者实体是分布式帐本网络.每个不同的网络都应该有自己的Basename和服务提供者ID(参见EPID和IAS说明).
  • EPID
    一个匿名证书系统.参见E. Brickell和Jiangtao Li:“来自双线性配对硬件认证的增强隐私ID”.IEEE International Conference on Social Computing / IEEE International Conference on Privacy, Security, Risk and Trust. 2010.
  • EPID Pseudonym
    在可链接引用中使用的SGX平台的假名.根据IAS API规范,它是IAS认证响应的一部分.它被计算为服务Basename(在我们的例子中是验证节点网络)和设备的EPID私钥的函数.
  • PPK,PSK
    由PoET Enclave创建的PoET ECC公钥和私钥.
  • IAS Report Key
    IAS公钥,用于签署当前IAS API指南中指定的认证报告.
  • PSEmanifest
    平台服务Enclave清单.这是SGX对enclave引用的一部分,enclave使用的平台服务包括可信时间和单调计数器.
  • AEP
    向IAS发送的验证有效负载(参见IAS API说明).包含引用的JSON编码、可选的PSEmanifest和可选的nonce.
  • AVR
    认证验证报告,对IAS引用认证请求的响应.通过IAS Report Key.它包含一个输入AEP的副本.
  • WaitCertId_n
    第n个或最近的WaitCertificate摘要.我们假设n>=0表示当前账本中的区块数.WaitCertId是等待证书内容的函数.例如WaitCertificate ECDSA签名的SHA256摘要.
  • OPK,OSK
    发起人ECDSA公钥和私钥.这些是验证节点用于签名消息的高级ECDSA密钥.
  • OPKhash
    OPK的SHA256摘要.
  • blockDigest
    验证节点想要提交的交易区块使用OSK的ECDSA签名SHA256摘要.
  • localMean
    估计本地平均等待时间.
  • MCID
    SGX单调计数器标识符.
  • SealKey
    SGX enclave密封密钥.它由SGX sgx_seal_data()sgx_unseal_data()函数使用.
  • PoetSealKey
    PoET SGX enclave密封密钥.它必须通过SGX SDK的sgx_get_key()函数获得,函数传递一个固定的32字节常量作为key_id参数.
  • PoET\_MRENCLAVE
    有效PoET SGX enclave的公共MRENCLAVE(参见SGX SDK文档)值.
  • T_{WT}
    WaitTimer秒级超时时间.验证节点最多只有TWT秒来使用WaitTimer,即在WaitTimer本身过期后在其上获得WaitCertificate.
  • K
    验证节点在注册新PPK之前可以提交的区块数.
  • c
    “注册延迟”,即验证节点在注册后必须等待的块数,才能开始参与选举.
  • minDuration
    WaitTimer的最少持续时间.

P2P PoET SGX Enclave Specifications

P2P PoET SGX enclave使用如下数据结构:

WaitTimer {
  double requestTime
  double duration
  byte[32] WaitCertId:sub:`n`
  double localMean
}

WaitCertificate {
  WaitTimer waitTimer
  byte[32] nonce
  byte[] blockDigest
}

它使用如下全局变量:

WaitTimer activeWT // 唯一的活动WaitTimer对象
byte[64] PPK
byte[64] PSK
MCID // SGX单调计数器标识符

它导出如下函数:
generateSignUpData(OPKhash)
Returns

byte[64]  PPK
byte[432] report // SGX报告数据结构
byte[256] PSEmanifest
byte[672] sealedSignUpData  // (PPK, PSK, MCID)元组使用Sealkey加密

Parameters

byte[32] OPKhash // OPK的SHA256摘要

描述
1.生成新的ECC密钥对(PPK, PSK)
2.创建单调计数器,并将其标识符保存为MCID
3.使用SGX sgx_seal_data()函数用SealKey(使用MRENCLAVE策略)加密(PPK, PSK, MCID) sealedSignupData=AES-GCM_{SealKey} (PPK | PSK | MCID)
4.创建SGX enclave report,在report_data字段中存储SHA256(OPKhash|PPK)
5.获得SGX PSE清单:PSEManifest
6.保存(PPK, PSK, MCID)作为enclave中的全局变量
7.将active WaitTimer实例activeWT设置为NULL
8.返回(PPK, report, PSEmanifest, sealedSignUpData)


!实现注意
通常情况下,可以创建的单调计数器的数量有上限。处理这种限制的一种方法是销毁以前创建的单调计数器,如果这不是第一次调用generateSignupData函数


unsealSignUpData(sealedSignUpData)
Returns

byte[64]  PPK

Parameters

byte[672] sealedSignUpData // (PPK, PSK, MCID)使用Sealkey加密后的数据 

描述
1.使用sgx_unseal_data()函数用SealKey(使用MRENCLAVE策略)将sealedSignUpData解密为(PPK、PSK、MCID)
2.保存(PPK, PSK, MCID)作为enclave中的全局变量
3.将全局active WaitTimer实例activeWT设置为NULL
4.返回PPK

createWaitTimer(localMean, WaitCertId_n)
Returns

WaitTimer waitTimer
byte[64] signature // waitTimer的ECDSA PSK签名

Parameters

double localMean // 估计本地平均等待时间
byte[32] WaitCertId_n // WaitCertificate拥有者ECDSA的SHA256摘要
                      // signature

描述
1.增加单调计数器MCID,在全局变量计数器中存储值
2.计算tag=AES-CMAC_{PoetSealKey} (WaitCertId_{n})
3.将最低的64位标签转换为双精度数字[0,1]:tagd
4.计算duration=minimumDuration-localMean*log(tagd)
5.设置requestTime等于SGX可信时间值
6.创建WaitTimer对象WaitTimer=WaitTimer(requestTime,duration,WaitCertId_{n},localMean)
7.使用PSK计算waitTimer的ECDSA签名:signature= ECDSA_ {PSK}(waitTimer)
8.设置全局active WaitTimer实例activeWT等于WaitTimer
9.返回(waitTimer,signature)

createWaitCertificate(blockDigest)
Returns

WaitCertificate waitCertificate
byte[64] signature // waitCertificate的ECDSA PSK签名

Parameters

byte[] blockDigest # 使用发起者私钥的ECDSA签名的SHA256
                   # 验证节点想要的交易区块的摘要
                   # 将要提交

描述
1.如果activeWT等于NULL,退出
2.读取单调计数器MCID,并将其值与全局变量值进行比较.如果值不匹配,退出
3.将SGX可信时间读入变量currentTime.如果当前时间小于waitTimer.requestTime + waitTimer.duration,退出(持续时间还没有过)
4.如果当前时间大于waitTimer.requestTime+waitTimer.duration+T_{WT},退出
5.生成随机的nonce
6.创建WaitCertificate对象WaitCertificate=WaitCertificate(waitTimer,nonce,blockDigest)
7.使用PSK计算waitCertificate的ECDSA签名:signature=ECDSA_ {PSK}(waitCertificate)
8.activeWT设置为NULL
9.返回(waitCertificate,signature)

注册阶段

参与者通过下载PoET SGX enclave和区块链的SPID证书作为验证节点进行连接.验证节点的客户端运行以下注册过程:

1.开始PoET SGX enclave: ENC
2.生成注册数据:(PPK,report,PSEmanifest,sealedSignUpData)=ENC.generateSignUpData(OPKhash)
报告体中的report_data(512位)字段包括(OPKhash | PPK)的SHA256摘要
3.询问SGX Quoting Enclave (QE),以获得报告上的可链接引用(使用验证器网络的Basename)
4.如果在IAS API中启用了Self Attestation:请求对可链接引用和PSE清单的认证到IAS.发送给IAS的AEP必须包含:

  • isvEnclaveQuote:base64编码的引用
  • pseManifest:base64编码的PSEmanifest
  • nonce:WaitCertId_{n}

IAS发回一个签名的AVR,其中包含输入AEP的副本和EPID假名
5.如果IAS API中启用了Self Attestation:向已知参与者广播自验证连接请求(OPK,PPK,AEP,AVR)
6.如果IAS API中没有启用Self Attestation:向已知参与者广播连接请求(OPK, PPK, quote, PSEmanifest)

在参与选举之前,验证节点必须等待c个区块在分布式帐本上发布.

验证节点的服务器端运行以下注册过程:

1.等待连接请求
2.在收到加入请求后,进行验证:

如果连接请求是自验证的(IAS API中启用了自验证):(OPK, PPK, AEP, AVR)
a.使用IAS报告密钥验证AVR的合法性并引用合法性
b.验证引用中的report_data字段包含(OPKhash | PPK)的
SHA256摘要
c.验证AVR中的nonce等于WaitCertId_{n},即最近提交的块的摘要.可能发送方还没有看到WaitCertId_{n},并且可能正在发送WaitCertId_{n'},n'<n.在这种情况下,应该敦促发送方通过附加新的块和重试来更新他/她看到的账本.接收验证节点也可能没有看到WaitCertId_{n},在这种情况下,他/她应该尝试更新他/她看到的账本并再次验证
d.验证引用中的MRENCLAVE值等于PoET_MRENCLAVE(允许存在多个值)
e.验证AVR中的PSE Manifest SHA256摘要等于AEP中PSEmanifest的SHA256摘要
f.验证引用中的basename等于分布式账本basename
g.验证引用中的属性字段具有允许的值(通常情况下,enclave必须处于初始化状态,而不是调试enclave)

如果连接请求没有自我验证(IAS API中没有启用自我验证):(OPK, PPK, quote, PSEmanifest)
a.创建含有引用和PSEmanifest的AEP:
  a.isvEnclaveQuote:base64编码引用
  b.pseManifest:base64编码的pseManifest
b.发送AEP到IAS.IAS发回一个签名的AVR
c.验证收到的AVR证明来确保引用和PSEmanifest的有效性并保存EPID假名
d.验证引用中的report_data字段包含(OPKhash | PPK)的SHA256摘要
e.验证引用中的MRENCLAVE值等于PoET_MRENCLAVE(允许存在多个值)
f.验证引用中的basename等于分布式账本basename
g.验证引用中的属性字段具有允许的值(通常情况下,enclave必须处于初始化状态,而不是调试enclave)

如果验证失败,退出.
如果验证成功,但引用中使用EPID假名标识的SGX平台已经注册,则忽略连接请求,退出.
如果验证成功:
a.将新参与者的注册证书(OPK, EPID 假名, PPK, current WaitCertId_{n})传递给上层,以便在端点注册中心注册
b.转到1

选举阶段

假设最近一个有效块的标识符是WaitCertId_{n}.广播消息由验证节点与其PPK签名.为了参与选举阶段,验证节点在客户端运行以下程序:
1.启动诗PoET SGX enclave: ENC
2.从磁盘读取sealedSignUpData,并将其加载到enclave: ENC.unsealSignUpData(sealedSignUpData)
3.调用(waitTimer,signature)=ENC.createWaitTimer(localMean4,WaitCertId_{n})
4.等待waitTimer.duration秒
5.调用(waitCertificate,signature)=ENC.createWaitCertificate(blockDigest)
6.如果createWaitCertificate()调用成功,广播(waitCertificate, signature, block, OPK, PPK),其中区块是由blockDigest标识的交易区块

在服务器端,验证器等待传入元组(waitCertificate, signature, block, OPK, PPK).当收到时进行以下有效性检查:
1.通过检查端点注册中心来验证PPK和OPK属于注册验证节点
2.使用发送方的PPK验证签名是否有效
3.通过检查端点注册中心来验证发送方提交的PPK少于K个区块(否则发送方需要重新签名)
4.通过与本地计算的localMean进行比较验证waitCertificate.waitTimer.localMean是正确的
5.使用OPK验证waitCertificate.blockDigest是一个有效的ECDSA签名的SHA256块散列
6.根据预期分布验证发送方已经赢得选举的频率(请参阅z-test文档)
7.验证发送方至少在c个提交区块之前注册,即满足c块启动延迟

一个有效的waitCertificate被传递给上层的账本层,拥有最小waitCertificate. waitTimer.duration的waitCertificate决定了选举的获胜者.

撤销

有两种机制可以将EPID Key被IAS撤销的验证节点列入黑名单.第一是验证节点定期地影响每个验证节点,尽管这种影响并不频繁.第二是异步撤销检查,每个验证节点可以在任何时候对其他验证节点的EPID Key执行.

1.周期性再生的PPK
如果验证节点的EPID Key被IAS撤销,那么它将无法获得任何有效的AVR,因此无法注册.强制验证节点定期使用新注册证书重新签名,会使其EPID Key被撤销的验证器退出系统.验证节点必须在提交K块后重新签名,如果没有,则被认为是被撤销的.
2.异步注册引用验证
验证节点可以(在任何时候)要求IAS对另一个验证节点注册的引用进行认证,以检查他/她的EPID Key是否已经被撤销.如果是这样,返回的AVR将指示key被撤销.从IAS获得AVR的验证节点可以在黑名单事务中传播它,以便所有验证节点都可以检查AVR的准确性并继续黑名单.为了限制使用黑名单交易来阻止恶意验证节点的活性,我们可以通过不同方式控制它们提交的速率:

  • 需要烧掉一定数量的参与令牌才能提交黑名单事务
  • 验证节点只能在赢得一次或多次选举后提交黑名单事务
  • 提交一定数量的非合法黑名单交易的验证节点被列入黑名单

安全考量

1.T_{WT}激励:
验证器最多只有T_{WT}秒来使用WaitTimer,即在WaitTimer本身过期后在其上获得WaitCertificate.强制执行此约束,以避免在一段时间内没有交易构建块的情况下,几个验证节点在等待WaitTimers的持续时间后可能会暂停,并且只在有足够的交易可用时才生成WaitCertificate.这时,他们都将发出他们的等待证书,这会产生大量的流量,可能还会导致分叉.设置timeout缓解了这个问题.

2.Enclave危险:
一个能够任意赢得选举的危险的SGX平台不能影响系统的正确性,但可以通过发布无效交易来阻碍进展.通过限制验证节点(由其PPK确定)在给定时间内赢得选举的频率,可以减轻这个问题(请参阅z-test文档).

3.WaitTimer持续时间操作:
a.在注册后设置c块参与延迟,可以防止验证器生成不同的OPK、PPK对,并选择下一个WaitTimer持续时间的最小值,如下所示:

  •   a.产生尽可能多的PPK,PSK对和单调计数器.
  •   b.不要注册,而是使用所有的enclave(每个enclave使用不同的PPK、PSK和MCID)在每次提交新块时创建一个WaitTimer,直到获得非常低的持续时间(赢得选举的好机会).然后收集所有不同的等待证书.
  •   c.要求每个enclave创建下一个waitTimer,其持续时间取决于每个不同的胜出waitCertIds.选择enclave的PPK,给出最低的下一个持续时间,然后使用它注册.
  •   d.因此,攻击者可以在第一次选举中获胜(概率很高),并可以链接以上三个步骤,以获得一个很好的机会,赢得多次选举连续.

b.WaitCertificate中的nonce字段被设置为一个随机值,以便验证节点不能控制结果WaitCertId_{n}.在选举中获胜的验证节点可以尝试不同的blockDigest输入值来创建WaitCertificate,并广播WaitCertificate,它的WaitCertId_{n}导致下一个WaitTimer持续时间最小.
c.在选举阶段(客户端)的步骤1中的调用createWaitTimer()由PoET enclave的内部状态绑定到对createWaitCertificate()的后续调用.更准确地说,在调用createWaitCertificate()(并且持续时间已经过去)之后,只允许对createWaitCertificate()进行一次调用,因为全局active WaitTimer对象activeWT的值在createWaitCertificate()的末尾设置为null,以便后续调用失败.因此,只能将一个交易块(由输入参数blockDigest标识)附加到WaitCertificate对象.这可以防止恶意用户在每次不重新创建WaitTimer(并等待其持续时间)的情况下创建多个WaitCertificates(每个waitcertificate都具有不同的nonce),从而产生不同的WaitCertId摘要.因此,只要WaitTimer的持续时间不太小,那么在当前选举中获胜的恶意验证节点对其下一个WaitTimer持续时间的控制就非常有限.
d.对单调计数器值的检查确保只有一个enclave实例在WaitTimer持续时间过期之后能获得WaitCertificate.这再次防止恶意用户运行enclave的多个实例以创建多个WaitCertificates(每个都具有不同的nonce),从而产生不同的WaitCertId摘要并选择一个会导致新WaitTimer持续时间最低的值的证书.
e.在生成PPK和PSK的同时创建一个带有id MCID的单调计数器,并使用带有封印密钥的AES-GCM对三重(MCID、PPK、PSK)进行加密,并保存在永久存储中.恶意验证器不能运行多个enclave实例(在注册之前)来创建多个单调计数器,而最终必须仅使用一个计数器.由于单调计数器与PPK绑定在一起,PSK通过带有封印密钥的AES-GCM加密,当验证器与PPK注册时,它自动提交使用与PPK、PSK一起创建的单调计数器.

4.注册AEP重播:
在AEP中使用nonce字段(设置为WaitCertId_{n})来防止旧AEPs的重播.

对多用户或多账本SGX Enclave服务的注释

通过将用户名和账本名作为输入参数输入到generateSignUpData()unsealSignUpData()中,可以为多个用户或总账使用相同的enclave。然后将注册元组(username, ledgername, PPK, PSK, MCID)密封到磁盘上,并使用用户名和账本名生成文件名.任何时候,只要用户对服务进行身份验证,后者就可以打开enclave并使用对应于该用户(和账本)的文件中的注册元组.

数目规模和局部平均计算

Parameters:
1.targetWaitTime:期望的平均等待时间.这取决于网络直径,并被选择以达最小化碰撞的概率.
2.initialWaitTime:引导阶段使用的初始等待时间,直到账本包含sampleLength块.
3.sampleLength:需要在账本上完成引导阶段并进入稳定阶段的块数.
4.minimumWaitTime:等待时间的下限。

人口规模计算方法如下:
1.sm=0
2.sw=0
3.foreach存储在账本上的等待证书wc
sw=sw+wc.waitTimer.duration-minimumWaitTime
sm=sm+wc.waitTimer.localMean
4.populationSize=sm/sw

假设b是当前存储在账本上的块数,则局部均值计算如下:
1.若b<sampleLength,则r=1.0·b/sampleLength
localMean=targetWaitTime·(1-r^2)+initialWaitTime·r^2
2.否则localMean=targetWaitTime·populationSize

z-test

z检验用于检验验证器以高于预期的平均率赢得选举的假设.
parameters:
1.zmax:测试值,测量与期望平均值的偏差。选择以便获得所需的置信区间\alpha.示例配置是:
a.ztest=1.645<->\alpha=0.05
b.ztest=2.325 ->\alpha=0.01
c.ztest=2.575 ->\alpha=0.005
d.ztest=3.075 ->\alpha=0.001
2.testIdentifier:测试中的验证节点标识符
3.blockArray:一个数组,其中包含验证节点标识和估计的规模大小(id,populationEstimate).每一对代表一个已发布的交易区块
4.minObserved:测试标识符需要观察的最少胜选次数

z-test如下计算:

observed = expected = blockCount = 0
foreach b = (id, populationEstimate) in blockArray:
    blockCount += 1
    expected += 1 / populationEstimate

    if id is equal to testIdentifier:
        observed += 1
        if observed > minObserved and observed > expected:
            p = expected / blockCount
            σ = sqrt(blockCount * p * (1.0 - p))
            z = (observed - expected) / σ
            if z > zmax:
                return False
return True

如果z-test失败(返回False),那么测试中的验证节点将以高于预期的平均率赢得选举.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容