Skip to content

Commit

Permalink
feat: schnorr signatures verification (#291)
Browse files Browse the repository at this point in the history
<!-- enter the gh issue after hash -->

- [X] follows contribution
[guide](https://github.com/keep-starknet-strange/shinigami/blob/main/CONTRIBUTING.md)
- [X] code change includes tests

Adding Schnorr signatures verification.
Works alongside with #289

---------

Co-authored-by: j1mbo64 <[email protected]>
  • Loading branch information
j1mbo64 and j1mbo64 authored Jan 16, 2025
1 parent 888ee06 commit a47fbd1
Show file tree
Hide file tree
Showing 41 changed files with 811 additions and 435 deletions.
32 changes: 16 additions & 16 deletions packages/cmds/src/main.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,30 @@ use shinigami_tests::validate;
#[derive(Clone, Drop)]
struct InputData {
ScriptSig: ByteArray,
ScriptPubKey: ByteArray
ScriptPubKey: ByteArray,
}

#[derive(Clone, Drop)]
struct InputDataWithFlags {
ScriptSig: ByteArray,
ScriptPubKey: ByteArray,
Flags: ByteArray
Flags: ByteArray,
}

#[derive(Clone, Drop)]
struct InputDataWithWitness {
ScriptSig: ByteArray,
ScriptPubKey: ByteArray,
Flags: ByteArray,
Witness: ByteArray
Witness: ByteArray,
}

fn run_with_flags(input: InputDataWithFlags) -> Result<(), felt252> {
println!(
"Running Bitcoin Script with ScriptSig: '{}', ScriptPubKey: '{}' and Flags: '{}'",
input.ScriptSig,
input.ScriptPubKey,
input.Flags
input.Flags,
);
let mut compiler = CompilerImpl::new();
let script_pubkey = compiler.compile(input.ScriptPubKey)?;
Expand All @@ -55,7 +55,7 @@ fn run_with_witness(input: InputDataWithWitness) -> Result<(), felt252> {
input.ScriptSig,
input.ScriptPubKey,
input.Flags,
input.Witness
input.Witness,
);
let mut compiler = CompilerImpl::new();
let script_pubkey = compiler.compile(input.ScriptPubKey)?;
Expand All @@ -64,7 +64,7 @@ fn run_with_witness(input: InputDataWithWitness) -> Result<(), felt252> {
let witness = witness::parse_witness_input(input.Witness);
let value = 1; // TODO
let tx = EngineInternalTransactionImpl::new_signed_witness(
script_sig, script_pubkey.clone(), witness, value
script_sig, script_pubkey.clone(), witness, value,
);
let flags = flags::parse_flags(input.Flags);
let hash_cache = HashCacheImpl::new(@tx);
Expand All @@ -77,7 +77,7 @@ fn run(input: InputData) -> Result<(), felt252> {
println!(
"Running Bitcoin Script with ScriptSig: '{}' and ScriptPubKey: '{}'",
input.ScriptSig,
input.ScriptPubKey
input.ScriptPubKey,
);
let mut compiler = CompilerImpl::new();
let script_pubkey = compiler.compile(input.ScriptPubKey)?;
Expand All @@ -95,15 +95,15 @@ fn run(input: InputData) -> Result<(), felt252> {
Result::Err(e) => {
println!("Execution failed: {}", felt252_to_byte_array(e));
Result::Err(e)
}
},
}
}

fn run_with_json(input: InputData) -> Result<(), felt252> {
println!(
"Running Bitcoin Script with ScriptSig: '{}' and ScriptPubKey: '{}'",
input.ScriptSig,
input.ScriptPubKey
input.ScriptPubKey,
);
let mut compiler = CompilerImpl::new();
let script_pubkey = compiler.compile(input.ScriptPubKey)?;
Expand All @@ -121,7 +121,7 @@ fn debug(input: InputData) -> Result<bool, felt252> {
println!(
"Running Bitcoin Script with ScriptSig: '{}' and ScriptPubKey: '{}'",
input.ScriptSig,
input.ScriptPubKey
input.ScriptPubKey,
);
let mut compiler = CompilerImpl::new();
let script_pubkey = compiler.compile(input.ScriptPubKey)?;
Expand Down Expand Up @@ -154,7 +154,7 @@ fn main(input: InputDataWithFlags) -> u8 {
Result::Err(e) => {
println!("Execution failed: {}", felt252_to_byte_array(e));
0
}
},
}
}

Expand All @@ -168,7 +168,7 @@ fn main_with_witness(input: InputDataWithWitness) -> u8 {
Result::Err(e) => {
println!("Execution failed: {}", felt252_to_byte_array(e));
0
}
},
}
}

Expand All @@ -182,7 +182,7 @@ fn backend_run(input: InputData) -> u8 {
Result::Err(e) => {
println!("Execution failed: {}", felt252_to_byte_array(e));
0
}
},
}
}

