DEV Community

Ahmed Castro
Ahmed Castro

Posted on

ZKML Prescripciones

Image description

Image description

1. Genera un modelo dummy

# Verifica si el notebook está en Colab try: # Instala ezkl y onnx si estás en Colab  import google.colab import subprocess import sys subprocess.check_call([sys.executable, "-m", "pip", "install", "ezkl"]) subprocess.check_call([sys.executable, "-m", "pip", "install", "onnx"]) except: pass # Si no, usa tu setup de ezkl local  # Importa las librería necesarias from torch import nn import torch import ezkl import os # Convert a 3-byte hex number to tensor def hex_to_byte_tensor(hex_value): # Ensure the hex value is 6 characters (3 bytes) by padding with zeros  hex_str = f"{hex_value:06x}" return torch.tensor([int(hex_str[i:i+2], 16) for i in range(0, 6, 2)], dtype=torch.uint8) # Example input value (can be changed as needed) input_value = 0x047732 # This will be converted to [04, 77, 32] input_tensor = hex_to_byte_tensor(input_value) print(f"Input Tensor: {input_tensor}") # Example input value (can be changed as needed) input_value = 0x010402 # This will be converted to [04, 77, 32] input_tensor = hex_to_byte_tensor(input_value) print(f"Input Tensor: {input_tensor}") # Define a model that outputs the same 3 bytes that it receives as input class ThreeByteModel(nn.Module): def __init__(self): super(ThreeByteModel, self).__init__() def forward(self, x): # x should be a tensor of shape (batch_size, 3)  return x # Instancia el modelo circuit = ThreeByteModel() # Example input for the model dummy_input = input_tensor.unsqueeze(0) # Add batch dimension  # Generate output output = circuit(dummy_input) print(f"Output (3 bytes): {output}") # Export the model in Onnx format torch.onnx.export( circuit, dummy_input, "three_byte_model.onnx", input_names=["input"], output_names=["output"], dynamic_axes={"input": {0: "batch_size"}, "output": {0: "batch_size"}} ) print("Model saved as 'three_byte_model.onnx'!") 
Enter fullscreen mode Exit fullscreen mode

2. Genera el contrato de Solidity

import asyncio from torch import nn import ezkl import os import json import torch # Import the hex_to_byte_tensor function and ThreeByteModel from generate_model.py def hex_to_byte_tensor(hex_value): hex_str = f"{hex_value:06x}" return torch.tensor([int(hex_str[i:i+2], 16) for i in range(0, 6, 2)], dtype=torch.uint8) class ThreeByteModel(nn.Module): def __init__(self): super(ThreeByteModel, self).__init__() def forward(self, x): return x async def generate_contract(): circuit = ThreeByteModel() model_path = 'three_byte_model.onnx' compiled_model_path = 'three_byte_model.compiled' pk_path = 'test.pk' vk_path = 'test.vk' settings_path = 'settings.json' witness_path = 'witness.json' data_path = 'input.json' # Create input data  input_value = 0x040102 x = hex_to_byte_tensor(input_value) x = x.unsqueeze(0) # Add batch dimension  # Export the model  torch.onnx.export( circuit, x, model_path, export_params=True, opset_version=10, do_constant_folding=True, input_names=['input'], output_names=['output'], dynamic_axes={'input': {0: 'batch_size'}, 'output': {0: 'batch_size'}} ) # Prepare input data for JSON  data_array = x.detach().numpy().reshape([-1]).tolist() data = dict(input_data=[data_array]) json.dump(data, open(data_path, 'w')) # Setup run arguments  py_run_args = ezkl.PyRunArgs() py_run_args.input_visibility = "public" py_run_args.output_visibility = "public" py_run_args.param_visibility = "fixed" # Generate settings  res = ezkl.gen_settings(model_path, settings_path, py_run_args=py_run_args) assert res == True # Calibrate settings  cal_path = "calibration.json" cal_data = dict(input_data=[x.detach().numpy().reshape([-1]).tolist()]) json.dump(cal_data, open(cal_path, 'w')) await ezkl.calibrate_settings(cal_path, model_path, settings_path, "resources") # Compile circuit  res = ezkl.compile_circuit(model_path, compiled_model_path, settings_path) assert res == True # Get SRS  await ezkl.get_srs(settings_path) # Generate witness  res = await ezkl.gen_witness(data_path, compiled_model_path, witness_path) assert os.path.isfile(witness_path) # Setup circuit  res = ezkl.setup(compiled_model_path, vk_path, pk_path) assert res == True # Generate proof  proof_path = 'test.pf' res = ezkl.prove(witness_path, compiled_model_path, pk_path, proof_path, "single") assert os.path.isfile(proof_path) # Verify proof  res = ezkl.verify(proof_path, settings_path, vk_path) assert res == True # Generate calldata  calldata = 'calldata.proof' res = ezkl.encode_evm_calldata(proof_path, calldata) calldata_hex = "0x" + ''.join(f"{byte:02x}" for byte in res) print("Calldata hex (EVM style):") print(calldata_hex) # Generate Solidity verifier  abi_path = 'test.abi' sol_code_path = 'test.sol' output_sol_path = 'verifier.sol' res = await ezkl.create_evm_verifier(vk_path, settings_path, sol_code_path, abi_path) assert res == True with open(sol_code_path, 'r') as source_file: with open(output_sol_path, 'w') as dest_file: dest_file.write(source_file.read()) print("Contract generated successfully!") return True async def main(): await generate_contract() if __name__ == "__main__": asyncio.run(main()) 
Enter fullscreen mode Exit fullscreen mode

3. Lanza el contrato de recetas médicas

// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; interface Halo2Verifier { function verifyProof(bytes calldata proof, uint256[] calldata instances) external view; } contract PrescriptionVerifier is ERC1155 { address public immutable HALO2_VERIFIER; constructor(address halo2Verifier) ERC1155("https://raw.githubusercontent.com/Turupawn/VoidRxMetadata/refs/heads/main/{id}.json") { HALO2_VERIFIER = halo2Verifier; } function extractThreeUintsFromProof(bytes memory proofCalldata) public pure returns (uint256 a, uint256 b, uint256 c) { uint256 len = proofCalldata.length; // Extract values from proof (0 if position out of bounds) a = (len >= 1) ? uint256(uint8(proofCalldata[len - 1])) : 0; b = (len >= 33) ? uint256(uint8(proofCalldata[len - 33])) : 0; c = (len >= 65) ? uint256(uint8(proofCalldata[len - 65])) : 0; } function processPrescription(bytes memory proofCalldata) public { // Verify proof first (bool success, bytes memory data) = HALO2_VERIFIER.call(proofCalldata); require(success && data.length == 32 && uint8(data[31]) == 1, "Invalid proof"); // Extract medication amounts from proof (uint256 medA, uint256 medB, uint256 medC) = extractThreeUintsFromProof(proofCalldata); // Mint corresponding tokens to sender if (medA > 0) _mint(msg.sender, 1, medA, ""); if (medB > 0) _mint(msg.sender, 2, medB, ""); if (medC > 0) _mint(msg.sender, 3, medC, ""); } } 
Enter fullscreen mode Exit fullscreen mode

Top comments (0)