Skip to content

Commit

Permalink
Implement FIXED32_LITTLE length operation
Browse files Browse the repository at this point in the history
  • Loading branch information
kostko committed Apr 19, 2021
1 parent 61321db commit 346d8d9
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 2 deletions.
7 changes: 6 additions & 1 deletion go/ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ics23
import (
"bytes"
"crypto"
"encoding/binary"

// adds sha256 capability to crypto.SHA256
_ "crypto/sha256"
Expand Down Expand Up @@ -158,11 +159,15 @@ func doLengthOp(lengthOp LengthOp, data []byte) ([]byte, error) {
return nil, errors.Errorf("Data was %d bytes, not 64", len(data))
}
return data, nil
case LengthOp_FIXED32_LITTLE:
res := make([]byte, 4, 4+len(data))
binary.LittleEndian.PutUint32(res[:4], uint32(len(data)))
res = append(res, data...)
return res, nil
// TODO
// case LengthOp_VAR_RLP:
// case LengthOp_FIXED32_BIG:
// case LengthOp_FIXED64_BIG:
// case LengthOp_FIXED32_LITTLE:
// case LengthOp_FIXED64_LITTLE:
}
return nil, errors.Errorf("Unsupported lengthop: %d", lengthOp)
Expand Down
13 changes: 13 additions & 0 deletions go/ops_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,19 @@ func TestLeafOp(t *testing.T) {
// echo -n 04666f6f6420a48c2d4f67b9f80374938535285ed285819d8a5a8fc1fccd1e3244e437cf290d | xxd -r -p | sha256sum
expected: fromHex("87e0483e8fb624aef2e2f7b13f4166cda485baa8e39f437c83d74c94bedb148f"),
},
"hash with length prefix (fixed 32-bit little-endian encoding)": {
op: &LeafOp{
Hash: HashOp_SHA256,
Length: LengthOp_FIXED32_LITTLE,
// no prehash
},
// echo -n food | xxs -ps
// and manually compute length bytes
key: []byte("food"), // 04000000666f6f64
value: []byte("some longer text"), // 10000000736f6d65206c6f6e6765722074657874
// echo -n 04000000666f6f6410000000736f6d65206c6f6e6765722074657874 | xxd -r -p | sha256sum
expected: fromHex("c853652437be02501c674744bf2a2b45d92a0a9f29c4b1044010fb3e2d43a949"),
},
}

for name, tc := range cases {
Expand Down
15 changes: 15 additions & 0 deletions js/src/ops.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,21 @@ describe("applyLeaf", () => {
expect(applyLeaf(op, key, value)).toEqual(expected);
});

it("hashes with length prefix (fixed 32-bit little-endian encoding)", () => {
const op: ics23.ILeafOp = {
hash: ics23.HashOp.SHA256,
length: ics23.LengthOp.FIXED32_LITTLE
};
// echo -n food | xxd -ps
const key = toAscii("food"); // 04000000666f6f64
const value = toAscii("some longer text"); // 10000000736f6d65206c6f6e6765722074657874
// echo -n 04000000666f6f6410000000736f6d65206c6f6e6765722074657874 | xxd -r -p | sha256sum
const expected = fromHex(
"c853652437be02501c674744bf2a2b45d92a0a9f29c4b1044010fb3e2d43a949"
);
expect(applyLeaf(op, key, value)).toEqual(expected);
});

it("hashes with prehash and length prefix", () => {
const op: ics23.ILeafOp = {
hash: ics23.HashOp.SHA256,
Expand Down
15 changes: 14 additions & 1 deletion js/src/ops.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,12 @@ function doLengthOp(lengthOp: ics23.LengthOp, data: Uint8Array): Uint8Array {
throw new Error(`Length is ${data.length}, not 64 bytes`);
}
return data;
case ics23.LengthOp.FIXED32_LITTLE:
return new Uint8Array([...encodeFixed32LE(data.length), ...data]);
// TODO
// case LengthOp_VAR_RLP:
// case LengthOp_FIXED32_BIG:
// case LengthOp_FIXED64_BIG:
// case LengthOp_FIXED32_LITTLE:
// case LengthOp_FIXED64_LITTLE:
}
throw new Error(`Unsupported lengthop: ${lengthOp}`);
Expand All @@ -155,3 +156,15 @@ function encodeVarintProto(n: number): Uint8Array {
enc = [...enc, l];
return new Uint8Array(enc);
}

function encodeFixed32LE(n: number): Uint8Array {
const enc = new Uint8Array(4);
let l = n;
for (let i = enc.length; i > 0; i--) {
/* tslint:disable */
enc[Math.abs(i - enc.length)] = l % 256;
/* tslint:enable */
l = Math.floor(l / 256);
}
return enc;
}
12 changes: 12 additions & 0 deletions rust/src/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ fn do_length(length: LengthOp, data: &[u8]) -> Result<Hash> {
len.extend(data);
return Ok(len);
}
LengthOp::Fixed32Little => {
let mut len = (data.len() as u32).to_le_bytes().to_vec();
len.extend(data);
return Ok(len);
}
_ => bail!("Unsupported LengthOp {:?}", length),
}
// if we don't error above or return custom string, just return item untouched (common case)
Expand Down Expand Up @@ -125,6 +130,13 @@ mod tests {
"proto prefix returned {}",
hex::encode(&prefixed),
);

let prefixed = do_length(LengthOp::Fixed32Little, b"food")?;
ensure!(
prefixed == hex::decode("04000000666f6f64")?,
"proto prefix returned {}",
hex::encode(&prefixed),
);
Ok(())
}

Expand Down

0 comments on commit 346d8d9

Please sign in to comment.