diff --git a/x/lazyledgerapp/types/payformessage.go b/x/lazyledgerapp/types/payformessage.go index 0f8128e4ed..b5337f2887 100644 --- a/x/lazyledgerapp/types/payformessage.go +++ b/x/lazyledgerapp/types/payformessage.go @@ -206,7 +206,10 @@ func (msg *SignedTransactionDataPayForMessage) GetSigners() []sdk.AccAddress { // https://github.com/lazyledger/lazyledger-specs/blob/master/rationale/message_block_layout.md#non-interactive-default-rules func CreateCommit(k uint64, namespace, message []byte) ([]byte, error) { // break message into shares - shares := ChunkMessage(message) + shares := chunkMessage(message) + + // add padding if necessary + shares = addSharePadding(shares) // organize shares for merkle mountain range heights := PowerOf2MountainRange(uint64(len(shares)), k) @@ -234,8 +237,8 @@ func CreateCommit(k uint64, namespace, message []byte) ([]byte, error) { return merkle.HashFromByteSlices(subTreeRoots), nil } -// ChunkMessage breaks the message into 256 byte pieces -func ChunkMessage(message []byte) [][]byte { +// chunkMessage breaks the message into 256 byte pieces +func chunkMessage(message []byte) [][]byte { var shares [][]byte for i := 0; i < len(message); i += ShareSize { end := i + ShareSize @@ -247,6 +250,22 @@ func ChunkMessage(message []byte) [][]byte { return shares } +// addSharePadding will add padding to the last share if necessary +func addSharePadding(shares [][]byte) [][]byte { + if len(shares) == 0 { + return shares + } + + // add padding to the last share if necessary + if len(shares[len(shares)-1]) != ShareSize { + padded := make([]byte, ShareSize) + copy(padded, shares[len(shares)-1]) + shares[len(shares)-1] = padded + } + + return shares +} + // PowerOf2MountainRange returns the heights of the subtrees for binary merkle // mountian range func PowerOf2MountainRange(l, k uint64) []uint64 { diff --git a/x/lazyledgerapp/types/payformessage_test.go b/x/lazyledgerapp/types/payformessage_test.go index dfa78c571f..8700bf54cb 100644 --- a/x/lazyledgerapp/types/payformessage_test.go +++ b/x/lazyledgerapp/types/payformessage_test.go @@ -111,12 +111,39 @@ func TestGetCommitmentSignBytes(t *testing.T) { TipRateMax: 1000, }, }, - expected: []byte(`{"fee":{"base_rate_max":"10000","tip_rate_max":"1000"},"message_namespace_id":"AQIDBAECAwQ=","message_share_commitment":"kLkMnfL0wruFOdgRJ4KnyjJBLJWlKxbEyks8SI0cfZs=","message_size":"4","nonce":"1"}`), + expected: []byte(`{"fee":{"base_rate_max":"10000","tip_rate_max":"1000"},"message_namespace_id":"AQIDBAECAwQ=","message_share_commitment":"byozRVIrw5NF/rU1PPyq6BAo3g2ny3uLTiOFedtgSwo=","message_size":"4","nonce":"1"}`), }, } for _, tt := range tests { - res, err := tt.msg.GetCommitmentSignBytes(64) + res, err := tt.msg.GetCommitmentSignBytes(SquareSize) assert.NoError(t, err) assert.Equal(t, tt.expected, res) } } + +func TestShareChunkingAndPadding(t *testing.T) { + type test struct { + input []byte + expect [][]byte + } + tests := []test{ + { + input: []byte{1}, + expect: [][]byte{append([]byte{1}, bytes.Repeat([]byte{0}, ShareSize-1)...)}, + }, + { + input: bytes.Repeat([]byte{1}, ShareSize), + expect: [][]byte{bytes.Repeat([]byte{1}, ShareSize)}, + }, + } + for _, tt := range tests { + shares := chunkMessage(tt.input) + shares = addSharePadding(shares) + for _, share := range shares { + if len(share) != ShareSize { + t.Errorf("invalid share length: got %d wanted core.ShareSize (%d)", len(share), ShareSize) + } + } + assert.Equal(t, tt.expect, shares) + } +}