How to tell if a module has encrypted contents
From Verific Design Automation FAQ
C++:
#include <cstring> // for memset #include "veri_file.h" // Make verilog reader available #include "VeriModule.h" // Definition of a VeriModule and VeriPrimitive #include "VeriVisitor.h" // Visitor base class definition #include "Protect.h" // For Protect class definition #include "Set.h" // Make associated hash table class Set available #include "Message.h" // Make message handlers available using namespace Verific ; /* -------------------------------------------------------------------------- */ class ExampleVisitor : public VeriVisitor { public: ExampleVisitor(); virtual ~ExampleVisitor(); // API to get all the modules having some encrypted contents Set *GetEncryptedModules() { return _encrypted_mods ; } private: virtual void VERI_VISIT(VeriTreeNode, node); virtual void VERI_VISIT(VeriModule, node); // Prevent the compiler from implementing the following ExampleVisitor(ExampleVisitor &node); ExampleVisitor& operator=(const ExampleVisitor &rhs); private: VeriModule *_current_mod ; Set *_encrypted_mods ; } ; /* -------------------------------------------------------------------------- */ ExampleVisitor::ExampleVisitor() : _current_mod(0), _encrypted_mods(0) { _encrypted_mods = new Set() ; } ExampleVisitor::~ExampleVisitor() { _current_mod = 0 ; delete _encrypted_mods ; } void ExampleVisitor::VERI_VISIT(VeriTreeNode, node) { // Check the line file if this parse-tree node is encrypted linefile_type lf = node.Linefile() ; if (_current_mod && LineFile::IsProtectedLinefile(lf)) { // This part is encrypted, put the current module in the encrypted list _encrypted_mods->Insert(_current_mod) ; } // Call base class visitor VeriVisitor::VERI_VISIT_NODE(VeriTreeNode, node) ; } void ExampleVisitor::VERI_VISIT(VeriModule, node) { VeriModule *prev_mod = _current_mod ; // Set the current module _current_mod = &node ; // Call base class visitor VeriVisitor::VERI_VISIT_NODE(VeriModule, node) ; _current_mod = prev_mod ; } /* -------------------------------------------------------------------------- */ class VFC_DLL_PORT Cipher : public Protect { public: Cipher() : Protect(64) {} virtual ~Cipher() {} virtual unsigned decrypt(const char *in_buf, char *out_buf, unsigned in_size) { if (!in_buf || !out_buf) return 0 ; unsigned in_len = Strings::len(in_buf) ; if (in_len > in_size) return 0 ; std::memset(out_buf, 0, in_size) ; // set all bytes to '\0' unsigned i = 0 ; for (i = 0 ; i < in_len ; ++i) { out_buf[i] = in_buf[i] - 1 ; // decrement the ASCII value } return in_size ; } // If RTL uses `pragma protect style as per section 34 in the // IEEE 1800 (2009) LRM, decrypt routine should check for the // encryption directives and return a decrypted string virtual char *decrypt(void) { // _directive_map has the <directive, value> pair for // all the directives in the same order they appear in // protection envelop. Use FOREACH_MAP_ITEM to iterate // over them and do the needful. // // For our simple application, we have a single directive // and fixed simple encryption. Just fetch the encrypted // text by the directive name. const char *in_buf = GetDirectiveValue("data_block") ; if (!in_buf) return 0 ; unsigned in_len = Strings::len(in_buf) ; char *out_buf = Strings::allocate(in_len+1) ; std::memset(out_buf, 0, in_len+1) ; // set all bytes to '\0' unsigned i = 0 ; for (i = 0 ; i < in_len ; ++i) { out_buf[i] = in_buf[i] - 1 ; // decrement the ASCII value } return out_buf ; // The string will be free'd outside } } ; /* -------------------------------------------------------------------------- */ int main (int argc, char **argv) { const char *file_nm ; // Stores the file name // If no file name is supplied then take the default file name switch (argc) { case 1: // That is if the user does not specify any option file_nm = "test.v" ; // Sets the file name to the default name break ; case 2: file_nm = argv[1] ; // Sets file name to name supplied by the user break ; default: Message::Error(0, "Too many options.") ; return 1 ; } // Plug in the decryoption algorithm to understand the encrypted RTL Cipher cipher ; // For `pragma protect construct : IEEE 1800 (2009) section 34 // use the same protection class object as it understands both // styles using separate decrypt APIs veri_file::SetPragmaProtectObject(&cipher) ; // Now analyze the Verilog file (into the work library). In case of any error do not process further. if (!veri_file::Analyze(file_nm, veri_file::VERILOG_2K)) return 2 ; // Get the list of top modules Array *top_mod_array = veri_file::GetTopModules() ; if (!top_mod_array || !top_mod_array->Size()) { // If there is no top level module then issue error Message::Error(0,"Cannot find any top level module. Check for recursive instantiation") ; return 4 ; } // Use a visitor pattern to easily accumulate the modules that have encrypted contents. ExampleVisitor visitor ; unsigned i ; VeriModule *top_mod ; FOREACH_ARRAY_ITEM(top_mod_array, i, top_mod) { if (top_mod) top_mod->Accept(visitor) ; } // Print the names of the modules having some encrypted contents. Set *encrypted_mods = visitor.GetEncryptedModules() ; SetIter si ; VeriModule *encrypted_mod ; FOREACH_SET_ITEM(encrypted_mods, si, &encrypted_mod) { if (encrypted_mod) Message::Info(0, "Module '", encrypted_mod->Name(), "' has encrypted contents.") ; } delete top_mod_array ; top_mod_array = 0 ; // Cleanup, it is not required anymore return 0 ; }
test.v:
module top (input in, output out); `pragma protect begin_protected `pragma protect data_block !!!!bttjho!pvu!>!jo!< `pragma protect end_protected endmodule module bot(input in, output out) ; assign out = in ; endmodule module foo (); endmodule module another_top (input in, output out); `pragma protect begin_protected `pragma protect data_block !!!!bttjho!pvu!>!jo!< `pragma protect end_protected endmodule
Run:
$ test-linux -- Analyzing Verilog file 'test.v' (VERI-1482) INFO: Module 'top' has encrypted contents. INFO: Module 'another_top' has encrypted contents. $