def make_random_fam_3_gate(levels, gate_name, gate_factory): """Creates a random family 3 gate using gate_factory. A family 3 gate takes in two inputs, at least one of which is from the level directly above it. Args: levels: a list of lists of gates, one corresponding to each level already created in the circuit. gate_name: the name which the new gate will have. gate_factory: the method used to generate the new gate. """ W = len(levels[0]) assert(all(len(level) == W for level in levels)) # make sure that we have at least two possible inputs: assert(W * len(levels) > 1) # find the first input among the circuit objects in the ultimate level: input1_index = sr.randint(0, W - 1) input1 = levels[-1][input1_index] # find the second input among all available circuit objects: input2_index = sr.randint(0, (len(levels) * W) - 1) while input2_index == input1_index: input2_index = sr.randint(0, (len(levels) * W) - 1) input2_inp_index = input2_index % W input2_level_index = len(levels) - ((input2_index - input2_inp_index) / W) - 1 input2_inp_index = input2_index % W input2 = levels[input2_level_index][input2_inp_index] # create the gate: inputs = [input1, input2] negations = [int(sr.getrandbits(1)) for neg_ind in xrange(2)] return gate_factory(gate_name, inputs, negations)
def make_random_gate(ultimate_level, fanin_frac, gate_name, gate_factory): """Creates a random family 1 or 2 gate using gate_factory. Args: ultimate_level: a list of gates or wires at the level directly above the one to which the new gate will belong. fanin_frac: the fraction of the gates at the ultimate_level which will serve as input to the new gate. gate_name: the name which the new gate will have. gate_factory: the method used to generate the new gate. """ if fanin_frac == 1: fanin = len(ultimate_level) inputs = ultimate_level else: max_fanin = len(ultimate_level) # compute the standard deviation sigma as per the test plan appendix: sigma = min(max_fanin * (1 - fanin_frac), max_fanin * fanin_frac) / 3 # compute the fanin as a normal distribution with mean max_fanin times # fanin frac, and standard deviation above: fanin = max(2, min(int(round(sr.gauss(max_fanin * fanin_frac, sigma))), max_fanin)) # choose random inputs: inputs = sr.sample(ultimate_level, fanin) # choose the negations: negations = [int(sr.getrandbits(1)) for neg_ind in xrange(fanin)] return gate_factory(gate_name, inputs, negations)
def test_balancing_randomized(self): """ Test to determine that balancing forces the desired output. Tests many randomized cases. """ num_tests = 100 min_num_inputs = 2 max_num_inputs = 20 for test_num in xrange(num_tests): num_inputs = sr.randint(min_num_inputs, max_num_inputs) inputs = [sw.StealthInputWire("wire", bool(sr.getrandbits(1))) for input_num in xrange(num_inputs)] negations = [bool(sr.getrandbits(1)) for input_num in xrange(num_inputs)] gate = sgx.StealthXorGate("xor_gate", inputs, negations) desired_output = bool(sr.getrandbits(1)) gate.balance(desired_output) self.assertEqual(gate.evaluate(), desired_output)
def test_balancing_randomized(self): """ Test to determine that balancing forces the desired output. Tests many randomized cases. """ num_tests = 100 min_num_inputs = 2 max_num_inputs = 20 for test_num in xrange(num_tests): num_inputs = sr.randint(min_num_inputs, max_num_inputs) inputs = [sw.StealthInputWire("wire", bool(sr.getrandbits(1))) for input_num in xrange(num_inputs)] negations = [bool(sr.getrandbits(1)) for input_num in xrange(num_inputs)] gate = sga.StealthAndGate("and_gate", inputs, negations) desired_output = bool(sr.getrandbits(1)) gate.balance(desired_output) self.assertEqual(gate.evaluate(), desired_output)
def make_random_one_inp_and_const_inp_gate(L, ultimate_level, penultimate_level, gate_name, circuit, gate_factory): """creates a random gate with one input and a constant that is an input batch.""" # This gate requires one input; at least one input should be available. assert(len(ultimate_level) + len(penultimate_level) > 0) input1_index = sr.randint(0, len(ultimate_level) - 1) input1 = ultimate_level[input1_index] const = ci.Input([ib.IBMBatch([int(sr.getrandbits(1)) for inp_ind in xrange(L)])]) return gate_factory(gate_name, input1, const, circuit)
def generate(self): """Populates the circuit, input and output files with a circuit, an input, and the corresponding output with the appropriate parameters.""" # create the header and write it to the circuit file: header_string = self._create_circuit_header() # create the input wires and write the inputs to the input file: input_wires = self._create_input_wires() # set set of all circuit objects already created: levels = [input_wires] # initialize the global gate counter, which acts as the unique numerical # id of each gate: unique_gate_num_gen = itertools.count() # for each level: for level_index in xrange(self._D): # Create the list of gates at this level: this_level = [None] * self._W for gate_ind in xrange(self._W): displayname = "".join(["G",str(unique_gate_num_gen.next())]) # make the new gate: new_gate = self._gate_maker(levels, displayname) new_gate_output = int(sr.getrandbits(1)) new_gate.balance(new_gate_output) # add this gate to our list of gates at this level: this_level[gate_ind] = new_gate # set things up for the next level: ultimate_level = this_level levels.append(this_level) output_gate = sr.choice(levels[-1]) output_gate.set_name("output_gate") # choose a random output, and write it to the output file: output = int(sr.getrandbits(1)) self._output_file.write(str(output)) # balance the output gate with respect to the chosen output: output_gate.balance(output) circ = sc.StealthCircuit(input_wires, output_gate) # write the circuit to the circuit file: self._circuit_file.write(circ.display())
def make_random_two_inp_and_const_inp_gate(L, ultimate_level, penultimate_level, gate_name, circuit, gate_factory): """creats a random gate with two inputs and a constant that is an input batch.""" # This gate requires two inputs; at least two inputs should be available. assert(len(ultimate_level) + len(penultimate_level) > 1) input1_index = sr.randint(0, len(ultimate_level) - 1) input1 = ultimate_level[input1_index] input2_index = sr.randint(0, len(ultimate_level) + len(penultimate_level) - 1) while input2_index == input1_index: input2_index = sr.randint(0, len(ultimate_level) + len(penultimate_level) - 1) if input2_index < len(ultimate_level): input2 = ultimate_level[input2_index] else: input2 = penultimate_level[input2_index - len(ultimate_level)] const = ci.Input([ib.IBMBatch([int(sr.getrandbits(1)) for inp_ind in xrange(L)])]) return gate_factory(gate_name, input1, input2, const, circuit)
def make_random_input(L, W): """Creates a random input with W batches, each with L bits.""" return ci.Input([ib.IBMBatch([int(sr.getrandbits(1)) for inp_num in xrange(L)]) for batch_num in xrange(W)])
def _randomize_negations(self): """Replaces the existing negations with new randomly chosen ones. Recomputes the stored value, since the negations were changed.""" self.__negations = [bool(sr.getrandbits(1)) for bal_ind in xrange(len(self.get_inputs()))] self.__value = None
def generate(self): """Populates the circuit, input and output files with a circuit, an input, and the corresponding output with the appropriate parameters.""" # create the header and write it to the circuit file: header_string = self._create_circuit_header() # create the input wires and write the inputs to the input file: input_wires = self._create_input_wires() # create the output and write it to the output file: output = self._create_output() # initialize the global gate counter, which acts as the unique numerical # id of each gate: unique_gate_num_gen = itertools.count(self._W, 1) # set the 'ultimate level' for the first level of gates: ultimate_level = input_wires # for each level: for level_ind in xrange(len(self._level_type_array)): if not self._trimming: # if this circuit is not being trimmed, then we have to write # 'L' to the circuit file, because we will not be creating a # circuit object to take care of our printing for us: self._circuit_file.write("\nL") # if this is an intermediate level: if self._level_type_array[level_ind] == LEVEL_TYPES.RANDOM: num_gates = self._G fanin_frac = self._fg make_gate = self._gate_maker # if this is an XOR level: elif self._level_type_array[level_ind] == LEVEL_TYPES.XOR: num_gates = self._X fanin_frac = self._fx make_gate = TYPE_TO_GATE_GEN[GATE_TYPES.XOR] # Create the list of gates at this level: this_level = [None] * num_gates for gate_ind in xrange(num_gates): displayname = "".join(["G", str(unique_gate_num_gen.next())]) # make the random gate: new_gate = make_gate(ultimate_level, fanin_frac, displayname) # choose a random output, and balance the new gate with respect # to that output: new_gate_output = int(sr.getrandbits(1)) new_gate.balance(new_gate_output) if not self._trimming: # if this circuit is not being trimmed, then we can just # write the gate to the circuit file right away: self._circuit_file.write( "".join(["\n", new_gate.get_full_display_string()])) # since this gate is already written to the circuit file, # we can save on memory space by re-representing it as an # input wire with the correct value: new_gate = sw.StealthInputWire(displayname, new_gate_output) # add this gate to our list of gates at this level: this_level[gate_ind] = new_gate # increment the global gate counter: # set things up for the next level: ultimate_level = this_level # create the output gate: negations = [int(sr.getrandbits(1)) for neg_ind in xrange(len(ultimate_level))] output_gate = self._gate_maker(ultimate_level, 1, "output_gate") # balance the output gate with respect to the chosen output: output_gate.balance(output) if self._trimming: # if this circuit is being trimmed, then we create a circuit and # write it to the circuit_file: circ = sc.StealthCircuit(input_wires, output_gate) self._circuit_file.write(circ.display()) else: # otherwise, we will have already written all the gates as we went # along, so we only need to record the output gate: self._circuit_file.write("".join(["\nL\n", output_gate.get_full_display_string()]))
def _create_output(self): """returns the output, and writes the output to the output file""" # choose a random output, and write it to the output file: output = int(sr.getrandbits(1)) self._output_file.write(str(output)) return output
def make_random_input(W): """Returns an array of W random bits.""" # TODO: this can probably be made to run faster by generating all W random # bits at once. return si.Input([int(sr.getrandbits(1)) for inp_num in xrange(W)])
def make_random_input_wire(displayname): """Makes a random input wire with the displayname. Its value is set to True with probability .5, and to False with probability .5.""" val = int(sr.getrandbits(1)) return sw.StealthInputWire(displayname, val)