Skip to content

Commit

Permalink
improve readability
Browse files Browse the repository at this point in the history
Signed-off-by: Ignacio Hagopian <[email protected]>
  • Loading branch information
jsign committed Jan 11, 2023
1 parent d011c02 commit 4c8f1f5
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 31 deletions.
10 changes: 4 additions & 6 deletions config_ipa.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ type IPAConfig struct {
type Config = IPAConfig

func (ipac *IPAConfig) CommitToPoly(poly []Fr, _ int) *Point {
c := ipac.conf.Commit(poly)
return &c
ret := ipac.conf.Commit(poly)
return &ret
}

var cfg *Config
Expand Down Expand Up @@ -69,10 +69,8 @@ func GetConfig() *Config {
return cfg
}

var (
FrZero Fr
FrOne Fr
)
var FrZero Fr
var FrOne Fr

func init() {
FrZero.SetZero()
Expand Down
78 changes: 53 additions & 25 deletions tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,10 @@ func (n *InternalNode) Delete(key []byte, resolver NodeResolverFn) error {
func (n *InternalNode) Flush(flush NodeFlushFn) {
n.Commit()

if n.depth <= 0 {
// If we're at the root internal node, we fire goroutines exploiting
// available cores. Those goroutines will recursively take care of downstream
// layers, so we avoid creating too many goroutines.
if n.depth == 0 {
batches := runtime.NumCPU()
batchSize := len(n.children) / batches
var wg sync.WaitGroup
Expand Down Expand Up @@ -585,8 +588,12 @@ func (n *InternalNode) Commitment() *Point {
}

func (n *InternalNode) Commit() *Point {
// If we're at the first or second layer, we do the Commit() in parallel
// leveraging available cores.
// If we're in further layers, we do single-goroutine Commit() since the top
// two layers already created enough goroutines doing downstream work.
if n.depth <= 1 {
return n.commitRoot()
return n.commitParallel()
}
if len(n.cow) != 0 {
polyp := frPool.Get().(*[]Fr)
Expand Down Expand Up @@ -627,7 +634,7 @@ func (n *InternalNode) Commit() *Point {
return n.commitment
}

func (n *InternalNode) commitRoot() *Point {
func (n *InternalNode) commitParallel() *Point {
if len(n.cow) != 0 {
polyp := frPool.Get().(*[]Fr)
poly := *polyp
Expand All @@ -639,50 +646,74 @@ func (n *InternalNode) commitRoot() *Point {
}()
emptyChildren := 256

// The idea below is to distribute calling Commit() in all COW-ed children in multiple goroutines.
// For example, if we have 2-cores, we calculate the first half of COW-ed new Commit() in a goroutine, and
// the other half in another goroutine.

// In `points` we'll have:
// - point[2*i]: the previous *Point value saved by COW.
// - point[2*i+1]: we'll calculate the new Commit() of that leaf value.
//
// First, we create the arrays to store this.
var i int
b := make([]byte, len(n.cow))
pointsIndexes := make([]byte, len(n.cow))
points := make([]*Point, 2*len(n.cow))
for idx := range n.cow {
emptyChildren--
b[i] = idx
pointsIndexes[i] = idx
i++
}

var wg sync.WaitGroup
f := func(start, end int) {
// `calculateChildsCommsInRange` does the mentioned calculation in `points`.
// It receives the range in the array where it should do the work. As mentioned earlier, each goroutine
// is assigned a range to do work. The complete range work is distributed in multiple goroutines.
calculateChildsCommsInRange := func(start, end int) {
defer wg.Done()
for i := start; i < end; i++ {
points[2*i] = n.cow[b[i]]
points[2*i+1] = n.children[b[i]].Commit()
points[2*i] = n.cow[pointsIndexes[i]]
points[2*i+1] = n.children[pointsIndexes[i]].Commit()
}
}
// Here we do the work distribution. We split the total range of work to do in `numBatches` batches and call
// the above function which does the work.
numBatches := runtime.NumCPU()
wg.Add(numBatches)
for i := 0; i < numBatches; i++ {
batchStart := i * (len(pointsIndexes) / numBatches)
if i < numBatches-1 {
go f(i*(len(b)/numBatches), (i+1)*(len(b)/numBatches))
go calculateChildsCommsInRange(batchStart, (i+1)*(len(pointsIndexes)/numBatches))
} else {
go f(i*(len(b)/numBatches), len(b))
go calculateChildsCommsInRange(batchStart, len(pointsIndexes))
}
}

// After calculating the new *Point (Commit() of touched children), we'll have to do the Point->Fr transformation.
frs := make([]*Fr, len(points))
for i := range frs {
if i%2 == 0 {
// For even slots (old COW commitment), we create a new empty Fr to store the result.
frs[i] = &Fr{}
} else {
frs[i] = &poly[b[i/2]]
// For odd slots (new commitment), we can use `poly` as a temporal storage to avoid allocations.
frs[i] = &poly[pointsIndexes[i/2]]
}
}
wg.Wait()

// Now that in `frs` we have where we want to store *all* the Point->Fr transformations, we do that in a single batch.
toFrMultiple(frs, points)

// For each
for i := 0; i < len(points)/2; i++ {
poly[b[i]].Sub(frs[2*i+1], frs[2*i])
// Now we do [newCommitment] - [oldCommitment], so we know the Fr difference between old and new commitments.
poly[pointsIndexes[i]].Sub(frs[2*i+1], frs[2*i])
}

n.cow = nil

// Now that in `poly` we have the Fr differences, we `CommitToPoly` and add to the current internal node
// commitment, finishing the diff-updating.
n.commitment.Add(n.commitment, cfg.CommitToPoly(poly, emptyChildren))
return n.commitment
}
Expand Down Expand Up @@ -1114,24 +1145,15 @@ func (leaf *LeafNode) Commit() *Point {
// Initialize the commitment with the extension tree
// marker and the stem.
count := 0
polyp, c1polyp := frPool.Get().(*[]Fr), frPool.Get().(*[]Fr)
// TODO(jsign): remove "poly" and reuse again c1poly
poly, c1poly := *polyp, *c1polyp
c1polyp := frPool.Get().(*[]Fr)
c1poly := *c1polyp
defer func() {
for i := 0; i < 256; i++ {
poly[i] = Fr{}
c1poly[i] = Fr{}
}
frPool.Put(polyp)
frPool.Put(c1polyp)
}()
poly[0].SetUint64(1)
StemFromBytes(&poly[1], leaf.stem)

// TODO(jsign)
if len(leaf.values) != 256 {
panic("leaf doesn't have 256 values")
}
count = fillSuffixTreePoly(c1poly[:], leaf.values[:128])
leaf.c1 = cfg.CommitToPoly(c1poly[:], 256-count)

Expand All @@ -1141,8 +1163,14 @@ func (leaf *LeafNode) Commit() *Point {
count = fillSuffixTreePoly(c1poly[:], leaf.values[128:])
leaf.c2 = cfg.CommitToPoly(c1poly[:], 256-count)

toFrMultiple([]*Fr{&poly[2], &poly[3]}, []*Point{leaf.c1, leaf.c2})
leaf.commitment = cfg.CommitToPoly(poly[:], 252)
for i := 0; i < 256; i++ {
c1poly[i] = Fr{}
}
c1poly[0].SetUint64(1)
StemFromBytes(&c1poly[1], leaf.stem)

toFrMultiple([]*Fr{&c1poly[2], &c1poly[3]}, []*Point{leaf.c1, leaf.c2})
leaf.commitment = cfg.CommitToPoly(c1poly[:], 252)

} else if len(leaf.cow) != 0 {
// If we've already have a calculated commitment, and there're touched leaf values, we do a diff update.
Expand Down

0 comments on commit 4c8f1f5

Please sign in to comment.