Skip to content

Commit

Permalink
crypto: add ecdsa malleability checks (#21)
Browse files Browse the repository at this point in the history
* crypto: add ecdsa malleability checks

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* Implement receipts (#22)

* types: add receipt structs

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* types/receipt: add logs bloom calculation

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* blockchain: add receipt generation

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

---------

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

---------

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
  • Loading branch information
jsign authored Feb 16, 2024
1 parent 81a3f2c commit 22e9429
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 28 deletions.
4 changes: 2 additions & 2 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
.hash = "1220ebf62505957cdd9c87b9c517ceba60c46f5c9578a504ab3299b3970cc3ab0a1d",
},
.@"zig-eth-secp256k1" = .{
.url = "https://github.com/jsign/zig-eth-secp256k1/archive/refs/tags/v0.1.0-beta-3.tar.gz",
.hash = "1220fcf062f8ee89b343e1588ac3cc002f37ee3f72841dd7f9493d9c09acad7915a3",
.url = "https://github.com/jsign/zig-eth-secp256k1/archive/refs/tags/v0.1.0-beta-4.tar.gz",
.hash = "1220c2dbdc5ddd85906c8858f2046b52870f4fe793e0c9af50b8591d10a3f267e250",
},
.httpz = .{
.url = "https://github.com/karlseguin/http.zig/archive/1a82beb0dfc22e6fc38e9918e323f8fbd3cb78a3.tar.gz",
Expand Down
31 changes: 11 additions & 20 deletions src/blockchain/blockchain.zig
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const StateDB = @import("../state/state.zig").StateDB;
const Hash32 = types.Hash32;
const Bytes32 = types.Bytes32;
const Address = types.Address;
const Receipt = types.Receipt;
const Log = types.Log;
const TxSigner = signer.TxSigner;
const VM = vm.VM;
const Keccak256 = std.crypto.hash.sha3.Keccak256;
Expand Down Expand Up @@ -176,7 +178,11 @@ pub const Blockchain = struct {
const exec_tx_result = try processTransaction(allocator, env, tx);
gas_available -= exec_tx_result.gas_used;

// TODO: make receipt and add to receipt tree.
// Create receipt.
const cumm_gas_used = block.header.gas_limit - gas_available;
const receipt = Receipt.init(tx, exec_tx_result.success, cumm_gas_used, &[_]Log{});
_ = receipt;

// TODO: do tx logs aggregation.
}

Expand Down Expand Up @@ -220,7 +226,7 @@ pub const Blockchain = struct {
return .{ .sender_address = sender_address, .effective_gas_price = effective_gas_price };
}

fn processTransaction(allocator: Allocator, env: Environment, tx: transaction.Tx) !struct { gas_used: u64 } {
fn processTransaction(allocator: Allocator, env: Environment, tx: transaction.Tx) !struct { success: bool, gas_used: u64 } {
if (!validateTransaction(tx))
return error.InvalidTransaction;

Expand Down Expand Up @@ -297,7 +303,7 @@ pub const Blockchain = struct {
env.state.destroyAccount(address);
}

return .{ .gas_used = total_gas_used };
return .{ .success = output.success, .gas_used = total_gas_used };
}

fn validateTransaction(tx: transaction.Tx) bool {
Expand Down Expand Up @@ -397,25 +403,10 @@ pub const Blockchain = struct {
return padded_address;
}

const MessageCallOutput = struct {
gas_left: u64,
refund_counter: u64,
// logs: Union[Tuple[()], Tuple[Log, ...]] TODO
// accounts_to_delete: AddressKeySet, // TODO (delete?)
// error TODO (required for future receipts)
};

fn processMessageCall(message: Message, env: Environment) !MessageCallOutput {
fn processMessageCall(message: Message, env: Environment) !vm.MessageCallOutput {
var vm_instance = VM.init(env);
defer vm_instance.deinit();

const result = try vm_instance.processMessageCall(message);
defer {
if (result.release) |release| release(&result);
}
return .{
.gas_left = @intCast(result.gas_left),
.refund_counter = @intCast(result.gas_refund),
};
return try vm_instance.processMessageCall(message);
}
};
20 changes: 18 additions & 2 deletions src/blockchain/vm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub const VM = struct {
}

// processMessageCall executes a message call.
pub fn processMessageCall(self: *VM, msg: Message) !evmc.struct_evmc_result {
pub fn processMessageCall(self: *VM, msg: Message) !MessageCallOutput {
const evmc_message: evmc.struct_evmc_message = .{
.kind = if (msg.target != null) evmc.EVMC_CALL else evmc.EVMC_CREATE,
.flags = 0,
Expand All @@ -81,7 +81,15 @@ pub const VM = struct {
.code_address = toEVMCAddress(msg.code_address),
};

return EVMOneHost.call(@ptrCast(self), @ptrCast(&evmc_message));
const result = EVMOneHost.call(@ptrCast(self), @ptrCast(&evmc_message));
defer {
if (result.release) |release| release(&result);
}
return .{
.gas_left = @intCast(result.gas_left),
.refund_counter = @intCast(result.gas_refund),
.success = result.status_code == evmc.EVMC_SUCCESS,
};
}
};

Expand Down Expand Up @@ -459,3 +467,11 @@ fn toEVMCUint256Be(num: u256) evmc.evmc_uint256be {
},
};
}

pub const MessageCallOutput = struct {
success: bool,
gas_left: u64,
refund_counter: u64,
// logs: Union[Tuple[()], Tuple[Log, ...]] TODO
// accounts_to_delete: AddressKeySet, // TODO (delete?)
};
10 changes: 10 additions & 0 deletions src/crypto/ecdsa.zig
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ pub const Signer = struct {
}
};

pub fn validateSignatureFields(r: u256, s: u256) !void {
if (r > secp256k1.Secp256k1.order) {
return error.InvalidR;
}
// Malleability check.
if (s > secp256k1.Secp256k1.order / 2) {
return error.InvalidS;
}
}

// The following test values where generated using geth, as a reference.
const hashed_msg = common.comptimeHexToBytes("05e0e0ff09b01e5626daac3165b82afa42be29197b82e8a5a8800740ee7519d2");
const private_key = common.comptimeHexToBytes("f457cd3bd0186e342d243ea40ad78fe8e81743f90852e87074e68d8c94c2a42e");
Expand Down
7 changes: 6 additions & 1 deletion src/signer/signer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ pub const TxSigner = struct {

var sig: ecdsa.Signature = undefined;

// TODO: solve malleability problem.
sig[64] = switch (tx) {
Tx.LegacyTx => |itx| blk: {
try ecdsa.validateSignatureFields(itx.r, itx.s);

std.mem.writeIntSlice(u256, sig[0..32], itx.r, std.builtin.Endian.Big);
std.mem.writeIntSlice(u256, sig[32..64], itx.s, std.builtin.Endian.Big);

Expand All @@ -58,11 +59,15 @@ pub const TxSigner = struct {
break :blk @intCast(itx.v - v_eip155);
},
Tx.AccessListTx => |itx| blk: {
try ecdsa.validateSignatureFields(itx.r, itx.s);

std.mem.writeIntSlice(u256, sig[0..32], itx.r, std.builtin.Endian.Big);
std.mem.writeIntSlice(u256, sig[32..64], itx.s, std.builtin.Endian.Big);
break :blk @intCast(itx.y_parity);
},
Tx.FeeMarketTx => |itx| blk: {
try ecdsa.validateSignatureFields(itx.r, itx.s);

std.mem.writeIntSlice(u256, sig[0..32], itx.r, std.builtin.Endian.Big);
std.mem.writeIntSlice(u256, sig[32..64], itx.s, std.builtin.Endian.Big);
break :blk @intCast(itx.y_parity);
Expand Down
2 changes: 1 addition & 1 deletion src/types/block.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ const Arena = std.heap.ArenaAllocator;
const Withdrawal = types.Withdrawal;
const Tx = types.Tx;
const Hash32 = types.Hash32;
const LogsBloom = types.LogsBloom;
const Bytes32 = types.Bytes32;
const Address = types.Address;

pub const empty_uncle_hash: types.Hash32 = [_]u8{ 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71 };
pub const LogsBloom = [256]u8;

pub const BlockHeader = struct {
parent_hash: Hash32,
Expand Down
62 changes: 62 additions & 0 deletions src/types/receipt.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const std = @import("std");
const types = @import("types.zig");
const crypto = @import("../crypto/crypto.zig");
const Allocator = std.mem.Allocator;
const hasher = crypto.hasher;
const Hash32 = types.Hash32;
const Address = types.Address;
const LogsBloom = types.LogsBloom;
const TxTypes = types.TxTypes;

pub const Receipt = struct {
tx_type: TxTypes,

succeeded: bool,
cumulative_gas_used: u64,
bloom: LogsBloom,
logs: []Log,

pub fn init(tx_type: TxTypes, succeeded: bool, cumulative_gas_used: u64, logs: []Log) Receipt {
return Receipt{
.tx_type = tx_type,
.succeeded = succeeded,
.cumulative_gas_used = cumulative_gas_used,
.bloom = calculateLogsBloom(logs),
.logs = logs,
};
}

fn calculateLogsBloom(logs: []Log) LogsBloom {
var logs_bloom = std.mem.zeroes(LogsBloom);

for (logs) |log| {
addToBloom(&logs_bloom, &log.address);
for (log.topics) |topic| {
addToBloom(&logs_bloom, &topic);
}
}

return logs_bloom;
}

fn addToBloom(bloom: *LogsBloom, value: []const u8) void {
const hash = hasher.keccak256(value);

inline for (0..3) |i| {
const hash_16bit_word = hash[i * 2 .. (i + 1) * 2].*;
const bit_to_set = @as(u11, @intCast(std.mem.readInt(u16, &hash_16bit_word, std.builtin.Endian.Big) & 0x07FF));
const bit_index = 0x07FF - bit_to_set;

const byte_index = bit_index / 8;
const bit_value = @as(u8, 1) << (7 - @as(u3, @intCast(bit_index % 8)));

bloom[byte_index] |= bit_value;
}
}
};

pub const Log = struct {
address: Address,
topics: []Hash32,
data: []u8,
};
9 changes: 7 additions & 2 deletions src/types/types.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@ pub const Bytes31 = [31]u8;
pub const Address = [20]u8;

// Blocks
pub const block = @import("block.zig");
const block = @import("block.zig");
pub const empty_uncle_hash = block.empty_uncle_hash;
pub const Block = block.Block;
pub const BlockHeader = block.BlockHeader;
pub const LogsBloom = block.LogsBloom;
pub const Withdrawal = @import("withdrawal.zig").Withdrawal;

// Receipt & Logs
const receipt = @import("receipt.zig");
pub const Receipt = receipt.Receipt;
pub const Log = receipt.Log;
pub const LogsBloom = [256]u8;

// Transactions
const transaction = @import("transaction.zig");
pub const AccessListTuple = transaction.AccessListTuple;
Expand Down

0 comments on commit 22e9429

Please sign in to comment.