OpenCores
URL https://opencores.org/ocsvn/iota_pow_vhdl/iota_pow_vhdl/trunk

Subversion Repositories iota_pow_vhdl

[/] [iota_pow_vhdl/] [trunk/] [vhdl_cyclone10_lp/] [curl.vhd] - Blame information for rev 4

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 4 microengin
-- IOTA Pearl Diver VHDL Port
2
--
3
-- Written 2018 by Thomas Pototschnig <microengineer18@gmail.com>
4
--
5
-- This source code is currently licensed under
6
-- Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)
7
-- 
8
-- http://www.microengineer.eu
9
-- 
10
-- If you like my project please consider a donation to
11
--
12
-- LLEYMHRKXWSPMGCMZFPKKTHSEMYJTNAZXSAYZGQUEXLXEEWPXUNWBFDWESOJVLHQHXOPQEYXGIRBYTLRWHMJAOSHUY
13
--
14
-- As soon as donations reach 1000MIOTA, everything will become
15
-- GPL and open for any use - commercial included.
16
 
17
library ieee;
18
 
19
use ieee.std_logic_1164.all;
20
use ieee.numeric_std.all;
21
use work.index_table.all;
22
 
23
entity curl is
24
        generic
25
        (
26
                HASH_LENGTH : integer := 243;
27
                STATE_LENGTH : integer := 729; -- 3 * HASH_LENGTH;
28
                NONCE_LENGTH : integer := 81; -- HASH_LENGTH / 3;
29
                NUMBER_OF_ROUNDS : integer := 81;
30
                PARALLEL : integer := 7;
31
                INTERN_NONCE_LENGTH : integer   := 32;
32
                BITS_MIN_WEIGHT_MAGINUTE_MAX : integer := 26;
33
                DATA_WIDTH : integer := 9
34
        );
35
 
36
        port
37
        (
38
                clk : in std_logic;
39
                clk_slow : in std_logic;
40
                reset : in std_logic;
41
 
42
                spi_data_rx : in std_logic_vector(31 downto 0);
43
                spi_data_tx : out std_logic_vector(31 downto 0);
44
                spi_data_rxen : in std_logic;
45
                overflow : out std_logic;
46
                running : out std_logic;
47
                found : out std_logic
48
        );
49
 
50
end curl;
51
 
52
architecture behv of curl is
53
 
54
subtype state_vector_type is std_logic_vector(PARALLEL-1 downto 0);
55
subtype mid_state_vector_type is std_logic_vector(DATA_WIDTH-1 downto 0);
56
 
57
type curl_state_array is array(integer range <>) of state_vector_type;
58
type mid_state_array is array(integer range <>) of mid_state_vector_type;
59
 
60
signal curl_state_low : curl_state_array(STATE_LENGTH-1 downto 0);
61
signal curl_state_high : curl_state_array(STATE_LENGTH-1 downto 0);
62
 
63
-- mid state data in 9bit packed format
64
signal curl_mid_state_low : mid_state_array((STATE_LENGTH/9)-1 downto 0);
65
signal curl_mid_state_high : mid_state_array((STATE_LENGTH/9)-1 downto 0);
66
 
67
signal flag_running : std_logic := '0';
68
signal flag_overflow : std_logic := '0';
69
signal flag_found : std_logic := '0';
70
signal flag_start : std_logic := '0';
71
 
72
signal binary_nonce : unsigned(INTERN_NONCE_LENGTH-1 downto 0);
73
signal mask : state_vector_type;
74
signal min_weight_magnitude : std_logic_vector(BITS_MIN_WEIGHT_MAGINUTE_MAX-1 downto 0);
75
 
76
 
77
begin
78
        overflow <= flag_overflow;
79
        running <= flag_running;
80
        found <= flag_found;
81
 
82
        process (clk_slow)
83
        -- because it looks prettier
84
                variable spi_cmd : std_logic_vector(5 downto 0);
85
                variable wraddr : integer range 0 to 127 := 0;
86
        begin
87
                if rising_edge(clk_slow) then
88
                        if reset='1' then
89
--                              binary_nonce <= (others => '0');
90
                                min_weight_magnitude <= (others => '0');
91
                                flag_start <= '0';
92
                        else
93
                                flag_start <= '0';
94
-- new spi data received
95
                                if spi_data_rxen = '1' then
96
                                        spi_cmd := spi_data_rx(31 downto 26);
97
                                        case spi_cmd is
98
                                                when "000000" => -- nop
99
                                                when "100001" => -- start / stop
100
                                                        if spi_data_rx(0) = '1' then
101
                                                                flag_start <= '1';
102
                                                        end if;
103
                                                when "100101" =>        -- write to wr address
104
                                                        wraddr := 0;
105
                                                when "100010" =>        -- write to mid state
106
                                                        curl_mid_state_low(wraddr) <= std_logic_vector(spi_data_rx(DATA_WIDTH-1 downto 0));
107
                                                        curl_mid_state_high(wraddr) <= std_logic_vector(spi_data_rx(DATA_WIDTH+8 downto DATA_WIDTH));
108
                                                        wraddr := wraddr + 1;
