Commit 2034e9b2 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

op-challenger: Include proof in challenge data (#9228)

* op-program: Support absorbing leaf with supplied commitment

* op-challenger: Include proofs with challenge data

* op-challenger: Use 0 bytes in hash when index not set
parent 7998bed9
......@@ -122,14 +122,8 @@ func (p *LargePreimageUploader) splitCalls(data *types.PreimageOracleData) (*mat
}
func (p *LargePreimageUploader) Squeeze(ctx context.Context, uuid *big.Int, stateMatrix *matrix.StateMatrix) error {
prestate, prestateProof, err := stateMatrix.PrestateWithProof()
if err != nil {
return fmt.Errorf("failed to generate prestate proof: %w", err)
}
poststate, poststateProof, err := stateMatrix.PoststateWithProof()
if err != nil {
return fmt.Errorf("failed to generate poststate proof: %w", err)
}
prestate, prestateProof := stateMatrix.PrestateWithProof()
poststate, poststateProof := stateMatrix.PoststateWithProof()
challengePeriod, err := p.contract.ChallengePeriod(ctx)
if err != nil {
return fmt.Errorf("failed to get challenge period: %w", err)
......
......@@ -37,38 +37,30 @@ var (
// [ErrValid] is returned if the provided inputs are valid and no challenge can be created.
func Challenge(data io.Reader, commitments []common.Hash) (types.Challenge, error) {
s := NewStateMatrix()
m := s.PackState()
var prestate types.Leaf
lastValidState := s.PackState()
var lastValidLeaf types.Leaf
var firstInvalidLeaf types.Leaf
for i := 0; ; i++ {
unpaddedLeaf, err := s.absorbNextLeafInput(data)
isEOF := errors.Is(err, io.EOF)
if err != nil && !isEOF {
return types.Challenge{}, fmt.Errorf("failed to verify inputs: %w", err)
}
validCommitment := s.StateCommitment()
if i >= len(commitments) {
// There should have been more commitments.
// The contracts should prevent this so it can't be challenged, return an error
return types.Challenge{}, ErrIncorrectCommitmentCount
}
claimedCommitment := commitments[i]
var paddedLeaf [types.BlockSize]byte
copy(paddedLeaf[:], unpaddedLeaf)
// TODO(client-pod#480): Add actual keccak padding to ensure the merkle proofs are correct
poststate := types.Leaf{
Input: paddedLeaf,
Index: big.NewInt(int64(i)),
StateCommitment: claimedCommitment,
_, err := s.absorbNextLeafInput(data, func() common.Hash { return claimedCommitment })
isEOF := errors.Is(err, io.EOF)
if err != nil && !isEOF {
return types.Challenge{}, fmt.Errorf("failed to verify inputs: %w", err)
}
validCommitment := s.StateCommitment()
if validCommitment != claimedCommitment {
// TODO(client-pod#480): Add merkle proofs for these (invalid) leaves
return types.Challenge{
StateMatrix: m,
Prestate: prestate,
Poststate: poststate,
}, nil
if firstInvalidLeaf == (types.Leaf{}) {
if validCommitment != claimedCommitment {
lastValidLeaf = s.prestateLeaf
firstInvalidLeaf = s.poststateLeaf
} else {
lastValidState = s.PackState()
}
}
if isEOF {
if i < len(commitments)-1 {
......@@ -78,8 +70,20 @@ func Challenge(data io.Reader, commitments []common.Hash) (types.Challenge, erro
}
break
}
prestate = poststate
m = s.PackState()
}
if firstInvalidLeaf != (types.Leaf{}) {
var prestateProof merkle.Proof
if lastValidLeaf != (types.Leaf{}) {
prestateProof = s.merkleTree.ProofAtIndex(lastValidLeaf.IndexUint64())
}
poststateProof := s.merkleTree.ProofAtIndex(firstInvalidLeaf.IndexUint64())
return types.Challenge{
StateMatrix: lastValidState,
Prestate: lastValidLeaf,
PrestateProof: prestateProof,
Poststate: firstInvalidLeaf,
PoststateProof: poststateProof,
}, nil
}
return types.Challenge{}, ErrValid
}
......@@ -87,13 +91,7 @@ func Challenge(data io.Reader, commitments []common.Hash) (types.Challenge, erro
// NewStateMatrix creates a new state matrix initialized with the initial, zero keccak block.
func NewStateMatrix() *StateMatrix {
return &StateMatrix{
s: newLegacyKeccak256(),
prestateLeaf: types.Leaf{
Index: big.NewInt(0),
},
poststateLeaf: types.Leaf{
Index: big.NewInt(0),
},
s: newLegacyKeccak256(),
merkleTree: merkle.NewBinaryMerkleTree(),
}
}
......@@ -117,10 +115,10 @@ func (d *StateMatrix) PackState() []byte {
// newLeafWithPadding creates a new [Leaf] from inputs, padding the input to the [BlockSize].
func newLeafWithPadding(input []byte, index *big.Int, commitment common.Hash) types.Leaf {
// TODO(client-pod#480): Add actual keccak padding to ensure the merkle proofs are correct (for readData)
paddedInput := make([]byte, types.BlockSize)
copy(paddedInput, input)
var paddedInput [types.BlockSize]byte
copy(paddedInput[:], input)
return types.Leaf{
Input: ([types.BlockSize]byte)(paddedInput),
Input: paddedInput,
Index: index,
StateCommitment: commitment,
}
......@@ -133,7 +131,7 @@ func (d *StateMatrix) AbsorbUpTo(in io.Reader, maxLen int) (types.InputData, err
input := make([]byte, 0, maxLen)
commitments := make([]common.Hash, 0, maxLen/types.BlockSize)
for len(input)+types.BlockSize <= maxLen {
readData, err := d.absorbNextLeafInput(in)
readData, err := d.absorbNextLeafInput(in, d.StateCommitment)
if errors.Is(err, io.EOF) {
input = append(input, readData...)
commitments = append(commitments, d.StateCommitment())
......@@ -157,26 +155,20 @@ func (d *StateMatrix) AbsorbUpTo(in io.Reader, maxLen int) (types.InputData, err
}
// PrestateWithProof returns the prestate leaf with its merkle proof.
func (d *StateMatrix) PrestateWithProof() (types.Leaf, merkle.Proof, error) {
proof, err := d.merkleTree.ProofAtIndex(d.prestateLeaf.Index.Uint64())
if err != nil {
return types.Leaf{}, merkle.Proof{}, err
}
return d.prestateLeaf, proof, nil
func (d *StateMatrix) PrestateWithProof() (types.Leaf, merkle.Proof) {
proof := d.merkleTree.ProofAtIndex(d.prestateLeaf.IndexUint64())
return d.prestateLeaf, proof
}
// PoststateWithProof returns the poststate leaf with its merkle proof.
func (d *StateMatrix) PoststateWithProof() (types.Leaf, merkle.Proof, error) {
proof, err := d.merkleTree.ProofAtIndex(d.poststateLeaf.Index.Uint64())
if err != nil {
return types.Leaf{}, merkle.Proof{}, err
}
return d.poststateLeaf, proof, nil
func (d *StateMatrix) PoststateWithProof() (types.Leaf, merkle.Proof) {
proof := d.merkleTree.ProofAtIndex(d.poststateLeaf.IndexUint64())
return d.poststateLeaf, proof
}
// absorbNextLeafInput reads up to [BlockSize] bytes from in and absorbs them into the state matrix.
// If EOF is reached while reading, the state matrix is finalized and [io.EOF] is returned.
func (d *StateMatrix) absorbNextLeafInput(in io.Reader) ([]byte, error) {
func (d *StateMatrix) absorbNextLeafInput(in io.Reader, stateCommitment func() common.Hash) ([]byte, error) {
data := make([]byte, types.BlockSize)
read := 0
final := false
......@@ -198,12 +190,13 @@ func (d *StateMatrix) absorbNextLeafInput(in io.Reader) ([]byte, error) {
// additional block. We can then return EOF to indicate there are no further blocks.
final = final && len(input) < types.BlockSize
d.absorbLeafInput(input, final)
if d.prestateLeaf.StateCommitment == (common.Hash{}) {
d.prestateLeaf = newLeafWithPadding(input, d.prestateLeaf.Index, d.StateCommitment())
d.poststateLeaf = newLeafWithPadding(input, d.prestateLeaf.Index, d.StateCommitment())
commitment := stateCommitment()
if d.poststateLeaf == (types.Leaf{}) {
d.prestateLeaf = types.Leaf{}
d.poststateLeaf = newLeafWithPadding(input, big.NewInt(0), commitment)
} else {
d.prestateLeaf = d.poststateLeaf
d.poststateLeaf = newLeafWithPadding(input, new(big.Int).Add(d.prestateLeaf.Index, big.NewInt(1)), d.StateCommitment())
d.poststateLeaf = newLeafWithPadding(input, new(big.Int).Add(d.prestateLeaf.Index, big.NewInt(1)), commitment)
}
d.merkleTree.AddLeaf(d.poststateLeaf.Hash())
if final {
......
......@@ -11,6 +11,7 @@ import (
"math/rand"
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/game/keccak/merkle"
"github.com/ethereum-optimism/optimism/op-challenger/game/keccak/types"
"github.com/ethereum-optimism/optimism/op-service/testutils"
"github.com/ethereum/go-ethereum/common"
......@@ -58,39 +59,47 @@ type testData struct {
PoststateLeaf []byte `json:"poststateLeaf"`
}
func TestReferenceCommitmentsFromReader(t *testing.T) {
func TestAbsorbNextLeaf_ReferenceCommitments(t *testing.T) {
var tests []testData
require.NoError(t, json.Unmarshal(refTests, &tests))
for i, test := range tests {
test := test
t.Run(fmt.Sprintf("Ref-%v", i), func(t *testing.T) {
t.Run(fmt.Sprintf("Ref-%v-%v", i, len(test.Input)), func(t *testing.T) {
prevLeaf := types.Leaf{}
s := NewStateMatrix()
commitments := []common.Hash{s.StateCommitment()}
in := bytes.NewReader(test.Input)
var prestateLeaf []byte
var poststateLeaf []byte
for {
readData, err := s.absorbNextLeafInput(in)
if errors.Is(err, io.EOF) {
if prestateLeaf == nil {
prestateLeaf = readData
}
poststateLeaf = readData
commitments = append(commitments, s.StateCommitment())
break
readData, err := s.absorbNextLeafInput(in, s.StateCommitment)
isEOF := errors.Is(err, io.EOF)
if !isEOF {
// Shouldn't get any error except EOF
require.NoError(t, err)
}
// Shouldn't get any error except EOF
require.NoError(t, err)
prestate, _ := s.PrestateWithProof()
poststate, _ := s.PoststateWithProof()
require.Equal(t, prevLeaf, prestate, "Prestate should be the previous post state")
require.Equal(t, poststate.Input[:len(readData)], readData, "Post state should have returned input data")
prevLeaf = poststate
commitments = append(commitments, s.StateCommitment())
prestateLeaf = readData
if isEOF {
break
}
}
actual := s.Hash()
expected := crypto.Keccak256Hash(test.Input)
require.Equal(t, expected, actual)
require.Equal(t, test.Commitments, commitments)
require.Equal(t, test.PrestateLeaf, prestateLeaf)
require.Equal(t, test.PoststateLeaf, poststateLeaf)
prestate, _ := s.PrestateWithProof()
var expectedPre [types.BlockSize]byte
copy(expectedPre[:], test.PrestateLeaf)
require.Equal(t, expectedPre, prestate.Input, "Final prestate")
poststate, _ := s.PoststateWithProof()
var expectedPost [types.BlockSize]byte
copy(expectedPost[:], test.PoststateLeaf)
require.Equal(t, expectedPost, poststate.Input, "Final poststate")
})
}
}
......@@ -179,7 +188,7 @@ func TestAbsorbUpTo_InvalidLengths(t *testing.T) {
}
}
func TestMatrix_AbsorbNextLeaf(t *testing.T) {
func TestMatrix_absorbNextLeaf(t *testing.T) {
fullLeaf := make([]byte, types.BlockSize)
for i := 0; i < types.BlockSize; i++ {
fullLeaf[i] = byte(i)
......@@ -222,7 +231,7 @@ func TestMatrix_AbsorbNextLeaf(t *testing.T) {
state := NewStateMatrix()
in := bytes.NewReader(test.input)
for i, leaf := range test.leafInputs {
buf, err := state.absorbNextLeafInput(in)
buf, err := state.absorbNextLeafInput(in, state.StateCommitment)
if errors.Is(err, io.EOF) {
require.Equal(t, test.errs[i], err)
break
......@@ -272,15 +281,31 @@ func TestVerifyPreimage(t *testing.T) {
return valid.Commitments
}
leafData := func(idx int) (out [types.BlockSize]byte) {
copy(out[:], preimage[idx*types.BlockSize:(idx+1)*types.BlockSize])
end := min((idx+1)*types.BlockSize, len(preimage))
copy(out[:], preimage[idx*types.BlockSize:end])
return
}
// merkleTree creates the final merkle tree after including all leaves.
merkleTree := func(commitments []common.Hash) *merkle.BinaryMerkleTree {
m := merkle.NewBinaryMerkleTree()
for i, commitment := range commitments {
leaf := types.Leaf{
Input: leafData(i),
Index: big.NewInt(int64(i)),
StateCommitment: commitment,
}
m.AddLeaf(leaf.Hash())
}
return m
}
challengeLeaf := func(commitments []common.Hash, invalidIdx int) types.Challenge {
invalidLeafStart := invalidIdx * types.BlockSize
s := NewStateMatrix()
_, err := s.AbsorbUpTo(bytes.NewReader(preimage), invalidLeafStart)
require.NoError(t, err)
fullMerkle := merkleTree(commitments)
prestateLeaf := leafData(invalidIdx - 1)
poststateLeaf := leafData(invalidIdx)
return types.Challenge{
......@@ -290,11 +315,14 @@ func TestVerifyPreimage(t *testing.T) {
Index: big.NewInt(int64(invalidIdx - 1)),
StateCommitment: commitments[invalidIdx-1],
},
PrestateProof: fullMerkle.ProofAtIndex(uint64(invalidIdx - 1)),
Poststate: types.Leaf{
Input: poststateLeaf,
Index: big.NewInt(int64(invalidIdx)),
StateCommitment: commitments[invalidIdx],
},
PoststateProof: fullMerkle.ProofAtIndex(uint64(invalidIdx)),
}
}
......@@ -312,23 +340,26 @@ func TestVerifyPreimage(t *testing.T) {
commitments: validCommitments,
expectedErr: ErrValid,
},
{
name: "IncorrectFirstLeaf",
commitments: func() []common.Hash {
commitments := validCommitments()
commitments[0] = common.Hash{0xaa}
return commitments
},
expected: types.Challenge{
StateMatrix: NewStateMatrix().PackState(),
Prestate: types.Leaf{},
Poststate: types.Leaf{
Input: poststateLeaf,
Index: big.NewInt(int64(0)),
StateCommitment: common.Hash{0xaa},
func() testInputs {
incorrectFirstCommitment := validCommitments()
incorrectFirstCommitment[0] = common.Hash{0xaa}
return testInputs{
name: "IncorrectFirstLeaf",
commitments: func() []common.Hash {
return incorrectFirstCommitment
},
},
},
expected: types.Challenge{
StateMatrix: NewStateMatrix().PackState(),
Prestate: types.Leaf{},
Poststate: types.Leaf{
Input: poststateLeaf,
Index: big.NewInt(int64(0)),
StateCommitment: common.Hash{0xaa},
},
PoststateProof: merkleTree(incorrectFirstCommitment).ProofAtIndex(0),
},
}
}(),
}
for i := 1; i < len(preimage)/types.BlockSize; i++ {
......@@ -348,7 +379,12 @@ func TestVerifyPreimage(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
challenge, err := Challenge(bytes.NewReader(preimage), test.commitments())
require.ErrorIs(t, err, test.expectedErr)
require.Equal(t, test.expected, challenge)
require.Equal(t, test.expected.StateMatrix, challenge.StateMatrix, "Correct state matrix")
require.Equal(t, test.expected.Prestate, challenge.Prestate, "Correct prestate")
require.Equal(t, test.expected.PrestateProof, challenge.PrestateProof, "Correct prestate proof")
require.Equal(t, test.expected.Poststate, challenge.Poststate, "Correct poststate")
require.Equal(t, test.expected.PoststateProof, challenge.PoststateProof, "Correct poststate proof")
require.Equal(t, test.expected, challenge, "Challenge correct overall")
})
}
}
......
......@@ -5,7 +5,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0x87d8548924b20b95fe1ed923236c44d2f98b8dc7a3c8c378e4193cc2745b1e8d"
],
"prestateLeaf": "kYbKyRm02RR58P+t8WPE/UNL4zmr4XIe3qfMfFwRZVWlpzgDSmAXGNhqCGJZivDoNDRM1zrLaPAk5Ol8dAyi3shQgLHaBur7TLczzwxS9b8rU7WKPhTMsK+zblk3ps19yKixxPMjzMA5L70JOy0ng7/ZoJJhMuHC7TD1SYL5LEA=",
"prestateLeaf": "",
"poststateLeaf": "kYbKyRm02RR58P+t8WPE/UNL4zmr4XIe3qfMfFwRZVWlpzgDSmAXGNhqCGJZivDoNDRM1zrLaPAk5Ol8dAyi3shQgLHaBur7TLczzwxS9b8rU7WKPhTMsK+zblk3ps19yKixxPMjzMA5L70JOy0ng7/ZoJJhMuHC7TD1SYL5LEA="
},
{
......@@ -33,7 +33,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0xafaa5d998cf20052dea34066e466691f3a59af8a6143b7ff5626f87cb76f820b"
],
"prestateLeaf": "QbjuDum/N3hGQLgqXL+MCiPEUrt4bF+xejAngdRK3D8IOKnZfk6TaiGMdsG8vg==",
"prestateLeaf": "",
"poststateLeaf": "QbjuDum/N3hGQLgqXL+MCiPEUrt4bF+xejAngdRK3D8IOKnZfk6TaiGMdsG8vg=="
},
{
......@@ -53,7 +53,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0xc59f075e03c34088cfe44693f1260a94c0ebb6075b07c00875d0c2c072a87708"
],
"prestateLeaf": "vKG+6yYjKSdPcwd7e0iBfiwk7dek86+aVEoSgpkf9IdxiukoQFjZsx4XiOHcwv4=",
"prestateLeaf": "",
"poststateLeaf": "vKG+6yYjKSdPcwd7e0iBfiwk7dek86+aVEoSgpkf9IdxiukoQFjZsx4XiOHcwv4="
},
{
......@@ -266,7 +266,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0xd587c1123b4ff0fa464810067afb76c630d2f55e699e10c87c0a0ef9b8066fb7"
],
"prestateLeaf": "aKNFw0pM0XmPQULBOYhXDEpG7xyGpTPpLKWdfAqcx/TsA8M5fxeCyWV01nQK",
"prestateLeaf": "",
"poststateLeaf": "aKNFw0pM0XmPQULBOYhXDEpG7xyGpTPpLKWdfAqcx/TsA8M5fxeCyWV01nQK"
},
{
......@@ -285,7 +285,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0x1a1f489ba334d4068d05ea8347fd83a14a73082101f8d2daba09553485e73c60"
],
"prestateLeaf": "7GzH5TVEhQ==",
"prestateLeaf": "",
"poststateLeaf": "7GzH5TVEhQ=="
},
{
......@@ -294,7 +294,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0x1811020a0424b78b1697b9cfaf67ea339be0988c5bfa859725bfbb0aec7ed76a"
],
"prestateLeaf": "x9xGIRFaMdQq0l4MEJbBDSzCSTZLsd/0UkOSiHtALhd75Gi/c7ObBdk=",
"prestateLeaf": "",
"poststateLeaf": "x9xGIRFaMdQq0l4MEJbBDSzCSTZLsd/0UkOSiHtALhd75Gi/c7ObBdk="
},
{
......@@ -303,7 +303,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0xdf980f53d2c8527c8438791243c129bd2aadb23872502fa0e4447e1b0b2202c3"
],
"prestateLeaf": "O3mF1GL0vHkl1aZEKundwta4m+07cngnlLAtOOlhZA2n9NVQHvffMRc7kgg1zs9nUWNPUcj+O994cRWgMC1k",
"prestateLeaf": "",
"poststateLeaf": "O3mF1GL0vHkl1aZEKundwta4m+07cngnlLAtOOlhZA2n9NVQHvffMRc7kgg1zs9nUWNPUcj+O994cRWgMC1k"
},
{
......@@ -322,7 +322,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0x85baa18bcb8dac402216a7c99c6bb508bfc96caabdfc83c7bccc0898a0389910"
],
"prestateLeaf": "Gy9pBTkfOeD0fUr8zbC58w5zP6YqVJZGv52nGLRXSlBlWeJLI35GmP219qhBhPZipJID71G+Hmjea/IB/N4poRzxS+9Ky/7wQNWMOadc/d+VVADXPu71Cy9IV3w=",
"prestateLeaf": "",
"poststateLeaf": "Gy9pBTkfOeD0fUr8zbC58w5zP6YqVJZGv52nGLRXSlBlWeJLI35GmP219qhBhPZipJID71G+Hmjea/IB/N4poRzxS+9Ky/7wQNWMOadc/d+VVADXPu71Cy9IV3w="
},
{
......@@ -341,7 +341,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0xf38cdf1a78988c925677b1078d433a759ca4500334818977f2a480532921d78d"
],
"prestateLeaf": "/tWP3uV4e9CVYkPJL8Z4kw==",
"prestateLeaf": "",
"poststateLeaf": "/tWP3uV4e9CVYkPJL8Z4kw=="
},
{
......@@ -360,7 +360,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0x38859b60e7bc24fc4fb617ce269ca5eb01359eaf45a40b0b50f9248cf0904a32"
],
"prestateLeaf": "evoB",
"prestateLeaf": "",
"poststateLeaf": "evoB"
},
{
......@@ -459,7 +459,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0x932653825685e7a4719f711e5de643e9325e3e584f4b1f4f173a1d8914f087ef"
],
"prestateLeaf": "sKUc0bS3vxziYuLSVP+8vjktAy0msieRxuSg0iLcAUuY03cmnnGtdmwOKwfuF2sHLGMDos8IwPbULHApG/i49Y3JAF4iRBWmppjET9h2cKwXgF83mrzd7Zd1bh7f/nz70AGPgfwuRVCYPRruYO36Lbynwg==",
"prestateLeaf": "",
"poststateLeaf": "sKUc0bS3vxziYuLSVP+8vjktAy0msieRxuSg0iLcAUuY03cmnnGtdmwOKwfuF2sHLGMDos8IwPbULHApG/i49Y3JAF4iRBWmppjET9h2cKwXgF83mrzd7Zd1bh7f/nz70AGPgfwuRVCYPRruYO36Lbynwg=="
},
{
......@@ -468,7 +468,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0x2a05292281cbe8bb141e10a2199e10229ea3b1c049f9c3837090109a6c2c2ecc"
],
"prestateLeaf": "iCvCPAopIESMi+Hl25arOaBs3JhDP9dQJg==",
"prestateLeaf": "",
"poststateLeaf": "iCvCPAopIESMi+Hl25arOaBs3JhDP9dQJg=="
},
{
......@@ -489,7 +489,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0xf4fd54da2d9deebfb13c263519bc96a75981aec25cfb546c9de7705284ae6c07"
],
"prestateLeaf": "NIvaQ23RKSRtOnN9vQ/eEvXlDlYOTTy9STSkj6bTYU9dIQEZy8rHsgD+UkPF8anrPL0ZUdMQ5S7mAa0VB4/vDfB8Kl9H5j3jISJWQEY8HaCuc9JsS1PyLxROveE=",
"prestateLeaf": "",
"poststateLeaf": "NIvaQ23RKSRtOnN9vQ/eEvXlDlYOTTy9STSkj6bTYU9dIQEZy8rHsgD+UkPF8anrPL0ZUdMQ5S7mAa0VB4/vDfB8Kl9H5j3jISJWQEY8HaCuc9JsS1PyLxROveE="
},
{
......@@ -542,7 +542,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0x759c2672c3bad10c418cbecf4d7562dba49569dfea68ffcb444d7660591e2d7d"
],
"prestateLeaf": "YmDfFJIJu992WScmzsVyne6MajcLV+PAuHQjjeqJffVgEfJQF5F63v7SVo2qm3F70XGO6LGinr8bUrXd/PKZp75uTG3THIudOg==",
"prestateLeaf": "",
"poststateLeaf": "YmDfFJIJu992WScmzsVyne6MajcLV+PAuHQjjeqJffVgEfJQF5F63v7SVo2qm3F70XGO6LGinr8bUrXd/PKZp75uTG3THIudOg=="
},
{
......@@ -653,7 +653,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0xe2a777a8bffe0bbba1ad4d89515f6eaa9440c7d843b5543ce53cf15cdd7dc4ef"
],
"prestateLeaf": "iaA3KhRXBhnFjkR2szfpxFslTINxAiauR6ZS41N7Tyfnk5iczJHJmjmPvWLUVbsoFWwbBvGkVPPJSyYV8z6Ll+CzQJmR",
"prestateLeaf": "",
"poststateLeaf": "iaA3KhRXBhnFjkR2szfpxFslTINxAiauR6ZS41N7Tyfnk5iczJHJmjmPvWLUVbsoFWwbBvGkVPPJSyYV8z6Ll+CzQJmR"
},
{
......@@ -901,7 +901,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0x6b0b2b4094f608f73c61f68be51329aff2fb0a5179de2b9b9467bfe9c3cdbe83"
],
"prestateLeaf": "BC+MRlxbvGUWnKSyfDm/ivblXLU9B8lijzAPSyuyDdTkYBZ/FSK4+2SMFmtm8KTghrh5OEvpwDz+NYX+y9wcxWFGBxy4zmC5QAmAZO78bJ0wSMdodhKgjE7JcPsUPgMuMGpvAa3TOQ==",
"prestateLeaf": "",
"poststateLeaf": "BC+MRlxbvGUWnKSyfDm/ivblXLU9B8lijzAPSyuyDdTkYBZ/FSK4+2SMFmtm8KTghrh5OEvpwDz+NYX+y9wcxWFGBxy4zmC5QAmAZO78bJ0wSMdodhKgjE7JcPsUPgMuMGpvAa3TOQ=="
},
{
......@@ -910,7 +910,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0x202223f2c589349b4674f6a6e32bf2ade3d3134b59a5c7c663117ecc87fa1455"
],
"prestateLeaf": "3L2fS5vNMdKj6LqS47x4oHrNhIIxLe9WYJ8inef4jgT/WXKUwlXH3SH1x9WDtYYD2A==",
"prestateLeaf": "",
"poststateLeaf": "3L2fS5vNMdKj6LqS47x4oHrNhIIxLe9WYJ8inef4jgT/WXKUwlXH3SH1x9WDtYYD2A=="
},
{
......@@ -919,7 +919,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0x6c7492b6bf953a71885ecd61168a95fc2e6d73ee46df0bf5ef3a366a34c364d3"
],
"prestateLeaf": "+1FoFm7ydb3xXIdbfSHG7FduytLO9fpgdX43FT+x7FtCbosJEV75Q81gxdLJ8JMMS3/Cxyk0dnEE7f/kI8tiaCdpoFMbXVSPETE+VhpYh3tqUsPx3XvxPp3UnsTT6QwXSWshkw==",
"prestateLeaf": "",
"poststateLeaf": "+1FoFm7ydb3xXIdbfSHG7FduytLO9fpgdX43FT+x7FtCbosJEV75Q81gxdLJ8JMMS3/Cxyk0dnEE7f/kI8tiaCdpoFMbXVSPETE+VhpYh3tqUsPx3XvxPp3UnsTT6QwXSWshkw=="
},
{
......@@ -984,7 +984,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0x5f19fac317da21422bb1f587b1dff8f3df060092fdbfdd227271e3bb3fc182fb"
],
"prestateLeaf": "5AOpWwV0q9zthtbxpvpnf/utrQl1riNtoHTJPRm2uWgO6XaJlJQNKMXa",
"prestateLeaf": "",
"poststateLeaf": "5AOpWwV0q9zthtbxpvpnf/utrQl1riNtoHTJPRm2uWgO6XaJlJQNKMXa"
},
{
......@@ -1015,7 +1015,7 @@
"0xee0a1a26c607ab52c6308165995365f7951a185fccca4b76c847b8860d9fea7a",
"0xd517103b16c5e12cca833ae2cc160e3d11c59c20aa380cfa5284aa10bdf4709a"
],
"prestateLeaf": "eCmovNYrO+YV73aWboXDY/ToIZIp6UfGwIarwJunhPk8EVjTQb3x5K8BPPMG5KRLbTh12+Pu31HC2xXyg7F+SmHbXmt+Uog9FXvnrI9emRAk",
"prestateLeaf": "",
"poststateLeaf": "eCmovNYrO+YV73aWboXDY/ToIZIp6UfGwIarwJunhPk8EVjTQb3x5K8BPPMG5KRLbTh12+Pu31HC2xXyg7F+SmHbXmt+Uog9FXvnrI9emRAk"
},
{
......
package merkle
import (
"errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)
......@@ -17,8 +15,6 @@ type Proof [BinaryMerkleTreeDepth]common.Hash
var (
// MaxLeafCount is the maximum number of leaves in the merkle tree.
MaxLeafCount = 1<<BinaryMerkleTreeDepth - 1 // 2^16 - 1
// IndexOutOfBoundsError is returned when an index is out of bounds.
IndexOutOfBoundsError = errors.New("index out of bounds")
// zeroHashes is a list of empty hashes in the binary merkle tree, indexed by height.
zeroHashes [BinaryMerkleTreeDepth]common.Hash
// rootHash is the known root hash of the empty binary merkle tree.
......@@ -131,9 +127,9 @@ func (m *BinaryMerkleTree) AddLeaf(hash common.Hash) {
}
// ProofAtIndex returns a merkle proof at the given leaf node index.
func (m *BinaryMerkleTree) ProofAtIndex(index uint64) (proof Proof, err error) {
func (m *BinaryMerkleTree) ProofAtIndex(index uint64) (proof Proof) {
if index >= uint64(MaxLeafCount) {
return proof, IndexOutOfBoundsError
panic("proof index out of bounds")
}
levelNode := m.walkDownToLeafCount(index + 1)
......@@ -154,5 +150,5 @@ func (m *BinaryMerkleTree) ProofAtIndex(index uint64) (proof Proof, err error) {
levelNode = levelNode.Parent
}
return proof, nil
return proof
}
......@@ -67,8 +67,7 @@ func TestBinaryMerkleTree_ProofAtIndex(t *testing.T) {
for i := 0; i < int(test.LeafCount); i++ {
tree.AddLeaf(leafHash(i))
}
proof, err := tree.ProofAtIndex(test.Index)
require.NoError(t, err)
proof := tree.ProofAtIndex(test.Index)
require.Equal(t, test.Proofs, proof)
})
}
......
......@@ -23,12 +23,25 @@ type Leaf struct {
StateCommitment common.Hash
}
func (l Leaf) IndexUint64() uint64 {
if l.Index == nil {
return 0
}
return l.Index.Uint64()
}
// Hash returns the hash of the leaf data. That is the
// bytewise concatenation of the input, index, and state commitment.
func (l Leaf) Hash() common.Hash {
concatted := make([]byte, 0, 136+32+32)
concatted = append(concatted, l.Input[:]...)
concatted = append(concatted, l.Index.Bytes()...)
var indexBytes []byte
if l.Index != nil {
indexBytes = l.Index.Bytes()
} else {
indexBytes = big.NewInt(0).Bytes()
}
concatted = append(concatted, indexBytes...)
concatted = append(concatted, l.StateCommitment.Bytes()...)
return crypto.Keccak256Hash(concatted)
}
......
......@@ -75,10 +75,7 @@ func DiffMerkle() {
}
// Generate the proof for the given index.
proof, err := merkleTree.ProofAtIndex(uint64(index))
if err != nil {
log.Fatal("Failed to generate proof: ", err)
}
proof := merkleTree.ProofAtIndex(uint64(index))
// Generate the merkle root.
root := merkleTree.RootHash()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment