diff --git a/etherlink/kernel_latest/kernel/src/block.rs b/etherlink/kernel_latest/kernel/src/block.rs index 16740584243177517b0068ee341e186638f8cc7e..4f0ed189cfadaea16a5060e16579cf25a1827ecc 100644 --- a/etherlink/kernel_latest/kernel/src/block.rs +++ b/etherlink/kernel_latest/kernel/src/block.rs @@ -587,8 +587,7 @@ mod tests { use super::*; use tezos_crypto_rs::hash::SecretKeyEd25519; use tezos_execution::account_storage::TezlinkAccount; - use tezos_tezlink::enc_wrappers::BlockHash; - use tezos_tezlink::operation::ManagerOperationContent; + use tezos_tezlink::operation::sign_operation; use tezos_tezlink::operation::Parameter; use crate::block_storage; @@ -617,8 +616,6 @@ mod tests { use evm_execution::precompiles::precompile_set; use primitive_types::{H160, U256}; use std::str::FromStr; - use tezos_crypto_rs::hash::UnknownSignature; - use tezos_data_encoding::enc::BinWriter; use tezos_data_encoding::types::Narith; use tezos_ethereum::block::BlockFees; use tezos_ethereum::transaction::{ @@ -687,27 +684,6 @@ mod tests { } } - fn sign_operation( - sk: &SecretKeyEd25519, - branch: &H256, - content: &ManagerOperationContent, - ) -> UnknownSignature { - // Watermark comes from `src/lib_crypto/signature_v2.ml` - // The watermark for a ManagerOperation is always `Generic_operation` - // encoded with `0x03` - let mut serialized_unsigned_operation = vec![3_u8]; - - let branch = branch.as_fixed_bytes(); - tezos_data_encoding::enc::put_bytes(branch, &mut serialized_unsigned_operation); - content - .bin_write(&mut serialized_unsigned_operation) - .unwrap(); - let signature = sk - .sign(serialized_unsigned_operation) - .expect("Signature should have succeeded"); - signature.into() - } - fn make_operation( fee: u64, counter: u64, @@ -716,7 +692,7 @@ mod tests { source: Bootstrap, content: OperationContent, ) -> Operation { - let branch = TezBlock::genesis_block_hash(); + let branch = TezBlock::genesis_block_hash().into(); let manager_op = ManagerOperation { source: source.pkh, fee: fee.into(), @@ -727,10 +703,10 @@ mod tests { } .into(); - let signature = sign_operation(&source.sk, &branch, &manager_op); + let signature = sign_operation(&source.sk, &branch, &manager_op).unwrap(); Operation { - branch: BlockHash::from(branch), + branch, content: manager_op, signature, } @@ -1096,8 +1072,8 @@ mod tests { let chain_config = dummy_tez_config(); let mut config = dummy_configuration(); - let boostrap = bootstrap1(); - let src = boostrap.pkh.clone(); + let bootstrap = bootstrap1(); + let src = bootstrap.pkh.clone(); let context = context::Context::from(&TEZLINK_SAFE_STORAGE_ROOT_PATH) .expect("Context creation should have succeeded"); @@ -1123,7 +1099,7 @@ mod tests { assert_eq!(Manager::NotRevealed(src), manager); // Reveal bootstrap 1 manager - let reveal = make_reveal_operation(0, 1, 0, 0, boostrap); + let reveal = make_reveal_operation(0, 1, 0, 0, bootstrap); store_blueprints::<_, MichelsonChainConfig>( &mut host, diff --git a/etherlink/kernel_latest/tezos/src/operation.rs b/etherlink/kernel_latest/tezos/src/operation.rs index 2cfedb72a3b3009656d304caabda2acbb3af0e8b..a0ac1dfa2b61397b43d47331b7cace2d3b28a079 100644 --- a/etherlink/kernel_latest/tezos/src/operation.rs +++ b/etherlink/kernel_latest/tezos/src/operation.rs @@ -11,13 +11,15 @@ use nom::Finish; use primitive_types::H256; use rlp::Decodable; use tezos_crypto_rs::blake2b::digest_256; -use tezos_crypto_rs::hash::{BlsSignature, UnknownSignature}; +use tezos_crypto_rs::hash::{BlsSignature, SecretKeyEd25519, UnknownSignature}; +use tezos_crypto_rs::PublicKeySignatureVerifier; use tezos_data_encoding::types::Narith; use tezos_data_encoding::{ enc::{BinError, BinWriter}, nom::{error::DecodeError, NomError, NomReader}, }; use tezos_smart_rollup::types::{Contract, PublicKey, PublicKeyHash}; +use thiserror::Error; #[derive(PartialEq, Debug, Clone, NomReader, BinWriter)] pub struct Parameter { @@ -207,6 +209,64 @@ impl From for ManagerOperation { } } +pub fn serialize_unsigned_operation( + branch: &BlockHash, + content: &ManagerOperationContent, +) -> Result, BinError> { + // Watermark comes from `src/lib_crypto/signature_v2.ml` + // The watermark for a ManagerOperation is always `Generic_operation` + // encoded with `0x03` + let watermark = 3_u8; + + let mut serialized_unsigned_operation = vec![watermark]; + + let branch: [u8; 32] = branch.0.to_fixed_bytes(); + tezos_data_encoding::enc::put_bytes(&branch, &mut serialized_unsigned_operation); + content.bin_write(&mut serialized_unsigned_operation)?; + + Ok(serialized_unsigned_operation) +} + +#[derive(Error, Debug)] +pub enum SignatureErrors { + #[error("Signing failed with encoding error {0}")] + BinError(#[from] BinError), + #[error("Signing failed with cryptographic error {0}")] + CryptoError(#[from] tezos_crypto_rs::CryptoError), +} + +pub fn sign_operation( + sk: &SecretKeyEd25519, + branch: &BlockHash, + content: &ManagerOperationContent, +) -> Result { + let serialized_unsigned_operation = serialize_unsigned_operation(branch, content)?; + + let signature = sk.sign(serialized_unsigned_operation)?; + + Ok(signature.into()) +} + +pub fn verify_signature( + pk: &PublicKey, + branch: &BlockHash, + operation: &ManagerOperationContent, + signature: UnknownSignature, +) -> Result { + let serialized_unsigned_operation = serialize_unsigned_operation(branch, operation)?; + + let signature = &signature.into(); + + // The verify_signature function never returns false. If the verification + // is incorrect the function will return an Error and it's up to us to + // transform that into a `false` boolean if we want. + let check = pk + .verify_signature(signature, &serialized_unsigned_operation) + .unwrap_or(false); + + Ok(check) +} + #[cfg(test)] fn make_dummy_operation( operation: OperationContent, diff --git a/etherlink/kernel_latest/tezos_execution/src/lib.rs b/etherlink/kernel_latest/tezos_execution/src/lib.rs index 63e8825bcf22611f5fd7bf14117bf431b826302f..3934eecc62cfafbc149f1869cac36bfa9f132048 100644 --- a/etherlink/kernel_latest/tezos_execution/src/lib.rs +++ b/etherlink/kernel_latest/tezos_execution/src/lib.rs @@ -453,18 +453,15 @@ pub fn apply_operation( #[cfg(test)] mod tests { use crate::{TezlinkImplicitAccount, TezlinkOriginatedAccount}; - use primitive_types::H256; - use tezos_crypto_rs::hash::{ContractKt1Hash, SecretKeyEd25519, UnknownSignature}; - use tezos_data_encoding::enc::BinWriter; + use tezos_crypto_rs::hash::{ContractKt1Hash, SecretKeyEd25519}; use tezos_data_encoding::types::Narith; use tezos_evm_runtime::runtime::{MockKernelHost, Runtime}; use tezos_smart_rollup::types::{Contract, PublicKey, PublicKeyHash}; use tezos_tezlink::{ block::TezBlock, - enc_wrappers::BlockHash, operation::{ - ManagerOperation, ManagerOperationContent, Operation, OperationContent, - Parameter, RevealContent, TransferContent, + sign_operation, ManagerOperation, Operation, OperationContent, Parameter, + RevealContent, TransferContent, }, operation_result::{ Balance, BalanceTooLow, BalanceUpdate, ContentResult, CounterError, @@ -515,27 +512,6 @@ mod tests { } } - fn sign_operation( - sk: &SecretKeyEd25519, - branch: &H256, - content: &ManagerOperationContent, - ) -> UnknownSignature { - // Watermark comes from `src/lib_crypto/signature_v2.ml` - // The watermark for a ManagerOperation is always `Generic_operation` - // encoded with `0x03` - let mut serialized_unsigned_operation = vec![3_u8]; - - let branch = branch.as_fixed_bytes(); - tezos_data_encoding::enc::put_bytes(branch, &mut serialized_unsigned_operation); - content - .bin_write(&mut serialized_unsigned_operation) - .unwrap(); - let signature = sk - .sign(serialized_unsigned_operation) - .expect("Signature should have succeeded"); - signature.into() - } - const CONTRACT_1: &str = "KT1EFxv88KpjxzGNu1ozh9Vta4BaV3psNknp"; static SCRIPT: &str = r#" @@ -555,7 +531,7 @@ mod tests { source: Bootstrap, content: OperationContent, ) -> Operation { - let branch = TezBlock::genesis_block_hash(); + let branch = TezBlock::genesis_block_hash().into(); let manager_op = ManagerOperation { source: source.pkh, fee: fee.into(), @@ -566,10 +542,10 @@ mod tests { } .into(); - let signature = sign_operation(&source.sk, &branch, &manager_op); + let signature = sign_operation(&source.sk, &branch, &manager_op).unwrap(); Operation { - branch: BlockHash::from(branch), + branch, content: manager_op, signature, } diff --git a/etherlink/kernel_latest/tezos_execution/src/validate.rs b/etherlink/kernel_latest/tezos_execution/src/validate.rs index 681cd2f54eee3a3fbaa07064635e3cbe249a9b3a..6681cc00585f4de2826078eb39c016cf5e2289d0 100644 --- a/etherlink/kernel_latest/tezos_execution/src/validate.rs +++ b/etherlink/kernel_latest/tezos_execution/src/validate.rs @@ -2,16 +2,14 @@ // // SPDX-License-Identifier: MIT -use tezos_crypto_rs::{hash::UnknownSignature, PublicKeySignatureVerifier}; -use tezos_data_encoding::enc::BinWriter; -use tezos_data_encoding::{enc::BinError, types::Narith}; +use tezos_crypto_rs::hash::UnknownSignature; +use tezos_data_encoding::types::Narith; use tezos_evm_logging::log; use tezos_evm_runtime::runtime::Runtime; use tezos_smart_rollup::types::PublicKey; use tezos_tezlink::enc_wrappers::BlockHash; -use tezos_tezlink::operation::ManagerOperationContent; use tezos_tezlink::{ - operation::{ManagerOperation, OperationContent, RevealContent}, + operation::{verify_signature, ManagerOperation, OperationContent, RevealContent}, operation_result::{CounterError, ValidityError}, }; @@ -93,35 +91,6 @@ fn get_revealed_key( } } -fn verify_signature( - pk: &PublicKey, - branch: &BlockHash, - operation: &ManagerOperationContent, - signature: UnknownSignature, -) -> Result { - // Watermark comes from `src/lib_crypto/signature_v2.ml` - // The watermark for a ManagerOperation is always `Generic_operation` - // encoded with `0x03` - let watermark = 3_u8; - - let mut serialized_unsigned_operation = vec![watermark]; - - let branch: [u8; 32] = branch.0.to_fixed_bytes(); - tezos_data_encoding::enc::put_bytes(&branch, &mut serialized_unsigned_operation); - operation.bin_write(&mut serialized_unsigned_operation)?; - - let signature = &signature.into(); - - // The verify_signature function never returns false. If the verification - // is incorrect the function will return an Error and it's up to us to - // transform that into a `false` boolean if we want. - let check = pk - .verify_signature(signature, &serialized_unsigned_operation) - .unwrap_or(false); - - Ok(check) -} - // Inspired from `check_gas_limit` in `src/proto_alpha/lib_protocol/gas_limit_repr.ml` fn check_gas_limit( hard_gas_limit_per_operation: &Narith,