How to tell if a module has encrypted contents

From Verific Design Automation FAQ
Revision as of 18:42, 24 August 2022 by Hoa (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

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