109
                                                when "100100" =>
110
                                                        min_weight_magnitude <= spi_data_rx(BITS_MIN_WEIGHT_MAGINUTE_MAX-1 downto 0);
111
 
112
                                                when "000001" =>        -- read flags
113
                                                        spi_data_tx <= "00000000000000000000000000000" & flag_overflow & flag_found & flag_running;
114
 
115
-- this costs an extreme amount of resources
116
-- interesting only for debugging 
117
--                                              when "000010" =>
118
--                                                      spi_addr := spi_data_rx(25 downto 16);
119
--                                                      spi_data_tx(0+PARALLEL-1 downto 0) <= curl_state_low(to_integer(unsigned(spi_addr)));
120
--                                                      spi_data_tx(8+PARALLEL-1 downto 8) <= curl_state_high(to_integer(unsigned(spi_addr)));
121
                                                when "000011" => -- read nonce
122
                                                        spi_data_tx(31 downto INTERN_NONCE_LENGTH) <= (others => '0');
123
                                                        spi_data_tx(INTERN_NONCE_LENGTH-1 downto 0) <= std_logic_vector(binary_nonce);
124
                                                when "000100" => -- read mask
125
                                                        spi_data_tx(PARALLEL-1 downto 0) <= mask;
126
                                                        spi_data_tx(31 downto PARALLEL) <= (others => '0');
127
                                                when "010101" => -- loop back read test inverted bits
128
                                                        spi_data_tx <= not spi_data_rx;
129
                                                when "000110" => -- read back parallel-level
