Module logiclocking.metrics

Cacluate logic-locking metrics.

Expand source code
"""Cacluate logic-locking metrics."""
from random import random
from statistics import mean

import circuitgraph as cg


def corruptibility(cl, key):
    """Apprixmate corruptability of a locked circuit for a specific key."""
    # set up miter
    ins = set(cl.startpoints() - key.keys())
    m = cg.miter(cl, startpoints=ins)
    set_key = {f"c0_{k}": v for k, v in key.items()}
    independent_set = {f"c1_{k}" for k in key} | ins

    # run approx
    errors = cg.approx_model_count(m, {**set_key, "sat": True}, independent_set)

    return errors / 2 ** len(independent_set)


def key_corruption(cl, key, attack_key):
    """Approximate corruption between two keys."""
    # set up miter
    ins = set(cl.startpoints() - key.keys())
    m = cg.miter(cl, startpoints=ins)
    c0_key = {f"c0_{k}": v for k, v in key.items()}
    c1_key = {f"c1_{k}": v for k, v in attack_key.items()}

    # run approx
    errors = cg.approx_model_count(m, {**c0_key, **c1_key, "sat": True}, ins)

    return errors / 2 ** len(ins)


def min_corruption(cl, key, e=0.1, min_samples=10, tol=0.1):
    """Approximate the minimum corruption."""
    # find total errors
    cor = corruptibility(cl, key)

    # get initial key corruptions
    key_corruptions = []
    for i in range(min_samples):
        sampled_key = {k: random() < 0.5 for k in key}
        key_corruptions.append(key_corruption(cl, key, sampled_key))

    # sample until distribution matches
    while abs(mean(key_corruptions) - cor) > tol:
        sampled_key = {k: random() < 0.5 for k in key}
        key_corruptions.append(key_corruption(cl, key, sampled_key))

    return len([kc for kc in key_corruptions if kc >= e]) / len(key_corruptions)


def avg_avg_sensitivity(cl, key={}):
    """Get the average average sensitivity under a given key."""
    # set key
    cl_key = cl.copy()
    for k, v in key.items():
        cl_key.set_type(k, v)

    avg_sens = []
    for o in cl.outputs():
        # estimate sen
        avg_sens.append(cl.avg_sensitivity(o, e=3, d=0.8) / len(cl.startpoints(o)))

    return mean(avg_sens)

Functions

def avg_avg_sensitivity(cl, key={})

Get the average average sensitivity under a given key.

Expand source code
def avg_avg_sensitivity(cl, key={}):
    """Get the average average sensitivity under a given key."""
    # set key
    cl_key = cl.copy()
    for k, v in key.items():
        cl_key.set_type(k, v)

    avg_sens = []
    for o in cl.outputs():
        # estimate sen
        avg_sens.append(cl.avg_sensitivity(o, e=3, d=0.8) / len(cl.startpoints(o)))

    return mean(avg_sens)
def corruptibility(cl, key)

Apprixmate corruptability of a locked circuit for a specific key.

Expand source code
def corruptibility(cl, key):
    """Apprixmate corruptability of a locked circuit for a specific key."""
    # set up miter
    ins = set(cl.startpoints() - key.keys())
    m = cg.miter(cl, startpoints=ins)
    set_key = {f"c0_{k}": v for k, v in key.items()}
    independent_set = {f"c1_{k}" for k in key} | ins

    # run approx
    errors = cg.approx_model_count(m, {**set_key, "sat": True}, independent_set)

    return errors / 2 ** len(independent_set)
def key_corruption(cl, key, attack_key)

Approximate corruption between two keys.

Expand source code
def key_corruption(cl, key, attack_key):
    """Approximate corruption between two keys."""
    # set up miter
    ins = set(cl.startpoints() - key.keys())
    m = cg.miter(cl, startpoints=ins)
    c0_key = {f"c0_{k}": v for k, v in key.items()}
    c1_key = {f"c1_{k}": v for k, v in attack_key.items()}

    # run approx
    errors = cg.approx_model_count(m, {**c0_key, **c1_key, "sat": True}, ins)

    return errors / 2 ** len(ins)
def min_corruption(cl, key, e=0.1, min_samples=10, tol=0.1)

Approximate the minimum corruption.

Expand source code
def min_corruption(cl, key, e=0.1, min_samples=10, tol=0.1):
    """Approximate the minimum corruption."""
    # find total errors
    cor = corruptibility(cl, key)

    # get initial key corruptions
    key_corruptions = []
    for i in range(min_samples):
        sampled_key = {k: random() < 0.5 for k in key}
        key_corruptions.append(key_corruption(cl, key, sampled_key))

    # sample until distribution matches
    while abs(mean(key_corruptions) - cor) > tol:
        sampled_key = {k: random() < 0.5 for k in key}
        key_corruptions.append(key_corruption(cl, key, sampled_key))

    return len([kc for kc in key_corruptions if kc >= e]) / len(key_corruptions)
def random()

random() -> x in the interval [0, 1).