finitefield 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.txt +6 -1
- data/examples/exampleUtils.rb +16 -0
- data/examples/logTables.rb +88 -0
- data/examples/raid6.rb +82 -0
- data/lib/finitefield.rb +40 -11
- data/test/tc_basic.rb +2 -0
- data/test/tc_gf2.rb +2 -0
- data/test/ts_finitefield.rb +2 -0
- metadata +14 -9
data/README.txt
CHANGED
@@ -8,4 +8,9 @@ supported.
|
|
8
8
|
The initial release of this library is limited in scope to only supporting
|
9
9
|
fields of the form 2^n.
|
10
10
|
|
11
|
-
|
11
|
+
Examples illustrating how to use the field are given in the examples directory.
|
12
|
+
Currently the following examples are provided:
|
13
|
+
* logTables.rb:
|
14
|
+
- log and antilog table generation given a field polynomial and generator.
|
15
|
+
* raid6.rb:
|
16
|
+
- RAID6 Q block generation using finite fields.
|
@@ -0,0 +1,16 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
|
3
|
+
# = exampleUtils.rb - Utility methods used by the other examples.
|
4
|
+
#
|
5
|
+
# Copyright (C) 2008 Stephen Doyle
|
6
|
+
#
|
7
|
+
|
8
|
+
# Utility method to print a nicely formatted 16xn table of hex values
|
9
|
+
def printTable(table)
|
10
|
+
(0...table.length).each do |i|
|
11
|
+
printf("%02x ", table[i])
|
12
|
+
if i!=0 and i%16==15
|
13
|
+
puts ''
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
|
3
|
+
# = logTables.rb - Generate the anti-log and log tables for a finite field.
|
4
|
+
#
|
5
|
+
# Copyright (C) 2008 Stephen Doyle
|
6
|
+
#
|
7
|
+
# This example illustrates using the finitefield library to generate the
|
8
|
+
# anti-log and log tables for a finite field for a given field polynomial
|
9
|
+
# and generator.
|
10
|
+
#
|
11
|
+
# The anti-log table for a finite field is constructed using a generator
|
12
|
+
# whose successive powers g^n for the range n[0, 255] produce all the
|
13
|
+
# in the field without repeating any element.
|
14
|
+
#
|
15
|
+
# If the anti-log and log tables are available for a finite field,
|
16
|
+
# multiplication can be performed very quickly using these tables, e.g.
|
17
|
+
# mult(a, b) = anti_log( [log(a) + log(b)] % 0xFF )
|
18
|
+
# where + is normal addition, i.e. not addition within the finite field.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'finitefield'
|
22
|
+
require 'exampleUtils'
|
23
|
+
|
24
|
+
# Compute the inverse or anti log table for a given field polynomial and generator.
|
25
|
+
# Note that the last value of the ilogTable is invalid and present in this example
|
26
|
+
# as a placeholder to produce a nicely dimensioned array.
|
27
|
+
def getILogTable(poly, generator)
|
28
|
+
field = FiniteField.new(8, poly)
|
29
|
+
ilogTable = [1]
|
30
|
+
|
31
|
+
1.upto(0xFF) do |i|
|
32
|
+
ilogTable[i] = field.multiply(ilogTable[i-1], generator)
|
33
|
+
end
|
34
|
+
return ilogTable
|
35
|
+
end
|
36
|
+
|
37
|
+
# Compute the log log table for a given field polynomial and generator.
|
38
|
+
def getLogTable(poly, generator)
|
39
|
+
# The log table is most easily generated from the inverse log table.
|
40
|
+
# Note that the last element in the inverse log table is invalid and so
|
41
|
+
# should be discarded to avoid introducing errors into the log table
|
42
|
+
# generation.
|
43
|
+
ilogTable = getILogTable(poly, generator)[0...-1]
|
44
|
+
tmp = {}
|
45
|
+
ilogTable.each_with_index { |value, index| tmp[value] = index }
|
46
|
+
logTable = [0] + tmp.sort.collect { |x| x[1]}
|
47
|
+
return logTable
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
# Generate and print the anti-log and log tables for two well known fields ...
|
52
|
+
# ... the 0x11D field is the default polynomial used for the GF(2^8)
|
53
|
+
# computations used in RAID 6 for the generation of the Q parity block.
|
54
|
+
puts "Inverse log table for polynomial 0x11D: "
|
55
|
+
ilogTable = getILogTable(0x11D, 2)
|
56
|
+
printTable(ilogTable)
|
57
|
+
puts ''
|
58
|
+
|
59
|
+
puts "Log table for polynomial 0x11D: "
|
60
|
+
logTable = getLogTable(0x11D, 2)
|
61
|
+
printTable(logTable)
|
62
|
+
puts ''
|
63
|
+
|
64
|
+
# ... the 0x11B polynomial is the polynomial used in AES computations.
|
65
|
+
# See: http://www.cs.utsa.edu/~wagner/laws/FFM.html for further details.
|
66
|
+
puts "Inverse log table for polynomial 0x11b:"
|
67
|
+
ilogTable = getILogTable(0x11b, 3)
|
68
|
+
printTable(ilogTable)
|
69
|
+
puts ''
|
70
|
+
|
71
|
+
puts "Log table for polynomial 0x11b: "
|
72
|
+
logTable = getLogTable(0x11b, 3)
|
73
|
+
printTable(logTable)
|
74
|
+
puts ''
|
75
|
+
|
76
|
+
# Demonstrate multiplication using the tables.
|
77
|
+
a = 0x12
|
78
|
+
b = 0x34
|
79
|
+
|
80
|
+
field = FiniteField.new(8, 0x11D)
|
81
|
+
r1 = field.multiply(a, b)
|
82
|
+
|
83
|
+
ilogTable = getILogTable(0x11D, 2)
|
84
|
+
logTable = getLogTable(0x11D, 2)
|
85
|
+
r2 = ilogTable[ (logTable[a] + logTable[b]) % 0xFF ]
|
86
|
+
|
87
|
+
puts "Result using FiniteField.multiply(): #{r1}"
|
88
|
+
puts "Result using log tables: #{r2}"
|
data/examples/raid6.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
|
3
|
+
# = raid6.rb - Generate the Q parity block for a RAID 6 array.
|
4
|
+
#
|
5
|
+
# Copyright (C) 2008 Stephen Doyle
|
6
|
+
#
|
7
|
+
# This example illustrates using the finitefield library in the context
|
8
|
+
# of RAID 6 to generate the Q parity block.
|
9
|
+
#
|
10
|
+
# == Background
|
11
|
+
# RAID 6 provides protection against double disk failures in an array of
|
12
|
+
# disks by using two disks in the array to hold parity information. The
|
13
|
+
# first parity block is known as the P block and generated by taking an
|
14
|
+
# XOR of the data blocks in the disk array (D0 + D1 + ... Dn). This is
|
15
|
+
# equivalent to addition over a finite field of the form F(2^8).
|
16
|
+
#
|
17
|
+
# The second parity block, aka the Q block, in a RAID 6 array is generated
|
18
|
+
# by multiplying each byte of the data blocks with a coefficient which is
|
19
|
+
# slected based upon the position of that disk in the array. The
|
20
|
+
# multiplication here is multiplication over a finite field of the form
|
21
|
+
# F(2^8) and the coefficients are taken from the anti-log table from the
|
22
|
+
# same field. The default RAID 6 polynimial is 0x11D.
|
23
|
+
#
|
24
|
+
# == What's covered in the example?
|
25
|
+
# This example illustrates the computation of both the P and Q blocks for
|
26
|
+
# a sample RAID 6 array using a stripe size of 512 bytes.
|
27
|
+
#
|
28
|
+
|
29
|
+
require 'finitefield'
|
30
|
+
require 'exampleUtils'
|
31
|
+
|
32
|
+
class Raid6
|
33
|
+
|
34
|
+
# Create a field of GF(2^n) using the specified generator polynomial
|
35
|
+
def initialize(polynomial)
|
36
|
+
@field = FiniteField.new(8, polynomial)
|
37
|
+
end
|
38
|
+
|
39
|
+
def getPBlock(dataBlocks)
|
40
|
+
pBlock = [0] * dataBlocks[0].length
|
41
|
+
dataBlocks.each do |blk|
|
42
|
+
(0...blk.length).each { |byteIdx| pBlock[byteIdx] ^= blk[byteIdx] }
|
43
|
+
end
|
44
|
+
return pBlock
|
45
|
+
end
|
46
|
+
|
47
|
+
def getQBlock(dataBlocks, coefficients)
|
48
|
+
qBlock = [0] * dataBlocks[0].length
|
49
|
+
dataBlocks.each_with_index do |blk, blkIdx|
|
50
|
+
(0...blk.length).each do |byteIdx|
|
51
|
+
qBlock[byteIdx] ^= @field.multiply(blk[byteIdx], coefficients[blkIdx])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
return qBlock
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# See logTables.rb for futher details.
|
59
|
+
def getILogTable(poly, generator)
|
60
|
+
field = FiniteField.new(8, poly)
|
61
|
+
ilogTable = [1]
|
62
|
+
|
63
|
+
1.upto(0xFF) do |i|
|
64
|
+
ilogTable[i] = field.multiply(ilogTable[i-1], generator)
|
65
|
+
end
|
66
|
+
return ilogTable
|
67
|
+
end
|
68
|
+
|
69
|
+
# Sample data
|
70
|
+
data = []
|
71
|
+
data[0] = [1]*512
|
72
|
+
data[1] = [2]*512
|
73
|
+
data[2] = [4]*512
|
74
|
+
data[3] = [5]*512
|
75
|
+
data[4] = [6]*512
|
76
|
+
data[5] = [9]*512
|
77
|
+
|
78
|
+
# Generate the blocks
|
79
|
+
raid = Raid6.new(0x11d)
|
80
|
+
coefficients = getILogTable(0x11d, 2)
|
81
|
+
pBlk = raid.getPBlock(data)
|
82
|
+
qBlk = raid.getQBlock(data, coefficients)
|
data/lib/finitefield.rb
CHANGED
@@ -1,9 +1,38 @@
|
|
1
|
-
|
2
|
-
#
|
1
|
+
# = finitefield.rb - Finite Field Arithmetic
|
2
|
+
#
|
3
|
+
# Copyright (C) 2008 Stephen Doyle
|
4
|
+
#
|
5
|
+
# == Features
|
6
|
+
# finitefield.rb currently supports arithmetic in finite fields of characteristic 2.
|
7
|
+
#
|
8
|
+
# The following operations are supported:
|
9
|
+
# * Addition
|
10
|
+
# * Subtraction
|
11
|
+
# * Multiplication
|
12
|
+
# * Division
|
13
|
+
# * Inverse
|
14
|
+
# * Reduction
|
15
|
+
# * Binary multiplication
|
16
|
+
# * Binary division
|
17
|
+
#
|
18
|
+
# == Example
|
19
|
+
#
|
20
|
+
# # Create a field
|
21
|
+
# field = FiniteField.new(8, 0x169) # <== F(2^8) with polynomial: 0x169
|
22
|
+
# # Addition
|
23
|
+
# result = field.add(7, 8)
|
24
|
+
# # Subtraction
|
25
|
+
# result = field.subtract(8, 5)
|
26
|
+
# # Multiplication
|
27
|
+
# result = field.multiply(9, 87)
|
28
|
+
# # Division
|
29
|
+
# result = field.divide(87, 9) # <== result = 87/9
|
30
|
+
# # Inverse
|
31
|
+
# result = field.inverse(31)
|
32
|
+
#
|
3
33
|
|
4
34
|
class FiniteField
|
5
35
|
attr_reader :polynomial
|
6
|
-
attr_reader :p
|
7
36
|
|
8
37
|
# Create a field of GF(2^n) using the specified generator polynomial
|
9
38
|
def initialize(n, polynomial)
|
@@ -50,7 +79,7 @@ class FiniteField
|
|
50
79
|
return result
|
51
80
|
end
|
52
81
|
|
53
|
-
# Reduce the input value by modulo with the generator polynomial
|
82
|
+
# Reduce the input value by modulo with the generator polynomial, i.e. result = a % polynomial.
|
54
83
|
def reduce(a)
|
55
84
|
result = 0
|
56
85
|
i = degree(a)
|
@@ -80,28 +109,27 @@ class FiniteField
|
|
80
109
|
auxillary[2] = 1
|
81
110
|
i = 2
|
82
111
|
|
83
|
-
# puts "#{remainder[i].to_s(base=16)} #{quotient[i].to_s(base=16)} #{auxillary[i].to_s(base=16)}"
|
84
|
-
|
85
112
|
while(remainder[i] > 1)
|
86
113
|
i += 1
|
87
114
|
result = binary_div(remainder[i-2], remainder[i-1])
|
88
115
|
remainder[i] = result[1]
|
89
116
|
quotient[i] = result[0]
|
90
117
|
auxillary[i] = binary_mul(quotient[i], auxillary[i-1]) ^ auxillary[i-2]
|
91
|
-
# puts "#{remainder[i].to_s(base=16)} #{quotient[i].to_s(base=16)} #{auxillary[i].to_s(base=16)}"
|
92
118
|
end
|
93
119
|
|
94
120
|
return auxillary[i]
|
95
121
|
end
|
96
122
|
|
97
|
-
# Division of two field elements (rhs
|
98
|
-
#
|
123
|
+
# Division of two field elements (lhs/rhs). This is the same as
|
124
|
+
# lhs * rhs^-1 i.e. multiply(lhs, inverse(rhs))
|
99
125
|
def divide(lhs, rhs)
|
100
126
|
multiply(lhs, inverse(rhs))
|
101
127
|
end
|
102
128
|
|
103
129
|
# Find the degree of the polynomial representing the input field
|
104
130
|
# element v. This takes O(degree(v)) operations.
|
131
|
+
#
|
132
|
+
# Example: degree(0x141) = 8 ==> 0x141 = x^8 + x^6 + 1
|
105
133
|
def degree(v)
|
106
134
|
if v != 0
|
107
135
|
result = -1
|
@@ -114,7 +142,7 @@ class FiniteField
|
|
114
142
|
return 0
|
115
143
|
end
|
116
144
|
|
117
|
-
# Binary multiplication. Or more explicitly - multiplication over a binary field
|
145
|
+
# Binary multiplication. Or more explicitly - multiplication over a binary field.
|
118
146
|
def binary_mul(lhs, rhs)
|
119
147
|
result = 0
|
120
148
|
a = [degree(lhs), degree(rhs)].max
|
@@ -127,7 +155,7 @@ class FiniteField
|
|
127
155
|
return result
|
128
156
|
end
|
129
157
|
|
130
|
-
# Binary division. Or more explicitly - division over a binary field
|
158
|
+
# Binary division. Or more explicitly - division over a binary field.
|
131
159
|
def binary_div(lhs, rhs)
|
132
160
|
q = 0
|
133
161
|
r = lhs
|
@@ -145,3 +173,4 @@ class FiniteField
|
|
145
173
|
end
|
146
174
|
|
147
175
|
end
|
176
|
+
|
data/test/tc_basic.rb
CHANGED
data/test/tc_gf2.rb
CHANGED
data/test/ts_finitefield.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: finitefield
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Doyle
|
@@ -9,12 +9,12 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-12-22 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
16
16
|
description: Finite Field implementation in Ruby.
|
17
|
-
email:
|
17
|
+
email:
|
18
18
|
executables: []
|
19
19
|
|
20
20
|
extensions: []
|
@@ -28,13 +28,18 @@ files:
|
|
28
28
|
- test/ts_finitefield.rb
|
29
29
|
- test/tc_basic.rb
|
30
30
|
- test/tc_gf2.rb
|
31
|
-
|
31
|
+
- examples/exampleUtils.rb
|
32
|
+
- examples/logTables.rb
|
33
|
+
- examples/raid6.rb
|
34
|
+
has_rdoc: true
|
32
35
|
homepage: http://finitefield.rubyforge.org/
|
33
36
|
post_install_message:
|
34
|
-
rdoc_options:
|
35
|
-
|
37
|
+
rdoc_options:
|
38
|
+
- --title
|
39
|
+
- FiniteField Documentation
|
36
40
|
require_paths:
|
37
41
|
- lib
|
42
|
+
- lib
|
38
43
|
required_ruby_version: !ruby/object:Gem::Requirement
|
39
44
|
requirements:
|
40
45
|
- - ">="
|
@@ -49,10 +54,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
54
|
version:
|
50
55
|
requirements: []
|
51
56
|
|
52
|
-
rubyforge_project:
|
57
|
+
rubyforge_project: finitefield
|
53
58
|
rubygems_version: 1.0.1
|
54
59
|
signing_key:
|
55
60
|
specification_version: 2
|
56
61
|
summary: Finite Field implementation in Ruby.
|
57
|
-
test_files:
|
58
|
-
|
62
|
+
test_files:
|
63
|
+
- test/ts_finitefield.rb
|