From e12c52f588c2cb9f7c271e5ad96294e48d0e5f04 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Fri, 27 Nov 2020 19:33:36 +0300 Subject: [PATCH] nef: change checksum calculation scheme It's now being calculated for whole file, not just header. --- cli/testdata/verify.nef | Bin 66 -> 66 bytes pkg/rpc/server/server_test.go | 2 +- pkg/rpc/server/testdata/testblocks.acc | Bin 7490 -> 7490 bytes pkg/smartcontract/nef/nef.go | 33 ++++++++++++------------- pkg/smartcontract/nef/nef_test.go | 8 +++--- 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/cli/testdata/verify.nef b/cli/testdata/verify.nef index 2d3a78cabc30f15fa95ff4cb0ebc05abf2b6cdb1..f8bf2ff484af657cb2466fb260319611cd3feac5 100755 GIT binary patch delta 19 acmZ>Anqb1m8P3Qc=n&4p?BF1?VI2S_iUeH% delta 19 acmZ>Anqb10;5FeEXE-B+phGwVvjYG(7zDQf diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index ff55d6b83..1c203176a 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -57,7 +57,7 @@ type rpcTestCase struct { } const testContractHash = "743ed26f78e29ecd595535b74a943b1f9ccbc444" -const deploymentTxHash = "f4abbf6a5af7b79819378cce1576dd72663a95961010383d67d8c4e1f00fac02" +const deploymentTxHash = "3f81bc99525ed4b1cbb4a3535feadf73176db646a2879aaf975737348a425edc" const genesisBlockHash = "a496577895eb8c227bb866dc44f99f21c0cf06417ca8f2a877cc5d761a50dac0" const verifyContractHash = "a2eb22340979804cb10cc1add0b8822c201f4d8a" diff --git a/pkg/rpc/server/testdata/testblocks.acc b/pkg/rpc/server/testdata/testblocks.acc index 167c4ab35b358e46cdf0ecacb10f12b01f6af994..999cb641fef7cc683c425d11b10ee86486fc93ae 100644 GIT binary patch delta 2069 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 EDrVBucK`qY diff --git a/pkg/smartcontract/nef/nef.go b/pkg/smartcontract/nef/nef.go index c65e061be..225f0ad86 100644 --- a/pkg/smartcontract/nef/nef.go +++ b/pkg/smartcontract/nef/nef.go @@ -23,10 +23,10 @@ import ( // | Compiler | 32 bytes | Compiler used | // | Version | 16 bytes | Compiler version (Major, Minor, Build, Version) | // +------------+-----------+------------------------------------------------------------+ -// | Checksum | 4 bytes | First four bytes of double SHA256 hash of the header | -// +------------+-----------+------------------------------------------------------------+ // | Script | Var bytes | Var bytes for the payload | // +------------+-----------+------------------------------------------------------------+ +// | Checksum | 4 bytes | First four bytes of double SHA256 hash of the header | +// +------------+-----------+------------------------------------------------------------+ const ( // Magic is a magic File header constant. @@ -40,8 +40,8 @@ const ( // File represents compiled contract file structure according to the NEF3 standard. type File struct { Header Header - Checksum uint32 Script []byte + Checksum uint32 } // Header represents File header. @@ -73,7 +73,7 @@ func NewFile(script []byte) (File, error) { return file, err } file.Header.Version = v - file.Checksum = file.Header.CalculateChecksum() + file.Checksum = file.CalculateChecksum() return file, nil } @@ -171,36 +171,35 @@ func (h *Header) DecodeBinary(r *io.BinReader) { } // CalculateChecksum returns first 4 bytes of double-SHA256(Header) converted to uint32. -func (h *Header) CalculateChecksum() uint32 { - buf := io.NewBufBinWriter() - h.EncodeBinary(buf.BinWriter) - if buf.Err != nil { - panic(buf.Err) +func (n *File) CalculateChecksum() uint32 { + bb, err := n.Bytes() + if err != nil { + panic(err) } - return binary.LittleEndian.Uint32(hash.Checksum(buf.Bytes())) + return binary.LittleEndian.Uint32(hash.Checksum(bb[:len(bb)-4])) } // EncodeBinary implements io.Serializable interface. func (n *File) EncodeBinary(w *io.BinWriter) { n.Header.EncodeBinary(w) - w.WriteU32LE(n.Checksum) w.WriteVarBytes(n.Script) + w.WriteU32LE(n.Checksum) } // DecodeBinary implements io.Serializable interface. func (n *File) DecodeBinary(r *io.BinReader) { n.Header.DecodeBinary(r) - n.Checksum = r.ReadU32LE() - checksum := n.Header.CalculateChecksum() - if checksum != n.Checksum { - r.Err = errors.New("CRC verification fail") - return - } n.Script = r.ReadVarBytes(MaxScriptLength) if len(n.Script) == 0 { r.Err = errors.New("empty script") return } + n.Checksum = r.ReadU32LE() + checksum := n.CalculateChecksum() + if checksum != n.Checksum { + r.Err = errors.New("checksum verification failure") + return + } } // Bytes returns byte array with serialized NEF File. diff --git a/pkg/smartcontract/nef/nef_test.go b/pkg/smartcontract/nef/nef_test.go index 1ed9575a3..d64897f77 100644 --- a/pkg/smartcontract/nef/nef_test.go +++ b/pkg/smartcontract/nef/nef_test.go @@ -36,20 +36,20 @@ func TestEncodeDecodeBinary(t *testing.T) { t.Run("zero-length script", func(t *testing.T) { expected.Script = make([]byte, 0) - expected.Checksum = expected.Header.CalculateChecksum() + expected.Checksum = expected.CalculateChecksum() checkDecodeError(t, expected) }) t.Run("invalid script length", func(t *testing.T) { newScript := make([]byte, MaxScriptLength+1) expected.Script = newScript - expected.Checksum = expected.Header.CalculateChecksum() + expected.Checksum = expected.CalculateChecksum() checkDecodeError(t, expected) }) t.Run("positive", func(t *testing.T) { expected.Script = script - expected.Checksum = expected.Header.CalculateChecksum() + expected.Checksum = expected.CalculateChecksum() expected.Header.Magic = Magic testserdes.EncodeDecodeBinary(t, expected, &File{}) }) @@ -76,7 +76,7 @@ func TestBytesFromBytes(t *testing.T) { }, Script: script, } - expected.Checksum = expected.Header.CalculateChecksum() + expected.Checksum = expected.CalculateChecksum() bytes, err := expected.Bytes() require.NoError(t, err)