grin中pow算法-cuckoo cycle的lean算法简单分析

最近实习,接触了一个比较新颖的工作量证明算法:cuckoo-cycle,基本原理是在一个极大二分图中找到一个长度为proofsize的回路。

源码在这:https://github.com/tromp/cuckoo

算法介绍在网上也有:https://www.zuocoin.com/a/news/experience/2019/0401/32897.html

1.二分图的生成

这是一个基于图的pow算法,当然需要生成一个初始化二分图,cuckoo中使用siphash函数来生成一条边,通过随机数nonce,密钥对sipkeys,奇偶参数uorv来生成一条连接一个连接两个节点的边<odd, even>,这里每个边是连接一个奇数节点和一个偶数节点。

通过nonce从0枚举到NEDGES - 1,生成NEDGES个边。

2.剪枝

很简单,如果节点是环路中的一部分,那么它的度数必为2以上,那么度数为0和1的节点就可以进行剪枝。

3.图的搜索

生成二分图,其实可以发现,在sipkeys和nonce已知的情况下,可以默认二分图已经生成,我们只需要遍历即可。

4.寻找环路

如果发现新的edge加入后形成了一个环路,那么使用一个set<unode, vnode>来存储环路,一个递归寻找路径过程。

以上就是算法主要步骤。

讲讲算法细节吧。

我负责的是cuckoo中一个分支算法lean,使用cpu和内存来存储图的,做了一些多线程和压缩存储。

1.多线程:

lean中引入多线程来进行trim过程,每个线程负责一个block,每个block有64条边信息。

2.twice_set

twice_set使用了一个bitmap来进行压缩存储。之前说了,剪枝需要减去的是degree = 0/1的节点,degree > 1的节点可以不剪,那么通过degree把节点分为三种状态:0、1、>1,那么三种状态,可以使用2bit来表示,其中>1状态论文有说恒定为2。

根据高位是否为0来很快判断这个节点是否需要剪枝了。

那么这样子是不是就把节点存储大小压缩到了2 * NNODES bits了呢?

答案是No。

我们来看twice_set的大小:

上面默认PART_BITS = 0,atwice = uint32,可以看到ONCE_BITS大小为NEDGES >> PART_BITS,默认情况下等于NEDGES,那么TWICE_BITS = 2 * ONCE_BITS = NNODES  != 2 * NNODES。

因为这里在bitmap的基础上,进行奇偶复用

之前说了每个edge和node通过sipnode函数生成,也代表了edge和node有着映射关系:

只需要调整uorv参数,就可以得到一个边对应的两个节点,一个为奇一个为偶,并且每轮剪枝都是一轮奇一轮偶进行的,那么可以肯定同一个边的两个节点在一次剪枝中不会重复出现,每一轮剪枝存储该边对应的奇/偶节点,那么也就不难理解ONCE_BITS大小为什么是NEDGES >> PART_BITS了。 

3.shrinkingset 

同样也是使用bitmap来进行压缩存储,0/1代表这个边是否为叶节点的边,每个bit为0代表alive(非叶节点边),1代表non-alive(叶节点边)。这里使用的是一个uint64数组,上文多线程提到的block大小为64bit,也就是代表这个数组,一个block代表一个数组元素。

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页