Commit bf6c63c6 authored by Luc Libralesso's avatar Luc Libralesso
Browse files

correct compute_set_of_operators + test xorNode

parent ea126c55
source 'https://rubygems.org'
gem 'slop'
gem 'pry'
\ No newline at end of file
gem 'pry'
gem 'rgl'
\ No newline at end of file
......@@ -58,12 +58,12 @@ class CryptoOperator
end
def check_inputs(values)
protected def check_inputs(values)
raise "CryptoOperator.check_inputs: values do not match (#{@values.length} should be #{@inputs.length})" unless values.length == @inputs.length
# TODO(all) check domains
end
def check_outputs(values)
protected def check_outputs(values)
raise "CryptoOperator.check_outputs: values do not match (#{@values.length} should be #{@outputs.length})" unless values.length == @outputs.length
# TODO(all) check domains
end
......@@ -93,6 +93,33 @@ class CryptoDagNode
@operators = operators
end
##
# @param i [usize] input number (should be < than the input size)
# @return [Vec<Variable>] flattened input
def flatten_input(i)
res = []
@inputs[i].each_index do |*index|
res.push(@inputs[i][*index])
end
return res
end
##
# @param i [usize] output number (should be < than the output size)
# @return [Vec<Variable>] flattened output
def flatten_output(i)
res = []
@outputs[i].each_index do |*index|
res.push(@outputs[i][*index])
end
return res
end
# # takes as inputs set of values and computes the outputs
# def compute(values)
# end
# simulates an input. Useful to validate that a cryptosystem is valid
## TODO(all) call operators and check that every output is covered by exactly 1 operator
# @param inputs [CryptoDagState({Dtable<Variables>, Vec<Multimatrix(2d, CryptoAtom)>})]: inputs testing the cryptoNode
......@@ -104,18 +131,18 @@ class CryptoDagNode
# return Marshal.load( Marshal.dump(@computed) )
# end
def register_to_model(model)
raise "CryptoDagNode: model should be of class Model" unless model.kind_of?(Model)
# dtable = ouputs.map{|e| ...}.to_dtable()
# model.add_variables(dtable)
@outputs.each { |tvar|
tvar.declarationMode = :folded
model.add_variables(tvar)
}
# add constraints
model.add_comment("CRYPTONODE #{@name} CONSTRAINTS")
@operators.each { |op| op.register_to_model model }
end
# def register_to_model(model)
# raise "CryptoDagNode: model should be of class Model" unless model.kind_of?(Model)
# # dtable = ouputs.map{|e| ...}.to_dtable()
# # model.add_variables(dtable)
# @outputs.each { |tvar|
# tvar.declarationMode = :folded
# model.add_variables(tvar)
# }
# # add constraints
# model.add_comment("CRYPTONODE #{@name} CONSTRAINTS")
# @operators.each { |op| op.register_to_model model }
# end
end
# represents a CryptoDag. Useful to get the graphviz visualization, etc.
......@@ -146,37 +173,37 @@ class CryptoDag
# @param inputs Vec<Multimatrix(2d, u8)>
# @return Vec<Multimatrix(2d, u8)>
# todo enforce input order
def compute(inputs:)
# recursively compute all nodes
opened = []
inputs.length.times do |i|
@input_nodes[i].compute(inputs[i])
@successors[@input_nodes[i]].each do |n|
opened.push(n)
end
end
filter_nonavailable_nodes(opened)
until opened.empty?
current = opened.shift()
current.compute(@precedencies[current].map | p | p.computed)
@successors[current].each do |n|
current.push(n)
end
filter_nonavailable_nodes(opened)
end
# return result for output nodes
compute_outputs.map do |output_node|
output_node.computed
end
end
# def compute(inputs:)
# # recursively compute all nodes
# opened = []
# inputs.length.times do |i|
# @input_nodes[i].compute(inputs[i])
# @successors[@input_nodes[i]].each do |n|
# opened.push(n)
# end
# end
# filter_nonavailable_nodes(opened)
# until opened.empty?
# current = opened.shift()
# current.compute(@precedencies[current].map | p | p.computed)
# @successors[current].each do |n|
# current.push(n)
# end
# filter_nonavailable_nodes(opened)
# end
# # return result for output nodes
# compute_outputs.map do |output_node|
# output_node.computed
# end
# end
def filter_nonavailable_nodes(openlist)
openlist.filter { |n|
(@precedencies[n].filter { |p| !p.computed }).empty?
}
end
# def filter_nonavailable_nodes(openlist)
# openlist.filter { |n|
# (@precedencies[n].filter { |p| !p.computed }).empty?
# }
# end
def find_all_nodes()
return @precedencies.keys()
end
end
# def find_all_nodes()
# return @precedencies.keys()
# end
end
\ No newline at end of file
......@@ -29,9 +29,10 @@ class XorNode < CryptoDagNode
# define operators here
operators = []
inputs.first.each_index do |*index|
operators.push(XorOperator.new(
op = XorOperator.new(
*(inputs.map { |e| e[*index] }), output[*index]
))
)
operators.push(op)
end
super(inputs: inputs, outputs: [output], operators: operators, name: name)
end
......
require 'rgl/adjacency'
require 'rgl/dot'
require 'rgl/topsort'
require_relative "./cryptodag.rb"
##
# Computes the values obtained by computing
# @param input_values [Vec<u8>] set of values for each variable
# @param input_variables [Vec<Variable>] set of input variables values
# @param output_variables [Vec<Variable>] set of output variables
# @param operators [Vec<Operators>] set of operators
def compute_set_of_operators(input_values, input_variables, output_variables, operators)
raise "compute_set_of_operators: inconsistent input_variables (#{input_values.length} should be of size #{input_variables.length})" unless input_values.length == input_variables.length
if operators.length == 0
return input_values
end
# executes a topological sort to find the order to execute operators
adj_list = []
operators.each do |e|
e.inputs.each do |a|
adj_list.push(a) # input comes before the operator
adj_list.push(e)
end
e.outputs.each do |a|
adj_list.push(e)
adj_list.push(a) # output comes after the operator
end
end
dg = RGL::DirectedAdjacencyGraph[*adj_list]
sorted_vertices = dg.topsort_iterator.to_a
sorted_vertices = sorted_vertices.filter{|v| v.class <= CryptoOperator}
# feed a variable map with initial values
value_map = {} # associates variables to their value
input_values.length.times do |i|
value_map[input_variables[i]] = input_values[i]
end
# execute operators
sorted_vertices.each do |op|
raise "compute_set_of_operators: should be a CryptoOperator (current #{op.class})" unless op.class <= CryptoOperator
values = []
op.inputs.each do |e|
if value_map.include?(e)
values.push(value_map[e])
else
raise "compute_set_of_operators: bad topological sort"
end
end
outputs = op.compute(values)
outputs.length.times do |i|
if !value_map.include?(op.outputs[i])
value_map[op.outputs[i]] = outputs[i]
end
end
end
# return operators values
return output_variables.map {|v| value_map[v]}
end
#!/usr/bin/ruby
## test InputNode
require_relative "../../nodes/input.rb"
require_relative "../../simulate_cryptodag.rb"
require "minitest/autorun"
require "pry"
class TestExecInputNode < Minitest::Unit::TestCase
def test_22input()
node = InputNode.new(name:"input1",dimensions:[2,2])
computed_outputs = compute_set_of_operators(
[1,2,3,4],
[node.outputs[0][0][0],node.outputs[0][0][1],node.outputs[0][1][0],node.outputs[0][1][1]],
[node.outputs[0][0][0],node.outputs[0][0][1],node.outputs[0][1][0],node.outputs[0][1][1]],
node.operators
)
assert_equal(computed_outputs, [1,2,3,4])
end
end
\ No newline at end of file
#!/usr/bin/ruby
## test XorNode
require_relative "../../nodes/input.rb"
require_relative "../../nodes/xor.rb"
require_relative "../../simulate_cryptodag.rb"
require "minitest/autorun"
require "pry"
class TestExecXorNode < Minitest::Unit::TestCase
def test_simple22xor()
a_node = InputNode.new(name:"input_a",dimensions:[2,2])
b_node = InputNode.new(name:"input_b",dimensions:[2,2])
xor_node = XorNode.new(name:"xor", inputs:[a_node.outputs[0], b_node.outputs[0]])
assert_equal(xor_node.operators.length, 4)
assert_equal(xor_node.outputs.length, 1)
assert_equal(xor_node.flatten_input(0).length, 4)
assert_equal(xor_node.flatten_output(0).length, 4)
computed_outputs = compute_set_of_operators(
[1,2,3,4]+[0,1,3,4], # input values
a_node.flatten_output(0)+b_node.flatten_output(0), # input variables
xor_node.flatten_output(0), # output variables
xor_node.operators
)
assert_equal(computed_outputs, [1,3,0,0])
end
def test_simple22xor()
a_node = InputNode.new(name:"input_a",dimensions:[2,2])
b_node = InputNode.new(name:"input_b",dimensions:[2,2])
c_node = XorNode.new(name:"xor_c", inputs:[a_node.outputs[0], b_node.outputs[0]])
d_node = InputNode.new(name:"input_d", dimensions:[2,2])
e_node = XorNode.new(name:"xor_e", inputs:[c_node.outputs[0], d_node.outputs[0]])
computed_outputs = compute_set_of_operators(
[1,2,3,4]+[0,1,3,4]+[0,2,1,1], # input values
a_node.flatten_output(0)+b_node.flatten_output(0)+d_node.flatten_output(0), # input variables
e_node.flatten_output(0), # output variables
e_node.operators+c_node.operators
)
assert_equal(computed_outputs, [1,1,1,1])
end
end
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment