Commit 0cd65368 authored by Luc Libralesso's avatar Luc Libralesso
Browse files

add implementation mixcolumns operator

parent 2e0fae21
......@@ -37,28 +37,31 @@ require_relative "constraints/model"
class CryptoOperator
attr_accessor :inputs # vector of input variables
attr_accessor :outputs # vector of output variables
attr_accessor :constraint # constraint implementing the operator
attr_accessor :constraints # constraints implementing the operator
##
# @param inputs [Vec<Variable>]
# @param outputs [Vec<Variable>]
# @param constraint [Constraint]
protected def initialize(inputs:, outputs:, constraint:)
# @param constraints [Vec<Constraint>]
protected def initialize(inputs:, outputs:, constraints:)
inputs.each do |e|
raise "CryptoOperator: inputs should be of type <= Variable (current class: #{e.class})" unless e.class <= Variable
end
outputs.each do |e|
raise "CryptoOperator: outputs should be of type <= Variable (current class: #{e.class})" unless e.class <= Variable
end
raise "CryptoOperator: constraint should be of type Constraint" unless constraint.class < Constraint
constraints.each do |e|
raise "CryptoOperator: constraint should be of type Constraint" unless e.class < Constraint
end
@inputs = inputs
@outputs = outputs
@constraint = constraint
@constraints = constraints
end
def register_to_model(model)
raise "CryptoOperator: model should be of class Model" unless model.kind_of?(Model)
model.add_constraints(@constraint)
model.add_constraints(*@constraints)
end
end
......
......@@ -13,7 +13,7 @@ class EqualityOperator < CryptoOperator
super(
inputs: [input],
outputs: [output],
constraint: Equality.new(input, output),
constraints: [Equality.new(input, output)],
)
end
end
......@@ -27,10 +27,10 @@ class XorOperator < CryptoOperator
super(
inputs: inputs,
outputs: [output],
constraint: Equality.new(
constraints: [Equality.new(
Xor.new(*inputs),
output
),
)],
)
end
end
......@@ -45,32 +45,59 @@ class SOperator < CryptoOperator
super(
inputs: [input],
outputs: [output],
constraint: TableConstraint.new(
constraints: [TableConstraint.new(
[input, output],
s_array.length.times.map { |i| [i, s_array[i]] }
),
)],
)
end
end
## MixColumns operator
class MixColumnsOperator < CryptoOperator
##
# @params inputs [Vec<u8>] 4 byte input
# @params outputs [Vec<u8>] 4 byte output
# @params m [Vec<Vec<u8>>] mixcolumns matrix
def initialize(inputs, outputs, m)
raise "MixColumnsOperator: matrix dimensions should be of the same size of the input (current y size: #{m.length})" unless inputs.length == m.length
raise "MixColumnsOperator: matrix dimensions should be of the same size of the input (current x size: #{m.first.length})" unless inputs.length == m.first.length
raise "MixColumnsOperator: output dimensions should be of the same size of the input (current size: #{outputs.length})" unless inputs.length == outputs.length
@m = m
super(
inputs: inputs,
outputs: outputs,
constraint: Equality.new(
# TODO(all) add And or ForEach constraint to "mix" all inputs and outputs
)
)
super(inputs:inputs, outputs:outputs)
##
# @params inputs [Vec<variable>] 4 byte input
# @params outputs [Vec<variable>] 4 byte output
# @params m [Vec<u8>] mixcolumns matrix vector
def initialize(inputs, outputs, m)
raise "MixColumnsOperator: matrix dimensions should be of the same size of the input (current y size: #{m.length})" unless inputs.length == m.length
raise "MixColumnsOperator: matrix dimensions should be of the same size of the input (current x size: #{m..first.length})" unless inputs.length == m.first.length
raise "MixColumnsOperator: output dimensions should be of the same size of the input (current size: #{outputs.length})" unless inputs.length == outputs.length
@m = m
constraints = []
inputs.length.times do |i| # add a constraint per output
constraints.push(Equality.new(
Xor.new(*inputs.length.times.map{ |j|
galois_field_multiply(inputs[j], m[i][j])
}),
outputs[i]
))
end
super(
inputs: inputs,
outputs: outputs,
constraints: constraints,
)
end
##
# @param e [Expression] value to multiply by the matrix element
# @param m [u8] value used to multiply
# @return [Expression] that multiplies e by m in the galois field
def galois_field_multiply(e, m)
if m == 0
return 0
elsif m == 1
return e
elsif m == 2
return Modulo.new(Mult.new(e, 2), 256)
elsif m == 3
return Modulo.new(
Xor.new(Mult.new(e, 2), e),
256
)
else
raise "galois_field_multiply: m=#{m} not supported yet (for now, it should be <= 3)"
end
end
end
#!/usr/bin/ruby
require 'minitest/autorun'
require_relative '../cryptonodes/input.rb'
class TestInput < Minitest::Unit::TestCase
def test_size()
c = InputNode.new(3,4,"I")
assert_equal(c.x, 3)
assert_equal(c.y, 4)
end
def test_compute()
c = InputNode.new(3,1,"I")
c.simulate_input([
[0,1,2]
])
assert_equal(c.compute(), [[0,1,2]])
end
end
\ No newline at end of file
......@@ -13,21 +13,6 @@ require "minitest/autorun"
require "pry"
# class TestOpEq < Minitest::Unit::TestCase
# def test_eq()
# o = EqualityOperator.new(CryptoByte.new(), CryptoByte.new())
# assert_equal(o.compute_call([0]), [0])
# assert_equal(o.compute_call([1]), [1])
# end
# def test_xor()
# o = XorOperator.new(CryptoByte.new(), CryptoByte.new(), CryptoByte.new())
# assert_equal(o.compute_call([0,0]), [0])
# assert_equal(o.compute_call([0,1]), [1])
# assert_equal(o.compute_call([1,1]), [0])
# assert_equal(o.compute_call([1,3]), [2])
# end
# end
class TestOpEq < Minitest::Unit::TestCase
def setup
......
#!/usr/bin/ruby
require_relative "../../cryptodag.rb"
require_relative "../../operators/elementary.rb"
require_relative "../../constraints/all.rb"
require_relative "../../backends/minizinc.rb"
require "minitest/autorun"
require "pry"
class TestMixColumns < Minitest::Unit::TestCase
def test_aes()
inputs = [
Variable.new("in_a", 0..255),
Variable.new("in_b", 0..255),
Variable.new("in_c", 0..255),
Variable.new("in_d", 0..255)
]
outputs = [
Variable.new("out_a", 0..255),
Variable.new("out_b", 0..255),
Variable.new("out_c", 0..255),
Variable.new("out_d", 0..255)
]
model = Model.new()
model.add_variables(*inputs)
model.add_variables(*outputs)
op = MixColumnsOperator.new(inputs, outputs, [
[2,3,1,1],
[1,2,3,1],
[1,1,2,3],
[3,1,1,2]
])
op.register_to_model(model)
puts Minizinc.new.generate_code(model)
end
end
\ No newline at end of file
#!/usr/bin/ruby
require 'minitest/autorun'
require_relative '../cryptonodes/input.rb'
require_relative '../cryptonodes/xor.rb'
class TestXor < Minitest::Unit::TestCase
def test_computed_imuable()
# create DAG
a = InputNode.new(1,1,"A")
b = InputNode.new(1,1,"B")
x = XorNode.new([a,b],name="X")
# simulate inputs and check results
a.simulate_input([[0]])
b.simulate_input([[0]])
assert_equal(x.compute(), [[0]])
res = x.compute()
res[0][0] = 1
assert_equal(x.compute(), [[0]])
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