Skip to content

Commit

Permalink
Update Gateways
Browse files Browse the repository at this point in the history
  • Loading branch information
SecretSaturn committed Jan 12, 2024
1 parent 557d9aa commit e897e38
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 113 deletions.
27 changes: 12 additions & 15 deletions TNLS-Gateways/public-gateway/src/Gateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,12 @@ contract Gateway is Initializable {

struct PostExecutionInfo {
bytes32 payload_hash;
bytes32 result_hash;
bytes32 input_hash;
bytes32 packet_hash;
bytes20 callback_address;
bytes4 callback_selector;
bytes4 callback_gas_limit;
bytes packet_signature;
bytes result_signature;
bytes result;
}

Expand Down Expand Up @@ -79,8 +78,6 @@ contract Gateway is Initializable {
/// @notice thrown when the signature is invalid
error InvalidSignature();

/// @notice Thrown when the recovered ResultHash or ResultSignature is invalid
error InvalidResultSignature();

/// @notice thrown when the PacketSignature is invalid
error InvalidPacketSignature();
Expand Down Expand Up @@ -223,8 +220,6 @@ contract Gateway is Initializable {
ExecutionInfo info
);

event logCompletedTask(uint256 indexed task_id, bytes32 payload_hash, bytes32 result_hash);

/// @notice Emitted when we recieve callback for our result of the computation
event ComputedResult(uint256 taskId, bytes result);

Expand All @@ -249,7 +244,7 @@ contract Gateway is Initializable {
}

/*//////////////////////////////////////////////////////////////
Initialization
Maintainance Functions
//////////////////////////////////////////////////////////////*/

/// @notice Initialize the verification address
Expand All @@ -259,10 +254,6 @@ contract Gateway is Initializable {
masterVerificationAddress = _masterVerificationAddress;
}

/*//////////////////////////////////////////////////////////////
Update Routes
//////////////////////////////////////////////////////////////*/

/// @notice Updating the route
/// @param _route Route name
/// @param _verificationAddress Address corresponding to the route
Expand All @@ -279,6 +270,14 @@ contract Gateway is Initializable {
route[_route] = _verificationAddress;
}

/// @notice Increase the task_id to check for problems
/// @param _newTaskId Route name

function increaseTaskId(uint256 _newTaskId) external onlyOwner {
require (_newTaskId > taskId, "New task id must be higher than the old task_id");
taskId = _newTaskId;
}

/*//////////////////////////////////////////////////////////////
Pre Execution
//////////////////////////////////////////////////////////////*/
Expand Down Expand Up @@ -408,14 +407,14 @@ contract Gateway is Initializable {

address checkerAddress = route[_sourceNetwork];

// Concatenate data elements
// Concatenate packet data elements
bytes memory data = bytes.concat(
bytes(_sourceNetwork),
bytes(uint256toString(block.chainid)),
bytes32(_taskId),
_info.input_hash,
_info.payload_hash,
_info.result,
_info.result_hash,
_info.callback_address,
_info.callback_selector);

Expand All @@ -429,8 +428,6 @@ contract Gateway is Initializable {

task.completed = true;

emit logCompletedTask(_taskId, _info.payload_hash, _info.result_hash);

// Continue with the function execution
// Additional conversion for Secret VRF into uint256[] if callback_selector matches the fullfillRandomWords selector.

Expand Down
13 changes: 4 additions & 9 deletions TNLS-Gateways/public-gateway/test/Contract.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,7 @@ contract ContractTest is Test {
Gateway.PostExecutionInfo memory assembledInfo = Gateway.PostExecutionInfo({
payload_hash: payloadHash,
result: result,
result_hash: resultHash,
result_signature: getResultSignature(result, 2),
input_hash: resultHash,
packet_hash: resultHash,
packet_signature: getResultSignature(result, 2),
callback_address: bytes20(address(gateway)),
Expand Down Expand Up @@ -384,8 +383,7 @@ contract ContractTest is Test {
Gateway.PostExecutionInfo memory assembledInfo = Gateway.PostExecutionInfo({
payload_hash: payloadHash,
result: result,
result_hash: resultHash,
result_signature: getResultSignature(result, 6),
input_hash: resultHash,
packet_hash: resultHash,
packet_signature: getResultSignature(result, 6),
callback_address: bytes20(address(gateway)),
Expand Down Expand Up @@ -477,9 +475,7 @@ contract ContractTest is Test {

// result
bytes memory result = hex"7b226d795f76616c7565223a327d";
bytes32 resultHash = hex"faef40ffa988468a70a21929200a40f1c8ea9f56fcf79a206ef9713032c4e28b";
bytes memory resultSignature =
hex"faad4e82fe9a6a05ef2a4387fca5471fe3bc7b53e81a3c08d4a5514ac7c6fddf2a266cf1c638654c156612a1943dbaf278105f138c5be67ab1eca4253c57ca7f1b";
bytes32 inputHash = hex"faef40ffa988468a70a21929200a40f1c8ea9f56fcf79a206ef9713032c4e28b";

// packet
bytes32 packetHash = hex"923b23c023d0e5e66ac122d9804414f4f9cab06d7a6ce6c4b8c586a1fa57264c";
Expand All @@ -489,8 +485,7 @@ contract ContractTest is Test {
Gateway.PostExecutionInfo memory assembledInfo = Gateway.PostExecutionInfo({
payload_hash: payloadHash,
result: result,
result_hash: resultHash,
result_signature: resultSignature,
input_hash: inputHash,
packet_hash: packetHash,
packet_signature: packetSignature,
callback_address: callback_address,
Expand Down
Binary file modified TNLS-Gateways/secret/contract.wasm.gz
Binary file not shown.
106 changes: 28 additions & 78 deletions TNLS-Gateways/secret/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
ExecuteMsg, InputResponse, InstantiateMsg, PostExecutionMsg, PreExecutionMsg,
PublicKeyResponse, QueryMsg, ResponseStatus::Success, SecretMsg,
},
state::{KeyPair, State, TaskInfo, CONFIG, CREATOR, MY_ADDRESS, TASK_MAP},
state::{KeyPair, State, Task, TaskInfo, CONFIG, CREATOR, MY_ADDRESS, TASK_MAP},
PrivContractHandleMsg,
};

Expand All @@ -23,7 +23,7 @@ use sha3::{Digest, Keccak256};
/// pad handle responses and log attributes to blocks of 256 bytes to prevent leaking info based on
/// response size
pub const BLOCK_SIZE: usize = 256;
pub const CHAIN_ID: &str = "secret-4";
pub const CHAIN_ID: &str = "pulsar-3";

#[cfg(feature = "contract")]
////////////////////////////////////// Init ///////////////////////////////////////
Expand Down Expand Up @@ -187,8 +187,13 @@ fn pre_execution(deps: DepsMut, _env: Env, msg: PreExecutionMsg) -> StdResult<Re
return Err(StdError::generic_err("Hashed Payload does not match payload hash"));
}

let new_task = Task {
network: msg.source_network.clone(),
task_id: msg.task_id.clone()
}.clone();

// check if the task wasn't executed before already
let map_contains_task = TASK_MAP.contains(deps.storage, &msg.task_id);
let map_contains_task = TASK_MAP.contains(deps.storage, &new_task);

if map_contains_task {
return Err(StdError::generic_err("Task ID already exists, not executing again"));
Expand All @@ -197,12 +202,14 @@ fn pre_execution(deps: DepsMut, _env: Env, msg: PreExecutionMsg) -> StdResult<Re
let input_values = payload.data;

// combine input values and task ID to create verification hash
let input_hash = sha_256(&[input_values.as_bytes(), &msg.task_id.to_be_bytes()].concat());
let unsafe_payload_bytes = if unsafe_payload { [1u8] } else { [0u8] };
let input_hash = sha_256(&[input_values.as_bytes(), &new_task.task_id.to_be_bytes(),&unsafe_payload_bytes].concat());

// create a task information store
let task_info = TaskInfo {
let task_info = TaskInfo {
payload: msg.payload, // storing the payload
payload_hash: msg.payload_hash,
unsafe_payload: unsafe_payload,
input_hash, // storing the input_values hashed together with task ID
source_network: msg.source_network,
user_address: payload.user_address.clone(),
Expand All @@ -212,7 +219,7 @@ fn pre_execution(deps: DepsMut, _env: Env, msg: PreExecutionMsg) -> StdResult<Re
};

// map task ID to task info
TASK_MAP.insert(deps.storage, &msg.task_id, &task_info)?;
TASK_MAP.insert(deps.storage, &new_task, &task_info)?;

// load this gateway's signing key
let mut signing_key_bytes = [0u8; 32];
Expand All @@ -239,7 +246,7 @@ fn pre_execution(deps: DepsMut, _env: Env, msg: PreExecutionMsg) -> StdResult<Re
input_values,
handle: msg.handle,
user_address: payload.user_address,
task_id: msg.task_id,
task: new_task.clone(),
input_hash: Binary(input_hash.to_vec()),
signature: Binary(signature),
},
Expand All @@ -252,15 +259,15 @@ fn pre_execution(deps: DepsMut, _env: Env, msg: PreExecutionMsg) -> StdResult<Re

Ok(Response::new()
.add_message(cosmos_msg)
.add_attribute_plaintext("task_id", msg.task_id.to_string())
.add_attribute_plaintext("task_id", &new_task.task_id.to_string())
.add_attribute_plaintext("status", "sent to private contract")
.set_data(to_binary(&InputResponse { status: Success })?))
}

fn post_execution(deps: DepsMut, _env: Env, msg: PostExecutionMsg) -> StdResult<Response> {
// load task info and remove task ID from map
let task_info = TASK_MAP
.get(deps.storage, &msg.task_id)
.get(deps.storage, &msg.task)
.ok_or_else(|| StdError::generic_err("task id not found"))?;

// verify that input hash is correct one for Task ID
Expand All @@ -279,64 +286,30 @@ fn post_execution(deps: DepsMut, _env: Env, msg: PostExecutionMsg) -> StdResult<
// "hasher" is used to perform multiple Keccak256 hashes
let mut hasher = Keccak256::new();

//create message hash of (result + payload + inputs)
let data = [
result.as_slice(),
task_info.payload.as_slice(),
&task_info.input_hash,
]
.concat();
hasher.update(&data);
let result_hash = hasher.finalize_reset();

// load this gateway's signing key
let private_key = CONFIG.load(deps.storage)?.signing_keys.sk;
let mut signing_key_bytes = [0u8; 32];
signing_key_bytes.copy_from_slice(private_key.as_slice());

// used in production to create signatures
// NOTE: api.secp256k1_sign() will perform an additional sha_256 hash operation on the given data
#[cfg(target_arch = "wasm32")]
let result_signature = deps.api.secp256k1_sign(&result_hash, &signing_key_bytes)
.map_err(|err| StdError::generic_err(err.to_string()))?;

// used only in unit testing to create signatures
#[cfg(not(target_arch = "wasm32"))]
let result_signature = {
let secp = secp256k1::Secp256k1::signing_only();
let sk = secp256k1::SecretKey::from_slice(&signing_key_bytes).unwrap();

let result_message = secp256k1::Message::from_slice(&result_hash)
.map_err(|err| StdError::generic_err(err.to_string()))?;
let result_signature = secp
.sign_ecdsa_recoverable(&result_message, &sk)
.serialize_compact();

result_signature.1
};


let mut task_id_padded = [0u8; 32]; // Create a 32-byte array filled with zeros
// Convert the task_id to an 8-byte big-endian array & Copy the 8-byte big-endian representation to the end of the result array
task_id_padded[32 - msg.task_id.to_be_bytes().len()..].copy_from_slice(msg.task_id.to_be_bytes().as_slice());
task_id_padded[32 - msg.task.task_id.to_be_bytes().len()..].copy_from_slice(msg.task.task_id.to_be_bytes().as_slice());

// create hash of entire packet (used to verify the message wasn't modified in transit)
let data = [
CHAIN_ID.as_bytes(), // source network
routing_info.as_bytes(), // task_destination_network
task_id_padded.as_slice(), //msg.task_id.to_be_bytes().as_slice(), // task ID
// task_info.payload.as_slice(), // payload (original encrypted or unencrypted payload)
task_info.input_hash.as_slice(),
task_info.payload_hash.as_slice(), // original payload message
result.as_slice(), // result
sha_256(&result_hash).as_slice(), // result message
//result_signature.as_slice(), // result signature
task_info.callback_address.as_slice(), // callback address
task_info.callback_selector.as_slice(), // callback selector
]
.concat();
hasher.update(&data);
let packet_hash = hasher.finalize();

// load this gateway's signing key
let private_key = CONFIG.load(deps.storage)?.signing_keys.sk;
let mut signing_key_bytes = [0u8; 32];
signing_key_bytes.copy_from_slice(private_key.as_slice());

// used in production to create signature
// NOTE: api.secp256k1_sign() will perform an additional sha_256 hash operation on the given data
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -374,21 +347,6 @@ fn post_execution(deps: DepsMut, _env: Env, msg: PostExecutionMsg) -> StdResult<
// Compress the public key
let compressed_public_key = uncompressed_public_key.serialize_compressed();

// Recover and compare public keys for result, do v = 0 (= 27 in ethereum) and v = 1 (= 28 in ethereum)
let result_public_key_27 = {deps.api.secp256k1_recover_pubkey(&sha_256(&result_hash), &result_signature, 0)
.map_err(|err| StdError::generic_err(err.to_string()))?};
let result_public_key_28 = {deps.api.secp256k1_recover_pubkey(&sha_256(&result_hash), &result_signature, 1)
.map_err(|err| StdError::generic_err(err.to_string()))?};

let result_recovery_id = if result_public_key_27 == compressed_public_key {
27
} else if result_public_key_28 == compressed_public_key {
28
}
else {
return Err(StdError::generic_err("Generation of Recovery ID for Result Signature failed"));
};

// Recover and compare public keys for packet, do v = 0 (= 27 in ethereum) and v = 1 (= 28 in ethereum)
let packet_public_key_27 = {deps.api.secp256k1_recover_pubkey(&sha_256(&packet_hash), &packet_signature, 0)
.map_err(|err| StdError::generic_err(err.to_string()))?};
Expand All @@ -404,13 +362,9 @@ fn post_execution(deps: DepsMut, _env: Env, msg: PostExecutionMsg) -> StdResult<
return Err(StdError::generic_err("Generation of Recovery ID for Packet Signature failed"));
};

let payload_hash = format!(
"0x{}",
task_info.payload_hash.as_slice().encode_hex::<String>()
);
let payload_hash = format!("0x{}",task_info.payload_hash.as_slice().encode_hex::<String>());
let input_hash = format!("0x{}", task_info.input_hash.as_slice().encode_hex::<String>());
let result = format!("0x{}", result.as_slice().encode_hex::<String>());
let result_hash = format!("0x{}", sha_256(&result_hash).encode_hex::<String>());
let result_signature = format!("0x{}{:x}", &result_signature.encode_hex::<String>(),result_recovery_id);
let packet_hash = format!("0x{}", sha_256(&packet_hash).encode_hex::<String>());
let packet_signature = format!("0x{}{:x}", &packet_signature.encode_hex::<String>(),packet_recovery_id);
let callback_address = format!("0x{}", task_info.callback_address.as_slice().encode_hex::<String>());
Expand All @@ -420,11 +374,10 @@ fn post_execution(deps: DepsMut, _env: Env, msg: PostExecutionMsg) -> StdResult<
Ok(Response::new()
.add_attribute_plaintext("source_network", CHAIN_ID)
.add_attribute_plaintext("task_destination_network", routing_info)
.add_attribute_plaintext("task_id", msg.task_id.to_string())
.add_attribute_plaintext("task_id", msg.task.task_id.to_string())
.add_attribute_plaintext("payload_hash", payload_hash)
.add_attribute_plaintext("input_hash", input_hash)
.add_attribute_plaintext("result", result)
.add_attribute_plaintext("result_hash", result_hash)
.add_attribute_plaintext("result_signature", result_signature)
.add_attribute_plaintext("packet_hash", packet_hash)
.add_attribute_plaintext("packet_signature", packet_signature)
.add_attribute_plaintext("callback_address", callback_address)
Expand Down Expand Up @@ -453,10 +406,7 @@ fn query_public_keys(deps: Deps) -> StdResult<Binary> {
let state: State = CONFIG.load(deps.storage)?;
to_binary(&PublicKeyResponse {
encryption_key: state.encryption_keys.pk,
verification_key: format!(
"0x{}",
state.signing_keys.pk.as_slice().encode_hex::<String>()
),
verification_key: format!("0x{}",state.signing_keys.pk.as_slice().encode_hex::<String>()),
})
}

Expand Down
9 changes: 5 additions & 4 deletions TNLS-Gateways/secret/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize};
use chacha20poly1305::aead::{Aead, NewAead};
use chacha20poly1305::{ChaCha20Poly1305, Nonce};
use secp256k1::{ecdh::SharedSecret, PublicKey, SecretKey};
use crate::state::Task;

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InstantiateMsg {
Expand Down Expand Up @@ -131,8 +132,8 @@ pub struct PrivContractHandleMsg {
pub handle: String,
/// Public network user address.
pub user_address: Addr,
/// Task ID passed along for later verification.
pub task_id: u64,
/// Task passed along for later verification.
pub task: Task,
/// SHA256 hash of `input_values`.
pub input_hash: Binary,
/// Signature of `input_hash`, signed by the private gateway.
Expand All @@ -144,8 +145,8 @@ pub struct PrivContractHandleMsg {
pub struct PostExecutionMsg {
/// JSON string of results from the private contract.
pub result: String,
/// Task ID from private contract for verification.
pub task_id: u64,
/// Task from private contract for verification.
pub task: Task,
/// SHA256 of decrypted (inputs + task ID) for verification.
pub input_hash: Binary,
}
Expand Down
Loading

0 comments on commit e897e38

Please sign in to comment.