-
Notifications
You must be signed in to change notification settings - Fork 67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[wip] SSZ-optimize proof (type 3) #447
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,7 +30,6 @@ import ( | |
"errors" | ||
"fmt" | ||
"sort" | ||
"unsafe" | ||
|
||
ipa "github.com/crate-crypto/go-ipa" | ||
"github.com/crate-crypto/go-ipa/common" | ||
|
@@ -83,17 +82,33 @@ type Proof struct { | |
PostValues [][]byte | ||
} | ||
|
||
type SuffixStateDiff struct { | ||
Suffix byte `json:"suffix"` | ||
CurrentValue *[32]byte `json:"currentValue"` | ||
NewValue *[32]byte `json:"newValue"` | ||
type StemStateDiff struct { | ||
Stem [StemSize]byte `json:"stem"` | ||
|
||
Updates []UpdateDiff `json:"updates"` | ||
Reads []ReadDiff `json:"reads"` | ||
Inserts []InsertDiff `json:"inserts"` | ||
Missing []MissingDiff `json:"missing"` | ||
} | ||
|
||
type SuffixStateDiffs []SuffixStateDiff | ||
type UpdateDiff struct { | ||
Suffix byte `json:"suffix"` | ||
Current [32]byte `json:"current"` | ||
New [32]byte `json:"new"` | ||
} | ||
|
||
type StemStateDiff struct { | ||
Stem [StemSize]byte `json:"stem"` | ||
SuffixDiffs SuffixStateDiffs `json:"suffixDiffs"` | ||
type ReadDiff struct { | ||
Suffix byte `json:"suffix"` | ||
Current [32]byte `json:"current"` | ||
} | ||
|
||
type InsertDiff struct { | ||
Suffix byte `json:"suffix"` | ||
New [32]byte `json:"new"` | ||
} | ||
|
||
type MissingDiff struct { | ||
Suffix byte `json:"suffix"` | ||
} | ||
|
||
type StateDiff []StemStateDiff | ||
|
@@ -102,18 +117,28 @@ func (sd StateDiff) Copy() StateDiff { | |
ret := make(StateDiff, len(sd)) | ||
for i := range sd { | ||
copy(ret[i].Stem[:], sd[i].Stem[:]) | ||
ret[i].SuffixDiffs = make([]SuffixStateDiff, len(sd[i].SuffixDiffs)) | ||
for j := range sd[i].SuffixDiffs { | ||
ret[i].SuffixDiffs[j].Suffix = sd[i].SuffixDiffs[j].Suffix | ||
if sd[i].SuffixDiffs[j].CurrentValue != nil { | ||
ret[i].SuffixDiffs[j].CurrentValue = &[32]byte{} | ||
copy((*ret[i].SuffixDiffs[j].CurrentValue)[:], (*sd[i].SuffixDiffs[j].CurrentValue)[:]) | ||
} | ||
if sd[i].SuffixDiffs[j].NewValue != nil { | ||
ret[i].SuffixDiffs[j].NewValue = &[32]byte{} | ||
copy((*ret[i].SuffixDiffs[j].NewValue)[:], (*sd[i].SuffixDiffs[j].NewValue)[:]) | ||
} | ||
|
||
ret[i].Updates = make([]UpdateDiff, len(sd[i].Updates)) | ||
for j := range sd[i].Updates { | ||
ret[i].Updates[j].Suffix = sd[i].Updates[j].Suffix | ||
ret[i].Updates[j].Current = sd[i].Updates[j].Current | ||
ret[i].Updates[j].New = sd[i].Updates[j].New | ||
} | ||
|
||
ret[i].Reads = make([]ReadDiff, len(sd[i].Reads)) | ||
for j := range sd[i].Reads { | ||
ret[i].Reads[j].Suffix = sd[i].Reads[j].Suffix | ||
ret[i].Reads[j].Current = sd[i].Reads[j].Current | ||
} | ||
|
||
ret[i].Inserts = make([]InsertDiff, len(sd[i].Inserts)) | ||
for j := range sd[i].Inserts { | ||
ret[i].Inserts[j].Suffix = sd[i].Inserts[j].Suffix | ||
ret[i].Inserts[j].New = sd[i].Inserts[j].New | ||
} | ||
|
||
ret[i].Missing = make([]MissingDiff, len(sd[i].Missing)) | ||
copy(ret[i].Missing, sd[i].Missing) | ||
} | ||
return ret | ||
} | ||
|
@@ -221,6 +246,16 @@ func VerifyVerkleProof(proof *Proof, Cs []*Point, indices []uint8, ys []*Fr, tc | |
return ipa.CheckMultiProof(tr, tc.conf, proof.Multipoint, Cs, ys, indices) | ||
} | ||
|
||
func isInsertion(preLen, postLen int) bool { | ||
return preLen == 0 && postLen != 0 | ||
} | ||
func isRead(preLen, postLen int) bool { | ||
return preLen != 0 && postLen == 0 | ||
} | ||
func isUpdate(preLen, postLen int) bool { | ||
return preLen != 0 && postLen != 0 | ||
} | ||
|
||
// SerializeProof serializes the proof in the rust-verkle format: | ||
// * len(Proof of absence stem) || Proof of absence stems | ||
// * len(depths) || serialize(depth || ext statusi) | ||
|
@@ -257,32 +292,35 @@ func SerializeProof(proof *Proof) (*VerkleProof, StateDiff, error) { | |
stemdiff = &statediff[len(statediff)-1] | ||
copy(stemdiff.Stem[:], stem) | ||
} | ||
stemdiff.SuffixDiffs = append(stemdiff.SuffixDiffs, SuffixStateDiff{Suffix: key[StemSize]}) | ||
newsd := &stemdiff.SuffixDiffs[len(stemdiff.SuffixDiffs)-1] | ||
|
||
var valueLen = len(proof.PreValues[i]) | ||
switch valueLen { | ||
case 0: | ||
// null value | ||
case 32: | ||
newsd.CurrentValue = (*[32]byte)(proof.PreValues[i]) | ||
preLen := len(proof.PreValues[i]) | ||
postLen := len(proof.PostValues[i]) | ||
switch { | ||
case isInsertion(preLen, postLen): | ||
var newValue [32]byte | ||
copy(newValue[:], proof.PostValues[i]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that we don't have to do the If Same applies to other cases. |
||
stemdiff.Inserts = append(stemdiff.Inserts, InsertDiff{ | ||
Suffix: key[StemSize], | ||
New: newValue, | ||
}) | ||
case isRead(preLen, postLen): | ||
var currentValue [32]byte | ||
copy(currentValue[:], proof.PreValues[i]) | ||
stemdiff.Reads = append(stemdiff.Reads, ReadDiff{ | ||
Suffix: key[StemSize], | ||
Current: currentValue, | ||
}) | ||
case isUpdate(preLen, postLen): | ||
var currentValue [32]byte | ||
copy(currentValue[:], proof.PreValues[i]) | ||
var newValue [32]byte | ||
copy(newValue[:], proof.PostValues[i]) | ||
stemdiff.Updates = append(stemdiff.Updates, UpdateDiff{ | ||
Suffix: key[StemSize], | ||
Current: currentValue, | ||
New: newValue, | ||
}) | ||
default: | ||
var aligned [32]byte | ||
copy(aligned[:valueLen], proof.PreValues[i]) | ||
newsd.CurrentValue = (*[32]byte)(unsafe.Pointer(&aligned[0])) | ||
} | ||
|
||
valueLen = len(proof.PostValues[i]) | ||
switch valueLen { | ||
case 0: | ||
// null value | ||
case 32: | ||
newsd.NewValue = (*[32]byte)(proof.PostValues[i]) | ||
default: | ||
// TODO remove usage of unsafe | ||
var aligned [32]byte | ||
copy(aligned[:valueLen], proof.PostValues[i]) | ||
newsd.NewValue = (*[32]byte)(unsafe.Pointer(&aligned[0])) | ||
stemdiff.Missing = append(stemdiff.Missing, MissingDiff{Suffix: key[StemSize]}) | ||
} | ||
} | ||
|
||
|
@@ -347,22 +385,37 @@ func DeserializeProof(vp *VerkleProof, statediff StateDiff) (*Proof, error) { | |
|
||
// turn statediff into keys and values | ||
for _, stemdiff := range statediff { | ||
for _, suffixdiff := range stemdiff.SuffixDiffs { | ||
for _, upt := range stemdiff.Updates { | ||
var k [32]byte | ||
copy(k[:StemSize], stemdiff.Stem[:]) | ||
k[StemSize] = suffixdiff.Suffix | ||
k[StemSize] = upt.Suffix | ||
keys = append(keys, k[:]) | ||
if suffixdiff.CurrentValue != nil { | ||
prevalues = append(prevalues, suffixdiff.CurrentValue[:]) | ||
} else { | ||
prevalues = append(prevalues, nil) | ||
} | ||
|
||
if suffixdiff.NewValue != nil { | ||
postvalues = append(postvalues, suffixdiff.NewValue[:]) | ||
} else { | ||
postvalues = append(postvalues, nil) | ||
} | ||
prevalues = append(prevalues, upt.Current[:]) | ||
postvalues = append(postvalues, upt.New[:]) | ||
} | ||
for _, ins := range stemdiff.Inserts { | ||
var k [32]byte | ||
copy(k[:StemSize], stemdiff.Stem[:]) | ||
k[StemSize] = ins.Suffix | ||
keys = append(keys, k[:]) | ||
prevalues = append(prevalues, nil) | ||
postvalues = append(postvalues, ins.New[:]) | ||
} | ||
for _, rd := range stemdiff.Reads { | ||
var k [32]byte | ||
copy(k[:StemSize], stemdiff.Stem[:]) | ||
k[StemSize] = rd.Suffix | ||
keys = append(keys, k[:]) | ||
prevalues = append(prevalues, rd.Current[:]) | ||
postvalues = append(postvalues, nil) | ||
} | ||
for _, mi := range stemdiff.Missing { | ||
var k [32]byte | ||
copy(k[:StemSize], stemdiff.Stem[:]) | ||
k[StemSize] = mi.Suffix | ||
keys = append(keys, k[:]) | ||
prevalues = append(prevalues, nil) | ||
postvalues = append(postvalues, nil) | ||
} | ||
} | ||
|
||
|
@@ -524,20 +577,20 @@ func PostStateTreeFromStateDiff(preroot VerkleNode, statediff StateDiff) (Verkle | |
|
||
for _, stemstatediff := range statediff { | ||
var ( | ||
values = make([][]byte, NodeWidth) | ||
overwrites bool | ||
values = make([][]byte, NodeWidth) | ||
overwrite bool | ||
) | ||
|
||
for _, suffixdiff := range stemstatediff.SuffixDiffs { | ||
if /* len(suffixdiff.NewValue) > 0 - this only works for a slice */ suffixdiff.NewValue != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This previous Both in |
||
// if this value is non-nil, it means InsertValuesAtStem should be | ||
// called, otherwise, skip updating the tree. | ||
overwrites = true | ||
values[suffixdiff.Suffix] = suffixdiff.NewValue[:] | ||
} | ||
for _, ins := range stemstatediff.Inserts { | ||
values[ins.Suffix] = ins.New[:] | ||
overwrite = true | ||
} | ||
for _, upd := range stemstatediff.Updates { | ||
values[upd.Suffix] = upd.New[:] | ||
overwrite = true | ||
} | ||
|
||
if overwrites { | ||
if overwrite { | ||
var stem [StemSize]byte | ||
copy(stem[:StemSize], stemstatediff.Stem[:]) | ||
if err := postroot.(*InternalNode).InsertValuesAtStem(stem[:], values, nil); err != nil { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,6 +29,7 @@ | |
"encoding/hex" | ||
"encoding/json" | ||
"fmt" | ||
"sort" | ||
) | ||
|
||
// HexToPrefixedString turns a byte slice into its hex representation | ||
|
@@ -183,92 +184,51 @@ | |
return nil | ||
} | ||
|
||
// TODO use gencodec if that works | ||
type stemStateDiffMarshaller struct { | ||
Stem string `json:"stem"` | ||
SuffixDiffs SuffixStateDiffs `json:"suffixDiffs"` | ||
Stem string `json:"stem"` | ||
Suffixes string `json:"suffixes"` | ||
Current []string `json:"current"` | ||
New []string `json:"new"` | ||
} | ||
|
||
func (ssd StemStateDiff) MarshalJSON() ([]byte, error) { | ||
suffixes := make([]byte, 0, len(ssd.Updates)+len(ssd.Inserts)) | ||
for i := range ssd.Updates { | ||
suffixes = append(suffixes, ssd.Updates[i].Suffix) | ||
} | ||
for i := range ssd.Inserts { | ||
suffixes = append(suffixes, ssd.Inserts[i].Suffix) | ||
} | ||
sort.Slice(suffixes, func(i, j int) bool { return suffixes[i] < suffixes[j] }) | ||
Comment on lines
+196
to
+203
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think in Type 2 there might be a bug since it's only inserting Updates, but prob we need both Updates+Inserts as I did here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that's possible, I'm only focusing on the SSZ encoding at the moment. We'll pick the best method and fix it if need be. |
||
return json.Marshal(&stemStateDiffMarshaller{ | ||
Stem: HexToPrefixedString(ssd.Stem[:]), | ||
SuffixDiffs: ssd.SuffixDiffs, | ||
Stem: HexToPrefixedString(ssd.Stem[:]), | ||
Suffixes: HexToPrefixedString(suffixes), | ||
// Current: | ||
// TODO implement if it makes sense. | ||
}) | ||
} | ||
|
||
func (ssd *StemStateDiff) UnmarshalJSON(data []byte) error { | ||
var aux stemStateDiffMarshaller | ||
if err := json.Unmarshal(data, &aux); err != nil { | ||
return fmt.Errorf("stemdiff unmarshal error: %w", err) | ||
} | ||
|
||
stem, err := PrefixedHexStringToBytes(aux.Stem) | ||
if err != nil { | ||
return fmt.Errorf("invalid hex string for stem: %w", err) | ||
} | ||
*ssd = StemStateDiff{ | ||
SuffixDiffs: aux.SuffixDiffs, | ||
} | ||
copy(ssd.Stem[:], stem) | ||
// var aux stemStateDiffMarshaller | ||
// if err := json.Unmarshal(data, &aux); err != nil { | ||
// return fmt.Errorf("stemdiff unmarshal error: %w", err) | ||
// } | ||
|
||
// stem, err := PrefixedHexStringToBytes(aux.Stem) | ||
// if err != nil { | ||
// return fmt.Errorf("invalid hex string for stem: %w", err) | ||
// } | ||
// *ssd = StemStateDiff{ | ||
// SuffixDiffs: aux.SuffixDiffs, | ||
// } | ||
// copy(ssd.Stem[:], stem) | ||
// TODO implement if it makes sense | ||
return nil | ||
} | ||
|
||
type suffixStateDiffMarshaller struct { | ||
Suffix byte `json:"suffix"` | ||
CurrentValue *string `json:"currentValue"` | ||
NewValue *string `json:"newValue"` | ||
} | ||
|
||
func (ssd SuffixStateDiff) MarshalJSON() ([]byte, error) { | ||
var cvstr, nvstr *string | ||
if ssd.CurrentValue != nil { | ||
tempstr := HexToPrefixedString(ssd.CurrentValue[:]) | ||
cvstr = &tempstr | ||
} | ||
if ssd.NewValue != nil { | ||
tempstr := HexToPrefixedString(ssd.NewValue[:]) | ||
nvstr = &tempstr | ||
} | ||
return json.Marshal(&suffixStateDiffMarshaller{ | ||
Suffix: ssd.Suffix, | ||
CurrentValue: cvstr, | ||
NewValue: nvstr, | ||
}) | ||
} | ||
|
||
func (ssd *SuffixStateDiff) UnmarshalJSON(data []byte) error { | ||
aux := &suffixStateDiffMarshaller{} | ||
|
||
if err := json.Unmarshal(data, &aux); err != nil { | ||
return fmt.Errorf("suffix diff unmarshal error: %w", err) | ||
} | ||
|
||
if aux.CurrentValue != nil && len(*aux.CurrentValue) != 64 && len(*aux.CurrentValue) != 0 && len(*aux.CurrentValue) != 66 { | ||
return fmt.Errorf("invalid hex string for current value: %s", *aux.CurrentValue) | ||
} | ||
|
||
*ssd = SuffixStateDiff{ | ||
Suffix: aux.Suffix, | ||
} | ||
|
||
if aux.CurrentValue != nil && len(*aux.CurrentValue) != 0 { | ||
currentValueBytes, err := PrefixedHexStringToBytes(*aux.CurrentValue) | ||
if err != nil { | ||
return fmt.Errorf("error decoding hex string for current value: %v", err) | ||
} | ||
|
||
ssd.CurrentValue = &[32]byte{} | ||
copy(ssd.CurrentValue[:], currentValueBytes) | ||
} | ||
|
||
if aux.NewValue != nil && len(*aux.NewValue) != 0 { | ||
newValueBytes, err := PrefixedHexStringToBytes(*aux.NewValue) | ||
if err != nil { | ||
return fmt.Errorf("error decoding hex string for current value: %v", err) | ||
} | ||
|
||
ssd.NewValue = &[32]byte{} | ||
copy(ssd.NewValue[:], newValueBytes) | ||
} | ||
|
||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we stop having
[]byte
, many ofif len(xxx) == 0
cases and similar are gone. We can always copy-by-value.