poseidon_hash 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/poseidon/constant.rb +233 -0
- data/lib/poseidon/hash.rb +123 -0
- data/lib/poseidon_hash.rb +2 -0
- metadata +45 -0
@@ -0,0 +1,123 @@
|
|
1
|
+
module Poseidon
|
2
|
+
class Hash
|
3
|
+
include Constant
|
4
|
+
|
5
|
+
def s_box(x)
|
6
|
+
p = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
|
7
|
+
a = (x * x) % p
|
8
|
+
b = (a * a) % p
|
9
|
+
(x * b) % p
|
10
|
+
end
|
11
|
+
|
12
|
+
def dotprod(a, b)
|
13
|
+
p = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
|
14
|
+
raise 'Length of a and b must be equal' unless a.length == b.length
|
15
|
+
|
16
|
+
res = 0
|
17
|
+
for i in 0...a.length
|
18
|
+
res += ((a[i] * b[i]) % p)
|
19
|
+
end
|
20
|
+
res % p
|
21
|
+
end
|
22
|
+
|
23
|
+
def matrix_multiply(m, x)
|
24
|
+
b = []
|
25
|
+
raise 'M must be a square matrix' unless m.length == m[0].length
|
26
|
+
raise 'Length of M and x must be equal' unless m.length == x.length
|
27
|
+
|
28
|
+
for i in 0...x.length
|
29
|
+
b << dotprod(m[i], x)
|
30
|
+
end
|
31
|
+
b
|
32
|
+
end
|
33
|
+
|
34
|
+
def perm(input_words, t)
|
35
|
+
p = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
|
36
|
+
raise 'Length of input_words must be equal to t' unless input_words.length == t
|
37
|
+
|
38
|
+
rp = get_RP(t)
|
39
|
+
rf = 4
|
40
|
+
m = get_mds(t)
|
41
|
+
rc = get_round_constants(t)
|
42
|
+
state_words = input_words.dup
|
43
|
+
|
44
|
+
rc_counter = 0
|
45
|
+
# First full rounds
|
46
|
+
for r in 0...rf
|
47
|
+
# Round constants, nonlinear layer, matrix multiplication
|
48
|
+
for i in 0...t
|
49
|
+
state_words[i] = (state_words[i] + rc[rc_counter]) % p
|
50
|
+
rc_counter += 1
|
51
|
+
end
|
52
|
+
for i in 0...t
|
53
|
+
state_words[i] = s_box(state_words[i])
|
54
|
+
end
|
55
|
+
state_words = matrix_multiply(m, state_words)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Middle partial rounds
|
59
|
+
for r in 0...rp
|
60
|
+
# Round constants, nonlinear layer, matrix multiplication
|
61
|
+
for i in 0...t
|
62
|
+
state_words[i] = (state_words[i] + rc[rc_counter]) % p
|
63
|
+
rc_counter += 1
|
64
|
+
end
|
65
|
+
state_words[0] = s_box(state_words[0])
|
66
|
+
state_words = matrix_multiply(m, state_words)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Last full rounds
|
70
|
+
for r in 0...rf
|
71
|
+
# Round constants, nonlinear layer, matrix multiplication
|
72
|
+
for i in 0...t
|
73
|
+
state_words[i] = (state_words[i] + rc[rc_counter]) % p
|
74
|
+
rc_counter += 1
|
75
|
+
end
|
76
|
+
for i in 0...t
|
77
|
+
state_words[i] = s_box(state_words[i])
|
78
|
+
end
|
79
|
+
state_words = matrix_multiply(m, state_words)
|
80
|
+
end
|
81
|
+
|
82
|
+
raise 'rc_counter must be equal to length of RC' unless rc_counter == rc.length
|
83
|
+
|
84
|
+
state_words
|
85
|
+
end
|
86
|
+
|
87
|
+
def hash(input, arity)
|
88
|
+
raise 'The length of the input must be equal to the arity' unless input.length == arity
|
89
|
+
|
90
|
+
copied_input = input.dup
|
91
|
+
state = [0] + copied_input
|
92
|
+
output = perm(state, arity + 1)
|
93
|
+
output[0]
|
94
|
+
end
|
95
|
+
|
96
|
+
def linear_hash_many(inputs, arity = 16)
|
97
|
+
# base case
|
98
|
+
if inputs.length <= arity
|
99
|
+
base_hash_inputs = inputs + ([0] * (arity - inputs.length))
|
100
|
+
current_hash = hash(base_hash_inputs, arity)
|
101
|
+
remaining_inputs = []
|
102
|
+
else
|
103
|
+
base_hash_inputs = inputs[0...arity]
|
104
|
+
remaining_inputs = inputs[arity..-1]
|
105
|
+
current_hash = hash(base_hash_inputs, arity)
|
106
|
+
end
|
107
|
+
|
108
|
+
while remaining_inputs.length > 0
|
109
|
+
if remaining_inputs.length <= arity - 1
|
110
|
+
hash_inputs = [current_hash] + remaining_inputs + ([0] * (arity - remaining_inputs.length - 1))
|
111
|
+
remaining_inputs = []
|
112
|
+
current_hash = hash(hash_inputs, arity)
|
113
|
+
else
|
114
|
+
hash_inputs = [current_hash] + remaining_inputs[0...arity - 1]
|
115
|
+
remaining_inputs = remaining_inputs[arity - 1..-1]
|
116
|
+
current_hash = hash(hash_inputs, arity)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
current_hash
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
metadata
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: poseidon_hash
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nhan Vu
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-06-29 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Ruby implementation of Poseidon hash function
|
14
|
+
email: nhannvu.19@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/poseidon/constant.rb
|
20
|
+
- lib/poseidon/hash.rb
|
21
|
+
- lib/poseidon_hash.rb
|
22
|
+
homepage: https://rubygems.org/gems/poseidon_hash
|
23
|
+
licenses:
|
24
|
+
- MIT
|
25
|
+
metadata: {}
|
26
|
+
post_install_message:
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
29
|
+
- lib
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubygems_version: 3.2.33
|
42
|
+
signing_key:
|
43
|
+
specification_version: 4
|
44
|
+
summary: Poseidon hash function
|
45
|
+
test_files: []
|