Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 46 additions & 21 deletions std/std.solc
Original file line number Diff line number Diff line change
Expand Up @@ -2606,28 +2606,34 @@ forall t . class t:MemoryPointer {

forall t . class t:MemoryEncode {
// Serialize the entire contents at a provided memory area.
function encodeInto(v: t, target: word) -> ();
// Returns the number of written bytes.
function encodeInto(v: t, target: word) -> word;
}

// Deconstruct tuples (incl. embedded tuples).
forall a b . a:MemoryEncode, b:MemoryEncode => instance (a,b):MemoryEncode {
function encodeInto(v: (a, b), target: word) -> word {
match v {
| (l, r) =>
let l_len = MemoryEncode.encodeInto(l, target);
let r_len = MemoryEncode.encodeInto(r, target + l_len);
return l_len + r_len;
}
}
}

// TODO: support variadic arguments
// Allocates new memory and concatenates the inputs into it.
forall a b . a:MemorySize, a:MemoryEncode, b:MemorySize, b:MemoryEncode => function concat(x: a, y: b) -> memory(bytes) {
let x_len = MemorySize.len(x);
let y_len = MemorySize.len(y);
let res: word = allocate_memory(32 + x_len + y_len);
mstore(res, x_len + y_len);
MemoryEncode.encodeInto(x, res + 32);
MemoryEncode.encodeInto(y, res + 32 + x_len);
forall a . a:MemoryEncode => function concat(v: a) -> memory(bytes) {
let res = get_free_memory();
let len = MemoryEncode.encodeInto(v, res + 32);
mstore(res, len);
set_free_memory(res + 32 + len);
return memory(res);
}

// This is a specialized 1-input version of concat.
forall a . a:MemorySize, a:MemoryEncode => function to_bytes(x: a) -> memory(bytes) {
let len = MemorySize.len(x);
let res = allocate_memory(32 + len);
mstore(res, len);
MemoryEncode.encodeInto(x, res + 32);
return memory(res);
forall a . a:MemorySize, a:MemoryEncode => function to_bytes(v: a) -> memory(bytes) {
return concat(v);
}

instance bytes32:MemorySize {
Expand All @@ -2637,8 +2643,22 @@ instance bytes32:MemorySize {
}

instance bytes32:MemoryEncode {
function encodeInto(v: bytes32, target: word) -> () {
function encodeInto(v: bytes32, target: word) -> word {
mstore(target, Typedef.rep(v));
return 32;
}
}

instance uint256:MemorySize {
function len(v: uint256) -> word {
return 32;
}
}

instance uint256:MemoryEncode {
function encodeInto(v: uint256, target: word) -> word {
mstore(target, Typedef.rep(v));
return 32;
}
}

Expand All @@ -2655,9 +2675,11 @@ instance memory(bytes):MemoryPointer {
}

instance memory(bytes):MemoryEncode {
function encodeInto(v: memory(bytes), target: word) -> () {
function encodeInto(v: memory(bytes), target: word) -> word {
let v_ = Typedef.rep(v);
mcopy(target, v_ + 32, mload(v_));
let len = mload(v_);
mcopy(target, v_ + 32, len);
return len;
}
}

Expand All @@ -2675,12 +2697,13 @@ instance empty:MemorySize {
}

instance empty:MemoryEncode {
function encodeInto(v: empty, target: word) -> () {
function encodeInto(v: empty, target: word) -> word {
let size;
match v {
| empty(size_) => size = size_;
}
zeroize_memory(target, size);
return size;
}
}

Expand All @@ -2707,9 +2730,11 @@ instance memory_ref:MemoryPointer {
}

instance memory_ref:MemoryEncode {
function encodeInto(v: memory_ref, target: word) -> () {
function encodeInto(v: memory_ref, target: word) -> word {
match v {
| memory_ref(ptr, len) => mcopy(target, ptr, len);
| memory_ref(ptr, len) =>
mcopy(target, ptr, len);
return len;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/examples/dispatch/concat.json
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@
"output": {
"returndata": "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000048111111111111111111111111111111111111111111111111111111111111111100000000000000003333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000",
"status": "success",
"gasUsed": "24304"
"gasUsed": "24181"
}
}
]
Expand Down
12 changes: 6 additions & 6 deletions test/examples/dispatch/concat.solc
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ contract C {
constructor() {}

public function concat_b32_b32(a: bytes32, b: bytes32) -> memory(bytes) {
return concat(a, b);
return concat((a, b));
}

public function concat_b32_bytes(a: bytes32, b: memory(bytes)) -> memory(bytes) {
return concat(a, b);
return concat((a, b));
}

public function concat_bytes_bytes(a: memory(bytes), b: memory(bytes)) -> memory(bytes) {
return concat(a, b);
return concat((a, b));
}

public function to_bytes_b32(a: bytes32) -> memory(bytes) {
Expand All @@ -29,14 +29,14 @@ contract C {
}

public function concat_b32_empty(a: bytes32, n: uint256) -> memory(bytes) {
return concat(a, empty(Typedef.rep(n)));
return concat((a, empty(Typedef.rep(n))));
}

public function concat_nested_b32(a: bytes32, b: bytes32, c: bytes32) -> memory(bytes) {
return concat(a, concat(b, c));
return concat((a, (b, c)));
}

public function concat_nested_empty(a: bytes32, n: uint256, c: bytes32) -> memory(bytes) {
return concat(a, concat(empty(Typedef.rep(n)), c));
return concat((a, (empty(Typedef.rep(n)), c)));
}
}
2 changes: 1 addition & 1 deletion test/examples/dispatch/deposit.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@
"output": {
"returndata": "",
"status": "success",
"gasUsed": "80164"
"gasUsed": "79898"
}
},

Expand Down
30 changes: 15 additions & 15 deletions test/examples/dispatch/deposit.solc
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ contract DepositContract {

// Compute hashes in empty sparse Merkle tree
for (let height = 0; height < (DEPOSIT_CONTRACT_TREE_DEPTH() - 1); height += 1) {
zero_hashes[height + 1] = sha256(concat(zero_hashes[height], zero_hashes[height]));
zero_hashes[height + 1] = sha256(concat((zero_hashes[height], zero_hashes[height])));
}
}

Expand All @@ -64,19 +64,19 @@ contract DepositContract {
let size = deposit_count;
for (let height = 0; height < DEPOSIT_CONTRACT_TREE_DEPTH(); height += 1) {
if ((size & 1) == 1) {
node = sha256(concat(branch[height], node));
node = sha256(concat((branch[height], node)));
} else {
node = sha256(concat(node, zero_hashes[height]));
node = sha256(concat((node, zero_hashes[height])));
}
size /= 2;
}
return sha256(concat(
concat(
return sha256(concat((
(
node,
to_little_endian_64(deposit_count)
),
empty(24)
));
)));
}

public function get_deposit_count() -> memory(bytes) {
Expand Down Expand Up @@ -126,15 +126,15 @@ contract DepositContract {
}

// Compute deposit data root (`DepositData` hash tree root)
let pubkey_root = sha256(concat(pubkey, empty(16)));
let signature_root = sha256(concat(
let pubkey_root = sha256(concat((pubkey, empty(16))));
let signature_root = sha256(concat((
sha256(truncate(signature, 64)),
sha256(concat(slice_(signature, 64), empty(32)))
));
let node = sha256(concat(
sha256(concat(pubkey_root, withdrawal_credentials)),
sha256(concat(concat(amount, empty(24)), signature_root))
));
sha256(concat((slice_(signature, 64), empty(32))))
)));
let node = sha256(concat((
sha256(concat((pubkey_root, withdrawal_credentials))),
sha256(concat(((amount, empty(24)), signature_root)))
)));

// Verify computed and expected deposit data roots match
require(node == deposit_data_root, Error(0x2ec2f183)); // ReconstructedDepositDataMismatch()
Expand All @@ -150,7 +150,7 @@ contract DepositContract {
branch[height] = node;
return ();
}
node = sha256(concat(branch[height], node));
node = sha256(concat((branch[height], node)));
size /= 2;
}

Expand Down
4 changes: 2 additions & 2 deletions test/examples/dispatch/eip712.solc
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import std.eip712.{*};
function hashPerson(nameHash: bytes32, wallet: address) -> bytes32 {
let typeHash = bytes32(keccakLit("Person(string name,address wallet)"));
return keccak256_(
concat(typeHash, concat(nameHash, bytes32(Typedef.rep(wallet))))
concat((typeHash, (nameHash, bytes32(Typedef.rep(wallet)))))
);
}

Expand All @@ -37,7 +37,7 @@ function hashMail(fromHash: bytes32, toHash: bytes32, contentsHash: bytes32) ->
keccakLit("Mail(Person from,Person to,string contents)Person(string name,address wallet)")
);
return keccak256_(
concat(typeHash, concat(fromHash, concat(toHash, contentsHash)))
concat((typeHash, (fromHash, (toHash, contentsHash))))
);
}

Expand Down
12 changes: 6 additions & 6 deletions test/examples/dispatch/slices.solc
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,27 @@ contract C {
// --- slice_/truncate over the result of a concat ---

public function slice_of_concat(a: bytes32, b: bytes32, start: uint256) -> memory(bytes) {
return to_bytes(slice_(concat(a, b), Typedef.rep(start)));
return to_bytes(slice_(concat((a, b)), Typedef.rep(start)));
}

public function truncate_of_concat(a: bytes32, b: bytes32, end: uint256) -> memory(bytes) {
return to_bytes(truncate(concat(a, b), Typedef.rep(end)));
return to_bytes(truncate(concat((a, b)), Typedef.rep(end)));
}

// to_bytes(truncate(slice_(concat(a, b), start), end)) -- the headline nesting:
// drop `start` bytes, then keep `end` of what remains (re-slicing a memory_slice).
public function window_of_concat(a: bytes32, b: bytes32, start: uint256, end: uint256) -> memory(bytes) {
return to_bytes(truncate(slice_(concat(a, b), Typedef.rep(start)), Typedef.rep(end)));
return to_bytes(truncate(slice_(concat((a, b)), Typedef.rep(start)), Typedef.rep(end)));
}

// --- a slice used as a concat operand ---

public function concat_slice_b32(a: memory(bytes), start: uint256, c: bytes32) -> memory(bytes) {
return concat(slice_(a, Typedef.rep(start)), c);
return concat((slice_(a, Typedef.rep(start)), c));
}

public function concat_two_slices(a: memory(bytes), sa: uint256, b: memory(bytes), eb: uint256) -> memory(bytes) {
return concat(slice_(a, Typedef.rep(sa)), truncate(b, Typedef.rep(eb)));
return concat((slice_(a, Typedef.rep(sa)), truncate(b, Typedef.rep(eb))));
}

// --- re-slicing a memory_slice ---
Expand All @@ -60,6 +60,6 @@ contract C {

// keccak256_(truncate(slice_(concat(a, b), start), end)) -- nested chain, hash endpoint.
public function keccak_window_concat(a: bytes32, b: bytes32, start: uint256, end: uint256) -> bytes32 {
return keccak256_(truncate(slice_(concat(a, b), Typedef.rep(start)), Typedef.rep(end)));
return keccak256_(truncate(slice_(concat((a, b)), Typedef.rep(start)), Typedef.rep(end)));
}
}
Loading