Rework builder & sampler (#697)
* add proof initializer for poseidon2 and `$` * fix padding and block selection * fix sample selection and input construction * fix sample selection & more descriptive names * add concrete types for sampler & builder * add missing digest calls * use concrete types * add sample test fixtures * use concrete types and don't fetch dummy blocks
This commit is contained in:
parent
afec86b3cf
commit
825766eea0
|
@ -7,16 +7,14 @@
|
||||||
## This file may not be copied, modified, or distributed except according to
|
## This file may not be copied, modified, or distributed except according to
|
||||||
## those terms.
|
## those terms.
|
||||||
|
|
||||||
import pkg/upraises
|
{.push raises: [].}
|
||||||
|
|
||||||
push: {.upraises: [].}
|
|
||||||
|
|
||||||
import std/bitops
|
import std/bitops
|
||||||
import std/sequtils
|
import std/sequtils
|
||||||
|
|
||||||
import pkg/questionable
|
import pkg/questionable
|
||||||
import pkg/questionable/results
|
import pkg/questionable/results
|
||||||
import pkg/libp2p/[cid, multicodec, multihash]
|
import pkg/libp2p/[cid, multicodec, multihash]
|
||||||
import pkg/stew/byteutils
|
|
||||||
|
|
||||||
import ../../utils
|
import ../../utils
|
||||||
import ../../rng
|
import ../../rng
|
||||||
|
@ -72,7 +70,7 @@ func getProof*(self: CodexTree, index: int): ?!CodexProof =
|
||||||
|
|
||||||
success proof
|
success proof
|
||||||
|
|
||||||
func verify*(self: CodexProof, leaf: MultiHash, root: MultiHash): ?!void =
|
func verify*(self: CodexProof, leaf: MultiHash, root: MultiHash): ?!bool =
|
||||||
## Verify hash
|
## Verify hash
|
||||||
##
|
##
|
||||||
|
|
||||||
|
@ -88,11 +86,9 @@ func verify*(self: CodexProof, leaf: MultiHash, root: MultiHash): ?!void =
|
||||||
leafBytes.len != leaf.size:
|
leafBytes.len != leaf.size:
|
||||||
return failure "Invalid hash length"
|
return failure "Invalid hash length"
|
||||||
|
|
||||||
? self.verify(leafBytes, rootBytes)
|
self.verify(leafBytes, rootBytes)
|
||||||
|
|
||||||
success()
|
func verify*(self: CodexProof, leaf: Cid, root: Cid): ?!bool =
|
||||||
|
|
||||||
func verify*(self: CodexProof, leaf: Cid, root: Cid): ?!void =
|
|
||||||
self.verify(? leaf.mhash.mapFailure, ? leaf.mhash.mapFailure)
|
self.verify(? leaf.mhash.mapFailure, ? leaf.mhash.mapFailure)
|
||||||
|
|
||||||
proc rootCid*(
|
proc rootCid*(
|
||||||
|
@ -124,16 +120,19 @@ func getLeafCid*(
|
||||||
Cid.init(version, dataCodec, mhash).mapFailure
|
Cid.init(version, dataCodec, mhash).mapFailure
|
||||||
|
|
||||||
proc `$`*(self: CodexTree): string =
|
proc `$`*(self: CodexTree): string =
|
||||||
"CodexTree( mcodec: " &
|
let root = if self.root.isOk: byteutils.toHex(self.root.get) else: "none"
|
||||||
$self.mcodec &
|
"CodexTree(" &
|
||||||
", leavesCount: " &
|
" root: " & root &
|
||||||
$self.leavesCount & " )"
|
", leavesCount: " & $self.leavesCount &
|
||||||
|
", levels: " & $self.levels &
|
||||||
|
", mcodec: " & $self.mcodec & " )"
|
||||||
|
|
||||||
proc `$`*(self: CodexProof): string =
|
proc `$`*(self: CodexProof): string =
|
||||||
"CodexProof( mcodec: " &
|
"CodexProof(" &
|
||||||
$self.mcodec & ", nleaves: " &
|
" nleaves: " & $self.nleaves &
|
||||||
$self.nleaves & ", index: " &
|
", index: " & $self.index &
|
||||||
$self.index & " )"
|
", path: " & $self.path.mapIt( byteutils.toHex(it) ) &
|
||||||
|
", mcodec: " & $self.mcodec & " )"
|
||||||
|
|
||||||
func compress*(
|
func compress*(
|
||||||
x, y: openArray[byte],
|
x, y: openArray[byte],
|
||||||
|
@ -226,7 +225,9 @@ proc fromNodes*(
|
||||||
index = Rng.instance.rand(nleaves - 1)
|
index = Rng.instance.rand(nleaves - 1)
|
||||||
proof = ? self.getProof(index)
|
proof = ? self.getProof(index)
|
||||||
|
|
||||||
? proof.verify(self.leaves[index], ? self.root) # sanity check
|
if not ? proof.verify(self.leaves[index], ? self.root): # sanity check
|
||||||
|
return failure "Unable to verify tree built from nodes"
|
||||||
|
|
||||||
success self
|
success self
|
||||||
|
|
||||||
func init*(
|
func init*(
|
||||||
|
|
|
@ -117,11 +117,8 @@ func reconstructRoot*[H, K](proof: MerkleProof[H, K], leaf: H): ?!H =
|
||||||
|
|
||||||
return success h
|
return success h
|
||||||
|
|
||||||
func verify*[H, K](proof: MerkleProof[H, K], leaf: H, root: H): ?!void =
|
func verify*[H, K](proof: MerkleProof[H, K], leaf: H, root: H): ?!bool =
|
||||||
return if bool(root == ? proof.reconstructRoot(leaf)):
|
success bool(root == ? proof.reconstructRoot(leaf))
|
||||||
success()
|
|
||||||
else:
|
|
||||||
failure("invalid proof")
|
|
||||||
|
|
||||||
func merkleTreeWorker*[H, K](
|
func merkleTreeWorker*[H, K](
|
||||||
self: MerkleTree[H, K],
|
self: MerkleTree[H, K],
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
## This file may not be copied, modified, or distributed except according to
|
## This file may not be copied, modified, or distributed except according to
|
||||||
## those terms.
|
## those terms.
|
||||||
|
|
||||||
|
{.push raises: [].}
|
||||||
|
|
||||||
import std/sequtils
|
import std/sequtils
|
||||||
|
|
||||||
import pkg/poseidon2
|
import pkg/poseidon2
|
||||||
|
@ -30,7 +32,8 @@ const
|
||||||
Poseidon2Zero* = zero
|
Poseidon2Zero* = zero
|
||||||
|
|
||||||
type
|
type
|
||||||
Poseidon2Hash* = F
|
Bn254Fr* = F
|
||||||
|
Poseidon2Hash* = Bn254Fr
|
||||||
|
|
||||||
PoseidonKeysEnum* = enum # can't use non-ordinals as enum values
|
PoseidonKeysEnum* = enum # can't use non-ordinals as enum values
|
||||||
KeyNone
|
KeyNone
|
||||||
|
@ -41,6 +44,19 @@ type
|
||||||
Poseidon2Tree* = MerkleTree[Poseidon2Hash, PoseidonKeysEnum]
|
Poseidon2Tree* = MerkleTree[Poseidon2Hash, PoseidonKeysEnum]
|
||||||
Poseidon2Proof* = MerkleProof[Poseidon2Hash, PoseidonKeysEnum]
|
Poseidon2Proof* = MerkleProof[Poseidon2Hash, PoseidonKeysEnum]
|
||||||
|
|
||||||
|
proc `$`*(self: Poseidon2Tree): string =
|
||||||
|
let root = if self.root.isOk: self.root.get.toHex else: "none"
|
||||||
|
"Poseidon2Tree(" &
|
||||||
|
" root: " & root &
|
||||||
|
", leavesCount: " & $self.leavesCount &
|
||||||
|
", levels: " & $self.levels & " )"
|
||||||
|
|
||||||
|
proc `$`*(self: Poseidon2Proof): string =
|
||||||
|
"Poseidon2Proof(" &
|
||||||
|
" nleaves: " & $self.nleaves &
|
||||||
|
", index: " & $self.index &
|
||||||
|
", path: " & $self.path.mapIt( it.toHex ) & " )"
|
||||||
|
|
||||||
func toArray32*(bytes: openArray[byte]): array[32, byte] =
|
func toArray32*(bytes: openArray[byte]): array[32, byte] =
|
||||||
result[0..<bytes.len] = bytes[0..<bytes.len]
|
result[0..<bytes.len] = bytes[0..<bytes.len]
|
||||||
|
|
||||||
|
@ -104,6 +120,29 @@ proc fromNodes*(
|
||||||
index = Rng.instance.rand(nleaves - 1)
|
index = Rng.instance.rand(nleaves - 1)
|
||||||
proof = ? self.getProof(index)
|
proof = ? self.getProof(index)
|
||||||
|
|
||||||
? proof.verify(self.leaves[index], ? self.root) # sanity check
|
if not ? proof.verify(self.leaves[index], ? self.root): # sanity check
|
||||||
|
return failure "Unable to verify tree built from nodes"
|
||||||
|
|
||||||
success self
|
success self
|
||||||
|
|
||||||
|
func init*(
|
||||||
|
_: type Poseidon2Proof,
|
||||||
|
index: int,
|
||||||
|
nleaves: int,
|
||||||
|
nodes: openArray[Poseidon2Hash]): ?!Poseidon2Proof =
|
||||||
|
|
||||||
|
if nodes.len == 0:
|
||||||
|
return failure "Empty nodes"
|
||||||
|
|
||||||
|
let
|
||||||
|
compressor = proc(
|
||||||
|
x, y: Poseidon2Hash,
|
||||||
|
key: PoseidonKeysEnum): ?!Poseidon2Hash {.noSideEffect.} =
|
||||||
|
success compress( x, y, key.toKey )
|
||||||
|
|
||||||
|
success Poseidon2Proof(
|
||||||
|
compress: compressor,
|
||||||
|
zero: Poseidon2Zero,
|
||||||
|
index: index,
|
||||||
|
nleaves: nleaves,
|
||||||
|
path: @nodes)
|
||||||
|
|
|
@ -38,9 +38,11 @@ import ./streams
|
||||||
import ./erasure
|
import ./erasure
|
||||||
import ./discovery
|
import ./discovery
|
||||||
import ./contracts
|
import ./contracts
|
||||||
|
import ./indexingstrategy
|
||||||
import ./utils
|
import ./utils
|
||||||
import ./errors
|
import ./errors
|
||||||
import ./logutils
|
import ./logutils
|
||||||
|
import ./utils/poseidon2digest
|
||||||
|
|
||||||
export logutils
|
export logutils
|
||||||
|
|
||||||
|
@ -390,7 +392,7 @@ proc setupRequest(
|
||||||
trace "Unable to erasure code dataset"
|
trace "Unable to erasure code dataset"
|
||||||
return failure(error)
|
return failure(error)
|
||||||
|
|
||||||
without builder =? SlotsBuilder.new(self.blockStore, encoded), err:
|
without builder =? Poseidon2Builder.new(self.blockStore, encoded), err:
|
||||||
trace "Unable to create slot builder"
|
trace "Unable to create slot builder"
|
||||||
return failure(err)
|
return failure(err)
|
||||||
|
|
||||||
|
@ -503,7 +505,7 @@ proc onStore(
|
||||||
trace "Unable to fetch manifest for cid", cid, err = err.msg
|
trace "Unable to fetch manifest for cid", cid, err = err.msg
|
||||||
return failure(err)
|
return failure(err)
|
||||||
|
|
||||||
without builder =? SlotsBuilder.new(self.blockStore, manifest), err:
|
without builder =? Poseidon2Builder.new(self.blockStore, manifest), err:
|
||||||
trace "Unable to create slots builder", err = err.msg
|
trace "Unable to create slots builder", err = err.msg
|
||||||
return failure(err)
|
return failure(err)
|
||||||
|
|
||||||
|
@ -528,8 +530,13 @@ proc onStore(
|
||||||
|
|
||||||
return success()
|
return success()
|
||||||
|
|
||||||
if blksIter =? builder.slotIndiciesIter(slotIdx) and
|
without indexer =? manifest.protectedStrategy.init(
|
||||||
err =? (await self.fetchBatched(
|
0, manifest.blocksCount() - 1, manifest.numSlots).catch and
|
||||||
|
blksIter =? indexer.getIndicies(slotIdx).catch, err:
|
||||||
|
trace "Unable to create indexing strategy from protected manifest", err = err.msg
|
||||||
|
return failure(err)
|
||||||
|
|
||||||
|
if err =? (await self.fetchBatched(
|
||||||
manifest.treeCid,
|
manifest.treeCid,
|
||||||
blksIter,
|
blksIter,
|
||||||
onBatch = updateExpiry)).errorOption:
|
onBatch = updateExpiry)).errorOption:
|
||||||
|
@ -572,7 +579,7 @@ proc onProve(
|
||||||
error "Unable to fetch manifest for cid", err = err.msg
|
error "Unable to fetch manifest for cid", err = err.msg
|
||||||
return failure(err)
|
return failure(err)
|
||||||
|
|
||||||
without builder =? SlotsBuilder.new(self.blockStore, manifest), err:
|
without builder =? Poseidon2Builder.new(self.blockStore, manifest), err:
|
||||||
error "Unable to create slots builder", err = err.msg
|
error "Unable to create slots builder", err = err.msg
|
||||||
return failure(err)
|
return failure(err)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
import ./builder/builder
|
import ./builder/builder
|
||||||
import ./converters
|
import ./converters
|
||||||
|
|
||||||
|
import ../merkletree
|
||||||
|
|
||||||
export builder, converters
|
export builder, converters
|
||||||
|
|
||||||
|
type
|
||||||
|
Poseidon2Builder* = SlotsBuilder[Poseidon2Tree, Poseidon2Hash]
|
||||||
|
|
|
@ -15,192 +15,165 @@ import std/sugar
|
||||||
|
|
||||||
import pkg/libp2p
|
import pkg/libp2p
|
||||||
import pkg/chronos
|
import pkg/chronos
|
||||||
|
import pkg/chronicles
|
||||||
import pkg/questionable
|
import pkg/questionable
|
||||||
import pkg/questionable/results
|
import pkg/questionable/results
|
||||||
import pkg/poseidon2
|
import pkg/constantine/math/io/io_fields
|
||||||
import pkg/poseidon2/io
|
|
||||||
import pkg/constantine/math/arithmetic/finite_fields
|
|
||||||
|
|
||||||
import ../../logutils
|
import ../../utils
|
||||||
import ../../indexingstrategy
|
|
||||||
import ../../merkletree
|
|
||||||
import ../../stores
|
import ../../stores
|
||||||
import ../../manifest
|
import ../../manifest
|
||||||
import ../../utils
|
import ../../merkletree
|
||||||
import ../../utils/asynciter
|
|
||||||
import ../../utils/digest
|
import ../../utils/digest
|
||||||
import ../../utils/poseidon2digest
|
import ../../utils/asynciter
|
||||||
|
import ../../indexingstrategy
|
||||||
|
|
||||||
import ../converters
|
import ../converters
|
||||||
|
|
||||||
export converters
|
export converters, asynciter
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "codex slotsbuilder"
|
topics = "codex slotsbuilder"
|
||||||
|
|
||||||
const
|
|
||||||
# TODO: Unified with the DefaultCellSize specified in branch "data-sampler"
|
|
||||||
# in the proving circuit.
|
|
||||||
|
|
||||||
DefaultEmptyBlock* = newSeq[byte](DefaultBlockSize.int)
|
|
||||||
DefaultEmptyCell* = newSeq[byte](DefaultCellSize.int)
|
|
||||||
|
|
||||||
type
|
type
|
||||||
# TODO: should be a generic type that
|
SlotsBuilder*[T, H] = ref object of RootObj
|
||||||
# supports all merkle trees
|
|
||||||
SlotsBuilder* = ref object of RootObj
|
|
||||||
store: BlockStore
|
store: BlockStore
|
||||||
manifest: Manifest
|
manifest: Manifest # current manifest
|
||||||
strategy: IndexingStrategy
|
strategy: IndexingStrategy # indexing strategy
|
||||||
cellSize: NBytes
|
cellSize: NBytes # cell size
|
||||||
emptyDigestTree: Poseidon2Tree
|
numSlotBlocks: Natural # number of blocks per slot (should yield a power of two number of cells)
|
||||||
blockPadBytes: seq[byte]
|
slotRoots: seq[H] # roots of the slots
|
||||||
slotsPadLeafs: seq[Poseidon2Hash]
|
emptyBlock: seq[byte] # empty block
|
||||||
rootsPadLeafs: seq[Poseidon2Hash]
|
verifiableTree: ?T # verification tree (dataset tree)
|
||||||
slotRoots: seq[Poseidon2Hash]
|
emptyDigestTree: T # empty digest tree for empty blocks
|
||||||
verifyTree: ?Poseidon2Tree
|
|
||||||
|
|
||||||
func slotRoots*(self: SlotsBuilder): seq[Poseidon2Hash] {.inline.} =
|
func verifiable*[T, H](self: SlotsBuilder[T, H]): bool {.inline.} =
|
||||||
|
## Returns true if the slots are verifiable.
|
||||||
|
##
|
||||||
|
|
||||||
|
self.manifest.verifiable
|
||||||
|
|
||||||
|
func slotRoots*[T, H](self: SlotsBuilder[T, H]): seq[H] {.inline.} =
|
||||||
## Returns the slot roots.
|
## Returns the slot roots.
|
||||||
##
|
##
|
||||||
|
|
||||||
self.slotRoots
|
self.slotRoots
|
||||||
|
|
||||||
func verifyTree*(self: SlotsBuilder): ?Poseidon2Tree {.inline.} =
|
func verifyTree*[T, H](self: SlotsBuilder[T, H]): ?T {.inline.} =
|
||||||
## Returns the slots tree (verification tree).
|
## Returns the slots tree (verification tree).
|
||||||
##
|
##
|
||||||
|
|
||||||
self.verifyTree
|
self.verifiableTree
|
||||||
|
|
||||||
func verifyRoot*(self: SlotsBuilder): ?Poseidon2Hash {.inline.} =
|
func verifyRoot*[T, H](self: SlotsBuilder[T, H]): ?H {.inline.} =
|
||||||
## Returns the slots root (verification root).
|
## Returns the slots root (verification root).
|
||||||
##
|
##
|
||||||
|
|
||||||
self.verifyTree.?root().?toOption
|
if tree =? self.verifyTree and root =? tree.root:
|
||||||
|
return some root
|
||||||
|
|
||||||
func nextPowerOfTwoPad*(a: int): int =
|
func numSlots*[T, H](self: SlotsBuilder[T, H]): Natural =
|
||||||
## Returns the difference between the original
|
|
||||||
## value and the next power of two.
|
|
||||||
##
|
|
||||||
|
|
||||||
nextPowerOfTwo(a) - a
|
|
||||||
|
|
||||||
func numBlockPadBytes*(self: SlotsBuilder): Natural =
|
|
||||||
## Number of padding bytes required for a pow2
|
|
||||||
## merkle tree for each block.
|
|
||||||
##
|
|
||||||
|
|
||||||
self.blockPadBytes.len
|
|
||||||
|
|
||||||
func numSlotsPadLeafs*(self: SlotsBuilder): Natural =
|
|
||||||
## Number of padding field elements required for a pow2
|
|
||||||
## merkle tree for each slot.
|
|
||||||
##
|
|
||||||
|
|
||||||
self.slotsPadLeafs.len
|
|
||||||
|
|
||||||
func numRootsPadLeafs*(self: SlotsBuilder): Natural =
|
|
||||||
## Number of padding field elements required for a pow2
|
|
||||||
## merkle tree for the slot roots.
|
|
||||||
##
|
|
||||||
|
|
||||||
self.rootsPadLeafs.len
|
|
||||||
|
|
||||||
func numSlots*(self: SlotsBuilder): Natural =
|
|
||||||
## Number of slots.
|
## Number of slots.
|
||||||
##
|
##
|
||||||
|
|
||||||
self.manifest.numSlots
|
self.manifest.numSlots
|
||||||
|
|
||||||
func numSlotBlocks*(self: SlotsBuilder): Natural =
|
func numSlotBlocks*[T, H](self: SlotsBuilder[T, H]): Natural =
|
||||||
## Number of blocks per slot.
|
## Number of blocks per slot.
|
||||||
##
|
##
|
||||||
|
|
||||||
self.manifest.blocksCount div self.manifest.numSlots
|
self.numSlotBlocks
|
||||||
|
|
||||||
func slotBytes*(self: SlotsBuilder): NBytes =
|
func numBlocks*[T, H](self: SlotsBuilder[T, H]): Natural =
|
||||||
|
## Number of blocks.
|
||||||
|
##
|
||||||
|
|
||||||
|
self.numSlotBlocks * self.manifest.numSlots
|
||||||
|
|
||||||
|
func slotBytes*[T, H](self: SlotsBuilder[T, H]): NBytes =
|
||||||
## Number of bytes per slot.
|
## Number of bytes per slot.
|
||||||
##
|
##
|
||||||
|
|
||||||
(self.manifest.blockSize.int * self.numSlotBlocks).NBytes
|
(self.manifest.blockSize.int * self.numSlotBlocks).NBytes
|
||||||
|
|
||||||
func numBlockCells*(self: SlotsBuilder): Natural =
|
func numBlockCells*[T, H](self: SlotsBuilder[T, H]): Natural =
|
||||||
## Number of cells per block.
|
## Number of cells per block.
|
||||||
##
|
##
|
||||||
|
|
||||||
(self.manifest.blockSize div self.cellSize).Natural
|
(self.manifest.blockSize div self.cellSize).Natural
|
||||||
|
|
||||||
func numBlockCellsPadded*(self: SlotsBuilder): Natural =
|
func cellSize*[T, H](self: SlotsBuilder[T, H]): NBytes =
|
||||||
## Number of cells per block including padding.
|
|
||||||
##
|
|
||||||
|
|
||||||
nextPowerOfTwo(self.numBlockCells.int).Natural
|
|
||||||
|
|
||||||
func cellSize*(self: SlotsBuilder): NBytes =
|
|
||||||
## Cell size.
|
## Cell size.
|
||||||
##
|
##
|
||||||
|
|
||||||
self.cellSize
|
self.cellSize
|
||||||
|
|
||||||
func numSlotCells*(self: SlotsBuilder): Natural =
|
func numSlotCells*[T, H](self: SlotsBuilder[T, H]): Natural =
|
||||||
## Number of cells per slot.
|
## Number of cells per slot.
|
||||||
##
|
##
|
||||||
|
|
||||||
self.numBlockCells * self.numSlotBlocks
|
self.numBlockCells * self.numSlotBlocks
|
||||||
|
|
||||||
func numSlotCellsPadded*(self: SlotsBuilder): Natural =
|
func slotIndiciesIter*[T, H](self: SlotsBuilder[T, H], slot: Natural): ?!Iter[int] =
|
||||||
## Number of cells per slot including padding.
|
|
||||||
##
|
|
||||||
|
|
||||||
nextPowerOfTwo(self.numBlockCellsPadded.int * self.numSlotBlocks.int).Natural
|
|
||||||
|
|
||||||
func emptyDigestTree*(self: SlotsBuilder): Poseidon2Tree {.inline.} =
|
|
||||||
## Returns the tree of a padding block.
|
|
||||||
##
|
|
||||||
|
|
||||||
self.emptyDigestTree
|
|
||||||
|
|
||||||
func slotIndiciesIter*(self: SlotsBuilder, slot: Natural): ?!Iter[int] =
|
|
||||||
## Returns the slot indices.
|
## Returns the slot indices.
|
||||||
##
|
##
|
||||||
|
|
||||||
self.strategy.getIndicies(slot).catch
|
self.strategy.getIndicies(slot).catch
|
||||||
|
|
||||||
func slotIndicies*(self: SlotsBuilder, slot: Natural): seq[int] =
|
func slotIndicies*[T, H](self: SlotsBuilder[T, H], slot: Natural): seq[int] =
|
||||||
## Returns the slot indices.
|
## Returns the slot indices.
|
||||||
##
|
##
|
||||||
|
|
||||||
if iter =? self.strategy.getIndicies(slot).catch:
|
if iter =? self.strategy.getIndicies(slot).catch:
|
||||||
toSeq(iter)
|
return toSeq(iter)
|
||||||
else:
|
|
||||||
trace "Failed to get slot indicies"
|
|
||||||
newSeq[int]()
|
|
||||||
|
|
||||||
func manifest*(self: SlotsBuilder): Manifest =
|
func manifest*[T, H](self: SlotsBuilder[T, H]): Manifest =
|
||||||
## Returns the manifest.
|
## Returns the manifest.
|
||||||
##
|
##
|
||||||
|
|
||||||
self.manifest
|
self.manifest
|
||||||
|
|
||||||
proc buildBlockTree*(
|
proc buildBlockTree*[T, H](
|
||||||
self: SlotsBuilder,
|
self: SlotsBuilder[T, H],
|
||||||
blkIdx: Natural): Future[?!(seq[byte], Poseidon2Tree)] {.async.} =
|
blkIdx: Natural,
|
||||||
|
slotPos: Natural): Future[?!(seq[byte], T)] {.async.} =
|
||||||
|
## Build the block digest tree and return a tuple with the
|
||||||
|
## block data and the tree.
|
||||||
|
##
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
blkIdx = blkIdx
|
||||||
|
slotPos = slotPos
|
||||||
|
numSlotBlocks = self.manifest.numSlotBlocks
|
||||||
|
cellSize = self.cellSize
|
||||||
|
|
||||||
|
trace "Building block tree"
|
||||||
|
|
||||||
|
if slotPos > (self.manifest.numSlotBlocks - 1):
|
||||||
|
# pad blocks are 0 byte blocks
|
||||||
|
trace "Returning empty digest tree for pad block"
|
||||||
|
return success (self.emptyBlock, self.emptyDigestTree)
|
||||||
|
|
||||||
without blk =? await self.store.getBlock(self.manifest.treeCid, blkIdx), err:
|
without blk =? await self.store.getBlock(self.manifest.treeCid, blkIdx), err:
|
||||||
error "Failed to get block CID for tree at index"
|
error "Failed to get block CID for tree at index", err = err.msg
|
||||||
return failure(err)
|
return failure(err)
|
||||||
|
|
||||||
if blk.isEmpty:
|
if blk.isEmpty:
|
||||||
success (DefaultEmptyBlock & self.blockPadBytes, self.emptyDigestTree)
|
success (self.emptyBlock, self.emptyDigestTree)
|
||||||
else:
|
else:
|
||||||
without tree =?
|
without tree =?
|
||||||
Poseidon2Tree.digestTree(blk.data & self.blockPadBytes, self.cellSize.int), err:
|
T.digestTree(blk.data, self.cellSize.int), err:
|
||||||
error "Failed to create digest for block"
|
error "Failed to create digest for block", err = err.msg
|
||||||
return failure(err)
|
return failure(err)
|
||||||
|
|
||||||
success (blk.data, tree)
|
success (blk.data, tree)
|
||||||
|
|
||||||
proc getBlockHashes*(
|
proc getCellHashes*[T, H](
|
||||||
self: SlotsBuilder,
|
self: SlotsBuilder[T, H],
|
||||||
slotIndex: Natural): Future[?!seq[Poseidon2Hash]] {.async.} =
|
slotIndex: Natural): Future[?!seq[H]] {.async.} =
|
||||||
|
## Collect all the cells from a block and return
|
||||||
|
## their hashes.
|
||||||
|
##
|
||||||
|
|
||||||
let
|
let
|
||||||
treeCid = self.manifest.treeCid
|
treeCid = self.manifest.treeCid
|
||||||
|
@ -209,38 +182,44 @@ proc getBlockHashes*(
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
treeCid = treeCid
|
treeCid = treeCid
|
||||||
blockCount = blockCount
|
origBlockCount = blockCount
|
||||||
numberOfSlots = numberOfSlots
|
numberOfSlots = numberOfSlots
|
||||||
index = blkIdx
|
|
||||||
slotIndex = slotIndex
|
slotIndex = slotIndex
|
||||||
|
|
||||||
let
|
let hashes = collect(newSeq):
|
||||||
hashes: seq[Poseidon2Hash] = collect(newSeq):
|
for i, blkIdx in self.strategy.getIndicies(slotIndex):
|
||||||
for blkIdx in self.strategy.getIndicies(slotIndex):
|
logScope:
|
||||||
trace "Getting block CID for tree at index"
|
blkIdx = blkIdx
|
||||||
|
pos = i
|
||||||
|
|
||||||
without (_, blockTree) =? (await self.buildBlockTree(blkIdx)) and
|
trace "Getting block CID for tree at index"
|
||||||
digest =? blockTree.root, err:
|
without (_, tree) =? (await self.buildBlockTree(blkIdx, i)) and
|
||||||
error "Failed to get block CID for block tree at index", err = err.msg
|
digest =? tree.root, err:
|
||||||
return failure(err)
|
error "Failed to get block CID for tree at index", err = err.msg
|
||||||
|
return failure(err)
|
||||||
|
|
||||||
digest
|
trace "Get block digest", digest = digest.toHex
|
||||||
|
digest
|
||||||
|
|
||||||
success hashes
|
success hashes
|
||||||
|
|
||||||
proc buildSlotTree*(
|
proc buildSlotTree*[T, H](
|
||||||
self: SlotsBuilder,
|
self: SlotsBuilder[T, H],
|
||||||
slotIndex: Natural): Future[?!Poseidon2Tree] {.async.} =
|
slotIndex: Natural): Future[?!T] {.async.} =
|
||||||
without blockHashes =? (await self.getBlockHashes(slotIndex)), err:
|
## Build the slot tree from the block digest hashes
|
||||||
|
## and return the tree.
|
||||||
|
|
||||||
|
without cellHashes =? (await self.getCellHashes(slotIndex)), err:
|
||||||
error "Failed to select slot blocks", err = err.msg
|
error "Failed to select slot blocks", err = err.msg
|
||||||
return failure(err)
|
return failure(err)
|
||||||
|
|
||||||
Poseidon2Tree.init(blockHashes & self.slotsPadLeafs)
|
T.init(cellHashes)
|
||||||
|
|
||||||
proc buildSlot*(
|
proc buildSlot*[T, H](
|
||||||
self: SlotsBuilder,
|
self: SlotsBuilder[T, H],
|
||||||
slotIndex: Natural): Future[?!Poseidon2Hash] {.async.} =
|
slotIndex: Natural): Future[?!H] {.async.} =
|
||||||
## Build a slot tree and store it in the block store.
|
## Build a slot tree and store the proofs in
|
||||||
|
## the block store.
|
||||||
##
|
##
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
|
@ -272,12 +251,10 @@ proc buildSlot*(
|
||||||
|
|
||||||
tree.root()
|
tree.root()
|
||||||
|
|
||||||
func buildVerifyTree*(
|
func buildVerifyTree*[T, H](self: SlotsBuilder[T, H], slotRoots: openArray[H]): ?!T =
|
||||||
self: SlotsBuilder,
|
T.init(@slotRoots)
|
||||||
slotRoots: openArray[Poseidon2Hash]): ?!Poseidon2Tree =
|
|
||||||
Poseidon2Tree.init(@slotRoots & self.rootsPadLeafs)
|
|
||||||
|
|
||||||
proc buildSlots*(self: SlotsBuilder): Future[?!void] {.async.} =
|
proc buildSlots*[T, H](self: SlotsBuilder[T, H]): Future[?!void] {.async.} =
|
||||||
## Build all slot trees and store them in the block store.
|
## Build all slot trees and store them in the block store.
|
||||||
##
|
##
|
||||||
|
|
||||||
|
@ -300,14 +277,14 @@ proc buildSlots*(self: SlotsBuilder): Future[?!void] {.async.} =
|
||||||
return failure(err)
|
return failure(err)
|
||||||
|
|
||||||
if verifyTree =? self.verifyTree and verifyRoot =? verifyTree.root:
|
if verifyTree =? self.verifyTree and verifyRoot =? verifyTree.root:
|
||||||
if verifyRoot != root: # TODO: `!=` doesn't work for SecretBool
|
if not bool(verifyRoot == root): # TODO: `!=` doesn't work for SecretBool
|
||||||
return failure "Existing slots root doesn't match reconstructed root."
|
return failure "Existing slots root doesn't match reconstructed root."
|
||||||
|
|
||||||
self.verifyTree = some tree
|
self.verifiableTree = some tree
|
||||||
|
|
||||||
success()
|
success()
|
||||||
|
|
||||||
proc buildManifest*(self: SlotsBuilder): Future[?!Manifest] {.async.} =
|
proc buildManifest*[T, H](self: SlotsBuilder[T, H]): Future[?!Manifest] {.async.} =
|
||||||
if err =? (await self.buildSlots()).errorOption:
|
if err =? (await self.buildSlots()).errorOption:
|
||||||
error "Failed to build slot roots", err = err.msg
|
error "Failed to build slot roots", err = err.msg
|
||||||
return failure(err)
|
return failure(err)
|
||||||
|
@ -321,68 +298,88 @@ proc buildManifest*(self: SlotsBuilder): Future[?!Manifest] {.async.} =
|
||||||
error "Failed to map slot roots to CIDs", err = err.msg
|
error "Failed to map slot roots to CIDs", err = err.msg
|
||||||
return failure(err)
|
return failure(err)
|
||||||
|
|
||||||
Manifest.new(self.manifest, rootProvingCid, rootCids)
|
Manifest.new(
|
||||||
|
self.manifest,
|
||||||
|
rootProvingCid,
|
||||||
|
rootCids,
|
||||||
|
self.cellSize,
|
||||||
|
self.strategy.strategyType)
|
||||||
|
|
||||||
proc new*(
|
proc new*[T, H](
|
||||||
T: type SlotsBuilder,
|
_: type SlotsBuilder[T, H],
|
||||||
store: BlockStore,
|
store: BlockStore,
|
||||||
manifest: Manifest,
|
manifest: Manifest,
|
||||||
strategy: ?IndexingStrategy = none IndexingStrategy,
|
strategy = SteppedStrategy,
|
||||||
cellSize = DefaultCellSize): ?!SlotsBuilder =
|
cellSize = DefaultCellSize): ?!SlotsBuilder[T, H] =
|
||||||
|
|
||||||
if not manifest.protected:
|
if not manifest.protected:
|
||||||
return failure("Can only create SlotsBuilder using protected manifests.")
|
trace "Manifest is not protected."
|
||||||
|
return failure("Manifest is not protected.")
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
blockSize = manifest.blockSize
|
||||||
|
strategy = strategy
|
||||||
|
cellSize = cellSize
|
||||||
|
|
||||||
if (manifest.blocksCount mod manifest.numSlots) != 0:
|
if (manifest.blocksCount mod manifest.numSlots) != 0:
|
||||||
|
trace "Number of blocks must be divisable by number of slots."
|
||||||
return failure("Number of blocks must be divisable by number of slots.")
|
return failure("Number of blocks must be divisable by number of slots.")
|
||||||
|
|
||||||
|
let cellSize = if manifest.verifiable: manifest.cellSize else: cellSize
|
||||||
if (manifest.blockSize mod cellSize) != 0.NBytes:
|
if (manifest.blockSize mod cellSize) != 0.NBytes:
|
||||||
|
trace "Block size must be divisable by cell size."
|
||||||
return failure("Block size must be divisable by cell size.")
|
return failure("Block size must be divisable by cell size.")
|
||||||
|
|
||||||
let
|
let
|
||||||
strategy = if strategy.isNone:
|
numBlockCells = (manifest.blockSize div cellSize).int # number of cells per block
|
||||||
? SteppedStrategy.init(
|
numSlotCells = manifest.numSlotBlocks * numBlockCells # number of uncorrected slot cells
|
||||||
0, manifest.blocksCount - 1, manifest.numSlots).catch
|
pow2SlotCells = nextPowerOfTwo(numSlotCells) # pow2 cells per slot
|
||||||
else:
|
numPadSlotBlocks = pow2SlotCells div numBlockCells # pow2 blocks per slot
|
||||||
strategy.get
|
numPadBlocksTotal = numPadSlotBlocks * manifest.numSlots # total number of pad blocks
|
||||||
|
|
||||||
# all trees have to be padded to power of two
|
emptyBlock = newSeq[byte](manifest.blockSize.int)
|
||||||
numBlockCells = (manifest.blockSize div cellSize).int # number of cells per block
|
emptyDigestTree = ? T.digestTree(emptyBlock, cellSize.int)
|
||||||
blockPadBytes = newSeq[byte](numBlockCells.nextPowerOfTwoPad * cellSize.int) # power of two padding for blocks
|
|
||||||
numSlotBlocks = (manifest.blocksCount div manifest.numSlots)
|
|
||||||
slotsPadLeafs = newSeqWith(numSlotBlocks.nextPowerOfTwoPad, Poseidon2Zero) # power of two padding for block roots
|
|
||||||
rootsPadLeafs = newSeqWith(manifest.numSlots.nextPowerOfTwoPad, Poseidon2Zero)
|
|
||||||
emptyDigestTree = ? Poseidon2Tree.digestTree(DefaultEmptyBlock & blockPadBytes, DefaultCellSize.int)
|
|
||||||
|
|
||||||
var self = SlotsBuilder(
|
strategy = ? strategy.init(
|
||||||
store: store,
|
0,
|
||||||
manifest: manifest,
|
numPadBlocksTotal - 1,
|
||||||
strategy: strategy,
|
manifest.numSlots).catch
|
||||||
cellSize: cellSize,
|
|
||||||
blockPadBytes: blockPadBytes,
|
logScope:
|
||||||
slotsPadLeafs: slotsPadLeafs,
|
numBlockCells = numBlockCells
|
||||||
rootsPadLeafs: rootsPadLeafs,
|
numSlotCells = numSlotCells
|
||||||
emptyDigestTree: emptyDigestTree)
|
pow2SlotCells = pow2SlotCells
|
||||||
|
numPadSlotBlocks = numPadSlotBlocks
|
||||||
|
numPadBlocksTotal = numPadBlocksTotal
|
||||||
|
strategy = strategy.strategyType
|
||||||
|
|
||||||
|
trace "Creating slots builder"
|
||||||
|
|
||||||
|
var
|
||||||
|
self = SlotsBuilder[T, H](
|
||||||
|
store: store,
|
||||||
|
manifest: manifest,
|
||||||
|
strategy: strategy,
|
||||||
|
cellSize: cellSize,
|
||||||
|
emptyBlock: emptyBlock,
|
||||||
|
numSlotBlocks: numPadSlotBlocks,
|
||||||
|
emptyDigestTree: emptyDigestTree)
|
||||||
|
|
||||||
if manifest.verifiable:
|
if manifest.verifiable:
|
||||||
if manifest.slotRoots.len == 0 or manifest.slotRoots.len != manifest.numSlots:
|
if manifest.slotRoots.len == 0 or
|
||||||
|
manifest.slotRoots.len != manifest.numSlots:
|
||||||
return failure "Manifest is verifiable but slot roots are missing or invalid."
|
return failure "Manifest is verifiable but slot roots are missing or invalid."
|
||||||
|
|
||||||
let slotRoots = manifest.slotRoots.mapIt( (? it.fromSlotCid()))
|
let
|
||||||
|
slotRoots = manifest.slotRoots.mapIt( (? it.fromSlotCid() ))
|
||||||
|
tree = ? self.buildVerifyTree(slotRoots)
|
||||||
|
expectedRoot = ? manifest.verifyRoot.fromVerifyCid()
|
||||||
|
verifyRoot = ? tree.root
|
||||||
|
|
||||||
without tree =? self.buildVerifyTree(slotRoots), err:
|
if verifyRoot != expectedRoot:
|
||||||
error "Failed to build slot roots tree", err = err.msg
|
return failure "Existing slots root doesn't match reconstructed root."
|
||||||
return failure(err)
|
|
||||||
|
|
||||||
without expectedRoot =? manifest.verifyRoot.fromVerifyCid(), err:
|
|
||||||
error "Unable to convert manifest verifyRoot to hash", error = err.msg
|
|
||||||
return failure(err)
|
|
||||||
|
|
||||||
if verifyRoot =? tree.root:
|
|
||||||
if verifyRoot != expectedRoot:
|
|
||||||
return failure "Existing slots root doesn't match reconstructed root."
|
|
||||||
|
|
||||||
self.slotRoots = slotRoots
|
self.slotRoots = slotRoots
|
||||||
self.verifyTree = some tree
|
self.verifiableTree = some tree
|
||||||
|
|
||||||
success self
|
success self
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
import ./sampler/sampler
|
import ./sampler/sampler
|
||||||
import ./sampler/utils
|
import ./sampler/utils
|
||||||
|
|
||||||
|
import ../merkletree
|
||||||
|
|
||||||
export sampler, utils
|
export sampler, utils
|
||||||
|
|
||||||
|
type
|
||||||
|
Poseidon2Sampler* = DataSampler[Poseidon2Tree, Poseidon2Hash]
|
||||||
|
|
|
@ -8,182 +8,146 @@
|
||||||
## those terms.
|
## those terms.
|
||||||
|
|
||||||
import std/sugar
|
import std/sugar
|
||||||
import std/sequtils
|
|
||||||
|
|
||||||
|
import pkg/chronicles
|
||||||
import pkg/chronos
|
import pkg/chronos
|
||||||
import pkg/questionable
|
import pkg/questionable
|
||||||
import pkg/questionable/results
|
import pkg/questionable/results
|
||||||
import pkg/constantine/math/arithmetic
|
|
||||||
import pkg/poseidon2
|
|
||||||
import pkg/poseidon2/types
|
|
||||||
import pkg/poseidon2/io
|
|
||||||
import pkg/stew/arrayops
|
import pkg/stew/arrayops
|
||||||
|
|
||||||
import ../../logutils
|
|
||||||
import ../../market
|
import ../../market
|
||||||
import ../../blocktype as bt
|
import ../../blocktype as bt
|
||||||
import ../../merkletree
|
import ../../merkletree
|
||||||
import ../../manifest
|
import ../../manifest
|
||||||
import ../../stores
|
import ../../stores
|
||||||
|
|
||||||
|
import ../converters
|
||||||
import ../builder
|
import ../builder
|
||||||
|
import ../types
|
||||||
import ./utils
|
import ./utils
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "codex datasampler"
|
topics = "codex datasampler"
|
||||||
|
|
||||||
type
|
type
|
||||||
Cell* = seq[byte]
|
DataSampler*[T, H] = ref object of RootObj
|
||||||
|
|
||||||
Sample* = object
|
|
||||||
data*: Cell
|
|
||||||
slotProof*: Poseidon2Proof
|
|
||||||
cellProof*: Poseidon2Proof
|
|
||||||
slotBlockIdx*: Natural
|
|
||||||
blockCellIdx*: Natural
|
|
||||||
|
|
||||||
ProofInput* = object
|
|
||||||
entropy*: Poseidon2Hash
|
|
||||||
verifyRoot*: Poseidon2Hash
|
|
||||||
verifyProof*: Poseidon2Proof
|
|
||||||
numSlots*: Natural
|
|
||||||
numCells*: Natural
|
|
||||||
slotIndex*: Natural
|
|
||||||
samples*: seq[Sample]
|
|
||||||
|
|
||||||
DataSampler* = ref object of RootObj
|
|
||||||
index: Natural
|
index: Natural
|
||||||
blockStore: BlockStore
|
blockStore: BlockStore
|
||||||
# The following data is invariant over time for a given slot:
|
builder: SlotsBuilder[T, H]
|
||||||
builder: SlotsBuilder
|
|
||||||
|
|
||||||
proc new*(
|
func getCell*[T, H](
|
||||||
T: type DataSampler,
|
self: DataSampler[T, H],
|
||||||
|
blkBytes: seq[byte],
|
||||||
|
blkCellIdx: Natural): seq[byte] =
|
||||||
|
|
||||||
|
let
|
||||||
|
cellSize = self.builder.cellSize.uint64
|
||||||
|
dataStart = cellSize * blkCellIdx.uint64
|
||||||
|
dataEnd = dataStart + cellSize
|
||||||
|
|
||||||
|
doAssert (dataEnd - dataStart) == cellSize, "Invalid cell size"
|
||||||
|
|
||||||
|
toInputData[H](blkBytes[dataStart ..< dataEnd])
|
||||||
|
|
||||||
|
proc getSample*[T, H](
|
||||||
|
self: DataSampler[T, H],
|
||||||
|
cellIdx: int,
|
||||||
|
slotTreeCid: Cid,
|
||||||
|
slotRoot: H): Future[?!Sample[H]] {.async.} =
|
||||||
|
|
||||||
|
let
|
||||||
|
cellsPerBlock = self.builder.numBlockCells
|
||||||
|
blkCellIdx = cellIdx.toCellInBlk(cellsPerBlock) # block cell index
|
||||||
|
blkSlotIdx = cellIdx.toBlkInSlot(cellsPerBlock) # slot tree index
|
||||||
|
origBlockIdx = self.builder.slotIndicies(self.index)[blkSlotIdx] # convert to original dataset block index
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
cellIdx = cellIdx
|
||||||
|
blkSlotIdx = blkSlotIdx
|
||||||
|
blkCellIdx = blkCellIdx
|
||||||
|
origBlockIdx = origBlockIdx
|
||||||
|
|
||||||
|
trace "Retrieving sample from block tree"
|
||||||
|
let
|
||||||
|
(_, proof) = (await self.blockStore.getCidAndProof(
|
||||||
|
slotTreeCid, blkSlotIdx.Natural)).valueOr:
|
||||||
|
return failure("Failed to get slot tree CID and proof")
|
||||||
|
|
||||||
|
slotProof = proof.toVerifiableProof().valueOr:
|
||||||
|
return failure("Failed to get verifiable proof")
|
||||||
|
|
||||||
|
(bytes, blkTree) = (await self.builder.buildBlockTree(
|
||||||
|
origBlockIdx, blkSlotIdx)).valueOr:
|
||||||
|
return failure("Failed to build block tree")
|
||||||
|
|
||||||
|
cellData = self.getCell(bytes, blkCellIdx)
|
||||||
|
cellProof = blkTree.getProof(blkCellIdx).valueOr:
|
||||||
|
return failure("Failed to get proof from block tree")
|
||||||
|
|
||||||
|
success Sample[H](
|
||||||
|
cellData: cellData,
|
||||||
|
merklePaths: (cellProof.path & slotProof.path))
|
||||||
|
|
||||||
|
proc getProofInput*[T, H](
|
||||||
|
self: DataSampler[T, H],
|
||||||
|
entropy: ProofChallenge,
|
||||||
|
nSamples: Natural): Future[?!ProofInput[H]] {.async.} =
|
||||||
|
## Generate proofs as input to the proving circuit.
|
||||||
|
##
|
||||||
|
|
||||||
|
let
|
||||||
|
entropy = H.fromBytes(
|
||||||
|
array[31, byte].initCopyFrom(entropy[0..30])) # truncate to 31 bytes, otherwise it _might_ be greater than mod
|
||||||
|
|
||||||
|
verifyTree = self.builder.verifyTree.toFailure.valueOr:
|
||||||
|
return failure("Failed to get verify tree")
|
||||||
|
|
||||||
|
slotProof = verifyTree.getProof(self.index).valueOr:
|
||||||
|
return failure("Failed to get slot proof")
|
||||||
|
|
||||||
|
datasetRoot = verifyTree.root().valueOr:
|
||||||
|
return failure("Failed to get dataset root")
|
||||||
|
|
||||||
|
slotTreeCid = self.builder.manifest.slotRoots[self.index]
|
||||||
|
slotRoot = self.builder.slotRoots[self.index]
|
||||||
|
cellIdxs = entropy.cellIndices(
|
||||||
|
slotRoot,
|
||||||
|
self.builder.numSlotCells,
|
||||||
|
nSamples)
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
cells = cellIdxs
|
||||||
|
|
||||||
|
trace "Collecting input for proof"
|
||||||
|
let samples = collect(newSeq):
|
||||||
|
for cellIdx in cellIdxs:
|
||||||
|
(await self.getSample(cellIdx, slotTreeCid, slotRoot)).valueOr:
|
||||||
|
return failure("Failed to get sample")
|
||||||
|
|
||||||
|
success ProofInput[H](
|
||||||
|
entropy: entropy,
|
||||||
|
datasetRoot: datasetRoot,
|
||||||
|
slotProof: slotProof.path,
|
||||||
|
nSlotsPerDataSet: self.builder.numSlots,
|
||||||
|
nCellsPerSlot: self.builder.numSlotCells,
|
||||||
|
slotRoot: slotRoot,
|
||||||
|
slotIndex: self.index,
|
||||||
|
samples: samples)
|
||||||
|
|
||||||
|
proc new*[T, H](
|
||||||
|
_: type DataSampler[T, H],
|
||||||
index: Natural,
|
index: Natural,
|
||||||
blockStore: BlockStore,
|
blockStore: BlockStore,
|
||||||
builder: SlotsBuilder): ?!DataSampler =
|
builder: SlotsBuilder[T, H]): ?!DataSampler[T, H] =
|
||||||
|
|
||||||
if index > builder.slotRoots.high:
|
if index > builder.slotRoots.high:
|
||||||
error "Slot index is out of range"
|
error "Slot index is out of range"
|
||||||
return failure("Slot index is out of range")
|
return failure("Slot index is out of range")
|
||||||
|
|
||||||
success DataSampler(
|
if not builder.verifiable:
|
||||||
|
return failure("Cannot instantiate DataSampler for non-verifiable builder")
|
||||||
|
|
||||||
|
success DataSampler[T, H](
|
||||||
index: index,
|
index: index,
|
||||||
blockStore: blockStore,
|
blockStore: blockStore,
|
||||||
builder: builder)
|
builder: builder)
|
||||||
|
|
||||||
proc getCell*(self: DataSampler, blkBytes: seq[byte], blkCellIdx: Natural): Cell =
|
|
||||||
let
|
|
||||||
cellSize = self.builder.cellSize.uint64
|
|
||||||
dataStart = cellSize * blkCellIdx.uint64
|
|
||||||
dataEnd = dataStart + cellSize
|
|
||||||
return blkBytes[dataStart ..< dataEnd]
|
|
||||||
|
|
||||||
proc createProofSample(self: DataSampler, slotTreeCid: Cid, cellIdx: Natural): Future[?!Sample] {.async.} =
|
|
||||||
let
|
|
||||||
cellsPerBlock = self.builder.numBlockCells
|
|
||||||
blkCellIdx = cellIdx.toBlockCellIdx(cellsPerBlock)
|
|
||||||
slotBlkIdx = cellIdx.toBlockIdx(cellsPerBlock)
|
|
||||||
|
|
||||||
logScope:
|
|
||||||
cellIdx = cellIdx
|
|
||||||
slotBlkIdx = slotBlkIdx
|
|
||||||
blkCellIdx = blkCellIdx
|
|
||||||
|
|
||||||
without (cid, proof) =? await self.blockStore.getCidAndProof(
|
|
||||||
slotTreeCid,
|
|
||||||
slotBlkIdx.Natural), err:
|
|
||||||
error "Failed to get block from block store", err = err.msg
|
|
||||||
return failure(err)
|
|
||||||
|
|
||||||
without slotProof =? proof.toVerifiableProof(), err:
|
|
||||||
error "Unable to convert slot proof to poseidon proof", error = err.msg
|
|
||||||
return failure(err)
|
|
||||||
|
|
||||||
# If the cell index is greater than or equal to the UNPADDED number of slot cells,
|
|
||||||
# Then we're sampling inside a padded block.
|
|
||||||
# In this case, we use the pre-generated zero-data and pre-generated padding-proof for this cell index.
|
|
||||||
if cellIdx >= self.builder.numSlotCells:
|
|
||||||
trace "Sampling a padded block"
|
|
||||||
|
|
||||||
without blockProof =? self.builder.emptyDigestTree.getProof(blkCellIdx), err:
|
|
||||||
error "Failed to get proof from empty block tree", err = err.msg
|
|
||||||
return failure(err)
|
|
||||||
|
|
||||||
success(Sample(
|
|
||||||
data: newSeq[byte](self.builder.cellSize.int),
|
|
||||||
slotProof: slotProof,
|
|
||||||
cellProof: blockProof,
|
|
||||||
slotBlockIdx: slotBlkIdx.Natural,
|
|
||||||
blockCellIdx: blkCellIdx.Natural))
|
|
||||||
|
|
||||||
else:
|
|
||||||
trace "Sampling a dataset block"
|
|
||||||
# This converts our slotBlockIndex to a datasetBlockIndex using the
|
|
||||||
# indexing-strategy used by the builder.
|
|
||||||
# We need this to fetch the block data. We can't do it by slotTree + slotBlkIdx.
|
|
||||||
let datasetBlockIndex = self.builder.slotIndicies(self.index)[slotBlkIdx]
|
|
||||||
|
|
||||||
without (bytes, blkTree) =? await self.builder.buildBlockTree(datasetBlockIndex), err:
|
|
||||||
error "Failed to build block tree", err = err.msg
|
|
||||||
return failure(err)
|
|
||||||
|
|
||||||
without blockProof =? blkTree.getProof(blkCellIdx), err:
|
|
||||||
error "Failed to get proof from block tree", err = err.msg
|
|
||||||
return failure(err)
|
|
||||||
|
|
||||||
success(Sample(
|
|
||||||
data: self.getCell(bytes, blkCellIdx),
|
|
||||||
slotProof: slotProof,
|
|
||||||
cellProof: blockProof,
|
|
||||||
slotBlockIdx: slotBlkIdx.Natural,
|
|
||||||
blockCellIdx: blkCellIdx.Natural))
|
|
||||||
|
|
||||||
proc getProofInput*(
|
|
||||||
self: DataSampler,
|
|
||||||
entropy: ProofChallenge,
|
|
||||||
nSamples: Natural): Future[?!ProofInput] {.async.} =
|
|
||||||
## Generate proofs as input to the proving circuit.
|
|
||||||
##
|
|
||||||
|
|
||||||
let
|
|
||||||
entropy = Poseidon2Hash.fromBytes(
|
|
||||||
array[31, byte].initCopyFrom(entropy[0..30])) # truncate to 31 bytes, otherwise it _might_ be greater than mod
|
|
||||||
|
|
||||||
without verifyTree =? self.builder.verifyTree and
|
|
||||||
verifyProof =? verifyTree.getProof(self.index) and
|
|
||||||
verifyRoot =? verifyTree.root(), err:
|
|
||||||
error "Failed to get slot proof from verify tree", err = err.msg
|
|
||||||
return failure(err)
|
|
||||||
|
|
||||||
let slotTreeCid = self.builder.manifest.slotRoots[self.index]
|
|
||||||
|
|
||||||
logScope:
|
|
||||||
index = self.index
|
|
||||||
samples = nSamples
|
|
||||||
slotTreeCid = slotTreeCid
|
|
||||||
|
|
||||||
trace "Collecting input for proof"
|
|
||||||
|
|
||||||
let cellIdxs = entropy.cellIndices(
|
|
||||||
self.builder.slotRoots[self.index],
|
|
||||||
self.builder.numSlotCellsPadded,
|
|
||||||
nSamples)
|
|
||||||
|
|
||||||
trace "Found cell indices", cellIdxs
|
|
||||||
let samples = collect(newSeq):
|
|
||||||
for cellIdx in cellIdxs:
|
|
||||||
without sample =? (await self.createProofSample(slotTreeCid, cellIdx)), err:
|
|
||||||
error "Failed to create proof sample", error = err.msg
|
|
||||||
return failure(err)
|
|
||||||
sample
|
|
||||||
|
|
||||||
success ProofInput(
|
|
||||||
entropy: entropy,
|
|
||||||
verifyRoot: verifyRoot,
|
|
||||||
verifyProof: verifyProof,
|
|
||||||
numSlots: self.builder.numSlots,
|
|
||||||
numCells: self.builder.numSlotCells,
|
|
||||||
slotIndex: self.index,
|
|
||||||
samples: samples)
|
|
||||||
|
|
|
@ -9,8 +9,9 @@
|
||||||
|
|
||||||
import std/sugar
|
import std/sugar
|
||||||
import std/bitops
|
import std/bitops
|
||||||
|
import std/sequtils
|
||||||
|
|
||||||
import pkg/chronicles
|
import pkg/questionable/results
|
||||||
import pkg/poseidon2
|
import pkg/poseidon2
|
||||||
import pkg/poseidon2/io
|
import pkg/poseidon2/io
|
||||||
|
|
||||||
|
@ -20,8 +21,11 @@ import pkg/constantine/math/io/io_fields
|
||||||
|
|
||||||
import ../../merkletree
|
import ../../merkletree
|
||||||
|
|
||||||
|
func toInputData*[H](data: seq[byte]): seq[byte] =
|
||||||
|
return toSeq(data.elements(H)).mapIt( @(it.toBytes) ).concat
|
||||||
|
|
||||||
func extractLowBits*[n: static int](elm: BigInt[n], k: int): uint64 =
|
func extractLowBits*[n: static int](elm: BigInt[n], k: int): uint64 =
|
||||||
assert( k > 0 and k <= 64 )
|
doAssert( k > 0 and k <= 64 )
|
||||||
var r = 0'u64
|
var r = 0'u64
|
||||||
for i in 0..<k:
|
for i in 0..<k:
|
||||||
let b = bit[n](elm, i)
|
let b = bit[n](elm, i)
|
||||||
|
@ -48,13 +52,13 @@ func ceilingLog2*(x : int) : int =
|
||||||
else:
|
else:
|
||||||
return (floorLog2(x-1) + 1)
|
return (floorLog2(x-1) + 1)
|
||||||
|
|
||||||
func toBlockIdx*(cell: Natural, numCells: Natural): Natural =
|
func toBlkInSlot*(cell: Natural, numCells: Natural): Natural =
|
||||||
let log2 = ceilingLog2(numCells)
|
let log2 = ceilingLog2(numCells)
|
||||||
doAssert( 1 shl log2 == numCells , "`numCells` is assumed to be a power of two" )
|
doAssert( 1 shl log2 == numCells , "`numCells` is assumed to be a power of two" )
|
||||||
|
|
||||||
return cell div numCells
|
return cell div numCells
|
||||||
|
|
||||||
func toBlockCellIdx*(cell: Natural, numCells: Natural): Natural =
|
func toCellInBlk*(cell: Natural, numCells: Natural): Natural =
|
||||||
let log2 = ceilingLog2(numCells)
|
let log2 = ceilingLog2(numCells)
|
||||||
doAssert( 1 shl log2 == numCells , "`numCells` is assumed to be a power of two" )
|
doAssert( 1 shl log2 == numCells , "`numCells` is assumed to be a power of two" )
|
||||||
|
|
||||||
|
@ -67,7 +71,7 @@ func cellIndex*(
|
||||||
let log2 = ceilingLog2(numCells)
|
let log2 = ceilingLog2(numCells)
|
||||||
doAssert( 1 shl log2 == numCells , "`numCells` is assumed to be a power of two" )
|
doAssert( 1 shl log2 == numCells , "`numCells` is assumed to be a power of two" )
|
||||||
|
|
||||||
let hash = Sponge.digest( @[ slotRoot, entropy, counter.toF ], rate = 2 )
|
let hash = Sponge.digest( @[ entropy, slotRoot, counter.toF ], rate = 2 )
|
||||||
return int( extractLowBits(hash, log2) )
|
return int( extractLowBits(hash, log2) )
|
||||||
|
|
||||||
func cellIndices*(
|
func cellIndices*(
|
||||||
|
@ -75,11 +79,8 @@ func cellIndices*(
|
||||||
slotRoot: Poseidon2Hash,
|
slotRoot: Poseidon2Hash,
|
||||||
numCells: Natural, nSamples: Natural): seq[Natural] =
|
numCells: Natural, nSamples: Natural): seq[Natural] =
|
||||||
|
|
||||||
trace "Calculating cell indices", numCells, nSamples
|
|
||||||
|
|
||||||
var indices: seq[Natural]
|
var indices: seq[Natural]
|
||||||
while (indices.len < nSamples):
|
while (indices.len < nSamples):
|
||||||
let idx = cellIndex(entropy, slotRoot, numCells, indices.len + 1)
|
let idx = cellIndex(entropy, slotRoot, numCells, indices.len + 1)
|
||||||
indices.add(idx.Natural)
|
indices.add(idx.Natural)
|
||||||
indices
|
indices
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
## Nim-Codex
|
||||||
|
## Copyright (c) 2024 Status Research & Development GmbH
|
||||||
|
## Licensed under either of
|
||||||
|
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||||
|
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||||
|
## at your option.
|
||||||
|
## This file may not be copied, modified, or distributed except according to
|
||||||
|
## those terms.
|
||||||
|
|
||||||
|
type
|
||||||
|
Sample*[H] = object
|
||||||
|
cellData*: seq[byte]
|
||||||
|
merklePaths*: seq[H]
|
||||||
|
|
||||||
|
PublicInputs*[H] = object
|
||||||
|
slotIndex*: int
|
||||||
|
datasetRoot*: H
|
||||||
|
entropy*: H
|
||||||
|
|
||||||
|
ProofInput*[H] = object
|
||||||
|
entropy*: H
|
||||||
|
datasetRoot*: H
|
||||||
|
slotIndex*: Natural
|
||||||
|
slotRoot*: H
|
||||||
|
nCellsPerSlot*: Natural
|
||||||
|
nSlotsPerDataSet*: Natural
|
||||||
|
slotProof*: seq[H]
|
||||||
|
samples*: seq[Sample[H]]
|
|
@ -10,29 +10,59 @@
|
||||||
import pkg/poseidon2
|
import pkg/poseidon2
|
||||||
import pkg/questionable/results
|
import pkg/questionable/results
|
||||||
import pkg/libp2p/multihash
|
import pkg/libp2p/multihash
|
||||||
|
import pkg/stew/byteutils
|
||||||
|
|
||||||
|
import pkg/constantine/math/arithmetic
|
||||||
|
import pkg/constantine/math/io/io_bigints
|
||||||
|
import pkg/constantine/math/io/io_fields
|
||||||
|
|
||||||
import ../merkletree
|
import ../merkletree
|
||||||
|
|
||||||
|
func spongeDigest*(
|
||||||
|
_: type Poseidon2Hash,
|
||||||
|
bytes: openArray[byte],
|
||||||
|
rate: static int = 2): ?!Poseidon2Hash =
|
||||||
|
## Hashes chunks of data with a sponge of rate 1 or 2.
|
||||||
|
##
|
||||||
|
|
||||||
|
success Sponge.digest(bytes, rate)
|
||||||
|
|
||||||
|
func spongeDigest*(
|
||||||
|
_: type Poseidon2Hash,
|
||||||
|
bytes: openArray[Bn254Fr],
|
||||||
|
rate: static int = 2): ?!Poseidon2Hash =
|
||||||
|
## Hashes chunks of elements with a sponge of rate 1 or 2.
|
||||||
|
##
|
||||||
|
|
||||||
|
success Sponge.digest(bytes, rate)
|
||||||
|
|
||||||
func digestTree*(
|
func digestTree*(
|
||||||
_: type Poseidon2Tree,
|
_: type Poseidon2Tree,
|
||||||
bytes: openArray[byte], chunkSize: int): ?!Poseidon2Tree =
|
bytes: openArray[byte],
|
||||||
|
chunkSize: int): ?!Poseidon2Tree =
|
||||||
## Hashes chunks of data with a sponge of rate 2, and combines the
|
## Hashes chunks of data with a sponge of rate 2, and combines the
|
||||||
## resulting chunk hashes in a merkle root.
|
## resulting chunk hashes in a merkle root.
|
||||||
##
|
##
|
||||||
|
|
||||||
|
# doAssert not(rate == 1 or rate == 2), "rate can only be 1 or 2"
|
||||||
|
|
||||||
|
if not chunkSize > 0:
|
||||||
|
return failure("chunkSize must be greater than 0")
|
||||||
|
|
||||||
var index = 0
|
var index = 0
|
||||||
var leaves: seq[Poseidon2Hash]
|
var leaves: seq[Poseidon2Hash]
|
||||||
while index < bytes.len:
|
while index < bytes.len:
|
||||||
let start = index
|
let start = index
|
||||||
let finish = min(index + chunkSize, bytes.len)
|
let finish = min(index + chunkSize, bytes.len)
|
||||||
let digest = Sponge.digest(bytes.toOpenArray(start, finish - 1), rate = 2)
|
let digest = ? Poseidon2Hash.spongeDigest(bytes.toOpenArray(start, finish - 1), 2)
|
||||||
leaves.add(digest)
|
leaves.add(digest)
|
||||||
index += chunkSize
|
index += chunkSize
|
||||||
return Poseidon2Tree.init(leaves)
|
return Poseidon2Tree.init(leaves)
|
||||||
|
|
||||||
func digest*(
|
func digest*(
|
||||||
_: type Poseidon2Tree,
|
_: type Poseidon2Tree,
|
||||||
bytes: openArray[byte], chunkSize: int): ?!Poseidon2Hash =
|
bytes: openArray[byte],
|
||||||
|
chunkSize: int): ?!Poseidon2Hash =
|
||||||
## Hashes chunks of data with a sponge of rate 2, and combines the
|
## Hashes chunks of data with a sponge of rate 2, and combines the
|
||||||
## resulting chunk hashes in a merkle root.
|
## resulting chunk hashes in a merkle root.
|
||||||
##
|
##
|
||||||
|
@ -41,7 +71,8 @@ func digest*(
|
||||||
|
|
||||||
func digestMhash*(
|
func digestMhash*(
|
||||||
_: type Poseidon2Tree,
|
_: type Poseidon2Tree,
|
||||||
bytes: openArray[byte], chunkSize: int): ?!MultiHash =
|
bytes: openArray[byte],
|
||||||
|
chunkSize: int): ?!MultiHash =
|
||||||
## Hashes chunks of data with a sponge of rate 2 and
|
## Hashes chunks of data with a sponge of rate 2 and
|
||||||
## returns the multihash of the root
|
## returns the multihash of the root
|
||||||
##
|
##
|
||||||
|
|
|
@ -0,0 +1,527 @@
|
||||||
|
{
|
||||||
|
"dataSetRoot": "16074246370508166450132968585287196391860062495017081813239200574579640171677"
|
||||||
|
, "entropy": "1234567"
|
||||||
|
, "nCellsPerSlot": 512
|
||||||
|
, "nSlotsPerDataSet": 11
|
||||||
|
, "slotIndex": 3
|
||||||
|
, "slotRoot": "20744935707483803411869804102043283881376973626291244537230284476834672019997"
|
||||||
|
, "slotProof":
|
||||||
|
[ "14279309641024220656349577745390262299143357053971618723978902485113885925133"
|
||||||
|
, "17350220251883387610715080716935498684002984280929482268590417788651882821293"
|
||||||
|
, "3614172556528990402229172918446087216573760062512459539027101853103043539066"
|
||||||
|
, "9593656216696187567506330076677122799107266567595923589824071605501987205034"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
]
|
||||||
|
, "cellData":
|
||||||
|
[ [ "211066599696340205996365563960462032209214145564176017965177408819390441927"
|
||||||
|
, "256399834032317991719099034134771774537377713676282398278615627599320306708"
|
||||||
|
, "40526956212941839024868120947422067322935297516255336725720469887577875470"
|
||||||
|
, "369406626072040375689238003388146123438765868500054546379159741776926336393"
|
||||||
|
, "333671948877941061129138970028865844558745266314244224980179694307884999701"
|
||||||
|
, "12844191661993811401197260475054004253686019503294245287625435635597431176"
|
||||||
|
, "103242505924551040184986153577926463300854479121445566984435820844932904541"
|
||||||
|
, "357267598134410031301285377503939045679462829143562392803919346036584141082"
|
||||||
|
, "162961530392479745020607594774288130869393650464001426863668385541077786641"
|
||||||
|
, "426633666684068667053061341108297711407154520752589357873877687002123230254"
|
||||||
|
, "131217200633679697678620573903653316618851166977399592012996945149000115543"
|
||||||
|
, "347806146382240882424437318028620747118202052207615339887983883245341422889"
|
||||||
|
, "373560143578047669373240014805175743607410583882636003337120578008437374619"
|
||||||
|
, "188643112726610812698950916978832639394489168469865816132268079928321994342"
|
||||||
|
, "261643693073361806247543578456646407192325702146752104760117340650316255422"
|
||||||
|
, "260425332276127964154119199351807753107358504026338378706506655351595199132"
|
||||||
|
, "374895089121103633563000003194929058314955925591115574099805066048344387554"
|
||||||
|
, "251251687633538360627384151887287228926166832908633974282160065378311171354"
|
||||||
|
, "72870348025150463132527129203816383011245664502016571773976961034605631401"
|
||||||
|
, "234969517550818492643515432666311755833657223377594670026839098818269671638"
|
||||||
|
, "250704662734070531273640113211555977086430125469327371276827055724111014200"
|
||||||
|
, "85287059658255939741261887818611116570376488685014337052369839580946343903"
|
||||||
|
, "148959658976765873884541474400081762855732313547557243964921157967555048302"
|
||||||
|
, "402116967301520959272239788104745348344918207829380669065019055837727389479"
|
||||||
|
, "440503687192139964066297025050080823601005280790824714962651368433530759519"
|
||||||
|
, "149064344353438643307231355233484617851197634669308957706338957575177745645"
|
||||||
|
, "249140840255377018814348914718469942883867200392561109698520706525194687651"
|
||||||
|
, "108796851176515124780842490199733462942992752881710253277179665118758071359"
|
||||||
|
, "168245155425564161902686596247453762364112240129335852645432169468767513906"
|
||||||
|
, "129930759770229612264501691941454447321585806001002088749773920103899362070"
|
||||||
|
, "26204732465033162738545933008873662562758704699080684615280202127289894343"
|
||||||
|
, "434343986187775289860542785529657444690073100436887472033336117760907652966"
|
||||||
|
, "361202432740487795596808128962740911600093857340619816047190021218849540225"
|
||||||
|
, "100616813001075101816809823591611435583084916492802624686700765550893945525"
|
||||||
|
, "262383566766515164611427346701355047932794351290691325516723194829671679460"
|
||||||
|
, "223966317895663049002893008659178463136086169222436544014405848127792334099"
|
||||||
|
, "416071800998333357259662686053338495720384342746822618737948080251761863079"
|
||||||
|
, "402582378631671531909245563300554883898015688826468151075059467077182712018"
|
||||||
|
, "271682867846395286938993638577506552857925968097084028550962231439839229096"
|
||||||
|
, "447239701195120035004067146414333903010840427278848992921567785105217019890"
|
||||||
|
, "275718367441702584521943480326858762208121719038684001399322597215141179102"
|
||||||
|
, "86424132534636958411139699704035287483951667275825975536719519441147485752"
|
||||||
|
, "149332313586183975744469174256094358432564607635406143904268565140988616920"
|
||||||
|
, "431284330776421588418608279008210842837281123158951642164956884286883748089"
|
||||||
|
, "328694410745471749523135644660455669483988686888634622076863114197617693825"
|
||||||
|
, "112671940998917362968156144648543607958275336559773039070338509488400224090"
|
||||||
|
, "40612851250697989627190554726382690498263128439797780029697069621854862060"
|
||||||
|
, "235047914228675997216342104196597257178021277585839376175077878186492271543"
|
||||||
|
, "169718735151210135199527910197065439221144015957220768545119706561079163228"
|
||||||
|
, "345850109040121443591415752965486014695272086901102608769402892906795715635"
|
||||||
|
, "107916794601837835951508003838161872232087225679609623116098837565956752373"
|
||||||
|
, "415195406060373162425374246348197423165008252112453298469572523506488563795"
|
||||||
|
, "18574536720926634955170276058049993354780447816096707123565164996905722992"
|
||||||
|
, "77316964375201096801231570737992491072607736322255206149311341101525354519"
|
||||||
|
, "198566211140075666401818378905444403588640345933666108724809349396921957675"
|
||||||
|
, "71926050707400318807625168942501384117254391471312636171205913503928815127"
|
||||||
|
, "303403754792341398295052586417779761162194818661412867094096550880325459639"
|
||||||
|
, "444796230931706624375881141460151785952798771079111017071124833045933389733"
|
||||||
|
, "430832727519144759265424205289522948157007336118070755365887670730658782114"
|
||||||
|
, "75431213985866235726407973044434444984663930761207296437571668004273515965"
|
||||||
|
, "9242635103653159191249730220870735855877366952081272723035956668095954838"
|
||||||
|
, "93770678769846326584848478152412123903909949977598807336203128684179492141"
|
||||||
|
, "438043261966019084676377174988310087831395864304423411701911688757793135582"
|
||||||
|
, "175357918416563657734972138036003712114814934655676571874083109097142591069"
|
||||||
|
, "301619681954194702458985259161884119574424456150215738560639417824784261940"
|
||||||
|
, "376627771252167062559065889174364784087884871999807562320457079200311413098"
|
||||||
|
, "77407"
|
||||||
|
]
|
||||||
|
, [ "424838222746158988229624788694939151178615656210585621868910231014323837551"
|
||||||
|
, "113188486246955346418956949679485575685258850346101035778277727456423482970"
|
||||||
|
, "275449978206132565019222655023969430014622832597654643418394602485645803413"
|
||||||
|
, "407856757018138010439232009766252068440920591566039673660874626878413077905"
|
||||||
|
, "433369046493777496016384947949950877133856528218602671493669395706908819748"
|
||||||
|
, "258364166531180422149545015891786023981872586904946376136311798402581278793"
|
||||||
|
, "111997719221028147522803956659709775148434180015507797582340706052412284571"
|
||||||
|
, "370086597976426508280413876667101417393598181708677558733730556109327409076"
|
||||||
|
, "394139601979449259075910238117153992797849553309541269624848742084205563806"
|
||||||
|
, "224088276319080487199395482893988152025671468715318212801266537036640477323"
|
||||||
|
, "412710245119809501914481942088314642684754542082140451180970198371889738885"
|
||||||
|
, "353872602359946553306242341162348980635834907495492814598834657175405697176"
|
||||||
|
, "252575199506028475372678621140654219936768774012823764047177692104580452933"
|
||||||
|
, "259093153824033122452869556249315839899366493071746219770487886456301642099"
|
||||||
|
, "433829976798312333371154167497560676982294392632725612538640639617101218872"
|
||||||
|
, "69918581382122563555200898078544150952625715196904114153232367538572342772"
|
||||||
|
, "337937520623192257595352158476909569245988839238498098464935654555688460123"
|
||||||
|
, "264739973232292969253318643276671532055689422253184191167449284055983944338"
|
||||||
|
, "326116252818829775096345069850111970510714050346103409479803743342138260656"
|
||||||
|
, "236666502377413649728378889488706275212721356921124776708954261777813709815"
|
||||||
|
, "211625935799984260567718228446525455893664313064841539301444509150157287163"
|
||||||
|
, "60213206239417039999880027112341976360540689886703427811513517396638607512"
|
||||||
|
, "68310118105957780876770075529546844404225720757669797609686816545988561625"
|
||||||
|
, "423863085551351065136684030270731679105571943009795949621903966660399419936"
|
||||||
|
, "388914614294393005039878123500859325222684672184567792659076815268598434245"
|
||||||
|
, "449456790291560508709069826219925144971979653209755565240911568965768874382"
|
||||||
|
, "448810363770763694447869940916735951256986784286793489549428379909616059117"
|
||||||
|
, "93646909783664049092056237949587618925209622020026157405117796611689551192"
|
||||||
|
, "352210795298632954574896499649181574584074853828419384742874364724522457331"
|
||||||
|
, "37455517056393404525863484733101879886413925183061645520768912552476716150"
|
||||||
|
, "386617357584684336812125385078476270301738184058813703112840991226785114117"
|
||||||
|
, "309940292044597334261558429176136686101590729982259514472573656131579113438"
|
||||||
|
, "375815246167575100319857872432879650174355611853064771241069582477717074415"
|
||||||
|
, "332214507344122806007757734266883566559371568252728459951766124888176633706"
|
||||||
|
, "148990259460952914990881100852534318351247069504848477833147446514732789712"
|
||||||
|
, "328669527889838880414072022433859139004058211332184916573516704632073044118"
|
||||||
|
, "39278026039348543645873027549112998051601664395028652771103624299930924528"
|
||||||
|
, "147717660530589785119644237145092759103012624422229579698752386490700965238"
|
||||||
|
, "374018518701362017594752095877197725242352803195413267746619111489936980685"
|
||||||
|
, "19185486483883210730969367354195688373879769005461272861759636600984416877"
|
||||||
|
, "61866046506558157021682973167090213780467780519546382332208868591026703563"
|
||||||
|
, "186854966504766517012887726614015646154225796572138017810371160981778288347"
|
||||||
|
, "87813550250328892091332566928942844770632705056120813488729800874811845697"
|
||||||
|
, "207775163424060266085108794048371834145545842567796157378282772999548202308"
|
||||||
|
, "369987573847786237689249538753881486995686208870889713177975415012214427429"
|
||||||
|
, "240880979016395044518849230927615466120209140082149273390921042537474853143"
|
||||||
|
, "174902051454932913375934735427101804474275543418199101786687925733405159872"
|
||||||
|
, "342217255652950822372803598682842961053537267723988087801275319754065261308"
|
||||||
|
, "403207518067666945448161377960706451817747922771285796668778802535227939962"
|
||||||
|
, "407191459999036791052261270163259267557900498930952521056725210031161568230"
|
||||||
|
, "338216472523551728793268225845396218561132966393725938551091882807069657206"
|
||||||
|
, "118364222678576550870375112494142500603091119946985793934499723872824782886"
|
||||||
|
, "269721611028665323587192624288165848310917029418261851436925829954710472436"
|
||||||
|
, "227424498125745236125352117206136621428869662458452610254773560636280935711"
|
||||||
|
, "334380807433339401906359555583987757411855090694162252260781648609761248049"
|
||||||
|
, "42470806516174819075107446234449247453971524726021445768611797530804156161"
|
||||||
|
, "418994916402918322951830716592888390611524984156817012683478842068581638820"
|
||||||
|
, "363263142412048420546716019774090729399081311227606555141174736853886128407"
|
||||||
|
, "192292715923468025058557166341646729623133127372303791236447550026886802680"
|
||||||
|
, "450253878713722337767292128303865371116770532625906889925779639839924402495"
|
||||||
|
, "412596147086332805611392200560087191411541689130482740065137300252639590489"
|
||||||
|
, "264059866105067484811456793906835462997849523506366903974724979936196358724"
|
||||||
|
, "80922384260325792825608274004101667366364502159441286540209512108302572137"
|
||||||
|
, "69261112192907071823876894642934902051254647002357333297635511793652550535"
|
||||||
|
, "342810644068354896385837929029331085645928473943142618800192452300937098227"
|
||||||
|
, "228361826362950356801549793202622774869100858404479869989505302905936946659"
|
||||||
|
, "89244"
|
||||||
|
]
|
||||||
|
, [ "359926778925154809567585559910064420821311221299937568759183366972901588855"
|
||||||
|
, "128688825421597555299113005875649976344934035310192572516197551102045945994"
|
||||||
|
, "225379354482053502673695304662016054746658452775856157938886424152134693969"
|
||||||
|
, "321872319934407904743844034025550739031781361848065513098922085967524180784"
|
||||||
|
, "250375637325405951645070615947051799520095842815922754899017741501395744611"
|
||||||
|
, "97676493052788080672307677749501730337551225267342432472194527468634722352"
|
||||||
|
, "140101187036396881926000630022834247990512766860086619783437252676747730662"
|
||||||
|
, "428833039353549335335605804240430918631639449874968791377641834408506136850"
|
||||||
|
, "418359203734539413977740838354554804415161215624809316660001820037711273005"
|
||||||
|
, "197411877418795659129213175603102238904459737200167987167255995825203749339"
|
||||||
|
, "221646252100316559257470803343058462853641953756978011126414924636869625612"
|
||||||
|
, "106393540293584181037890192557883541231531964825708650997196071036779482686"
|
||||||
|
, "121473330828208543539643554911190528237124877123871673169194452404939833883"
|
||||||
|
, "234055622144947293638512253368547046093971383516706577723613696162225606040"
|
||||||
|
, "68307451767502390304445005915787226559811433450721625085741437522802389574"
|
||||||
|
, "446891883436763112014492564462451523127134145501201571918449345324780633462"
|
||||||
|
, "83718652783543018019599555197511164121642363321504039439786358267060414949"
|
||||||
|
, "90267297500929836073049162292104311427365986272517761342871530827272320168"
|
||||||
|
, "398425606698859520268856768787424690872952910789754531465894080258173664751"
|
||||||
|
, "323570139379118444589557840594603212198136718240764273769210492735883659788"
|
||||||
|
, "318597103584099056378057647488068323974418467250708490151864712850204121402"
|
||||||
|
, "6299083430773359277240726214182464517380839990956316267425262319606033077"
|
||||||
|
, "27638206326925436960316131682014727983280820447721477666884742925275976240"
|
||||||
|
, "434344186848869917381375812528446841024676181532946456237439060027443649574"
|
||||||
|
, "64735754118644738348599761514174981324344130078598038275246522384474432918"
|
||||||
|
, "53068717269762105498508401788249005564862415051761175636612434108259085043"
|
||||||
|
, "35813044996911619267309099508360887777226716179396659295580849861836012116"
|
||||||
|
, "67751791392924142809580984450371772015056060429352159361446914484238646676"
|
||||||
|
, "68534949135677447506316576616742207938855454921330757052467057435206318183"
|
||||||
|
, "98510151949547604999069864337574320742530406479752176012935179772005228326"
|
||||||
|
, "342190252152505345443004241184891966319091967630257822491352072978326623645"
|
||||||
|
, "362701658859425316334005554473186516818256386066010799465369887406035738447"
|
||||||
|
, "266999116654850467726292928465517542818678046748008340458185725047959981772"
|
||||||
|
, "227089355966197874086821090531951502393729872265201602128464978982907992285"
|
||||||
|
, "240800343500959216904535208047288234867926058830277460630902462914796702354"
|
||||||
|
, "447956858573680756485556898469710354624642653441041335815079102198306530583"
|
||||||
|
, "89422712944117481549242421245588048728782658978853365197341587057196539094"
|
||||||
|
, "72610343179362050463955730204044877712105879926618304878262944723464870506"
|
||||||
|
, "8676698500519447254981838968537883138182811064381378248657969913325524054"
|
||||||
|
, "180453700216061196739413267121764366438386031039311941313645439527087166894"
|
||||||
|
, "63346784016053253727621352882430122335280702556586808389293772066791583857"
|
||||||
|
, "400031453850139978805133735852120986024101930860924735862305444817383365395"
|
||||||
|
, "230104622290558570218036071349472289358926019290368625724986905348610140188"
|
||||||
|
, "175689489221336091369196327293045073133701056385414159213338224521167050830"
|
||||||
|
, "73310331103509697419315970265031228794034932318600293733074730812482185479"
|
||||||
|
, "371383255255842707875498538452907102684511927320158672347778293876877893808"
|
||||||
|
, "165319345890230193939972313953881372394171342391835626454759321320435952720"
|
||||||
|
, "184753541001210613115361457830691571384268642766106935428207829332011259768"
|
||||||
|
, "378810733004878432563271790625801205570962762395854282745166380274493181314"
|
||||||
|
, "86321674336629444862383262780020871828941143514651008200999725989892879714"
|
||||||
|
, "332634533993388248915777870988529817692938793120418377552247997050250349749"
|
||||||
|
, "41742010257820712511267405684781534740157292266212120171929853763272599516"
|
||||||
|
, "224101330592139734390658213442359402546038743346294438455635537496290117560"
|
||||||
|
, "204363902046137087420878796391135987770418514008394389852388361468850216359"
|
||||||
|
, "296526036888463156867153847102999031430641220536577556044554029990778763710"
|
||||||
|
, "137568796227115931047082828377698464185467276723279763304686078869351280509"
|
||||||
|
, "147456720891843338735232645318045656082153590170441596326500204393398792771"
|
||||||
|
, "297291342309626392877004635010131510068476699687818509485687346071074942006"
|
||||||
|
, "20748013593486831233186810444485136836664689496258849465507672301203832324"
|
||||||
|
, "335431726883875036252568773858744219410188302724423071283643221351691013313"
|
||||||
|
, "50487384098835523033417523223562560857744547945136829388944024807752630716"
|
||||||
|
, "425952679139710019732649156938676226492714486376811103362264146658191708598"
|
||||||
|
, "439787938069461539508728805881194071103269524405653997968488488049426387373"
|
||||||
|
, "279863410796988495259178322026394289028023166886112128504434877538089779477"
|
||||||
|
, "398941099058270093463626870965433502581301413791423667994257456160377865247"
|
||||||
|
, "5759692644185723491187478313102540786562625675495805072053262277490225012"
|
||||||
|
, "115176"
|
||||||
|
]
|
||||||
|
, [ "199440901482393381753657315848210955092644686957900737971520778206058989647"
|
||||||
|
, "339215657660349719251187938243949119362753238126598750470832739830379601048"
|
||||||
|
, "17957417011314891245400567671664723859427624136284133790923936126779445290"
|
||||||
|
, "294761585889095249928492042608516765584723814657871392207964321318076158536"
|
||||||
|
, "367304199921887970655898837985855454346911090426896946930048519042744277770"
|
||||||
|
, "173405546837606747721292792526074597519538685230485266741646923399938591491"
|
||||||
|
, "13202798104529529703580600642858924379886936325402696094624200032343206719"
|
||||||
|
, "28211272278315691894282764239983301742024079691520980592618486887749800025"
|
||||||
|
, "73792448247120972778500624350664849847034095641998271809779791788652649022"
|
||||||
|
, "386961947078838359430674078072441680475090687247027225632133013772954043342"
|
||||||
|
, "247859266401821616700765969075270662915024391205665146199401830650793676517"
|
||||||
|
, "243938047874995926342875119559105623088213951205962677439167259642163766960"
|
||||||
|
, "14909501249861872673329370269106359532506159818320693170564856401208688898"
|
||||||
|
, "200331653478898243177761429526240803993101536716611440775588088625522029071"
|
||||||
|
, "127891684617049394579738365914860024509007913559921966744972525605976847919"
|
||||||
|
, "202912167983786187592861727924433749852786012202809544200943965898118027816"
|
||||||
|
, "176370650316309755425558132466370508977563252342126855874617990006444464573"
|
||||||
|
, "179490319446297562731655155074196383539396893457024237113284509223965454107"
|
||||||
|
, "118703379899134287650980989454755985628620830085932176414465582081598659194"
|
||||||
|
, "102025594191113707886629488454876652037341696284939671367279050169222988689"
|
||||||
|
, "421132375430104331136732058548913808473025321492255503838896123601628815453"
|
||||||
|
, "328334791815856213206267892694535121226673194052951034497930366807851111845"
|
||||||
|
, "83012322813281668737061895967682970093636853452224812061110092135287899376"
|
||||||
|
, "329204708391107220275172926348002826875172581958734129645882445887919889321"
|
||||||
|
, "410748869385474485539728045765785256294532845070137964737879849265390625591"
|
||||||
|
, "197274807717335387012872999914232051341799797613667869923402386359379902675"
|
||||||
|
, "235713095185988155553500217595661312303861624791720350423698435045853678746"
|
||||||
|
, "150631584359141913552843813384841153102535679219851913018874172414598353488"
|
||||||
|
, "207783836843813911284913666774420250626019971129676431904589416081127483900"
|
||||||
|
, "15728034718954665549174230921445077500399069880555428849958014406422697976"
|
||||||
|
, "69799423545177501667748653663121504155622623013014583690766769624482972893"
|
||||||
|
, "265665371394145560256710553779588458846778960884758560117805511822299802326"
|
||||||
|
, "149195925869584039415331014261414953602245337159354350672030141190471260449"
|
||||||
|
, "162328395279114064180857718453973759378615891406692054752029241989300597156"
|
||||||
|
, "104643123291849369328362168243087456326274773811561124607060302871149280568"
|
||||||
|
, "320704123383295724141970902124509237736831907552238934395000039155541269937"
|
||||||
|
, "77914486216152383968400591704791756847610018757857965758408455442143531631"
|
||||||
|
, "238365259321088298905088250444146071545398991768186471689605160523129613763"
|
||||||
|
, "279409375422154593510552116666741774885392805494152031820287626934209978908"
|
||||||
|
, "195118776021452609708543280509123101181249086555819844047203390788132717252"
|
||||||
|
, "197977884437087886153482042453896079316138251415359773453987232734849953584"
|
||||||
|
, "168185043240980087638006965666857387510828226074470344841850764460631595331"
|
||||||
|
, "231157923359356077977363679818678437836536420121744865399935742538602805912"
|
||||||
|
, "177903771863742191900138437188329108771172098110036075491750018158192424072"
|
||||||
|
, "313552174443290416730632310997197097951229162137491595709733420111980331403"
|
||||||
|
, "273253450712049988786741336540196077743997302924525995219038781650977490211"
|
||||||
|
, "421908030281055821389377531613150504859996607596444776050212044919345332385"
|
||||||
|
, "180108184992593746898140529947178182204857361841304042854173884504394805936"
|
||||||
|
, "37075272799330399065679301151342697855905822543084867570322173216259074746"
|
||||||
|
, "364885615491975468180698816037289079302391684470748470356247509218051645743"
|
||||||
|
, "397482868106190800111749908137311511782294652288655656060379563261618687603"
|
||||||
|
, "192853269627895017416381451198403197013798085262867793715522216458130791820"
|
||||||
|
, "450480853450142791928572953497280890976328598410525218090104787739409705079"
|
||||||
|
, "40278654070502961330170439514434669768416784968274956021022493731441898222"
|
||||||
|
, "251277143131769020481025315216040765839561111684608785317366609258959942695"
|
||||||
|
, "95094468748825454459610961968601800404132682484160170977941285794444806916"
|
||||||
|
, "160586633865113902389134480029183924655750088163491531655080014223476604929"
|
||||||
|
, "211661229493873434581423107377168478957907088187044576032505407590783850232"
|
||||||
|
, "409651293631434750272174456674594508340952460788494035327119354167465019826"
|
||||||
|
, "233213211946836553080627522409887799285199986120567245752841080275284294566"
|
||||||
|
, "143182900674482411759481361336063079267405785923487419697568907351386146653"
|
||||||
|
, "430050085956999990041799366370428972519385994997821389120583306252090911051"
|
||||||
|
, "241257468571530133762629460194062384921386438426367660851087853915892684115"
|
||||||
|
, "106478922860328643074356032194102718325829441005019365153538120054339275205"
|
||||||
|
, "252933430690486626644000908036895289326526510137514385824014300035301154822"
|
||||||
|
, "242924628511152862437189415942615812459145003511499320946981326550434266392"
|
||||||
|
, "107566"
|
||||||
|
]
|
||||||
|
, [ "10892488375325920610152294701785926476935321890453222549428070867493882259"
|
||||||
|
, "230776541958253414701326765204413805639078570664616139597900921490475143840"
|
||||||
|
, "162235550819840758141721889536295480113278275911087429090017541814695333320"
|
||||||
|
, "318634611531007856220026646570492630940047240387334221027051366284225674524"
|
||||||
|
, "347695480420330337439096561080975864031317110001559084872978387417651465445"
|
||||||
|
, "243301070227446762125488369714708670219289121859111929877695012393609726208"
|
||||||
|
, "312153141205681954392441579373652470334482191990502803524039048245142338874"
|
||||||
|
, "243769659456658813016931656268556893289414122189859136776671772112510762644"
|
||||||
|
, "235510946617019540983239794402008700611014664578713646813426116406215382253"
|
||||||
|
, "394638234040056271265534896894991100558052611842099314808878257003754175212"
|
||||||
|
, "112730195097163222179949980634599934392634120069300673310070655800491242211"
|
||||||
|
, "112545144551723145227061757291353149296490850338535641681237178578430772288"
|
||||||
|
, "399161925498018051746424503488168548076537557369822821644005390567188305750"
|
||||||
|
, "291823556779130095044851238536860577785281148245623338113991004798525195947"
|
||||||
|
, "443006765181360772964201996695219533539991249361936300010158089981376772939"
|
||||||
|
, "74018417655448362012716269253153545524112649147848318337218250865231619883"
|
||||||
|
, "361038295627629757439073080656763633087074408866229383288288831546300069767"
|
||||||
|
, "269655542872834422597617091710145830035767834433114567250727497135451412216"
|
||||||
|
, "58289072717559976781527037332370898163550414718655391280446986067842922181"
|
||||||
|
, "365399954331278626941053447122605263207706937018525782908294459265663426953"
|
||||||
|
, "83576501872896181822963149907518188809522341045703363171261203985876068484"
|
||||||
|
, "203403783686919490357886887779316222746544665267595235714814853282937072937"
|
||||||
|
, "226090172488558641139782927103632452136731207206963592401497570070700221117"
|
||||||
|
, "249813560776802008219945831355163226098682741553305882699128946352901227282"
|
||||||
|
, "236586835155013316983057471119105606475813711035522306026673814184519826069"
|
||||||
|
, "420611449257527132395951061920868895981487081726689195426673433565077012458"
|
||||||
|
, "414979562418422585161189066520079202660418565693776869373399931253524536378"
|
||||||
|
, "115851377630895049619958829726730418778383692593973233290077769966938018584"
|
||||||
|
, "248071158447148977966329235335508229928647083339924308951291087789494073866"
|
||||||
|
, "8254100651607835318906499132096926759832050649688561036854000785129084907"
|
||||||
|
, "91385483239630999205401307763890943367451672856478206313711901403403429289"
|
||||||
|
, "369346641925770698935046191632374874762045839747680407985443471202350286304"
|
||||||
|
, "236809023553698844817613980395588655518336237009075203833474757804664254158"
|
||||||
|
, "8367847400805682648908349286699722579431227561083498361702537964306290078"
|
||||||
|
, "599241730770400067632779114435635342549228985534229813617556932580328166"
|
||||||
|
, "347112528350917448294202348829052279076907614831011498643025223836596915573"
|
||||||
|
, "384244379244118003891043669466323943736726794634167201471569326059716944701"
|
||||||
|
, "118013777197672343498581960057939216208494837962825017767101107204031333144"
|
||||||
|
, "27234916267695376599463409893017377196853108034589808756909998459364893467"
|
||||||
|
, "443519198016088819704735929590164254445884637317806160485888215392818578737"
|
||||||
|
, "396780482611567392375183169345153676737175342167284140440545202776279411157"
|
||||||
|
, "420351155303051883480975795437743307852799862858964108014000673383502660760"
|
||||||
|
, "17379377743250873773932440622865094720355292220433235366224143179854831702"
|
||||||
|
, "299671454782683147939928632170233327590769402224392134648893444626929909373"
|
||||||
|
, "143062753141414050359792615867774312517100868919516205179025540179759009492"
|
||||||
|
, "79497692490953838158801094558761984613913564034406069659969793097043605498"
|
||||||
|
, "422748645389700647011491406944374966856916994331478229959954030359911549565"
|
||||||
|
, "101802829812014644970197499895811874607753186302439171072935333706660468030"
|
||||||
|
, "376428369998893026519415315112012919906032811618495880392785036762185101192"
|
||||||
|
, "193969030999254195249242252871597931610859408264053152789041067245597391073"
|
||||||
|
, "262277607928686742238285487190873200602833495734085188071246746209841324139"
|
||||||
|
, "154099884960502807271641574310268486840763221700920893692135020347157046386"
|
||||||
|
, "155875061164585018658671842995328931296342883770473498362059838106632382461"
|
||||||
|
, "248574435283666782825705601259695525637993294311364397935499480206725256362"
|
||||||
|
, "171325185063038052248966557755722232979612702743265316145563443527135798688"
|
||||||
|
, "19982746887818897250405980185937061235439217109294376948752373205830077881"
|
||||||
|
, "363719103724181291346130833008745948141602173373912337315631878022251200824"
|
||||||
|
, "174596812883797666354579747966720458118607233660798323559531788300018084931"
|
||||||
|
, "296611197821867585469311917529661698312828606304722408477045992233526328708"
|
||||||
|
, "115884038550627840768260751168697204665962542002024023842649383174518895165"
|
||||||
|
, "265597417366164841889730505737916646261040505851159477903649773521314216810"
|
||||||
|
, "59890857222664166616144499778264545115438678877460924559608721809777680238"
|
||||||
|
, "150275344313515259978222149421664752546204516114655782705875535407472455999"
|
||||||
|
, "119762211657733951640135703777940013374803447228667976561992857374027112851"
|
||||||
|
, "124750313254270944205036764607428674226393862430770588148329786501973600535"
|
||||||
|
, "223562415856611692667255745278751292230311455355383541649772348032933666931"
|
||||||
|
, "70851"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, "merklePaths":
|
||||||
|
[ [ "12330511756602656312909435206144412037562550923861053314147193494605624608532"
|
||||||
|
, "11626412651279744307149389430094868876817959605147995292836995419396445628874"
|
||||||
|
, "5992799448428980485292103987999399446160713735809250167288027256759377161164"
|
||||||
|
, "19665782623633007009046423286205585606029554995684266199914536255425604862856"
|
||||||
|
, "16487082247902739801276638140231448150060608377815926330854457096549924699346"
|
||||||
|
, "13757776896542890425183206586238760231244468647794123671233758868377423038254"
|
||||||
|
, "5689382212199289790852870716648320118282913659439556386010574440270030991956"
|
||||||
|
, "19397819444005071538172083272808000152189643623980212079104170950073560541073"
|
||||||
|
, "13602141253349313166682170066159161155345481788270338632198566205283140117430"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
]
|
||||||
|
, [ "20475873274412005481064639175076772466269555202404881992985142339142752174247"
|
||||||
|
, "16346160910918020455716115524174351294558871582658635761456705803199256575588"
|
||||||
|
, "2853750013041818757293788273269978233503065226276819540991640203844566736443"
|
||||||
|
, "9192572535522846104757923561847416578417599996904208474460700268961782558170"
|
||||||
|
, "11041850361074018956732434352769265303294549935255362322653487210796196161858"
|
||||||
|
, "20835509643844784930831626622202658364476409300598072395494952478408974334325"
|
||||||
|
, "15426115581767819720710837762133134950520914636073261355445708100826108573907"
|
||||||
|
, "7565353224987902191368863653499353764559862741092477570130316358454603122676"
|
||||||
|
, "2622681935585012630617774892501744551457568716225188460692779556142778732663"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
]
|
||||||
|
, [ "13099868869639061574800067722436547911616384523753701384396275064543709640456"
|
||||||
|
, "353757809120595355213201328586632712724405232919181040928026587840976194078"
|
||||||
|
, "17653300914565730132855106316678548541847283141888106932466281385199556950861"
|
||||||
|
, "15467462085462582082877261755656498905479817107855355753427299990712166382496"
|
||||||
|
, "8291733777946446853018893495264026584437749231931118771866890345692346711355"
|
||||||
|
, "15510790697317206014779022286261864844918915222875014882833700758879700055506"
|
||||||
|
, "5689382212199289790852870716648320118282913659439556386010574440270030991956"
|
||||||
|
, "19397819444005071538172083272808000152189643623980212079104170950073560541073"
|
||||||
|
, "13602141253349313166682170066159161155345481788270338632198566205283140117430"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
]
|
||||||
|
, [ "123238869181525326412236116167249816873084559218151119452851092131080991962"
|
||||||
|
, "9610314342084317647296061595824603740114670828357751076517430572434680540425"
|
||||||
|
, "16802740554584732104294972716558962567961331277692246600846665155168171370476"
|
||||||
|
, "151083360419914122898584757765086723506432610661508069194962432698872036623"
|
||||||
|
, "10357032992337239725601662829902169825217513617307319193581711776597892496381"
|
||||||
|
, "10120699018002766520605012835043517238241846918467244955580419060582311503402"
|
||||||
|
, "21149604008153751948441881526949680605328007895979738537313721955134548786062"
|
||||||
|
, "5720106921878932614189421948890362637585879521377362100104826996201092964473"
|
||||||
|
, "2622681935585012630617774892501744551457568716225188460692779556142778732663"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
]
|
||||||
|
, [ "19153513112714782931111012244694922243101677748840856395814929006033044311081"
|
||||||
|
, "21046138187228318287277629107063936540039891592394801899272249280765102572688"
|
||||||
|
, "18057980437430910028015917806534512217725128031222973066601095455076586015436"
|
||||||
|
, "5766677914654397407881589917461473873246279171605373166264025525757502238061"
|
||||||
|
, "12019967669236656188577515900815533059046454955207846938479617973037184411021"
|
||||||
|
, "14504305765289705714959523666100275156034056689367568164630385862257567596209"
|
||||||
|
, "7152002871325824138073253423783370852632926621899161541618248808716037342022"
|
||||||
|
, "9714587356194206699401761190093056901650105401919163689816999407566849779455"
|
||||||
|
, "13602141253349313166682170066159161155345481788270338632198566205283140117430"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
, "0"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ import pkg/codex/erasure
|
||||||
import pkg/codex/merkletree
|
import pkg/codex/merkletree
|
||||||
import pkg/codex/blocktype as bt
|
import pkg/codex/blocktype as bt
|
||||||
import pkg/codex/utils/asynciter
|
import pkg/codex/utils/asynciter
|
||||||
|
import pkg/codex/indexingstrategy
|
||||||
|
|
||||||
import pkg/codex/node {.all.}
|
import pkg/codex/node {.all.}
|
||||||
|
|
||||||
|
@ -54,7 +55,7 @@ asyncchecksuite "Test Node - Host contracts":
|
||||||
manifestCidStr: string
|
manifestCidStr: string
|
||||||
manifestCid: Cid
|
manifestCid: Cid
|
||||||
market: MockMarket
|
market: MockMarket
|
||||||
builder: SlotsBuilder
|
builder: Poseidon2Builder
|
||||||
verifiable: Manifest
|
verifiable: Manifest
|
||||||
verifiableBlock: bt.Block
|
verifiableBlock: bt.Block
|
||||||
protected: Manifest
|
protected: Manifest
|
||||||
|
@ -84,7 +85,7 @@ asyncchecksuite "Test Node - Host contracts":
|
||||||
(await localStore.putBlock(manifestBlock)).tryGet()
|
(await localStore.putBlock(manifestBlock)).tryGet()
|
||||||
|
|
||||||
protected = (await erasure.encode(manifest, 3, 2)).tryGet()
|
protected = (await erasure.encode(manifest, 3, 2)).tryGet()
|
||||||
builder = SlotsBuilder.new(localStore, protected).tryGet()
|
builder = Poseidon2Builder.new(localStore, protected).tryGet()
|
||||||
verifiable = (await builder.buildManifest()).tryGet()
|
verifiable = (await builder.buildManifest()).tryGet()
|
||||||
verifiableBlock = bt.Block.new(
|
verifiableBlock = bt.Block.new(
|
||||||
verifiable.encode().tryGet(),
|
verifiable.encode().tryGet(),
|
||||||
|
@ -127,9 +128,12 @@ asyncchecksuite "Test Node - Host contracts":
|
||||||
return success()
|
return success()
|
||||||
|
|
||||||
(await onStore(request, 1.u256, onBlocks)).tryGet()
|
(await onStore(request, 1.u256, onBlocks)).tryGet()
|
||||||
check fetchedBytes == 786432
|
check fetchedBytes == 851968
|
||||||
|
|
||||||
for index in builder.slotIndicies(1):
|
let indexer = verifiable.protectedStrategy.init(
|
||||||
|
0, verifiable.blocksCount - 1, verifiable.numSlots)
|
||||||
|
|
||||||
|
for index in indexer.getIndicies(1):
|
||||||
let
|
let
|
||||||
blk = (await localStore.getBlock(verifiable.treeCid, index)).tryGet
|
blk = (await localStore.getBlock(verifiable.treeCid, index)).tryGet
|
||||||
expiryKey = (createBlockExpirationMetadataKey(blk.cid)).tryGet
|
expiryKey = (createBlockExpirationMetadataKey(blk.cid)).tryGet
|
||||||
|
|
|
@ -126,7 +126,7 @@ asyncchecksuite "Test Node - Basic":
|
||||||
codec = ManifestCodec).tryGet()
|
codec = ManifestCodec).tryGet()
|
||||||
|
|
||||||
protected = (await erasure.encode(manifest, 3, 2)).tryGet()
|
protected = (await erasure.encode(manifest, 3, 2)).tryGet()
|
||||||
builder = SlotsBuilder.new(localStore, protected).tryGet()
|
builder = Poseidon2Builder.new(localStore, protected).tryGet()
|
||||||
verifiable = (await builder.buildManifest()).tryGet()
|
verifiable = (await builder.buildManifest()).tryGet()
|
||||||
verifiableBlock = bt.Block.new(
|
verifiableBlock = bt.Block.new(
|
||||||
verifiable.encode().tryGet(),
|
verifiable.encode().tryGet(),
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
|
||||||
|
import std/sequtils
|
||||||
|
import std/sugar
|
||||||
|
import std/strutils
|
||||||
|
|
||||||
|
import pkg/poseidon2
|
||||||
|
import pkg/constantine/math/arithmetic
|
||||||
|
import pkg/constantine/math/io/io_bigints
|
||||||
|
import pkg/constantine/math/io/io_fields
|
||||||
|
|
||||||
|
import pkg/codex/merkletree
|
||||||
|
import pkg/codex/slots
|
||||||
|
import pkg/codex/slots/types
|
||||||
|
import pkg/codex/utils/json
|
||||||
|
|
||||||
|
export types
|
||||||
|
|
||||||
|
func fromCircomData*[H](cellData: seq[byte]): seq[H] =
|
||||||
|
var
|
||||||
|
pos = 0
|
||||||
|
cellElms: seq[Bn254Fr]
|
||||||
|
while pos < cellData.len:
|
||||||
|
var
|
||||||
|
step = 32
|
||||||
|
offset = min(pos + step, cellData.len)
|
||||||
|
data = cellData[pos..<offset]
|
||||||
|
let ff = Bn254Fr.fromBytes(data.toArray32).get
|
||||||
|
cellElms.add(ff)
|
||||||
|
pos += data.len
|
||||||
|
|
||||||
|
cellElms
|
||||||
|
|
||||||
|
func toPublicInputs*[H](input: ProofInput[H]): PublicInputs[H] =
|
||||||
|
PublicInputs[H](
|
||||||
|
slotIndex: input.slotIndex,
|
||||||
|
datasetRoot: input.datasetRoot,
|
||||||
|
entropy: input.entropy
|
||||||
|
)
|
||||||
|
|
||||||
|
func toJsonDecimal*(big: BigInt[254]): string =
|
||||||
|
let s = big.toDecimal.strip( leading = true, trailing = false, chars = {'0'} )
|
||||||
|
if s.len == 0: "0" else: s
|
||||||
|
|
||||||
|
func toJson*[H](input: ProofInput[H]): JsonNode =
|
||||||
|
var
|
||||||
|
input = input
|
||||||
|
|
||||||
|
%* {
|
||||||
|
"dataSetRoot": input.datasetRoot.toBig.toJsonDecimal,
|
||||||
|
"entropy": input.entropy.toBig.toJsonDecimal,
|
||||||
|
"nCellsPerSlot": input.nCellsPerSlot,
|
||||||
|
"nSlotsPerDataSet": input.nSlotsPerDataSet,
|
||||||
|
"slotIndex": input.slotIndex,
|
||||||
|
"slotRoot": input.slotRoot.toDecimal,
|
||||||
|
"slotProof": input.slotProof.mapIt( it.toBig.toJsonDecimal ),
|
||||||
|
"cellData": input.samples.mapIt(
|
||||||
|
toSeq( it.cellData.elements(H) ).mapIt( it.toBig.toJsonDecimal )
|
||||||
|
),
|
||||||
|
"merklePaths": input.samples.mapIt(
|
||||||
|
it.merklePaths.mapIt( it.toBig.toJsonDecimal )
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func jsonToProofInput*[H](inputJson: JsonNode): ProofInput[H] =
|
||||||
|
let
|
||||||
|
cellData =
|
||||||
|
inputJson["cellData"].mapIt(
|
||||||
|
it.mapIt(
|
||||||
|
block:
|
||||||
|
var
|
||||||
|
big: BigInt[256]
|
||||||
|
data = newSeq[byte](big.bits div 8)
|
||||||
|
assert bool(big.fromDecimal( it.str ))
|
||||||
|
data.marshal(big, littleEndian)
|
||||||
|
data
|
||||||
|
).concat # flatten out elements
|
||||||
|
)
|
||||||
|
|
||||||
|
merklePaths =
|
||||||
|
inputJson["merklePaths"].mapIt(
|
||||||
|
it.mapIt(
|
||||||
|
block:
|
||||||
|
var
|
||||||
|
big: BigInt[254]
|
||||||
|
hash: H
|
||||||
|
assert bool(big.fromDecimal( it.getStr ))
|
||||||
|
hash.fromBig( big )
|
||||||
|
hash
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
slotProof = inputJson["slotProof"].mapIt(
|
||||||
|
block:
|
||||||
|
var
|
||||||
|
big: BigInt[254]
|
||||||
|
hash: H
|
||||||
|
assert bool(big.fromDecimal( it.str ))
|
||||||
|
hash.fromBig( big )
|
||||||
|
hash
|
||||||
|
)
|
||||||
|
|
||||||
|
datasetRoot = block:
|
||||||
|
var
|
||||||
|
big: BigInt[254]
|
||||||
|
hash: H
|
||||||
|
assert bool(big.fromDecimal( inputJson["dataSetRoot"].str ))
|
||||||
|
hash.fromBig( big )
|
||||||
|
hash
|
||||||
|
|
||||||
|
slotRoot = block:
|
||||||
|
var
|
||||||
|
big: BigInt[254]
|
||||||
|
hash: H
|
||||||
|
assert bool(big.fromDecimal( inputJson["slotRoot"].str ))
|
||||||
|
hash.fromBig( big )
|
||||||
|
hash
|
||||||
|
|
||||||
|
entropy = block:
|
||||||
|
var
|
||||||
|
big: BigInt[254]
|
||||||
|
hash: H
|
||||||
|
assert bool(big.fromDecimal( inputJson["entropy"].str ))
|
||||||
|
hash.fromBig( big )
|
||||||
|
hash
|
||||||
|
|
||||||
|
nCellsPerSlot = inputJson["nCellsPerSlot"].getInt
|
||||||
|
nSlotsPerDataSet = inputJson["nSlotsPerDataSet"].getInt
|
||||||
|
slotIndex = inputJson["slotIndex"].getInt
|
||||||
|
|
||||||
|
ProofInput[H](
|
||||||
|
entropy: entropy,
|
||||||
|
slotIndex: slotIndex,
|
||||||
|
datasetRoot: datasetRoot,
|
||||||
|
slotProof: slotProof,
|
||||||
|
slotRoot: slotRoot,
|
||||||
|
nCellsPerSlot: nCellsPerSlot,
|
||||||
|
nSlotsPerDataSet: nSlotsPerDataSet,
|
||||||
|
samples: zip(cellData, merklePaths)
|
||||||
|
.mapIt(Sample[H](
|
||||||
|
cellData: it[0],
|
||||||
|
merklePaths: it[1]
|
||||||
|
))
|
||||||
|
)
|
|
@ -0,0 +1,166 @@
|
||||||
|
|
||||||
|
import std/sugar
|
||||||
|
|
||||||
|
import pkg/chronos
|
||||||
|
import pkg/libp2p/cid
|
||||||
|
|
||||||
|
import pkg/codex/codextypes
|
||||||
|
import pkg/codex/stores
|
||||||
|
import pkg/codex/merkletree
|
||||||
|
import pkg/codex/manifest
|
||||||
|
import pkg/codex/blocktype as bt
|
||||||
|
import pkg/codex/chunker
|
||||||
|
import pkg/codex/indexingstrategy
|
||||||
|
import pkg/codex/slots
|
||||||
|
import pkg/codex/rng
|
||||||
|
import pkg/codex/utils/poseidon2digest
|
||||||
|
|
||||||
|
import ../helpers
|
||||||
|
|
||||||
|
proc storeManifest*(store: BlockStore, manifest: Manifest): Future[?!bt.Block] {.async.} =
|
||||||
|
without encodedVerifiable =? manifest.encode(), err:
|
||||||
|
trace "Unable to encode manifest"
|
||||||
|
return failure(err)
|
||||||
|
|
||||||
|
without blk =? bt.Block.new(data = encodedVerifiable, codec = ManifestCodec), error:
|
||||||
|
trace "Unable to create block from manifest"
|
||||||
|
return failure(error)
|
||||||
|
|
||||||
|
if err =? (await store.putBlock(blk)).errorOption:
|
||||||
|
trace "Unable to store manifest block", cid = blk.cid, err = err.msg
|
||||||
|
return failure(err)
|
||||||
|
|
||||||
|
success blk
|
||||||
|
|
||||||
|
proc makeManifest*(
|
||||||
|
cids: seq[Cid],
|
||||||
|
datasetSize: NBytes,
|
||||||
|
blockSize: NBytes,
|
||||||
|
store: BlockStore,
|
||||||
|
hcodec = Sha256HashCodec,
|
||||||
|
dataCodec = BlockCodec): Future[?!Manifest] {.async.} =
|
||||||
|
without tree =? CodexTree.init(cids), err:
|
||||||
|
return failure(err)
|
||||||
|
|
||||||
|
without treeCid =? tree.rootCid(CIDv1, dataCodec), err:
|
||||||
|
return failure(err)
|
||||||
|
|
||||||
|
for index, cid in cids:
|
||||||
|
without proof =? tree.getProof(index), err:
|
||||||
|
return failure(err)
|
||||||
|
|
||||||
|
if err =? (await store.putCidAndProof(treeCid, index, cid, proof)).errorOption:
|
||||||
|
# TODO add log here
|
||||||
|
return failure(err)
|
||||||
|
|
||||||
|
let
|
||||||
|
manifest = Manifest.new(
|
||||||
|
treeCid = treeCid,
|
||||||
|
blockSize = blockSize,
|
||||||
|
datasetSize = datasetSize,
|
||||||
|
version = CIDv1,
|
||||||
|
hcodec = hcodec,
|
||||||
|
codec = dataCodec)
|
||||||
|
|
||||||
|
without manifestBlk =? await store.storeManifest(manifest), err:
|
||||||
|
trace "Unable to store manifest"
|
||||||
|
return failure(err)
|
||||||
|
|
||||||
|
success manifest
|
||||||
|
|
||||||
|
proc createBlocks*(
|
||||||
|
chunker: Chunker,
|
||||||
|
store: BlockStore): Future[seq[bt.Block]] {.async.} =
|
||||||
|
|
||||||
|
collect(newSeq):
|
||||||
|
while (let chunk = await chunker.getBytes(); chunk.len > 0):
|
||||||
|
let blk = bt.Block.new(chunk).tryGet()
|
||||||
|
discard await store.putBlock(blk)
|
||||||
|
blk
|
||||||
|
|
||||||
|
proc createProtectedManifest*(
|
||||||
|
datasetBlocks: seq[bt.Block],
|
||||||
|
store: BlockStore,
|
||||||
|
numDatasetBlocks: int,
|
||||||
|
ecK: int, ecM: int,
|
||||||
|
blockSize: NBytes,
|
||||||
|
originalDatasetSize: int,
|
||||||
|
totalDatasetSize: int):
|
||||||
|
Future[tuple[manifest: Manifest, protected: Manifest]] {.async.} =
|
||||||
|
|
||||||
|
let
|
||||||
|
cids = datasetBlocks.mapIt(it.cid)
|
||||||
|
datasetTree = CodexTree.init(cids[0..<numDatasetBlocks]).tryGet()
|
||||||
|
datasetTreeCid = datasetTree.rootCid().tryGet()
|
||||||
|
|
||||||
|
protectedTree = CodexTree.init(cids).tryGet()
|
||||||
|
protectedTreeCid = protectedTree.rootCid().tryGet()
|
||||||
|
|
||||||
|
for index, cid in cids[0..<numDatasetBlocks]:
|
||||||
|
let proof = datasetTree.getProof(index).tryget()
|
||||||
|
(await store.putCidAndProof(datasetTreeCid, index, cid, proof)).tryGet
|
||||||
|
|
||||||
|
for index, cid in cids:
|
||||||
|
let proof = protectedTree.getProof(index).tryget()
|
||||||
|
(await store.putCidAndProof(protectedTreeCid, index, cid, proof)).tryGet
|
||||||
|
|
||||||
|
let
|
||||||
|
manifest = Manifest.new(
|
||||||
|
treeCid = datasetTreeCid,
|
||||||
|
blockSize = blockSize,
|
||||||
|
datasetSize = originalDatasetSize.NBytes)
|
||||||
|
|
||||||
|
protectedManifest = Manifest.new(
|
||||||
|
manifest = manifest,
|
||||||
|
treeCid = protectedTreeCid,
|
||||||
|
datasetSize = totalDatasetSize.NBytes,
|
||||||
|
ecK = ecK,
|
||||||
|
ecM = ecM,
|
||||||
|
strategy = SteppedStrategy)
|
||||||
|
|
||||||
|
manifestBlock = bt.Block.new(
|
||||||
|
manifest.encode().tryGet(),
|
||||||
|
codec = ManifestCodec).tryGet()
|
||||||
|
|
||||||
|
protectedManifestBlock = bt.Block.new(
|
||||||
|
protectedManifest.encode().tryGet(),
|
||||||
|
codec = ManifestCodec).tryGet()
|
||||||
|
|
||||||
|
(await store.putBlock(manifestBlock)).tryGet()
|
||||||
|
(await store.putBlock(protectedManifestBlock)).tryGet()
|
||||||
|
|
||||||
|
(manifest, protectedManifest)
|
||||||
|
|
||||||
|
proc createVerifiableManifest*(
|
||||||
|
store: BlockStore,
|
||||||
|
numDatasetBlocks: int,
|
||||||
|
ecK: int, ecM: int,
|
||||||
|
blockSize: NBytes,
|
||||||
|
cellSize: NBytes):
|
||||||
|
Future[tuple[manifest: Manifest, protected: Manifest, verifiable: Manifest]] {.async.} =
|
||||||
|
|
||||||
|
let
|
||||||
|
numSlots = ecK + ecM
|
||||||
|
numTotalBlocks = calcEcBlocksCount(numDatasetBlocks, ecK, ecM) # total number of blocks in the dataset after
|
||||||
|
# EC (should will match number of slots)
|
||||||
|
originalDatasetSize = numDatasetBlocks * blockSize.int
|
||||||
|
totalDatasetSize = numTotalBlocks * blockSize.int
|
||||||
|
|
||||||
|
chunker = RandomChunker.new(Rng.instance(), size = totalDatasetSize, chunkSize = blockSize)
|
||||||
|
datasetBlocks = await chunker.createBlocks(store)
|
||||||
|
|
||||||
|
(manifest, protectedManifest) =
|
||||||
|
await createProtectedManifest(
|
||||||
|
datasetBlocks,
|
||||||
|
store,
|
||||||
|
numDatasetBlocks,
|
||||||
|
ecK, ecM,
|
||||||
|
blockSize,
|
||||||
|
originalDatasetSize,
|
||||||
|
totalDatasetSize)
|
||||||
|
|
||||||
|
builder = Poseidon2Builder.new(store, protectedManifest, cellSize = cellSize).tryGet
|
||||||
|
verifiableManifest = (await builder.buildManifest()).tryGet
|
||||||
|
|
||||||
|
# build the slots and manifest
|
||||||
|
(manifest, protectedManifest, verifiableManifest)
|
|
@ -1,194 +0,0 @@
|
||||||
import std/sequtils
|
|
||||||
import std/math
|
|
||||||
|
|
||||||
import pkg/questionable/results
|
|
||||||
import pkg/poseidon2/io
|
|
||||||
import pkg/poseidon2
|
|
||||||
import pkg/chronos
|
|
||||||
import pkg/codex/stores/cachestore
|
|
||||||
import pkg/codex/chunker
|
|
||||||
import pkg/codex/stores
|
|
||||||
import pkg/codex/blocktype as bt
|
|
||||||
import pkg/codex/contracts/requests
|
|
||||||
import pkg/codex/contracts
|
|
||||||
import pkg/codex/merkletree
|
|
||||||
import pkg/codex/stores/cachestore
|
|
||||||
import pkg/codex/indexingstrategy
|
|
||||||
|
|
||||||
import pkg/codex/slots/converters
|
|
||||||
import pkg/codex/slots/builder/builder
|
|
||||||
import pkg/codex/utils/poseidon2digest
|
|
||||||
import pkg/codex/utils/asynciter
|
|
||||||
|
|
||||||
import ../helpers
|
|
||||||
import ../merkletree/helpers
|
|
||||||
|
|
||||||
const
|
|
||||||
# The number of slot blocks and number of slots, combined with
|
|
||||||
# the bytes per block, make it so that there are exactly 256 cells
|
|
||||||
# in the dataset.
|
|
||||||
bytesPerBlock* = 64 * 1024
|
|
||||||
cellsPerBlock* = bytesPerBlock div DefaultCellSize.int
|
|
||||||
numberOfSlotBlocks* = 3
|
|
||||||
numberOfSlotBlocksPadded* = numberOfSlotBlocks.nextPowerOfTwo
|
|
||||||
totalNumberOfSlots* = 2
|
|
||||||
datasetSlotIndex* = 1
|
|
||||||
cellsPerSlot* = (bytesPerBlock * numberOfSlotBlocks) div DefaultCellSize.int
|
|
||||||
totalNumCells = ((numberOfSlotBlocks * totalNumberOfSlots * bytesPerBlock) div DefaultCellSize.int)
|
|
||||||
|
|
||||||
type
|
|
||||||
ProvingTestEnvironment* = ref object
|
|
||||||
# Invariant:
|
|
||||||
# These challenges are chosen such that with the testenv default values
|
|
||||||
# and nSamples=3, they will land on [3x data cells + 0x padded cell],
|
|
||||||
# and [2x data cells + 1x padded cell] respectively:
|
|
||||||
challengeNoPad*: Poseidon2Hash
|
|
||||||
challengeOnePad*: Poseidon2Hash
|
|
||||||
blockPadBytes*: seq[byte]
|
|
||||||
emptyBlockTree*: Poseidon2Tree
|
|
||||||
emptyBlockCid*: Cid
|
|
||||||
# Variant:
|
|
||||||
localStore*: CacheStore
|
|
||||||
manifest*: Manifest
|
|
||||||
manifestBlock*: bt.Block
|
|
||||||
slot*: Slot
|
|
||||||
datasetBlocks*: seq[bt.Block]
|
|
||||||
slotTree*: Poseidon2Tree
|
|
||||||
slotRootCid*: Cid
|
|
||||||
slotRoots*: seq[Poseidon2Hash]
|
|
||||||
datasetToSlotTree*: Poseidon2Tree
|
|
||||||
datasetRootHash*: Poseidon2Hash
|
|
||||||
|
|
||||||
proc createDatasetBlocks(self: ProvingTestEnvironment): Future[void] {.async.} =
|
|
||||||
var data: seq[byte] = @[]
|
|
||||||
|
|
||||||
# This generates a number of blocks that have different data, such that
|
|
||||||
# Each cell in each block is unique, but nothing is random.
|
|
||||||
for i in 0 ..< totalNumCells:
|
|
||||||
data = data & (i.byte).repeat(DefaultCellSize.uint64)
|
|
||||||
|
|
||||||
let chunker = MockChunker.new(
|
|
||||||
dataset = data,
|
|
||||||
chunkSize = bytesPerBlock)
|
|
||||||
|
|
||||||
while true:
|
|
||||||
let chunk = await chunker.getBytes()
|
|
||||||
if chunk.len <= 0:
|
|
||||||
break
|
|
||||||
let b = bt.Block.new(chunk).tryGet()
|
|
||||||
self.datasetBlocks.add(b)
|
|
||||||
discard await self.localStore.putBlock(b)
|
|
||||||
|
|
||||||
proc createSlotTree(self: ProvingTestEnvironment, dSlotIndex: uint64): Future[Poseidon2Tree] {.async.} =
|
|
||||||
let
|
|
||||||
slotSize = (bytesPerBlock * numberOfSlotBlocks).uint64
|
|
||||||
blocksInSlot = slotSize div bytesPerBlock.uint64
|
|
||||||
datasetBlockIndexingStrategy = SteppedStrategy.init(0, self.datasetBlocks.len - 1, totalNumberOfSlots)
|
|
||||||
datasetBlockIndices = toSeq(datasetBlockIndexingStrategy.getIndicies(dSlotIndex.int))
|
|
||||||
|
|
||||||
let
|
|
||||||
slotBlocks = datasetBlockIndices.mapIt(self.datasetBlocks[it])
|
|
||||||
slotBlockRoots = slotBlocks.mapIt(Poseidon2Tree.digest(it.data & self.blockPadBytes, DefaultCellSize.int).tryGet())
|
|
||||||
slotBlockRootPads = newSeqWith((slotBlockRoots.len).nextPowerOfTwoPad, Poseidon2Zero)
|
|
||||||
tree = Poseidon2Tree.init(slotBlockRoots & slotBlockRootPads).tryGet()
|
|
||||||
treeCid = tree.root().tryGet().toSlotCid().tryGet()
|
|
||||||
|
|
||||||
for i in 0 ..< numberOfSlotBlocksPadded:
|
|
||||||
var blkCid: Cid
|
|
||||||
if i < slotBlockRoots.len:
|
|
||||||
blkCid = slotBlockRoots[i].toCellCid().tryGet()
|
|
||||||
else:
|
|
||||||
blkCid = self.emptyBlockCid
|
|
||||||
|
|
||||||
let proof = tree.getProof(i).tryGet().toEncodableProof().tryGet()
|
|
||||||
discard await self.localStore.putCidAndProof(treeCid, i, blkCid, proof)
|
|
||||||
|
|
||||||
return tree
|
|
||||||
|
|
||||||
proc createDatasetRootHashAndSlotTree(self: ProvingTestEnvironment): Future[void] {.async.} =
|
|
||||||
var slotTrees = newSeq[Poseidon2Tree]()
|
|
||||||
for i in 0 ..< totalNumberOfSlots:
|
|
||||||
slotTrees.add(await self.createSlotTree(i.uint64))
|
|
||||||
self.slotTree = slotTrees[datasetSlotIndex]
|
|
||||||
self.slotRootCid = slotTrees[datasetSlotIndex].root().tryGet().toSlotCid().tryGet()
|
|
||||||
self.slotRoots = slotTrees.mapIt(it.root().tryGet())
|
|
||||||
let rootsPadLeafs = newSeqWith(totalNumberOfSlots.nextPowerOfTwoPad, Poseidon2Zero)
|
|
||||||
self.datasetToSlotTree = Poseidon2Tree.init(self.slotRoots & rootsPadLeafs).tryGet()
|
|
||||||
self.datasetRootHash = self.datasetToSlotTree.root().tryGet()
|
|
||||||
|
|
||||||
proc createManifest(self: ProvingTestEnvironment): Future[void] {.async.} =
|
|
||||||
let
|
|
||||||
cids = self.datasetBlocks.mapIt(it.cid)
|
|
||||||
tree = CodexTree.init(cids).tryGet()
|
|
||||||
treeCid = tree.rootCid(CIDv1, BlockCodec).tryGet()
|
|
||||||
|
|
||||||
for i in 0 ..< self.datasetBlocks.len:
|
|
||||||
let
|
|
||||||
blk = self.datasetBlocks[i]
|
|
||||||
leafCid = blk.cid
|
|
||||||
proof = tree.getProof(i).tryGet()
|
|
||||||
discard await self.localStore.putBlock(blk)
|
|
||||||
discard await self.localStore.putCidAndProof(treeCid, i, leafCid, proof)
|
|
||||||
|
|
||||||
# Basic manifest:
|
|
||||||
self.manifest = Manifest.new(
|
|
||||||
treeCid = treeCid,
|
|
||||||
blockSize = bytesPerBlock.NBytes,
|
|
||||||
datasetSize = (bytesPerBlock * numberOfSlotBlocks * totalNumberOfSlots).NBytes)
|
|
||||||
|
|
||||||
# Protected manifest:
|
|
||||||
self.manifest = Manifest.new(
|
|
||||||
manifest = self.manifest,
|
|
||||||
treeCid = treeCid,
|
|
||||||
datasetSize = self.manifest.datasetSize,
|
|
||||||
ecK = totalNumberOfSlots,
|
|
||||||
ecM = 0,
|
|
||||||
strategy = StrategyType.SteppedStrategy
|
|
||||||
)
|
|
||||||
|
|
||||||
# Verifiable manifest:
|
|
||||||
self.manifest = Manifest.new(
|
|
||||||
manifest = self.manifest,
|
|
||||||
verifyRoot = self.datasetRootHash.toVerifyCid().tryGet(),
|
|
||||||
slotRoots = self.slotRoots.mapIt(it.toSlotCid().tryGet())
|
|
||||||
).tryGet()
|
|
||||||
|
|
||||||
self.manifestBlock = bt.Block.new(self.manifest.encode().tryGet(), codec = ManifestCodec).tryGet()
|
|
||||||
discard await self.localStore.putBlock(self.manifestBlock)
|
|
||||||
|
|
||||||
proc createSlot(self: ProvingTestEnvironment): void =
|
|
||||||
self.slot = Slot(
|
|
||||||
request: StorageRequest(
|
|
||||||
ask: StorageAsk(
|
|
||||||
slots: totalNumberOfSlots.uint64,
|
|
||||||
slotSize: u256(bytesPerBlock * numberOfSlotBlocks)
|
|
||||||
),
|
|
||||||
content: StorageContent(
|
|
||||||
cid: $self.manifestBlock.cid
|
|
||||||
),
|
|
||||||
),
|
|
||||||
slotIndex: u256(datasetSlotIndex)
|
|
||||||
)
|
|
||||||
|
|
||||||
proc createProvingTestEnvironment*(): Future[ProvingTestEnvironment] {.async.} =
|
|
||||||
let
|
|
||||||
numBlockCells = bytesPerBlock.int div DefaultCellSize.int
|
|
||||||
blockPadBytes = newSeq[byte](numBlockCells.nextPowerOfTwoPad * DefaultCellSize.int)
|
|
||||||
emptyBlockTree = Poseidon2Tree.digestTree(DefaultEmptyBlock & blockPadBytes, DefaultCellSize.int).tryGet()
|
|
||||||
emptyBlockCid = emptyBlockTree.root.tryGet().toCellCid().tryGet()
|
|
||||||
|
|
||||||
var testEnv = ProvingTestEnvironment(
|
|
||||||
challengeNoPad: toF(6),
|
|
||||||
challengeOnePad: toF(9),
|
|
||||||
blockPadBytes: blockPadBytes,
|
|
||||||
emptyBlockTree: emptyBlockTree,
|
|
||||||
emptyBlockCid: emptyBlockCid
|
|
||||||
)
|
|
||||||
|
|
||||||
testEnv.localStore = CacheStore.new()
|
|
||||||
await testEnv.createDatasetBlocks()
|
|
||||||
await testEnv.createDatasetRootHashAndSlotTree()
|
|
||||||
await testEnv.createManifest()
|
|
||||||
testEnv.createSlot()
|
|
||||||
|
|
||||||
return testEnv
|
|
|
@ -0,0 +1,173 @@
|
||||||
|
import std/sequtils
|
||||||
|
import std/options
|
||||||
|
import std/importutils
|
||||||
|
|
||||||
|
import ../../../asynctest
|
||||||
|
|
||||||
|
import pkg/questionable
|
||||||
|
import pkg/questionable/results
|
||||||
|
import pkg/datastore
|
||||||
|
|
||||||
|
import pkg/codex/rng
|
||||||
|
import pkg/codex/stores
|
||||||
|
import pkg/codex/merkletree
|
||||||
|
import pkg/codex/utils/json
|
||||||
|
import pkg/codex/codextypes
|
||||||
|
import pkg/codex/slots
|
||||||
|
import pkg/codex/slots/builder
|
||||||
|
import pkg/codex/utils/poseidon2digest
|
||||||
|
import pkg/codex/slots/sampler/utils
|
||||||
|
|
||||||
|
import pkg/constantine/math/arithmetic
|
||||||
|
import pkg/constantine/math/io/io_bigints
|
||||||
|
import pkg/constantine/math/io/io_fields
|
||||||
|
|
||||||
|
import ../backends/helpers
|
||||||
|
import ../helpers
|
||||||
|
import ../../helpers
|
||||||
|
|
||||||
|
suite "Test control samples":
|
||||||
|
|
||||||
|
var
|
||||||
|
inputData: string
|
||||||
|
inputJson: JsonNode
|
||||||
|
proofInput: ProofInput[Poseidon2Hash]
|
||||||
|
|
||||||
|
setup:
|
||||||
|
inputData = readFile("tests/circuits/fixtures/input.json")
|
||||||
|
inputJson = parseJson(inputData)
|
||||||
|
proofInput = jsonToProofInput[Poseidon2Hash](inputJson)
|
||||||
|
|
||||||
|
test "Should verify control samples":
|
||||||
|
let
|
||||||
|
blockCells = 32
|
||||||
|
cellIdxs = proofInput.entropy.cellIndices(proofInput.slotRoot, proofInput.nCellsPerSlot, 5)
|
||||||
|
|
||||||
|
for i, cellIdx in cellIdxs:
|
||||||
|
let
|
||||||
|
sample = proofInput.samples[i]
|
||||||
|
cellIdx = cellIdxs[i]
|
||||||
|
|
||||||
|
cellProof = Poseidon2Proof.init(
|
||||||
|
cellIdx.toCellInBlk(blockCells),
|
||||||
|
proofInput.nCellsPerSlot,
|
||||||
|
sample.merklePaths[0..<5]).tryGet
|
||||||
|
|
||||||
|
slotProof = Poseidon2Proof.init(
|
||||||
|
cellIdx.toBlkInSlot(blockCells),
|
||||||
|
proofInput.nCellsPerSlot,
|
||||||
|
sample.merklePaths[5..<9]).tryGet
|
||||||
|
|
||||||
|
cellData = fromCircomData[Poseidon2Hash](sample.cellData)
|
||||||
|
cellLeaf = Poseidon2Hash.spongeDigest(cellData, rate = 2).tryGet
|
||||||
|
slotLeaf = cellProof.reconstructRoot(cellLeaf).tryGet
|
||||||
|
|
||||||
|
check slotProof.verify(slotLeaf, proofInput.slotRoot).tryGet
|
||||||
|
|
||||||
|
test "Should verify control dataset root":
|
||||||
|
let
|
||||||
|
datasetProof = Poseidon2Proof.init(
|
||||||
|
proofInput.slotIndex,
|
||||||
|
proofInput.nSlotsPerDataSet,
|
||||||
|
proofInput.slotProof[0..<4]).tryGet
|
||||||
|
|
||||||
|
check datasetProof.verify(proofInput.slotRoot, proofInput.datasetRoot).tryGet
|
||||||
|
|
||||||
|
suite "Test sampler samples":
|
||||||
|
|
||||||
|
let
|
||||||
|
slotIndex = 3
|
||||||
|
nSamples = 5
|
||||||
|
ecK = 3
|
||||||
|
ecM = 2
|
||||||
|
datasetBlocks = 8
|
||||||
|
entropy = 1234567.toF
|
||||||
|
blockSize = DefaultBlockSize
|
||||||
|
cellSize = DefaultCellSize
|
||||||
|
|
||||||
|
var
|
||||||
|
store: RepoStore
|
||||||
|
builder: Poseidon2Builder
|
||||||
|
manifest: Manifest
|
||||||
|
protected: Manifest
|
||||||
|
verifiable: Manifest
|
||||||
|
|
||||||
|
setup:
|
||||||
|
let
|
||||||
|
repoDs = SQLiteDatastore.new(Memory).tryGet()
|
||||||
|
metaDs = SQLiteDatastore.new(Memory).tryGet()
|
||||||
|
|
||||||
|
store = RepoStore.new(repoDs, metaDs)
|
||||||
|
|
||||||
|
(manifest, protected, verifiable) =
|
||||||
|
await createVerifiableManifest(
|
||||||
|
store,
|
||||||
|
datasetBlocks,
|
||||||
|
ecK, ecM,
|
||||||
|
blockSize,
|
||||||
|
cellSize)
|
||||||
|
|
||||||
|
# create sampler
|
||||||
|
builder = Poseidon2Builder.new(store, verifiable).tryGet
|
||||||
|
|
||||||
|
teardown:
|
||||||
|
await store.close()
|
||||||
|
|
||||||
|
test "Should fail instantiating for invalid slot index":
|
||||||
|
let
|
||||||
|
sampler = Poseidon2Sampler.new(builder.slotRoots.len, store, builder)
|
||||||
|
|
||||||
|
check sampler.isErr
|
||||||
|
|
||||||
|
test "Should fail instantiating for non verifiable builder":
|
||||||
|
let
|
||||||
|
nonVerifiableBuilder = Poseidon2Builder.new(store, protected).tryGet
|
||||||
|
sampler = Poseidon2Sampler.new(slotIndex, store, nonVerifiableBuilder)
|
||||||
|
|
||||||
|
check sampler.isErr
|
||||||
|
|
||||||
|
test "Should verify samples":
|
||||||
|
let
|
||||||
|
sampler = Poseidon2Sampler.new(slotIndex, store, builder).tryGet
|
||||||
|
|
||||||
|
verifyTree = builder.verifyTree.get # get the dataset tree
|
||||||
|
slotProof = verifyTree.getProof(slotIndex).tryGet # get slot proof for index
|
||||||
|
datasetRoot = verifyTree.root().tryGet # get dataset root
|
||||||
|
slotTreeCid = verifiable.slotRoots[slotIndex] # get slot tree cid to retrieve proof from storage
|
||||||
|
slotRoot = builder.slotRoots[slotIndex] # get slot root hash
|
||||||
|
cellIdxs = entropy.cellIndices(slotRoot, builder.numSlotCells, nSamples)
|
||||||
|
|
||||||
|
nBlockCells = builder.numBlockCells
|
||||||
|
nSlotCells = builder.numSlotCells
|
||||||
|
|
||||||
|
for i, cellIdx in cellIdxs:
|
||||||
|
let
|
||||||
|
sample = (await sampler.getSample(cellIdx, slotTreeCid, slotRoot)).tryGet
|
||||||
|
|
||||||
|
cellProof = Poseidon2Proof.init(
|
||||||
|
cellIdx.toCellInBlk(nBlockCells),
|
||||||
|
nSlotCells,
|
||||||
|
sample.merklePaths[0..<5]).tryGet
|
||||||
|
|
||||||
|
slotProof = Poseidon2Proof.init(
|
||||||
|
cellIdx.toBlkInSlot(nBlockCells),
|
||||||
|
nSlotCells,
|
||||||
|
sample.merklePaths[5..<sample.merklePaths.len]).tryGet
|
||||||
|
|
||||||
|
cellData = fromCircomData[Poseidon2Hash](sample.cellData)
|
||||||
|
cellLeaf = Poseidon2Hash.spongeDigest(cellData, rate = 2).tryGet
|
||||||
|
slotLeaf = cellProof.reconstructRoot(cellLeaf).tryGet
|
||||||
|
|
||||||
|
check slotProof.verify(slotLeaf, slotRoot).tryGet
|
||||||
|
|
||||||
|
test "Should verify dataset root":
|
||||||
|
let
|
||||||
|
sampler = Poseidon2Sampler.new(slotIndex, store, builder).tryGet
|
||||||
|
proofInput = (await sampler.getProofInput(entropy.toBytes.toArray32, nSamples)).tryGet
|
||||||
|
|
||||||
|
datasetProof = Poseidon2Proof.init(
|
||||||
|
proofInput.slotIndex,
|
||||||
|
builder.slotRoots.len,
|
||||||
|
proofInput.slotProof).tryGet
|
||||||
|
|
||||||
|
check datasetProof.verify(builder.slotRoots[slotIndex], builder.verifyRoot.get).tryGet
|
|
@ -2,7 +2,8 @@ import std/sequtils
|
||||||
import std/sugar
|
import std/sugar
|
||||||
import std/random
|
import std/random
|
||||||
import std/strutils
|
import std/strutils
|
||||||
import std/math
|
|
||||||
|
import ../../../asynctest
|
||||||
|
|
||||||
import pkg/questionable/results
|
import pkg/questionable/results
|
||||||
import pkg/constantine/math/arithmetic
|
import pkg/constantine/math/arithmetic
|
||||||
|
@ -10,7 +11,6 @@ import pkg/constantine/math/io/io_fields
|
||||||
import pkg/poseidon2/io
|
import pkg/poseidon2/io
|
||||||
import pkg/poseidon2
|
import pkg/poseidon2
|
||||||
import pkg/chronos
|
import pkg/chronos
|
||||||
import pkg/codex/stores/cachestore
|
|
||||||
import pkg/codex/chunker
|
import pkg/codex/chunker
|
||||||
import pkg/codex/stores
|
import pkg/codex/stores
|
||||||
import pkg/codex/blocktype as bt
|
import pkg/codex/blocktype as bt
|
||||||
|
@ -19,31 +19,27 @@ import pkg/codex/contracts
|
||||||
import pkg/codex/merkletree
|
import pkg/codex/merkletree
|
||||||
import pkg/codex/stores/cachestore
|
import pkg/codex/stores/cachestore
|
||||||
|
|
||||||
|
import pkg/codex/slots/types
|
||||||
import pkg/codex/slots/sampler/utils
|
import pkg/codex/slots/sampler/utils
|
||||||
|
|
||||||
import ../../asynctest
|
import ../backends/helpers
|
||||||
import ../helpers
|
import ../../helpers
|
||||||
import ../examples
|
import ../../examples
|
||||||
import ../merkletree/helpers
|
import ../../merkletree/helpers
|
||||||
import ./provingtestenv
|
|
||||||
|
|
||||||
asyncchecksuite "Test proof sampler utils":
|
asyncchecksuite "Test proof sampler utils":
|
||||||
let knownIndices: seq[Natural] = @[57, 82, 49]
|
let
|
||||||
|
cellsPerBlock = DefaultBlockSize div DefaultCellSize
|
||||||
|
|
||||||
var
|
var
|
||||||
env: ProvingTestEnvironment
|
inputData: string
|
||||||
slotRoot: Poseidon2Hash
|
inputJson: JsonNode
|
||||||
numCells: Natural
|
proofInput: ProofInput[Poseidon2Hash]
|
||||||
numCellsPadded: Natural
|
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
env = await createProvingTestEnvironment()
|
inputData = readFile("tests/circuits/fixtures/input.json")
|
||||||
slotRoot = env.slotRoots[datasetSlotIndex]
|
inputJson = parseJson(inputData)
|
||||||
numCells = cellsPerSlot
|
proofInput = jsonToProofInput[Poseidon2Hash](inputJson)
|
||||||
numCellsPadded = numCells.nextPowerOfTwo
|
|
||||||
|
|
||||||
teardown:
|
|
||||||
reset(env)
|
|
||||||
|
|
||||||
test "Extract low bits":
|
test "Extract low bits":
|
||||||
proc extract(value: uint64, nBits: int): uint64 =
|
proc extract(value: uint64, nBits: int): uint64 =
|
||||||
|
@ -64,45 +60,39 @@ asyncchecksuite "Test proof sampler utils":
|
||||||
|
|
||||||
test "Can find single slot-cell index":
|
test "Can find single slot-cell index":
|
||||||
proc slotCellIndex(i: Natural): Natural =
|
proc slotCellIndex(i: Natural): Natural =
|
||||||
return cellIndex(env.challengeNoPad, slotRoot, numCellsPadded, i)
|
return cellIndex(proofInput.entropy, proofInput.slotRoot, proofInput.nCellsPerSlot, i)
|
||||||
|
|
||||||
proc getExpectedIndex(i: int): Natural =
|
proc getExpectedIndex(i: int): Natural =
|
||||||
let
|
let
|
||||||
numberOfCellsInSlot = (bytesPerBlock * numberOfSlotBlocks) div DefaultCellSize.uint64.int
|
hash = Sponge.digest(@[proofInput.entropy, proofInput.slotRoot, toF(i)], rate = 2)
|
||||||
numberOfCellsInSlotPadded = numberOfCellsInSlot.nextPowerOfTwo
|
|
||||||
hash = Sponge.digest(@[slotRoot, env.challengeNoPad, toF(i)], rate = 2)
|
|
||||||
|
|
||||||
return int(extractLowBits(hash.toBig(), ceilingLog2(numberOfCellsInSlotPadded)))
|
return int(extractLowBits(hash.toBig(), ceilingLog2(proofInput.nCellsPerSlot)))
|
||||||
|
|
||||||
check:
|
check:
|
||||||
slotCellIndex(1) == getExpectedIndex(1)
|
slotCellIndex(1) == getExpectedIndex(1)
|
||||||
slotCellIndex(1) == knownIndices[0]
|
|
||||||
slotCellIndex(2) == getExpectedIndex(2)
|
slotCellIndex(2) == getExpectedIndex(2)
|
||||||
slotCellIndex(2) == knownIndices[1]
|
|
||||||
slotCellIndex(3) == getExpectedIndex(3)
|
slotCellIndex(3) == getExpectedIndex(3)
|
||||||
slotCellIndex(3) == knownIndices[2]
|
|
||||||
|
|
||||||
test "Can find sequence of slot-cell indices":
|
test "Can find sequence of slot-cell indices":
|
||||||
proc slotCellIndices(n: int): seq[Natural] =
|
proc slotCellIndices(n: int): seq[Natural] =
|
||||||
cellIndices(env.challengeNoPad, slotRoot, numCellsPadded, n)
|
cellIndices(proofInput.entropy, proofInput.slotRoot, numCells = proofInput.nCellsPerSlot, n)
|
||||||
|
|
||||||
proc getExpectedIndices(n: int): seq[Natural] =
|
proc getExpectedIndices(n: int): seq[Natural] =
|
||||||
return collect(newSeq, (for i in 1..n: cellIndex(env.challengeNoPad, slotRoot, numCellsPadded, i)))
|
return collect(newSeq, (for i in 1..n: cellIndex(proofInput.entropy, proofInput.slotRoot, proofInput.nCellsPerSlot, i)))
|
||||||
|
|
||||||
check:
|
check:
|
||||||
slotCellIndices(3) == getExpectedIndices(3)
|
slotCellIndices(3) == getExpectedIndices(3)
|
||||||
slotCellIndices(3) == knownIndices
|
|
||||||
|
|
||||||
for (input, expected) in [(10, 0), (31, 0), (32, 1), (63, 1), (64, 2)]:
|
for (input, expected) in [(10, 0), (31, 0), (32, 1), (63, 1), (64, 2)]:
|
||||||
test "Can get slotBlockIndex from slotCellIndex (" & $input & " -> " & $expected & ")":
|
test "Can get slotBlockIndex from slotCellIndex (" & $input & " -> " & $expected & ")":
|
||||||
let slotBlockIndex = toBlockIdx(input, numCells = 32)
|
let slotBlockIndex = toBlkInSlot(input, numCells = cellsPerBlock)
|
||||||
|
|
||||||
check:
|
check:
|
||||||
slotBlockIndex == expected
|
slotBlockIndex == expected
|
||||||
|
|
||||||
for (input, expected) in [(10, 10), (31, 31), (32, 0), (63, 31), (64, 0)]:
|
for (input, expected) in [(10, 10), (31, 31), (32, 0), (63, 31), (64, 0)]:
|
||||||
test "Can get blockCellIndex from slotCellIndex (" & $input & " -> " & $expected & ")":
|
test "Can get blockCellIndex from slotCellIndex (" & $input & " -> " & $expected & ")":
|
||||||
let blockCellIndex = toBlockCellIdx(input, numCells = 32)
|
let blockCellIndex = toCellInBlk(input, numCells = cellsPerBlock)
|
||||||
|
|
||||||
check:
|
check:
|
||||||
blockCellIndex == expected
|
blockCellIndex == expected
|
|
@ -1,155 +1,4 @@
|
||||||
import std/sequtils
|
import ./sampler/testsampler
|
||||||
import std/sugar
|
import ./sampler/testutils
|
||||||
import std/random
|
|
||||||
import std/strutils
|
|
||||||
|
|
||||||
import pkg/questionable/results
|
{.warning[UnusedImport]: off.}
|
||||||
import pkg/constantine/math/arithmetic
|
|
||||||
import pkg/constantine/math/io/io_fields
|
|
||||||
import pkg/poseidon2/io
|
|
||||||
import pkg/poseidon2
|
|
||||||
import pkg/chronos
|
|
||||||
import pkg/nimcrypto
|
|
||||||
import pkg/codex/stores/cachestore
|
|
||||||
import pkg/codex/chunker
|
|
||||||
import pkg/codex/stores
|
|
||||||
import pkg/codex/blocktype as bt
|
|
||||||
import pkg/codex/contracts/requests
|
|
||||||
import pkg/codex/contracts
|
|
||||||
import pkg/codex/merkletree
|
|
||||||
import pkg/codex/stores/cachestore
|
|
||||||
|
|
||||||
import pkg/codex/slots/sampler
|
|
||||||
import pkg/codex/slots/builder/builder
|
|
||||||
|
|
||||||
import ../helpers
|
|
||||||
import ../examples
|
|
||||||
import ../merkletree/helpers
|
|
||||||
import ../../asynctest
|
|
||||||
import ./testsampler_expected
|
|
||||||
import ./provingtestenv
|
|
||||||
|
|
||||||
asyncchecksuite "Test DataSampler":
|
|
||||||
var
|
|
||||||
env: ProvingTestEnvironment
|
|
||||||
dataSampler: DataSampler
|
|
||||||
blk: bt.Block
|
|
||||||
cell0Bytes: seq[byte]
|
|
||||||
cell1Bytes: seq[byte]
|
|
||||||
cell2Bytes: seq[byte]
|
|
||||||
|
|
||||||
proc createDataSampler(): Future[void] {.async.} =
|
|
||||||
dataSampler = DataSampler.new(
|
|
||||||
datasetSlotIndex,
|
|
||||||
env.localStore,
|
|
||||||
SlotsBuilder.new(env.localStore, env.manifest).tryGet()).tryGet()
|
|
||||||
|
|
||||||
setup:
|
|
||||||
randomize()
|
|
||||||
env = await createProvingTestEnvironment()
|
|
||||||
let bytes = newSeqWith(bytesPerBlock, rand(uint8))
|
|
||||||
blk = bt.Block.new(bytes).tryGet()
|
|
||||||
cell0Bytes = bytes[0..<DefaultCellSize.uint64]
|
|
||||||
cell1Bytes = bytes[DefaultCellSize.uint64..<(DefaultCellSize.uint64*2)]
|
|
||||||
cell2Bytes = bytes[(DefaultCellSize.uint64*2)..<(DefaultCellSize.uint64*3)]
|
|
||||||
|
|
||||||
await createDataSampler()
|
|
||||||
|
|
||||||
teardown:
|
|
||||||
reset(env)
|
|
||||||
reset(dataSampler)
|
|
||||||
|
|
||||||
test "Can get cell from block":
|
|
||||||
let
|
|
||||||
sample0 = dataSampler.getCell(blk.data, 0)
|
|
||||||
sample1 = dataSampler.getCell(blk.data, 1)
|
|
||||||
sample2 = dataSampler.getCell(blk.data, 2)
|
|
||||||
|
|
||||||
check:
|
|
||||||
sample0 == cell0Bytes
|
|
||||||
sample1 == cell1Bytes
|
|
||||||
sample2 == cell2Bytes
|
|
||||||
|
|
||||||
test "Can gather proof input":
|
|
||||||
let
|
|
||||||
nSamples = 3
|
|
||||||
challengeBytes = env.challengeNoPad.toBytes()
|
|
||||||
input = (await dataSampler.getProofInput(challengeBytes, nSamples)).tryget()
|
|
||||||
|
|
||||||
proc equal(a: Poseidon2Hash, b: Poseidon2Hash): bool =
|
|
||||||
a.toDecimal() == b.toDecimal()
|
|
||||||
|
|
||||||
proc toStr(proof: Poseidon2Proof): string =
|
|
||||||
let a = proof.path.mapIt(toHex(it))
|
|
||||||
join(a)
|
|
||||||
|
|
||||||
let
|
|
||||||
expectedBlockSlotProofs = getExpectedBlockSlotProofs()
|
|
||||||
expectedCellBlockProofs = getExpectedCellBlockProofs()
|
|
||||||
expectedCellData = getExpectedCellData()
|
|
||||||
expectedProof = env.datasetToSlotTree.getProof(datasetSlotIndex).tryGet()
|
|
||||||
|
|
||||||
check:
|
|
||||||
equal(input.verifyRoot, env.datasetRootHash)
|
|
||||||
equal(input.entropy, env.challengeNoPad)
|
|
||||||
input.numCells == ((bytesPerBlock * numberOfSlotBlocks) div DefaultCellSize.int).Natural
|
|
||||||
input.numSlots == totalNumberOfSlots.Natural
|
|
||||||
input.slotIndex == env.slot.slotIndex.truncate(Natural)
|
|
||||||
input.verifyProof == expectedProof
|
|
||||||
|
|
||||||
# block-slot proofs
|
|
||||||
input.samples[0].slotBlockIdx == 1
|
|
||||||
input.samples[1].slotBlockIdx == 2
|
|
||||||
input.samples[2].slotBlockIdx == 1
|
|
||||||
toStr(input.samples[0].slotProof) == expectedBlockSlotProofs[0]
|
|
||||||
toStr(input.samples[1].slotProof) == expectedBlockSlotProofs[1]
|
|
||||||
toStr(input.samples[2].slotProof) == expectedBlockSlotProofs[2]
|
|
||||||
|
|
||||||
# cell-block proofs
|
|
||||||
input.samples[0].blockCellIdx == 25
|
|
||||||
input.samples[1].blockCellIdx == 18
|
|
||||||
input.samples[2].blockCellIdx == 17
|
|
||||||
toStr(input.samples[0].cellProof) == expectedCellBlockProofs[0]
|
|
||||||
toStr(input.samples[1].cellProof) == expectedCellBlockProofs[1]
|
|
||||||
toStr(input.samples[2].cellProof) == expectedCellBlockProofs[2]
|
|
||||||
|
|
||||||
# cell data
|
|
||||||
nimcrypto.toHex(input.samples[0].data) == expectedCellData[0]
|
|
||||||
nimcrypto.toHex(input.samples[1].data) == expectedCellData[1]
|
|
||||||
nimcrypto.toHex(input.samples[2].data) == expectedCellData[2]
|
|
||||||
|
|
||||||
test "Can select samples in padded cells":
|
|
||||||
let
|
|
||||||
nSamples = 3
|
|
||||||
challengeBytes = env.challengeOnePad.toBytes()
|
|
||||||
input = (await dataSampler.getProofInput(challengeBytes, nSamples)).tryget()
|
|
||||||
|
|
||||||
proc equal(a: Poseidon2Hash, b: Poseidon2Hash): bool =
|
|
||||||
a.toDecimal() == b.toDecimal()
|
|
||||||
|
|
||||||
proc toStr(proof: Poseidon2Proof): string =
|
|
||||||
let a = proof.path.mapIt(toHex(it))
|
|
||||||
join(a)
|
|
||||||
|
|
||||||
let expectedProof = env.datasetToSlotTree.getProof(datasetSlotIndex).tryGet()
|
|
||||||
|
|
||||||
check:
|
|
||||||
equal(input.verifyRoot, env.datasetRootHash)
|
|
||||||
equal(input.entropy, env.challengeOnePad)
|
|
||||||
input.numCells == ((bytesPerBlock * numberOfSlotBlocks) div DefaultCellSize.int).Natural
|
|
||||||
input.numSlots == totalNumberOfSlots.Natural
|
|
||||||
input.slotIndex == env.slot.slotIndex.truncate(Natural)
|
|
||||||
input.verifyProof == expectedProof
|
|
||||||
|
|
||||||
input.samples[0].slotBlockIdx == 2
|
|
||||||
input.samples[1].slotBlockIdx == 2
|
|
||||||
input.samples[2].slotBlockIdx == 3
|
|
||||||
# The third sample is a padded sample
|
|
||||||
toStr(input.samples[2].slotProof) == toStr(env.slotTree.getProof(3).tryGet())
|
|
||||||
|
|
||||||
input.samples[0].blockCellIdx == 29
|
|
||||||
input.samples[1].blockCellIdx == 26
|
|
||||||
input.samples[2].blockCellIdx == 30
|
|
||||||
toStr(input.samples[2].cellProof) == toStr(env.emptyBlockTree.getProof(30).tryGet())
|
|
||||||
|
|
||||||
input.samples[2].data == newSeq[byte](DefaultCellSize.int)
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
# Snapshot of expected values for testsampler.
|
|
||||||
|
|
||||||
import std/strutils
|
|
||||||
import pkg/codex/codextypes
|
|
||||||
|
|
||||||
proc getExpectedCellBlockProofs*(): seq[string] =
|
|
||||||
@[
|
|
||||||
"0x13935d7f73028fd425e557b8e0b737fcba3f8bcda0e07a9047868bc7c5a2519e0x17d36c9bcef9febb77b129e8bbe971b754d7b3e1df8c7d881b64bf0aa055f5570x02610a45fa39d4859e5c0c53bda9cc6bd627ae4b5aa462f9e86f47f3db96b2700x27a362c0f92c887d74ee77df2df5e51f0f66b0564a2af8b1c11b02dab0a34f780x095eb3c0d166c19f9cac8ea0e6ba274dfeef802cf7d01c90378585fd4d788e56",
|
|
||||||
"0x128b43cb1f87736d5b826c5a440d373c0e4c147a81a0edc40b106abd2c10af960x2160ba1c1ed893685b849a8f1be6d32bb11a6ebb8690c5af95e0ce0e9d72b6580x1332185d0ef7b76e55c7464f37df96d41f256249d74678d8191030912036b7aa0x0522383db3f9cb9c75d5b209bd795566e9cffa632819628194416a479998a4270x1decd3fb7ff458261149731115657cecd7eb2fe4a6cf84f3c6761aa8b0dd6b9a",
|
|
||||||
"0x2a2c8663e354dbc1857a654134de3b690d73ffedcc7c0ba770a39f3e48675ee10x01914d98d4103889ea59ce6e970dae95f7e463350184c5f7f3806997e10748520x10e8f6235ac7e95af5aea6fc77ebe60e1028b48eb84027ea46d403d809852b6b0x04bd51be7ff42db27a7605124d3d2d1c4cbca43f93d1997060ac8a1009fa48b40x095eb3c0d166c19f9cac8ea0e6ba274dfeef802cf7d01c90378585fd4d788e56"
|
|
||||||
]
|
|
||||||
|
|
||||||
proc getExpectedBlockSlotProofs*(): seq[string] =
|
|
||||||
@[
|
|
||||||
"0x008fccffc5d2e5010a44bc718fed80d4d891e6517c022ba1bff65763dd79dbb90x117662f365386ee6784274dfa3a3b35126291cdf013c5e90d07bee79f32b2f40",
|
|
||||||
"0x00000000000000000000000000000000000000000000000000000000000000000x2a66917fa49371e835376fcece0d854c77008ac1195740963b1ac4491ee1aaf1",
|
|
||||||
"0x008fccffc5d2e5010a44bc718fed80d4d891e6517c022ba1bff65763dd79dbb90x117662f365386ee6784274dfa3a3b35126291cdf013c5e90d07bee79f32b2f40"
|
|
||||||
]
|
|
||||||
|
|
||||||
proc getExpectedCellData*(): seq[string] =
|
|
||||||
@[
|
|
||||||
"79".repeat(DefaultCellSize.int),
|
|
||||||
"B2".repeat(DefaultCellSize.int),
|
|
||||||
"71".repeat(DefaultCellSize.int)
|
|
||||||
]
|
|
|
@ -3,6 +3,8 @@ import std/math
|
||||||
import std/importutils
|
import std/importutils
|
||||||
import std/sugar
|
import std/sugar
|
||||||
|
|
||||||
|
import ../../asynctest
|
||||||
|
|
||||||
import pkg/chronos
|
import pkg/chronos
|
||||||
import pkg/questionable/results
|
import pkg/questionable/results
|
||||||
import pkg/codex/blocktype as bt
|
import pkg/codex/blocktype as bt
|
||||||
|
@ -13,12 +15,13 @@ import pkg/codex/merkletree
|
||||||
import pkg/codex/manifest {.all.}
|
import pkg/codex/manifest {.all.}
|
||||||
import pkg/codex/utils
|
import pkg/codex/utils
|
||||||
import pkg/codex/utils/digest
|
import pkg/codex/utils/digest
|
||||||
|
import pkg/codex/utils/poseidon2digest
|
||||||
import pkg/datastore
|
import pkg/datastore
|
||||||
import pkg/poseidon2
|
import pkg/poseidon2
|
||||||
import pkg/poseidon2/io
|
import pkg/poseidon2/io
|
||||||
import constantine/math/io/io_fields
|
import pkg/constantine/math/io/io_fields
|
||||||
|
|
||||||
import ../../asynctest
|
import ./helpers
|
||||||
import ../helpers
|
import ../helpers
|
||||||
import ../examples
|
import ../examples
|
||||||
import ../merkletree/helpers
|
import ../merkletree/helpers
|
||||||
|
@ -26,9 +29,12 @@ import ../merkletree/helpers
|
||||||
import pkg/codex/indexingstrategy {.all.}
|
import pkg/codex/indexingstrategy {.all.}
|
||||||
import pkg/codex/slots {.all.}
|
import pkg/codex/slots {.all.}
|
||||||
|
|
||||||
privateAccess(SlotsBuilder) # enable access to private fields
|
privateAccess(Poseidon2Builder) # enable access to private fields
|
||||||
privateAccess(Manifest) # enable access to private fields
|
privateAccess(Manifest) # enable access to private fields
|
||||||
|
|
||||||
|
const
|
||||||
|
Strategy = SteppedStrategy
|
||||||
|
|
||||||
suite "Slot builder":
|
suite "Slot builder":
|
||||||
let
|
let
|
||||||
blockSize = NBytes 1024
|
blockSize = NBytes 1024
|
||||||
|
@ -37,98 +43,49 @@ suite "Slot builder":
|
||||||
ecM = 2
|
ecM = 2
|
||||||
|
|
||||||
numSlots = ecK + ecM
|
numSlots = ecK + ecM
|
||||||
numDatasetBlocks = 100
|
numDatasetBlocks = 50
|
||||||
numBlockCells = (blockSize div cellSize).int
|
numTotalBlocks = calcEcBlocksCount(numDatasetBlocks, ecK, ecM) # total number of blocks in the dataset after
|
||||||
|
# EC (should will match number of slots)
|
||||||
|
originalDatasetSize = numDatasetBlocks * blockSize.int
|
||||||
|
totalDatasetSize = numTotalBlocks * blockSize.int
|
||||||
|
|
||||||
numTotalBlocks = calcEcBlocksCount(numDatasetBlocks, ecK, ecM) # total number of blocks in the dataset after
|
numBlockCells = (blockSize div cellSize).int # number of cells per block
|
||||||
# EC (should will match number of slots)
|
numSlotBlocks = numTotalBlocks div numSlots # number of blocks per slot
|
||||||
originalDatasetSize = numDatasetBlocks * blockSize.int # size of the dataset before EC
|
numSlotCells = numSlotBlocks * numBlockCells # number of uncorrected slot cells
|
||||||
totalDatasetSize = numTotalBlocks * blockSize.int # size of the dataset after EC
|
pow2SlotCells = nextPowerOfTwo(numSlotCells) # pow2 cells per slot
|
||||||
numTotalSlotBlocks = nextPowerOfTwo(numTotalBlocks div numSlots)
|
numPadSlotBlocks = pow2SlotCells div numBlockCells # pow2 blocks per slot
|
||||||
|
numPadBlocksTotal = numPadSlotBlocks * numSlots # total number of pad blocks
|
||||||
|
|
||||||
blockPadBytes =
|
# empty digest
|
||||||
newSeq[byte](numBlockCells.nextPowerOfTwoPad * cellSize.int) # power of two padding for blocks
|
emptyDigest = SpongeMerkle.digest(newSeq[byte](blockSize.int), cellSize.int)
|
||||||
|
|
||||||
slotsPadLeafs =
|
|
||||||
newSeqWith((numTotalBlocks div numSlots).nextPowerOfTwoPad, Poseidon2Zero) # power of two padding for block roots
|
|
||||||
|
|
||||||
rootsPadLeafs =
|
|
||||||
newSeqWith(numSlots.nextPowerOfTwoPad, Poseidon2Zero)
|
|
||||||
|
|
||||||
var
|
var
|
||||||
datasetBlocks: seq[bt.Block]
|
datasetBlocks: seq[bt.Block]
|
||||||
|
padBlocks: seq[bt.Block]
|
||||||
localStore: BlockStore
|
localStore: BlockStore
|
||||||
manifest: Manifest
|
manifest: Manifest
|
||||||
protectedManifest: Manifest
|
protectedManifest: Manifest
|
||||||
expectedEmptyCid: Cid
|
builder: Poseidon2Builder
|
||||||
slotBuilder: SlotsBuilder
|
|
||||||
chunker: Chunker
|
chunker: Chunker
|
||||||
|
|
||||||
proc createBlocks(): Future[void] {.async.} =
|
|
||||||
while true:
|
|
||||||
let chunk = await chunker.getBytes()
|
|
||||||
if chunk.len <= 0:
|
|
||||||
break
|
|
||||||
let blk = bt.Block.new(chunk).tryGet()
|
|
||||||
datasetBlocks.add(blk)
|
|
||||||
discard await localStore.putBlock(blk)
|
|
||||||
|
|
||||||
proc createProtectedManifest(): Future[void] {.async.} =
|
|
||||||
let
|
|
||||||
cids = datasetBlocks.mapIt(it.cid)
|
|
||||||
datasetTree = CodexTree.init(cids[0..<numDatasetBlocks]).tryGet()
|
|
||||||
datasetTreeCid = datasetTree.rootCid().tryGet()
|
|
||||||
|
|
||||||
protectedTree = CodexTree.init(cids).tryGet()
|
|
||||||
protectedTreeCid = protectedTree.rootCid().tryGet()
|
|
||||||
|
|
||||||
for index, cid in cids[0..<numDatasetBlocks]:
|
|
||||||
let proof = datasetTree.getProof(index).tryget()
|
|
||||||
(await localStore.putCidAndProof(datasetTreeCid, index, cid, proof)).tryGet
|
|
||||||
|
|
||||||
for index, cid in cids:
|
|
||||||
let proof = protectedTree.getProof(index).tryget()
|
|
||||||
(await localStore.putCidAndProof(protectedTreeCid, index, cid, proof)).tryGet
|
|
||||||
|
|
||||||
manifest = Manifest.new(
|
|
||||||
treeCid = datasetTreeCid,
|
|
||||||
blockSize = blockSize.NBytes,
|
|
||||||
datasetSize = originalDatasetSize.NBytes)
|
|
||||||
|
|
||||||
protectedManifest = Manifest.new(
|
|
||||||
manifest = manifest,
|
|
||||||
treeCid = protectedTreeCid,
|
|
||||||
datasetSize = totalDatasetSize.NBytes,
|
|
||||||
ecK = ecK,
|
|
||||||
ecM = ecM,
|
|
||||||
strategy = StrategyType.SteppedStrategy)
|
|
||||||
|
|
||||||
let
|
|
||||||
manifestBlock = bt.Block.new(
|
|
||||||
manifest.encode().tryGet(),
|
|
||||||
codec = ManifestCodec).tryGet()
|
|
||||||
|
|
||||||
protectedManifestBlock = bt.Block.new(
|
|
||||||
protectedManifest.encode().tryGet(),
|
|
||||||
codec = ManifestCodec).tryGet()
|
|
||||||
|
|
||||||
(await localStore.putBlock(manifestBlock)).tryGet()
|
|
||||||
(await localStore.putBlock(protectedManifestBlock)).tryGet()
|
|
||||||
|
|
||||||
expectedEmptyCid = emptyCid(
|
|
||||||
protectedManifest.version,
|
|
||||||
protectedManifest.hcodec,
|
|
||||||
protectedManifest.codec).tryGet()
|
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
let
|
let
|
||||||
repoDs = SQLiteDatastore.new(Memory).tryGet()
|
repoDs = SQLiteDatastore.new(Memory).tryGet()
|
||||||
metaDs = SQLiteDatastore.new(Memory).tryGet()
|
metaDs = SQLiteDatastore.new(Memory).tryGet()
|
||||||
localStore = RepoStore.new(repoDs, metaDs)
|
|
||||||
|
|
||||||
|
localStore = RepoStore.new(repoDs, metaDs)
|
||||||
chunker = RandomChunker.new(Rng.instance(), size = totalDatasetSize, chunkSize = blockSize)
|
chunker = RandomChunker.new(Rng.instance(), size = totalDatasetSize, chunkSize = blockSize)
|
||||||
await createBlocks()
|
datasetBlocks = await chunker.createBlocks(localStore)
|
||||||
await createProtectedManifest()
|
|
||||||
|
(manifest, protectedManifest) =
|
||||||
|
await createProtectedManifest(
|
||||||
|
datasetBlocks,
|
||||||
|
localStore,
|
||||||
|
numDatasetBlocks,
|
||||||
|
ecK, ecM,
|
||||||
|
blockSize,
|
||||||
|
originalDatasetSize,
|
||||||
|
totalDatasetSize)
|
||||||
|
|
||||||
teardown:
|
teardown:
|
||||||
await localStore.close()
|
await localStore.close()
|
||||||
|
@ -142,11 +99,10 @@ suite "Slot builder":
|
||||||
reset(localStore)
|
reset(localStore)
|
||||||
reset(manifest)
|
reset(manifest)
|
||||||
reset(protectedManifest)
|
reset(protectedManifest)
|
||||||
reset(expectedEmptyCid)
|
reset(builder)
|
||||||
reset(slotBuilder)
|
|
||||||
reset(chunker)
|
reset(chunker)
|
||||||
|
|
||||||
test "Can only create slotBuilder with protected manifest":
|
test "Can only create builder with protected manifest":
|
||||||
let
|
let
|
||||||
unprotectedManifest = Manifest.new(
|
unprotectedManifest = Manifest.new(
|
||||||
treeCid = Cid.example,
|
treeCid = Cid.example,
|
||||||
|
@ -154,8 +110,8 @@ suite "Slot builder":
|
||||||
datasetSize = originalDatasetSize.NBytes)
|
datasetSize = originalDatasetSize.NBytes)
|
||||||
|
|
||||||
check:
|
check:
|
||||||
SlotsBuilder.new(localStore, unprotectedManifest, cellSize = cellSize)
|
Poseidon2Builder.new(localStore, unprotectedManifest, cellSize = cellSize)
|
||||||
.error.msg == "Can only create SlotsBuilder using protected manifests."
|
.error.msg == "Manifest is not protected."
|
||||||
|
|
||||||
test "Number of blocks must be devisable by number of slots":
|
test "Number of blocks must be devisable by number of slots":
|
||||||
let
|
let
|
||||||
|
@ -168,10 +124,10 @@ suite "Slot builder":
|
||||||
datasetSize = totalDatasetSize.NBytes,
|
datasetSize = totalDatasetSize.NBytes,
|
||||||
ecK = ecK - 1,
|
ecK = ecK - 1,
|
||||||
ecM = ecM,
|
ecM = ecM,
|
||||||
strategy = StrategyType.SteppedStrategy)
|
strategy = Strategy)
|
||||||
|
|
||||||
check:
|
check:
|
||||||
SlotsBuilder.new(localStore, mismatchManifest, cellSize = cellSize)
|
Poseidon2Builder.new(localStore, mismatchManifest, cellSize = cellSize)
|
||||||
.error.msg == "Number of blocks must be divisable by number of slots."
|
.error.msg == "Number of blocks must be divisable by number of slots."
|
||||||
|
|
||||||
test "Block size must be divisable by cell size":
|
test "Block size must be divisable by cell size":
|
||||||
|
@ -185,146 +141,150 @@ suite "Slot builder":
|
||||||
datasetSize = (totalDatasetSize - 1).NBytes,
|
datasetSize = (totalDatasetSize - 1).NBytes,
|
||||||
ecK = ecK,
|
ecK = ecK,
|
||||||
ecM = ecM,
|
ecM = ecM,
|
||||||
strategy = StrategyType.SteppedStrategy)
|
strategy = Strategy)
|
||||||
|
|
||||||
check:
|
check:
|
||||||
SlotsBuilder.new(localStore, mismatchManifest, cellSize = cellSize)
|
Poseidon2Builder.new(localStore, mismatchManifest, cellSize = cellSize)
|
||||||
.error.msg == "Block size must be divisable by cell size."
|
.error.msg == "Block size must be divisable by cell size."
|
||||||
|
|
||||||
test "Should build correct slot builder":
|
test "Should build correct slot builder":
|
||||||
slotBuilder = SlotsBuilder.new(
|
builder = Poseidon2Builder.new(
|
||||||
localStore,
|
localStore,
|
||||||
protectedManifest,
|
protectedManifest,
|
||||||
cellSize = cellSize).tryGet()
|
cellSize = cellSize).tryGet()
|
||||||
|
|
||||||
check:
|
check:
|
||||||
slotBuilder.numBlockPadBytes == blockPadBytes.len
|
builder.cellSize == cellSize
|
||||||
slotBuilder.numSlotsPadLeafs == slotsPadLeafs.len
|
builder.numSlots == numSlots
|
||||||
slotBuilder.numRootsPadLeafs == rootsPadLeafs.len
|
builder.numBlockCells == numBlockCells
|
||||||
|
builder.numSlotBlocks == numPadSlotBlocks
|
||||||
|
builder.numSlotCells == pow2SlotCells
|
||||||
|
builder.numBlocks == numPadBlocksTotal
|
||||||
|
|
||||||
test "Should build slot hashes for all slots":
|
test "Should build slot hashes for all slots":
|
||||||
let
|
let
|
||||||
steppedStrategy = SteppedStrategy.init(0, numTotalBlocks - 1, numSlots)
|
steppedStrategy = Strategy.init(
|
||||||
slotBuilder = SlotsBuilder.new(
|
0, numPadBlocksTotal - 1, numSlots)
|
||||||
|
|
||||||
|
builder = Poseidon2Builder.new(
|
||||||
localStore,
|
localStore,
|
||||||
protectedManifest,
|
protectedManifest,
|
||||||
cellSize = cellSize).tryGet()
|
cellSize = cellSize).tryGet()
|
||||||
|
|
||||||
for i in 0 ..< numSlots:
|
# for i in 0..<numSlots:
|
||||||
let
|
let
|
||||||
expectedBlock = steppedStrategy
|
expectedHashes = collect(newSeq):
|
||||||
.getIndicies(i)
|
for j, idx in steppedStrategy.getIndicies(0):
|
||||||
.mapIt( datasetBlocks[it] )
|
if j > (protectedManifest.numSlotBlocks - 1):
|
||||||
|
emptyDigest
|
||||||
|
else:
|
||||||
|
SpongeMerkle.digest(datasetBlocks[idx].data, cellSize.int)
|
||||||
|
|
||||||
expectedHashes: seq[Poseidon2Hash] = collect(newSeq):
|
cellHashes = (await builder.getCellHashes(0)).tryGet()
|
||||||
for blk in expectedBlock:
|
|
||||||
SpongeMerkle.digest(blk.data & blockPadBytes, cellSize.int)
|
|
||||||
|
|
||||||
cellHashes = (await slotBuilder.getBlockHashes(i)).tryGet()
|
check:
|
||||||
|
cellHashes.len == expectedHashes.len
|
||||||
check:
|
cellHashes == expectedHashes
|
||||||
expectedHashes == cellHashes
|
|
||||||
|
|
||||||
test "Should build slot trees for all slots":
|
test "Should build slot trees for all slots":
|
||||||
let
|
let
|
||||||
steppedStrategy = SteppedStrategy.init(0, numTotalBlocks - 1, numSlots)
|
steppedStrategy = Strategy.init(
|
||||||
slotBuilder = SlotsBuilder.new(
|
0, numPadBlocksTotal - 1, numSlots)
|
||||||
|
|
||||||
|
builder = Poseidon2Builder.new(
|
||||||
localStore,
|
localStore,
|
||||||
protectedManifest,
|
protectedManifest,
|
||||||
cellSize = cellSize).tryGet()
|
cellSize = cellSize).tryGet()
|
||||||
|
|
||||||
for i in 0 ..< numSlots:
|
for i in 0..<numSlots:
|
||||||
let
|
let
|
||||||
expectedBlock = steppedStrategy
|
expectedHashes = collect(newSeq):
|
||||||
.getIndicies(i)
|
for j, idx in steppedStrategy.getIndicies(i):
|
||||||
.mapIt( datasetBlocks[it] )
|
if j > (protectedManifest.numSlotBlocks - 1):
|
||||||
|
emptyDigest
|
||||||
|
else:
|
||||||
|
SpongeMerkle.digest(datasetBlocks[idx].data, cellSize.int)
|
||||||
|
|
||||||
expectedHashes: seq[Poseidon2Hash] = collect(newSeq):
|
expectedRoot = Merkle.digest(expectedHashes)
|
||||||
for blk in expectedBlock:
|
slotTree = (await builder.buildSlotTree(i)).tryGet()
|
||||||
SpongeMerkle.digest(blk.data & blockPadBytes, cellSize.int)
|
|
||||||
expectedRoot = Merkle.digest(expectedHashes & slotsPadLeafs)
|
|
||||||
|
|
||||||
slotTree = (await slotBuilder.buildSlotTree(i)).tryGet()
|
|
||||||
|
|
||||||
check:
|
check:
|
||||||
expectedRoot == slotTree.root().tryGet()
|
slotTree.root().tryGet() == expectedRoot
|
||||||
|
|
||||||
test "Should persist trees for all slots":
|
test "Should persist trees for all slots":
|
||||||
let
|
let
|
||||||
slotBuilder = SlotsBuilder.new(
|
builder = Poseidon2Builder.new(
|
||||||
localStore,
|
localStore,
|
||||||
protectedManifest,
|
protectedManifest,
|
||||||
cellSize = cellSize).tryGet()
|
cellSize = cellSize).tryGet()
|
||||||
|
|
||||||
for i in 0 ..< numSlots:
|
for i in 0..<numSlots:
|
||||||
let
|
let
|
||||||
slotTree = (await slotBuilder.buildSlotTree(i)).tryGet()
|
slotTree = (await builder.buildSlotTree(i)).tryGet()
|
||||||
slotRoot = (await slotBuilder.buildSlot(i)).tryGet()
|
slotRoot = (await builder.buildSlot(i)).tryGet()
|
||||||
slotCid = slotRoot.toSlotCid().tryGet()
|
slotCid = slotRoot.toSlotCid().tryGet()
|
||||||
|
|
||||||
for cellIndex in 0..<numTotalSlotBlocks:
|
for cellIndex in 0..<numPadSlotBlocks:
|
||||||
let
|
let
|
||||||
(cellCid, proof) = (await localStore.getCidAndProof(slotCid, cellIndex)).tryGet()
|
(cellCid, proof) = (await localStore.getCidAndProof(slotCid, cellIndex)).tryGet()
|
||||||
verifiableProof = proof.toVerifiableProof().tryGet()
|
verifiableProof = proof.toVerifiableProof().tryGet()
|
||||||
posProof = slotTree.getProof(cellIndex).tryGet
|
posProof = slotTree.getProof(cellIndex).tryGet()
|
||||||
|
|
||||||
check:
|
check:
|
||||||
|
verifiableProof.path == posProof.path
|
||||||
verifiableProof.index == posProof.index
|
verifiableProof.index == posProof.index
|
||||||
verifiableProof.nleaves == posProof.nleaves
|
verifiableProof.nleaves == posProof.nleaves
|
||||||
verifiableProof.path == posProof.path
|
|
||||||
|
|
||||||
test "Should build correct verification root":
|
test "Should build correct verification root":
|
||||||
let
|
let
|
||||||
steppedStrategy = SteppedStrategy.init(0, numTotalBlocks - 1, numSlots)
|
steppedStrategy = Strategy.init(0, numPadBlocksTotal - 1, numSlots)
|
||||||
slotBuilder = SlotsBuilder.new(
|
builder = Poseidon2Builder.new(
|
||||||
localStore,
|
localStore,
|
||||||
protectedManifest,
|
protectedManifest,
|
||||||
cellSize = cellSize).tryGet()
|
cellSize = cellSize).tryGet()
|
||||||
|
|
||||||
(await slotBuilder.buildSlots()).tryGet
|
(await builder.buildSlots()).tryGet
|
||||||
let
|
let
|
||||||
slotsHashes = collect(newSeq):
|
slotsHashes = collect(newSeq):
|
||||||
for i in 0 ..< numSlots:
|
for i in 0..<numSlots:
|
||||||
let
|
let
|
||||||
expectedBlocks = steppedStrategy
|
slotHashes = collect(newSeq):
|
||||||
.getIndicies(i)
|
for j, idx in steppedStrategy.getIndicies(i):
|
||||||
.mapIt( datasetBlocks[it] )
|
if j > (protectedManifest.numSlotBlocks - 1):
|
||||||
|
emptyDigest
|
||||||
|
else:
|
||||||
|
SpongeMerkle.digest(datasetBlocks[idx].data, cellSize.int)
|
||||||
|
|
||||||
slotHashes: seq[Poseidon2Hash] = collect(newSeq):
|
Merkle.digest(slotHashes)
|
||||||
for blk in expectedBlocks:
|
|
||||||
SpongeMerkle.digest(blk.data & blockPadBytes, cellSize.int)
|
|
||||||
|
|
||||||
Merkle.digest(slotHashes & slotsPadLeafs)
|
expectedRoot = Merkle.digest(slotsHashes)
|
||||||
|
rootHash = builder.buildVerifyTree(builder.slotRoots).tryGet().root.tryGet()
|
||||||
expectedRoot = Merkle.digest(slotsHashes & rootsPadLeafs)
|
|
||||||
rootHash = slotBuilder.buildVerifyTree(slotBuilder.slotRoots).tryGet().root.tryGet()
|
|
||||||
|
|
||||||
check:
|
check:
|
||||||
expectedRoot == rootHash
|
expectedRoot == rootHash
|
||||||
|
|
||||||
test "Should build correct verification root manifest":
|
test "Should build correct verification root manifest":
|
||||||
let
|
let
|
||||||
steppedStrategy = SteppedStrategy.init(0, numTotalBlocks - 1, numSlots)
|
steppedStrategy = Strategy.init(0, numPadBlocksTotal - 1, numSlots)
|
||||||
slotBuilder = SlotsBuilder.new(
|
builder = Poseidon2Builder.new(
|
||||||
localStore,
|
localStore,
|
||||||
protectedManifest,
|
protectedManifest,
|
||||||
cellSize = cellSize).tryGet()
|
cellSize = cellSize).tryGet()
|
||||||
|
|
||||||
slotsHashes = collect(newSeq):
|
slotsHashes = collect(newSeq):
|
||||||
for i in 0 ..< numSlots:
|
for i in 0..<numSlots:
|
||||||
let
|
let
|
||||||
expectedBlocks = steppedStrategy
|
slotHashes = collect(newSeq):
|
||||||
.getIndicies(i)
|
for j, idx in steppedStrategy.getIndicies(i):
|
||||||
.mapIt( datasetBlocks[it] )
|
if j > (protectedManifest.numSlotBlocks - 1):
|
||||||
|
emptyDigest
|
||||||
|
else:
|
||||||
|
SpongeMerkle.digest(datasetBlocks[idx].data, cellSize.int)
|
||||||
|
|
||||||
slotHashes: seq[Poseidon2Hash] = collect(newSeq):
|
Merkle.digest(slotHashes)
|
||||||
for blk in expectedBlocks:
|
|
||||||
SpongeMerkle.digest(blk.data & blockPadBytes, cellSize.int)
|
|
||||||
|
|
||||||
Merkle.digest(slotHashes & slotsPadLeafs)
|
expectedRoot = Merkle.digest(slotsHashes)
|
||||||
|
manifest = (await builder.buildManifest()).tryGet()
|
||||||
expectedRoot = Merkle.digest(slotsHashes & rootsPadLeafs)
|
|
||||||
manifest = (await slotBuilder.buildManifest()).tryGet()
|
|
||||||
mhash = manifest.verifyRoot.mhash.tryGet()
|
mhash = manifest.verifyRoot.mhash.tryGet()
|
||||||
mhashBytes = mhash.digestBytes
|
mhashBytes = mhash.digestBytes
|
||||||
rootHash = Poseidon2Hash.fromBytes(mhashBytes.toArray32).get
|
rootHash = Poseidon2Hash.fromBytes(mhashBytes.toArray32).get
|
||||||
|
@ -334,69 +294,69 @@ suite "Slot builder":
|
||||||
|
|
||||||
test "Should not build from verifiable manifest with 0 slots":
|
test "Should not build from verifiable manifest with 0 slots":
|
||||||
var
|
var
|
||||||
slotBuilder = SlotsBuilder.new(
|
builder = Poseidon2Builder.new(
|
||||||
localStore,
|
localStore,
|
||||||
protectedManifest,
|
protectedManifest,
|
||||||
cellSize = cellSize).tryGet()
|
cellSize = cellSize).tryGet()
|
||||||
verifyManifest = (await slotBuilder.buildManifest()).tryGet()
|
verifyManifest = (await builder.buildManifest()).tryGet()
|
||||||
|
|
||||||
verifyManifest.slotRoots = @[]
|
verifyManifest.slotRoots = @[]
|
||||||
check SlotsBuilder.new(
|
check Poseidon2Builder.new(
|
||||||
localStore,
|
localStore,
|
||||||
verifyManifest,
|
verifyManifest,
|
||||||
cellSize = cellSize).isErr
|
cellSize = cellSize).isErr
|
||||||
|
|
||||||
test "Should not build from verifiable manifest with incorrect number of slots":
|
test "Should not build from verifiable manifest with incorrect number of slots":
|
||||||
var
|
var
|
||||||
slotBuilder = SlotsBuilder.new(
|
builder = Poseidon2Builder.new(
|
||||||
localStore,
|
localStore,
|
||||||
protectedManifest,
|
protectedManifest,
|
||||||
cellSize = cellSize).tryGet()
|
cellSize = cellSize).tryGet()
|
||||||
|
|
||||||
verifyManifest = (await slotBuilder.buildManifest()).tryGet()
|
verifyManifest = (await builder.buildManifest()).tryGet()
|
||||||
|
|
||||||
verifyManifest.slotRoots.del(
|
verifyManifest.slotRoots.del(
|
||||||
verifyManifest.slotRoots.len - 1
|
verifyManifest.slotRoots.len - 1
|
||||||
)
|
)
|
||||||
|
|
||||||
check SlotsBuilder.new(
|
check Poseidon2Builder.new(
|
||||||
localStore,
|
localStore,
|
||||||
verifyManifest,
|
verifyManifest,
|
||||||
cellSize = cellSize).isErr
|
cellSize = cellSize).isErr
|
||||||
|
|
||||||
test "Should not build from verifiable manifest with invalid verify root":
|
test "Should not build from verifiable manifest with invalid verify root":
|
||||||
let
|
let
|
||||||
slotBuilder = SlotsBuilder.new(
|
builder = Poseidon2Builder.new(
|
||||||
localStore,
|
localStore,
|
||||||
protectedManifest,
|
protectedManifest,
|
||||||
cellSize = cellSize).tryGet()
|
cellSize = cellSize).tryGet()
|
||||||
|
|
||||||
verifyManifest = (await slotBuilder.buildManifest()).tryGet()
|
verifyManifest = (await builder.buildManifest()).tryGet()
|
||||||
offset = verifyManifest.verifyRoot.data.buffer.len div 2
|
offset = verifyManifest.verifyRoot.data.buffer.len div 2
|
||||||
|
|
||||||
rng.shuffle(
|
rng.shuffle(
|
||||||
Rng.instance,
|
Rng.instance,
|
||||||
verifyManifest.verifyRoot.data.buffer)
|
verifyManifest.verifyRoot.data.buffer)
|
||||||
|
|
||||||
check SlotsBuilder.new(
|
check Poseidon2Builder.new(
|
||||||
localStore,
|
localStore,
|
||||||
verifyManifest,
|
verifyManifest,
|
||||||
cellSize = cellSize).isErr
|
cellSize = cellSize).isErr
|
||||||
|
|
||||||
test "Should build from verifiable manifest":
|
test "Should build from verifiable manifest":
|
||||||
let
|
let
|
||||||
slotBuilder = SlotsBuilder.new(
|
builder = Poseidon2Builder.new(
|
||||||
localStore,
|
localStore,
|
||||||
protectedManifest,
|
protectedManifest,
|
||||||
cellSize = cellSize).tryGet()
|
cellSize = cellSize).tryGet()
|
||||||
|
|
||||||
verifyManifest = (await slotBuilder.buildManifest()).tryGet()
|
verifyManifest = (await builder.buildManifest()).tryGet()
|
||||||
|
|
||||||
verificationBuilder = SlotsBuilder.new(
|
verificationBuilder = Poseidon2Builder.new(
|
||||||
localStore,
|
localStore,
|
||||||
verifyManifest,
|
verifyManifest,
|
||||||
cellSize = cellSize).tryGet()
|
cellSize = cellSize).tryGet()
|
||||||
|
|
||||||
check:
|
check:
|
||||||
slotBuilder.slotRoots == verificationBuilder.slotRoots
|
builder.slotRoots == verificationBuilder.slotRoots
|
||||||
slotBuilder.verifyRoot == verificationBuilder.verifyRoot
|
builder.verifyRoot == verificationBuilder.verifyRoot
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import ./slots/testslotbuilder
|
import ./slots/testslotbuilder
|
||||||
import ./slots/testutils
|
|
||||||
import ./slots/testsampler
|
import ./slots/testsampler
|
||||||
import ./slots/testconverters
|
import ./slots/testconverters
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue