-
Notifications
You must be signed in to change notification settings - Fork 0
/
field_element.rb
89 lines (65 loc) · 2.03 KB
/
field_element.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
class FieldElement
attr_reader :int, :prime
def initialize(int:, prime:)
@int = int
@prime = prime
end
def ==(comparand)
field_element_validation!(comparand)
(int == comparand.int) && (prime == comparand.prime)
end
def +(summand)
field_element_validation!(summand)
int_sum = (int + summand.int) % prime
FieldElement.new(int: int_sum, prime: prime)
end
def -(subtrahend)
field_element_validation!(subtrahend)
int_difference = (int - subtrahend.int) % prime
FieldElement.new(int: int_difference, prime: prime)
end
def *(multiplicand)
field_element_validation!(multiplicand)
int_product = (int * multiplicand.int) % prime
FieldElement.new(int: int_product, prime: prime)
end
def **(exponent)
raise 'Must provide an integer' unless exponent.is_a?(Integer)
if exponent < 0
# int ** -n == 1 / int ** n
positive_product = int ** exponent.abs
identity_element / positive_product
else
int_product = (int ** exponent) % prime
FieldElement.new(int: int_product, prime: prime)
end
end
def /(divisor)
# (divisor ** (prime - 1)) % prime == 1 by Fermat's Little Theorem
# int / divisor == int * (divisor ** -1)
# int / divisor == int * (divisor ** -1) * 1
# int / divisor == int * (divisor ** -1) * (divisor ** (prime - 1)) % prime
# int / divisor == int * (divisor ** (prime - 2)) % prime
multiplicative_inverse = (divisor.to_i ** (prime - 2)) % prime
int_quotient = (int * multiplicative_inverse) % prime
FieldElement.new(int: int_quotient, prime: prime)
end
def identity_element
@_identity_element ||= FieldElement.new(int: 1, prime: prime)
end
def -@
FieldElement.new(int: -int, prime: prime)
end
def to_i
int % prime
end
private
def field_element_validation!(operand)
unless operand.is_a?(FieldElement)
raise 'Must provide a FieldElement'
end
unless prime == operand.prime
raise 'Operands must have the same primes'
end
end
end