Expand All @@ -196,7 +196,7 @@ fn backend_debug(input: InputData) -> u8 {
Result::Err(e) => {
println!("Execution failed: {}", felt252_to_byte_array(e));
0
}
},
}
}

Expand Down Expand Up @@ -235,7 +235,7 @@ fn run_raw_transaction(mut input: ValidateRawInput) -> u8 {
amount: *hint.amount,
pubkey_script: pubkey_script,
block_height: *hint.block_height,
}
},
);
};

Expand All @@ -248,6 +248,6 @@ fn run_raw_transaction(mut input: ValidateRawInput) -> u8 {
Result::Err(e) => {
println!("Execution failed: {}", felt252_to_byte_array(e));
0
}
},
}
}
2 changes: 1 addition & 1 deletion packages/compiler/src/compiler.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::utils::{is_hex, is_number, is_string};
#[derive(Destruct)]
pub struct Compiler {
// Dict containing opcode names to their bytecode representation
opcodes: Felt252Dict<Nullable<u8>>
opcodes: Felt252Dict<Nullable<u8>>,
}

pub trait CompilerTrait {
Expand Down
4 changes: 2 additions & 2 deletions packages/engine/src/cond_stack.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub struct ConditionalStack {
#[generate_trait()]
pub impl ConditionalStackImpl of ConditionalStackTrait {
fn new() -> ConditionalStack {
ConditionalStack { stack: Default::default(), len: 0, }
ConditionalStack { stack: Default::default(), len: 0 }
}

fn push(ref self: ConditionalStack, value: u8) {
Expand Down Expand Up @@ -43,7 +43,7 @@ pub impl ConditionalStackImpl of ConditionalStackTrait {
0 => self.stack.insert(cond_idx.into(), 1),
1 => self.stack.insert(cond_idx.into(), 0),
2 => self.stack.insert(cond_idx.into(), 2),
_ => panic!("Invalid condition")
_ => panic!("Invalid condition"),
}
}
}
16 changes: 8 additions & 8 deletions packages/engine/src/engine.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::opcodes::opcodes::Opcode;
use crate::flags::ScriptFlags;
use crate::stack::{ScriptStack, ScriptStackImpl};
use crate::transaction::{
EngineTransactionInputTrait, EngineTransactionOutputTrait, EngineTransactionTrait
EngineTransactionInputTrait, EngineTransactionOutputTrait, EngineTransactionTrait,
};
use crate::hash_cache::{HashCache, HashCacheTrait};
use crate::witness;
Expand Down Expand Up @@ -76,7 +76,7 @@ pub trait EngineTrait<
+EngineTransactionInputTrait<I>,
+EngineTransactionOutputTrait<O>,
+EngineTransactionTrait<T, I, O>,
+HashCacheTrait<I, O, T>
+HashCacheTrait<I, O, T>,
> {
// Create a new Engine with the given script
fn new(
Expand All @@ -85,7 +85,7 @@ pub trait EngineTrait<
tx_idx: u32,
flags: u32,
amount: i64,
hash_cache: @HashCache<T>
hash_cache: @HashCache<T>,
) -> Result<Engine<T>, felt252>;
// Executes a single step of the script, returning true if more steps are needed
fn step(ref self: Engine<T>) -> Result<bool, felt252>;
Expand All @@ -100,7 +100,7 @@ pub impl EngineImpl<
impl IEngineTransactionInput: EngineTransactionInputTrait<I>,
impl IEngineTransactionOutput: EngineTransactionOutputTrait<O>,
impl IEngineTransaction: EngineTransactionTrait<
T, I, O, IEngineTransactionInput, IEngineTransactionOutput
T, I, O, IEngineTransactionInput, IEngineTransactionOutput,
>,
+Drop<I>,
+Drop<O>,
Expand All @@ -113,7 +113,7 @@ pub impl EngineImpl<
tx_idx: u32,
flags: u32,
amount: i64,
hash_cache: @HashCache<T>
hash_cache: @HashCache<T>,
) -> Result<Engine<T>, felt252> {
let transaction_inputs = transaction.get_transaction_inputs();
if tx_idx >= transaction_inputs.len() {
Expand Down Expand Up @@ -230,7 +230,7 @@ pub impl EngineImpl<

if witness_program.len() != 0 {
let (witness_version, witness_program) = witness::parse_witness_program(
@witness_program
@witness_program,
)?;
engine.witness_version = witness_version;
engine.witness_program = witness_program;
Expand Down Expand Up @@ -477,7 +477,7 @@ pub impl EngineInternalImpl<
impl IEngineTransactionInput: EngineTransactionInputTrait<I>,
impl IEngineTransactionOutput: EngineTransactionOutputTrait<O>,
impl IEngineTransaction: EngineTransactionTrait<
T, I, O, IEngineTransactionInput, IEngineTransactionOutput
T, I, O, IEngineTransactionInput, IEngineTransactionOutput,
>,
+Drop<I>,
+Drop<O>,
Expand Down Expand Up @@ -650,7 +650,7 @@ pub impl EngineInternalImpl<

if witness_len == 1 {
TaprootContextImpl::verify_taproot_spend(
@self.witness_program, witness[0], self.transaction, self.tx_idx
ref self, @self.witness_program, witness[0], self.transaction, self.tx_idx,
)?;
self.taproot_context.must_succeed = true;
return Result::Ok(());
Expand Down
9 changes: 8 additions & 1 deletion packages/engine/src/errors.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ pub mod Error {
pub const UNSATISFIED_LOCKTIME: felt252 = 'Unsatisfied locktime';
pub const SCRIPT_STRICT_MULTISIG: felt252 = 'OP_CHECKMULTISIG invalid dummy';
pub const FINALIZED_TX_CLTV: felt252 = 'Finalized tx in OP_CLTV';
pub const INVALID_TX_VERSION: felt252 = 'Invalid transaction version';
pub const SCRIPT_INVALID: felt252 = 'Invalid script data';
pub const INVALID_COINBASE: felt252 = 'Invalid coinbase transaction';
pub const SIG_NULLFAIL: felt252 = 'Sig non-zero on failed checksig';
pub const MINIMAL_DATA: felt252 = 'Opcode represents non-minimal';
pub const MINIMAL_IF: felt252 = 'If conditional must be 0 or 1';
pub const DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM: felt252 = 'Upgradable witness program';
pub const INVALID_PUBKEY_UNCOMP_SIZE: felt252 = 'Bad pub key uncompressed size';
pub const WITNESS_PROGRAM_INVALID: felt252 = 'Invalid witness program';
pub const WITNESS_PROGRAM_MISMATCH: felt252 = 'Witness program mismatch';
pub const WITNESS_UNEXPECTED: felt252 = 'Unexpected witness data';
Expand All @@ -35,16 +37,21 @@ pub mod Error {
pub const CODESEPARATOR_NON_SEGWIT: felt252 = 'CODESEPARATOR in non-segwit';
pub const TAPROOT_MULTISIG: felt252 = 'Multisig in taproot script';
pub const TAPROOT_EMPTY_PUBKEY: felt252 = 'Empty pubkey in taproot script';
pub const TAPROOT_INVALID_PUBKEY_SIZE: felt252 = 'Bad pubkey size in tapscript';
pub const TAPROOT_INVALID_CONTROL_BLOCK: felt252 = 'Invalid control block';
pub const TAPROOT_INVALID_SIG: felt252 = 'Invalid signature in tap script';
pub const TAPROOT_PARITY_MISMATCH: felt252 = 'Parity mismatch in tap script';
pub const TAPROOT_INVALID_MERKLE_PROOF: felt252 = 'Invalid taproot merkle proof';
pub const SCHNORR_INVALID_SIG_SIZE: felt252 = 'Invalid schnorr sig size';
pub const SCHNORR_INVALID_SIG_R_FIELD: felt252 = 'Schnorr sig r >= field';
pub const SCHNORR_INVALID_MSG_SIZE: felt252 = 'Schnorr msg size != 32';
pub const DISCOURAGE_OP_SUCCESS: felt252 = 'OP_SUCCESS is discouraged';
pub const DISCOURAGE_UPGRADABLE_TAPROOT_VERSION: felt252 = 'Upgradable taproot version';
pub const DISCOURAGE_UPGRADABLE_PUBKEY_TYPE: felt252 = 'Upgradable pubkey type';
pub const TAPROOT_SIGOPS_EXCEEDED: felt252 = 'Taproot sigops exceeded';
pub const INVALID_P2MS: felt252 = 'Invalid P2MS transaction';
pub const SCRIPT_UNFINISHED: felt252 = 'Script unfinished';
pub const SCRIPT_ERR_SIG_DER: felt252 = 'Signature DER error';
pub const SECP256K1_INVALID_POINT: felt252 = 'Invalid secp256k1 point';
pub const PUBKEYTYPE: felt252 = 'Unsupported public key type';
pub const SIG_HIGH_S: felt252 = 'Sig not canonical high S value';
pub const SIG_HASHTYPE: felt252 = 'invalid hash type';
Expand Down
18 changes: 9 additions & 9 deletions packages/engine/src/hash_cache.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::transaction::{
EngineTransactionInputTrait, EngineTransactionOutputTrait, EngineTransactionTrait
EngineTransactionInputTrait, EngineTransactionOutputTrait, EngineTransactionTrait,
};
use shinigami_utils::bytecode::write_var_int;
use shinigami_utils::hash::double_sha256;
Expand All @@ -8,7 +8,7 @@ use shinigami_utils::hash::double_sha256;
pub struct SegwitSigHashMidstate {
pub hash_prevouts_v0: u256,
pub hash_sequence_v0: u256,
pub hash_outputs_v0: u256
pub hash_outputs_v0: u256,
}

pub trait SigHashMidstateTrait<
Expand All @@ -17,7 +17,7 @@ pub trait SigHashMidstateTrait<
T,
+EngineTransactionInputTrait<I>,
+EngineTransactionOutputTrait<O>,
+EngineTransactionTrait<T, I, O>
+EngineTransactionTrait<T, I, O>,
> {
fn new(transaction: @T) -> SegwitSigHashMidstate;
}
Expand All @@ -29,8 +29,8 @@ pub impl SigHashMidstateImpl<
impl IEngineTransactionInput: EngineTransactionInputTrait<I>,
impl IEngineTransactionOutput: EngineTransactionOutputTrait<O>,
impl IEngineTransaction: EngineTransactionTrait<
T, I, O, IEngineTransactionInput, IEngineTransactionOutput
>
T, I, O, IEngineTransactionInput, IEngineTransactionOutput,
>,
> of SigHashMidstateTrait<I, O, T> {
fn new(transaction: @T) -> SegwitSigHashMidstate {
let mut prevouts_v0_bytes: ByteArray = "";
Expand All @@ -55,7 +55,7 @@ pub impl SigHashMidstateImpl<
SegwitSigHashMidstate {
hash_prevouts_v0: double_sha256(@prevouts_v0_bytes),
hash_sequence_v0: double_sha256(@sequence_v0_bytes),
hash_outputs_v0: double_sha256(@outputs_v0_bytes)
hash_outputs_v0: double_sha256(@outputs_v0_bytes),
}
}
}
Expand All @@ -80,7 +80,7 @@ pub trait HashCacheTrait<
T,
+EngineTransactionInputTrait<I>,
+EngineTransactionOutputTrait<O>,
+EngineTransactionTrait<T, I, O>
+EngineTransactionTrait<T, I, O>,
> {
fn new(transaction: @T) -> HashCache<T>;

Expand All @@ -104,8 +104,8 @@ pub impl HashCacheImpl<
impl IEngineTransactionInput: EngineTransactionInputTrait<I>,
impl IEngineTransactionOutput: EngineTransactionOutputTrait<O>,
impl IEngineTransaction: EngineTransactionTrait<
T, I, O, IEngineTransactionInput, IEngineTransactionOutput
>
T, I, O, IEngineTransactionInput, IEngineTransactionOutput,
>,
> of HashCacheTrait<I, O, T> {
fn new(transaction: @T) -> HashCache<T> {
HashCache {}
Expand Down
Loading

0 comments on commit a47fbd1

Please sign in to comment.