-
Notifications
You must be signed in to change notification settings - Fork 0
/
Poseidon.cs
114 lines (94 loc) · 2.84 KB
/
Poseidon.cs
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
namespace Drm_Mina;
public static class Poseidon
{
private static int fullRounds;
private static int partialRounds;
private static bool hasInitialRoundConstant;
private static int stateSize;
private static int rate;
private static int power;
private static Field[][] roundConstants;
private static Field[,] mds;
static Poseidon()
{
fullRounds = Constants.FullRounds;
partialRounds = Constants.PartialRounds;
hasInitialRoundConstant = Constants.HasInitialRoundConstant;
stateSize = Constants.StateSize;
rate = Constants.Rate;
power = Constants.Power;
roundConstants = Constants.RoundConstants;
mds = Constants.MdsMatrix;
if (partialRounds != 0)
{
throw new ArgumentException("o1js don't support partial rounds");
}
}
public static Field Hash(Field[] input)
{
var state = Update(InitialState(), input);
return state[0];
}
private static Field[] InitialState()
{
var state = new Field[stateSize];
for (int i = 0; i < stateSize; i++)
{
state[i] = new Field(0);
}
return state;
}
private static Field[] Update(Field[] state, Field[] input)
{
if (input.Length == 0)
{
Permutation(state);
return state;
}
int n = (int)Math.Ceiling((double)input.Length / rate) * rate;
var paddedInput = new Field[n];
Array.Copy(input, paddedInput, input.Length);
for (int i = input.Length; i < n; i++)
{
paddedInput[i] = new Field(0);
}
for (int blockIndex = 0; blockIndex < n; blockIndex += rate)
{
for (int i = 0; i < rate; i++)
{
state[i] = state[i] + paddedInput[blockIndex + i];
}
Permutation(state);
}
return state;
}
private static void Permutation(Field[] state)
{
int offset = 0;
if (hasInitialRoundConstant)
{
for (int i = 0; i < state.Length; i++)
{
state[i] = state[i] + roundConstants[0][i];
}
offset = 1;
}
for (int round = 0; round < fullRounds; round++)
{
for (int i = 0; i < state.Length; i++)
{
state[i] = Field.Power(state[i], power);
}
var oldState = (Field[])state.Clone();
for (int i = 0; i < state.Length; i++)
{
Field[] mdsRow = new Field[state.Length];
for (int j = 0; j < state.Length; j++)
{
mdsRow[j] = mds[i, j];
}
state[i] = Field.Dot(mdsRow, oldState) + roundConstants[round + offset][i];
}
}
}
}