Skip to content

Commit

Permalink
Add OP_SHA256
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonatan Chaverri committed Sep 18, 2024
1 parent 7c82b47 commit 8502439
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ pie showData
| opWithin | 0xa5 || Returns 1 if x is within the specified range (left-inclusive), 0 otherwise. |
| opRipeMd160 | 0xa6 || The input is hashed using RIPEMD-160. |
| opSha1 | 0xa7 || The input is hashed using SHA-1. |
| opSha256 | 0xa8 | | The input is hashed using SHA-256. |
| opSha256 | 0xa8 | | The input is hashed using SHA-256. |
| opHash160 | 0xa9 || The input is hashed twice: first with SHA-256 and then with RIPEMD-160. |
| opHash256 | 0xaa || The input is hashed two times with SHA-256. |
| opCodeSeparator | 0xab || All of the signature checking words will only match signatures to the data after the most recently-executed opCODESEPARATOR. |
Expand Down
40 changes: 40 additions & 0 deletions src/script/engine.zig
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const arithmetic = @import("opcodes/arithmetic.zig");
const Opcode = @import("opcodes/constant.zig").Opcode;
const isUnnamedPushNDataOpcode = @import("opcodes/constant.zig").isUnnamedPushNDataOpcode;
const EngineError = @import("lib.zig").EngineError;
const Sha256 = std.crypto.hash.sha2.Sha256;
/// Engine is the virtual machine that executes Bitcoin scripts
pub const Engine = struct {
/// The script being executed
Expand Down Expand Up @@ -137,6 +138,7 @@ pub const Engine = struct {
Opcode.OP_MIN => try arithmetic.opMin(self),
Opcode.OP_MAX => try arithmetic.opMax(self),
Opcode.OP_WITHIN => try arithmetic.opWithin(self),
Opcode.OP_SHA256 => try self.opSha256(),
Opcode.OP_HASH160 => try self.opHash160(),
Opcode.OP_CHECKSIG => try self.opCheckSig(),
Opcode.OP_NIP => try self.opNip(),
Expand Down Expand Up @@ -441,6 +443,21 @@ pub const Engine = struct {
try self.opVerify();
}

/// OP_Sha256: The input is hashed with SHA-256.
///
/// # Returns
/// - `EngineError`: If an error occurs during execution
fn opSha256(self: *Engine) !void {
const arr = try self.stack.pop();
defer self.allocator.free(arr);

// Create a digest buffer to hold the hash result
var hash: [Sha256.digest_length]u8 = undefined;
Sha256.hash(arr, &hash, .{});

try self.stack.pushByteArray(&hash);
}

/// OP_HASH160: Hash the top stack item with SHA256 and RIPEMD160
///
/// # Returns
Expand Down Expand Up @@ -780,3 +797,26 @@ test "Script execution OP_1 OP_2 OP_3 OP_SIZE" {
try std.testing.expectEqual(1, element0);
try std.testing.expectEqual(3, element1);
}

test "Script execution - OP_SHA256" {
const allocator = std.testing.allocator;

const script_bytes = [_]u8{ 0x51, 0xa8 }; // OP_1 followed by OP_SHA256
const script = Script.init(&script_bytes);

var engine = Engine.init(allocator, script, .{});
defer engine.deinit(); // Ensure engine is deinitialized and memory is freed

try engine.execute();

try std.testing.expectEqual(1, engine.stack.len());

const hash_bytes = try engine.stack.pop(); // Pop the result
defer engine.allocator.free(hash_bytes); // Free the popped byte array

try std.testing.expectEqual(Sha256.digest_length, hash_bytes.len);

var expected_hash: [Sha256.digest_length]u8 = undefined;
Sha256.hash(&[_]u8{1}, &expected_hash, .{});
try std.testing.expectEqualSlices(u8, expected_hash[0..], hash_bytes);
}

0 comments on commit 8502439

Please sign in to comment.