130
                                                        spi_data_tx <= std_logic_vector(to_unsigned(PARALLEL, spi_data_tx'length));
131
                                                when others =>
132
                                                        spi_data_tx <= (others => '1');
133
                                        end case;
134
                                end if;
135
                        end if;
136
                end if;
137
        end process;
138
 
139
        process (clk)
140
                variable        state : integer range 0 to 31 := 0;
141
                variable round : integer range 0 to 127 := 0;
142
 
143
                variable imask : state_vector_type;
144
 
145
                variable i_min_weight_magnitude : std_logic_vector(BITS_MIN_WEIGHT_MAGINUTE_MAX-1 downto 0);
146
 
147
                -- temporary registers get optimized away
148
                variable alpha : curl_state_array(STATE_LENGTH-1 downto 0);
149
                variable beta : curl_state_array(STATE_LENGTH-1 downto 0);
150
                variable gamma : curl_state_array(STATE_LENGTH-1 downto 0);
151
                variable delta : curl_state_array(STATE_LENGTH-1 downto 0);
152
                variable epsilon : curl_state_array(STATE_LENGTH-1 downto 0);
153
 
154
                variable tmp_index : integer range 0 to 1023;
155
                variable tmp_mod : integer range 0 to 31;
156
        begin
157
                if rising_edge(clk) then
158
                        if reset='1' then
159
                                state := 0;
160
                                flag_found <= '0';
161
                                flag_running <= '0';
162
                                flag_overflow <= '0';
163
                                binary_nonce <= (others => '0');
164
                        else
165
                                case state is
166
                                        when 0 =>
167
                                                flag_running <= '0';
168
                                                if flag_start = '1' then
169
                                                        i_min_weight_magnitude := min_weight_magnitude;
170
                                                        state := 1;
171
                                                end if;
172
                                                -- nop until start from spi
173
                                        when 1 =>
174
                                                binary_nonce <= (others => '0');
175
                                                flag_found <= '0';
176
                                                flag_running <= '1';
177
                                                flag_overflow <= '0';
178
                                                state := 8;
179
                                        when 8 =>       -- copy mid state and insert nonce
180
                                                -- pipeline adder for speed
181
                                                binary_nonce <= binary_nonce + 1;
182
 
183
                                                -- copy and fully expand mid-state to curl-state
184
                                                for I in 0 to (STATE_LENGTH/DATA_WIDTH)-1 loop
185
                                                        for J in 0 to DATA_WIDTH-1 loop
186
                                                                tmp_index := I*DATA_WIDTH+J;
187
                                                                if  tmp_index < 162 or tmp_index > HASH_LENGTH-1 then
188
                                                                        if curl_mid_state_low(I)(J) = '1' then
189
                                                                                curl_state_low(tmp_index) <= (others => '1');
190
                                                                        else
191
                                                                                curl_state_low(tmp_index) <= (others => '0');
192
                                                                        end if;
193
 
194
                                                                        if curl_mid_state_high(I)(J) = '1' then
195
                                                                                curl_state_high(tmp_index) <= (others => '1');
196
                                                                        else
197
                                                                                curl_state_high(tmp_index) <= (others => '0');
198
                                                                        end if;
199
                                                                end if;
200
                                                        end loop;
201
                                                end loop;
202
 
203
--                                              -- generate bitmuster in first two trit-arrays of counter depending from PARALLEL setting
204
--                                              -- doesn't need additional resources for pow or division because everything is constant
205
                                                for J in 0 to 1 loop     -- TODO make adjustable ... it's okay up to PARALLEL = 9
206
                                                        for I in 0 to PARALLEL-1 loop
207
                                                                tmp_mod := (I/(3**J)) mod 3;
208
                                                                if tmp_mod = 0 then
209
                                                                        curl_state_low(162+J)(I) <= '1';
210
                                                                        curl_state_high(162+J)(I) <= '1';
211
                                                                elsif tmp_mod = 1 then
212
                                                                        curl_state_low(162+J)(I) <= '0';
213
                                                                        curl_state_high(162+J)(I) <= '1';
214
                                                                elsif tmp_mod = 2 then
215
                                                                        curl_state_low(162+J)(I) <= '1';
216
                                                                        curl_state_high(162+J)(I) <= '0';
217
                                                                end if;
218
                                                        end loop;
219
                                                end loop;
220
 
221
 
222
                                                -- lowest trits for counter from 0 to 4 (for 5bit)
223
--                                              curl_state_low(162) <=  "01101"; 
224
--                                              curl_state_high(162) <= "11011";
225
--                                              curl_state_low(163) <=  "00111";
226
--                                              curl_state_high(163) <= "11111";
227
 
228
                                                -- insert and convert binary nonce to trinary nonce
229
                                                -- It's a fake trinary nonce but integer-values are strictly monotonously rising 
230
                                                -- with integer values of binary nonce.
231
                                                -- Doesn't bring the exact same result like reference implementation with real
232
                                                -- trinary adder - but it doesn't matter and it is way faster.
233
                                                for I in 164 to 164+INTERN_NONCE_LENGTH-1 loop
234
                                                        if binary_nonce(I-164) = '1' then
235
                                                                curl_state_low(I) <= (others => '1');
236
                                                                curl_state_high(I) <= (others => '0');
237
                                                        else
238
                                                                curl_state_low(I) <= (others => '0');
239
                                                                curl_state_high(I) <= (others => '1');
240
                                                        end if;
241
                                                end loop;
242
 
243
                                                -- fill remaining trits with '11' (=0)
244
                                                for I in 164+INTERN_NONCE_LENGTH to HASH_LENGTH-1 loop
245
                                                        curl_state_low(I) <= (others => '1');
246
                                                        curl_state_high(I) <= (others => '1');
247
                                                end loop;
248
 
249
                                                -- initialize round-counter
250
                                                round := NUMBER_OF_ROUNDS;
251
 
252
                                                state := 10;
253
                                        when 10 =>      -- do the curl hash round without any copying needed
254
                                                for I in 0 to STATE_LENGTH-1 loop
255
                                                        alpha(I) := curl_state_low(index_table(I));
256
                                                        beta(I) := curl_state_high(index_table(I));
257
                                                        gamma(I) := curl_state_high(index_table(I+1));
258
 
259
                                                        delta(I) := (alpha(I) or (not gamma(I))) and (curl_state_low(index_table(I+1)) xor beta(I));
260
 
261
                                                        curl_state_low(I) <= not delta(I);
262
                                                        curl_state_high(I) <= (alpha(I) xor gamma(I)) or delta(I);
263
                                                end loop;
264
 
265
                                                round := round - 1;
266
                                                if round = 0 then
267
                                                        state := 16;
268
                                                end if;
269
                                        when 16 =>  -- find out which solution - if any
270
                                                imask := (others => '1');
271
 
272
                                                -- doesn't work like the 2nd variant ... why? TODO^^ 
273
                                                for I in 0 to PARALLEL-1 loop
274
                                                        for J in 0 to BITS_MIN_WEIGHT_MAGINUTE_MAX-1 loop
275
                                                                if i_min_weight_magnitude(J) = '1' and (curl_state_low(HASH_LENGTH - 1 - J)(I) /= '1' or curl_state_high(HASH_LENGTH - 1 - J)(I) /= '1') then
276
                                                                        imask(I) := '0';
277
                                                                end if;
278
                                                        end loop;
279
                                                end loop;
280
 
281
--                                              imask := (others => '1');
282
--                                              for I in 0 to BITS_MIN_WEIGHT_MAGINUTE_MAX-1 loop 
283
--                                                      if i_min_weight_magnitude(I) = '1' then
284
--                                                              imask := imask and not (curl_state_low(HASH_LENGTH - 1 - I) xor curl_state_high(HASH_LENGTH - 1 - I));
285
--                                                      end if;
286
--                                              end loop;
287
--                                              mask <= imask;                                          
288
 
289
                                                -- no solution found?
290
                                                if unsigned(imask) = 0 then
291
                                                        -- is overflow?
292
                                                        if binary_nonce = x"ffffffff" then
293
                                                                flag_overflow <= '1';
294
                                                                state := 0;
295
                                                        else
296
                                                                state := 8;     -- and try again
297
                                                        end if;
298
                                                else
299
                                                        state := 30;    -- nonce found
300
                                                end if;
301
                                        when 30 =>
302
                                                mask <= imask;
303
                                                flag_found <= '1';
304
                                                state := 0;
305
                                        when others =>
306
                                                state := 0;
307
                                end case;
308
                        end if;
309
                end if;
310
        end process;
311
end behv;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.