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. $