poseidon_hash 1.0.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.
- 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: []
|