Commit 13573f88 authored by Luc Libralesso's avatar Luc Libralesso
Browse files

add midori128.rb (need some debugs + tests) + add IndexedSubBytesNode

parent 7cae31bb
......@@ -59,10 +59,6 @@ class CryptoOperator
protected def check_inputs(values)
# puts "###"
# p @inputs
# p values
# puts "==="
raise "CryptoOperator.check_inputs: values do not match (#{@values.length} should be #{@inputs.length})" unless values.length == @inputs.length
# TODO(all) check domains
end
......@@ -118,96 +114,19 @@ class CryptoDagNode
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
# @return outputs [Vec<Multimatrix(2d, u8)>]: outputs obtained by the computation of the operators given the "input" parameter
# def compute(inputs:)
# return Marshal.load( Marshal.dump(@computed) ) if @computed
# # compute @computed here
# # @computed = # TODO
# 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
end
# represents a CryptoDag. Useful to get the graphviz visualization, etc.
# @param input_nodes [Vec<CryptoDagNode>]
# @param output_nodes [Vec<CryptoDagNode>]
# @param nodes [Vec<CryptoDagNode>] includes all nodes of the dag
#
class CryptoDag
def initialize()
@precedencies = {} # Map<K=CryptoDagNode, V=Vec<CryptoDagNode>>
@successors = Hash.new { [] } # Map<K=CryptoDagNode, V=Vec<CryptoDagNode>>
@input_nodes = []
end
def add_node(node, preds)
@precedencies[node] = preds.dup
@input_nodes.push(node) if preds.empty?
preds.each do |n|
@successors[n].push(node)
end
def initialize(input_nodes, output_nodes, nodes)
@input_nodes = input_nodes
@output_nodes = output_nodes
@nodes = nodes
end
def register_to_model(model)
# for each node: register its outputs and operators
end
def compute_outputs()
return @successors.keys.filter { |e| @successors[e].empty? }
end
##
# @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 filter_nonavailable_nodes(openlist)
# openlist.filter { |n|
# (@precedencies[n].filter { |p| !p.computed }).empty?
# }
# end
# def find_all_nodes()
# return @precedencies.keys()
# end
end
\ No newline at end of file
......@@ -4,52 +4,70 @@ require_relative './constants.rb'
require_relative '../../cryptodag.rb'
require_relative '../../cryptonodes/input.rb'
require_relative '../../cryptonodes/constant.rb'
require_relative '../../cryptonodes/output.rb'
require_relative '../../cryptonodes/keyseparation.rb'
require_relative '../../cryptonodes/xor.rb'
require_relative '../../cryptonodes/subcell.rb'
require_relative '../../cryptonodes/shufflecell.rb'
require_relative '../../cryptonodes/mixcolumn.rb'
require_relative '../../nodes/input.rb'
require_relative '../../nodes/indexedsubbytes.rb'
require_relative '../../nodes/shufflecell.rb'
require_relative '../../nodes/mixcolumn.rb'
require_relative '../../nodes/xor.rb'
# require_relative '../../cryptonodes/input.rb'
# require_relative '../../cryptonodes/constant.rb'
# require_relative '../../cryptonodes/output.rb'
# require_relative '../../cryptonodes/keyseparation.rb'
# require_relative '../../cryptonodes/xor.rb'
# require_relative '../../cryptonodes/subcell.rb'
# require_relative '../../cryptonodes/shufflecell.rb'
# require_relative '../../cryptonodes/mixcolumn.rb'
class Midori128_Dag < CryptoDag
def initialize(nb_rounds=20)
# define input nodes
nodes = []
@nb_rounds = nb_rounds
@x = InputNode.new(4,4, name="X")
@k = InputNode.new(4,4, name="K")
@x = InputNode.new(name:"X", dimensions:[4,4])
nodes.push(@x)
@k = InputNode.new(name:"K", dimensions:[4,4])
nodes.push(@k)
@csts = []
for i in 0..nb_rounds-2 do
cst = ConstantNode.new(4,4, name="Cst_%d"%[i])
cst = InputNode.new(name:"Cst_#{i}", dimensions:[4,4], values:cst_tabs(i))
nodes.push(cst)
@csts.append(cst)
end
#define internal nodes
addkey = XorNode.new([@x,@k], name="addKey")
addkey = XorNode.new(name:"addKey", inputs:[@x.outputs[0],@k.outputs[0]])
nodes.push(addkey)
for i in 0..nb_rounds-2 do
subcell = SubCellNode.new(addkey, method(:subcell_function), name="subCell_%d"%[i])
shufflecell = ShuffleCellNode.new(subcell, shufflecell_matrix, name="shuffleCell_%d"%[i])
mixcolumns = MixColumnNode.new(shufflecell, mixcolumns_matrix, name="mixColumns_%d"%[i])
rk = XorNode.new([@csts[i], @k], name="roundKey_%d"%[i])
addkey = XorNode.new([mixcolumns, rk], name="endRound_%d"%[i])
subbytes = IndexedSubBytesNode.new(name:"SB_#{i}", input:addkey.outputs[0], subtable_function: method(:subcell_function))
nodes.push(subbytes)
shufflecell = ShuffleCellNode.new(name:"SC_#{i}", input:subbytes.outputs[0], permutation:shufflecell_matrix)
nodes.push(shufflecell)
mixcolumns = MixColumnNode.new(name:"MC_#{i}", input:shufflecell.outputs[0], m:mixcolumns_matrix)
nodes.push(mixcolumns)
rk = XorNode.new(name:"RK_#{i}", inputs:[@csts[i].outputs[0], @k.outputs[0]])
nodes.push(rk)
addkey = XorNode.new(name:"End_#{i}", inputs:[mixcolumns.outputs[0],rk.outputs[0]])
nodes.push(addkey)
end
subcell = SubCellNode.new(addkey, method(:subcell_function), name="subCell_#{nb_rounds-1}")
out_xor = XorNode.new([subcell, @k], name="xor_end")
# define output
super(OutputNode.new(out_xor, "C"))
subcell = IndexedSubBytesNode.new(name:"SB_#{nb_rounds-1}", input:addkey.outputs[0], subtable_function: method(:subcell_function))
nodes.push(subcell)
out_xor = XorNode.new(name:"End", inputs:[subcell.outputs[0], @k.outputs[0]])
nodes.push(out_xor)
# define dag inputs/outputs
super([@x,@k], [out_xor], nodes)
end
def simulate_behavior(x,k)
# simulates constants
for i in 0..@nb_rounds-2 do
@csts[i].simulate_input(cst_tabs(i))
end
# simulates x,k input
@x.simulate_input(x)
@k.simulate_input(k)
# recursively computes c value and returns it
return @output.compute()
end
# def simulate_behavior(x,k)
# # simulates constants
# for i in 0..@nb_rounds-2 do
# @csts[i].simulate_input(cst_tabs(i))
# end
# # simulates x,k input
# @x.simulate_input(x)
# @k.simulate_input(k)
# # recursively computes c value and returns it
# return @output.compute()
# end
end
\ No newline at end of file
# IndexedSubBytes operator. Takes as a parameter a function that applies a substitution matrix depending on indices
require_relative "../cryptodag.rb"
require_relative "../operators/elementary.rb"
class IndexedSubBytesNode < CryptoDagNode
##
# @param name [String] name of the node
# @param input [DTable<Variable>] input variables
# @param subtable_function [(indices:Vec<usize>)->Vec<u8>] table that maps bytes to be substitued
def initialize(name:, input:, subtable_function:)
output = DTable.new("#{name}", input.type, input.dimensions)
operators = []
@subtable_function = subtable_function
input.each_index do |*index|
# raise "#{@subtable_function}"
s_table = @subtable_function.call(index)
operators.push(SOperator.new(
input[*index],
output[*index],
s_table
))
end
super(inputs: [input], outputs: [output], operators: operators, name: name)
end
end
......@@ -9,7 +9,7 @@ class InputNode < CryptoDagNode
# @param name [ String ] Name of the Table
# @param type [ Type ] : Type of the variables
# @param dimensions [ Array(int) ] : dimensions of the Matrix
# @param domain [ Array ] : values of the variable
# @param values [ Array ] : values of the variable
def initialize(name:, type: 0..255, dimensions:, values: nil)
# create output variables
output = DTable.new(name, type, dimensions, values)
......
# SubCell operator. Takes as a parameter a substitution matrix and applies it to the original matrix
# SubBytes node. Takes as a parameter a substitution matrix and applies it to the original matrix
require_relative "../cryptodag.rb"
require_relative "../operators/elementary.rb"
class SubBytesNode < CryptoDagNode
##
# @param name [String] name of the node
# @param input [DTable<Variable>] input variables
# @param subtable [Vec<u8>] table that maps bytes to be substitued
def initialize(name:, input:, subtable:)
output = DTable.new("#{name}", input.type, input.dimensions)
operators = []
......
## Tests cryptodag class features
\ No newline at end of file
#!/usr/bin/ruby
require 'minitest/autorun'
require_relative "../../cryptosystems/midori128/midori128.rb"
class TestMidori128 < Minitest::Unit::TestCase
def test_construction()
# create DAG
dag = Midori128_Dag.new(nb_rounds=3)
# # simulate behavior
# output = dag.simulate_behavior(
# [
# [0x51,0xe7,0xec,0xbc],
# [0x08,0x3a,0x87,0x29],
# [0x4c,0x5c,0xd7,0x75],
# [0xe6,0xa2,0xba,0x43]
# ],
# [
# [0x68,0x3c,0x5b,0x3e],
# [0x7d,0x85,0x10,0x2a],
# [0xed,0xb3,0x09,0x8c],
# [0x3b,0xf3,0x86,0xbf]
# ]
# )
# assert_equal(output, [
# [0x1e, 0xdf, 0x18, 0xe4],
# [0x0a, 0xf7, 0x01, 0xaf],
# [0xc4, 0x1b, 0xb7, 0xc8],
# [0xfd, 0x4c, 0x3e, 0x3d]
# ])
end
end
\ No newline at end of file
#!/usr/bin/ruby
require "minitest/autorun"
# require "minitest/color"
require "pry"
require_relative "../../cryptodag.rb"
require_relative "../../nodes/input.rb"
require_relative "../../nodes/shiftrows.rb"
require_relative "../../constraints/all.rb"
require_relative "../../constraints/model.rb"
require_relative "../../backends/minizinc.rb"
class TestNodeXor < Minitest::Unit::TestCase
def setup
@input_a = InputNode.new(name: "key", dimensions: [2, 2])
@model = Model.new()
@input_a.register_to_model(@model)
end
def test_inputs
sr_node = ShiftRowsNode.new(name: "SR", input: @input_a.outputs[0])
sr_node.register_to_model(@model)
puts Minizinc.new.generate_code(@model)
assert_equal(true, true)
end
end
\ No newline at end of file
#!/usr/bin/ruby
require "minitest/autorun"
# require "minitest/color"
require "pry"
require_relative "../../cryptodag.rb"
require_relative "../../nodes/input.rb"
require_relative "../../nodes/shufflecell.rb"
require_relative "../../constraints/all.rb"
require_relative "../../constraints/model.rb"
require_relative "../../backends/minizinc.rb"
class TestNodeXor < Minitest::Unit::TestCase
def setup
@input_a = InputNode.new(name: "key", dimensions: [2, 2])
@model = Model.new()
@input_a.register_to_model(@model)
end
def test_inputs
sc_node = ShuffleCellNode.new(name: "SC", input: @input_a.outputs[0], permutation: [1,2,3,0])
sc_node.register_to_model(@model)
puts Minizinc.new.generate_code(@model)
assert_equal(true, true)
end
end
\ No newline at end of file
#!/usr/bin/ruby
require "minitest/autorun"
# require "minitest/color"
require "pry"
require_relative "../../cryptodag.rb"
require_relative "../../nodes/input.rb"
require_relative "../../nodes/xor.rb"
require_relative "../../constraints/all.rb"
require_relative "../../constraints/model.rb"
require_relative "../../backends/minizinc.rb"
class TestNodeXor < Minitest::Unit::TestCase
def setup
@input_a = InputNode.new(name: "key", dimensions: [2, 2])
@input_b = InputNode.new(name: "X", dimensions: [2, 2])
@input_c = InputNode.new(name: "Bonus", dimensions: [2, 2])
@model = Model.new()
@input_a.register_to_model(@model)
@input_b.register_to_model(@model)
@input_c.register_to_model(@model)
end
def test_inputs
xor_node = XorNode.new(name: "ARK", inputs: [@input_a.outputs[0], @input_b.outputs[0]])
xor_node.register_to_model(@model)
# @model.variables.each { |e| p e }
# p @model.variables
puts Minizinc.new.generate_code(@model)
assert_equal(true, true)
end
def test_inputs_3
xor_node = XorNode.new(name: "ARK", inputs: [@input_a.outputs[0], @input_b.outputs[0], @input_c.outputs[0]])
xor_node.register_to_model(@model)
# @model.variables.each { |e| p e }
# p @model.variables
puts Minizinc.new.generate_code(@model)
assert_equal(true, true)
end
def test_inputs_complex
xor_node = XorNode.new(name: "ARK", inputs: [@input_a.outputs[0], @input_b.outputs[0]])
xor_node.register_to_model(@model)
arb = XorNode.new(name: "ARB", inputs: [xor_node.outputs[0], @input_c.outputs[0]])
arb.register_to_model(@model)
# @model.variables.each { |e| p e }
# p @model.variables
puts Minizinc.new.generate_code(@model)
assert_equal(true, true)
end
end
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