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 5

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 5 microengin
 
19 4 microengin
use ieee.std_logic_1164.all;
20
use ieee.numeric_std.all;
21
use work.index_table.all;
22 5 microengin
 
23 4 microengin
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 5 microengin
                DATA_WIDTH : integer := 9;
34
                NONCE_OFFSET : integer := 162   -- we hope it nevery changes
35 4 microengin
        );
36
 
37
        port
38
        (
39
                clk : in std_logic;
40
                clk_slow : in std_logic;
41
                reset : in std_logic;
42
 
43
                spi_data_rx : in std_logic_vector(31 downto 0);
44
                spi_data_tx : out std_logic_vector(31 downto 0);
45
                spi_data_rxen : in std_logic;
46
                overflow : out std_logic;
47
                running : out std_logic;
48
                found : out std_logic
49
        );
50
 
51
end curl;
52
 
53
architecture behv of curl is
54
 
55
subtype state_vector_type is std_logic_vector(PARALLEL-1 downto 0);
56
subtype mid_state_vector_type is std_logic_vector(DATA_WIDTH-1 downto 0);
57 5 microengin
subtype min_weight_magnitude_type is std_logic_vector(BITS_MIN_WEIGHT_MAGINUTE_MAX-1 downto 0);
58 4 microengin
 
59
type curl_state_array is array(integer range <>) of state_vector_type;
60
type mid_state_array is array(integer range <>) of mid_state_vector_type;
61 5 microengin
type min_weight_magnitude_array is array(integer range<>) of min_weight_magnitude_type;
62 4 microengin
 
63
signal curl_state_low : curl_state_array(STATE_LENGTH-1 downto 0);
64
signal curl_state_high : curl_state_array(STATE_LENGTH-1 downto 0);
65
 
66
-- mid state data in 9bit packed format
67
signal curl_mid_state_low : mid_state_array((STATE_LENGTH/9)-1 downto 0);
68
signal curl_mid_state_high : mid_state_array((STATE_LENGTH/9)-1 downto 0);
69
 
70
signal flag_running : std_logic := '0';
71
signal flag_overflow : std_logic := '0';
72
signal flag_found : std_logic := '0';
73
signal flag_start : std_logic := '0';
74
 
75
signal binary_nonce : unsigned(INTERN_NONCE_LENGTH-1 downto 0);
76
signal mask : state_vector_type;
77 5 microengin
signal min_weight_magnitude : min_weight_magnitude_type;
78 4 microengin
 
79 5 microengin
function expand(b : std_logic)
80
        return state_vector_type is
81 4 microengin
begin
82 5 microengin
        if b = '1' then
83
                return (others => '1');
84
        else
85
                return (others => '0');
86
        end if;
87
end expand;
88
 
89
begin
90 4 microengin
        overflow <= flag_overflow;
91
        running <= flag_running;
92
        found <= flag_found;
93
 
94
        process (clk_slow)
95
        -- because it looks prettier
96
                variable spi_cmd : std_logic_vector(5 downto 0);
97 5 microengin
                variable addrptr : unsigned(7 downto 0) := x"00";
98 4 microengin
        begin
99
                if rising_edge(clk_slow) then
100
                        if reset='1' then
101
                                min_weight_magnitude <= (others => '0');
102
                                flag_start <= '0';
103 5 microengin
                                spi_data_tx <= (others => '0');
104
--                              curl_mid_state_low <= (others => (others => '0'));
105
--                              curl_mid_state_high <= (others => (others => '0'));
106
                                addrptr := x"00";
107 4 microengin
                        else
108
                                flag_start <= '0';
109
-- new spi data received
110
                                if spi_data_rxen = '1' then
111
                                        spi_cmd := spi_data_rx(31 downto 26);
112
                                        case spi_cmd is
113 5 microengin
                                                when "000000" => -- nop (mainly for reading back data)
114 4 microengin
                                                when "100001" => -- start / stop
115 5 microengin
                                                        flag_start <= spi_data_rx(0);
116 4 microengin
                                                when "100101" =>        -- write to wr address
117 5 microengin
                                                        addrptr := unsigned(spi_data_rx(7 downto 0));
118 4 microengin
                                                when "100010" =>        -- write to mid state
119 5 microengin
                                                        if (addrptr <= (STATE_LENGTH/9)-1) then
120
                                                                curl_mid_state_low(to_integer(addrptr)) <= spi_data_rx(DATA_WIDTH-1 downto 0);
121
                                                                curl_mid_state_high(to_integer(addrptr)) <= spi_data_rx(DATA_WIDTH+8 downto DATA_WIDTH);
122
                                                        end if;
123
                                                        spi_data_tx <= spi_data_rx;
124
                                                        addrptr := addrptr + 1;
125 4 microengin
                                                when "100100" =>
126
                                                        min_weight_magnitude <= spi_data_rx(BITS_MIN_WEIGHT_MAGINUTE_MAX-1 downto 0);
127
 
128
                                                when "000001" =>        -- read flags
129 5 microengin
                                                        spi_data_tx(2 downto 0) <= flag_overflow & flag_found & flag_running;
130
 
131
-- for debugging onle ... read back curl_state
132 4 microengin
--                                              when "000010" =>
133
--                                                      spi_addr := spi_data_rx(25 downto 16);
134
--                                                      spi_data_tx(0+PARALLEL-1 downto 0) <= curl_state_low(to_integer(unsigned(spi_addr)));
135
--                                                      spi_data_tx(8+PARALLEL-1 downto 8) <= curl_state_high(to_integer(unsigned(spi_addr)));
136 5 microengin
 
137
-- for debugging only ... read back mid_state
138
--                                              when "000111" =>
139
--                                                      if (addrptr <= (STATE_LENGTH/9)-1) then
140
--                                                              spi_data_tx(DATA_WIDTH-1 downto 0) <= curl_mid_state_low(to_integer(addrptr));
141
--                                                              spi_data_tx(DATA_WIDTH+8 downto DATA_WIDTH) <= curl_mid_state_high(to_integer(addrptr));
142
--                                                      else
143
--                                                              spi_data_tx <= (others => '0');
144
--                                                      end if;
145
--                                                      addrptr := addrptr + 1; -- dual-used for debugging purposes 
146 4 microengin
                                                when "000011" => -- read nonce
147
                                                        spi_data_tx(INTERN_NONCE_LENGTH-1 downto 0) <= std_logic_vector(binary_nonce);
148
                                                when "000100" => -- read mask
149
                                                        spi_data_tx(PARALLEL-1 downto 0) <= mask;
150
                                                when "010101" => -- loop back read test inverted bits
151
                                                        spi_data_tx <= not spi_data_rx;
152
                                                when "000110" => -- read back parallel-level
153 5 microengin
                                                        spi_data_tx(3 downto 0) <= std_logic_vector(to_unsigned(PARALLEL, 4));
154 4 microengin
                                                when others =>
155
                                                        spi_data_tx <= (others => '1');
156
                                        end case;
157
                                end if;
158
                        end if;
159
                end if;
160
        end process;
161
 
162 5 microengin
 
163
 
164 4 microengin
        process (clk)
165
                variable        state : integer range 0 to 31 := 0;
166
                variable round : integer range 0 to 127 := 0;
167
 
168
                variable imask : state_vector_type;
169
 
170 5 microengin
                variable i_min_weight_magnitude : min_weight_magnitude_type;
171
                variable tmp_weight_magnitude : min_weight_magnitude_array(0 to PARALLEL-1);
172
                variable i_binary_nonce : unsigned(INTERN_NONCE_LENGTH-1 downto 0);
173 4 microengin
 
174
                -- temporary registers get optimized away
175
                variable alpha : curl_state_array(STATE_LENGTH-1 downto 0);
176
                variable beta : curl_state_array(STATE_LENGTH-1 downto 0);
177
                variable gamma : curl_state_array(STATE_LENGTH-1 downto 0);
178
                variable delta : curl_state_array(STATE_LENGTH-1 downto 0);
179
 
180
                variable tmp_index : integer range 0 to 1023;
181 5 microengin
                variable tmp_highest_bit : integer range 0 to 31;
182 4 microengin
        begin
183
                if rising_edge(clk) then
184
                        if reset='1' then
185
                                state := 0;
186 5 microengin
                                round := 0;
187 4 microengin
                                flag_found <= '0';
188
                                flag_running <= '0';
189
                                flag_overflow <= '0';
190
                                binary_nonce <= (others => '0');
191 5 microengin
                                mask <= (others => '0');
192
--                              curl_state_low <= (others => (others => '0'));
193
--                              curl_state_high <= (others => (others => '0'));
194
--                              tmp_weight_magnitude := (others => (others => '0'));
195
                                i_binary_nonce := (others => '0');
196
                                imask := (others => '0');
197
                                i_min_weight_magnitude := (others => '0');
198
                                alpha := (others => (others => '0'));
199
                                beta := (others => (others => '0'));
200
                                gamma := (others => (others => '0'));
201
                                delta := (others => (others => '0'));
202
                                tmp_index := 0;
203 4 microengin
                        else
204
                                case state is
205
                                        when 0 =>
206 5 microengin
                                                mask <= imask;
207
                                                binary_nonce <= i_binary_nonce;
208 4 microengin
                                                flag_running <= '0';
209
                                                if flag_start = '1' then
210 5 microengin
                                                        i_binary_nonce := x"00000000";
211 4 microengin
                                                        i_min_weight_magnitude := min_weight_magnitude;
212
                                                        state := 1;
213
                                                end if;
214
                                                -- nop until start from spi
215
                                        when 1 =>
216
                                                flag_found <= '0';
217
                                                flag_running <= '1';
218
                                                flag_overflow <= '0';
219
                                                state := 8;
220
                                        when 8 =>       -- copy mid state and insert nonce
221
 
222
                                                -- copy and fully expand mid-state to curl-state
223
                                                for I in 0 to (STATE_LENGTH/DATA_WIDTH)-1 loop
224
                                                        for J in 0 to DATA_WIDTH-1 loop
225
                                                                tmp_index := I*DATA_WIDTH+J;
226 5 microengin
                                                                if  tmp_index < NONCE_OFFSET or tmp_index > NONCE_OFFSET + NONCE_LENGTH - 1 then
227
                                                                        curl_state_low(tmp_index) <= expand(curl_mid_state_low(I)(J));
228
                                                                        curl_state_high(tmp_index) <= expand(curl_mid_state_high(I)(J));
229 4 microengin
                                                                end if;
230
                                                        end loop;
231
                                                end loop;
232
 
233 5 microengin
                                                -- fill all ... synthesizer is smart enough to optimize away what is not needed
234
                                                for I in NONCE_OFFSET to NONCE_OFFSET + NONCE_LENGTH - 1 loop
235
                                                        curl_state_low(I) <= expand('1');
236
                                                        curl_state_high(I) <= expand('1');
237
                                                end loop;
238
 
239
                                                -- calculate log2(x) by determining the place of highest set bit
240
                                                -- this is calculated on constants, so no logic needed
241
                                                tmp_highest_bit := 0;
242
                                                for I in 0 to 31 loop    -- 32 is enough ...^^
243
                                                        if to_unsigned(PARALLEL-1, 32)(I) = '1' then
244
                                                                tmp_highest_bit := I;
245
                                                        end if;
246
                                                end loop;
247
 
248
--                                              -- generate bitmuster in first trit-arrays of nonce depending on PARALLEL setting
249
                                                -- this is calculated on constants, so no logic needed
250
                                                for I in 0 to PARALLEL-1 loop
251
                                                        for J in 0 to tmp_highest_bit loop
252
                                                                curl_state_low(NONCE_OFFSET+J)(I) <= to_unsigned(I, tmp_highest_bit+1)(J);
253
                                                                curl_state_high(NONCE_OFFSET+J)(I) <= not to_unsigned(I, tmp_highest_bit+1)(J);
254 4 microengin
                                                        end loop;
255
                                                end loop;
256
 
257 5 microengin
                                                -- insert and convert binary nonce to ternary nonce
258
                                                -- It's a fake ternary nonce but integer-values are strictly monotonously rising 
259 4 microengin
                                                -- with integer values of binary nonce.
260
                                                -- Doesn't bring the exact same result like reference implementation with real
261 5 microengin
                                                -- ternary adder - but it doesn't matter and it is way faster.
262
                                                -- conveniently put nonce counter at the end of nonce
263
                                                for I in 0 to INTERN_NONCE_LENGTH-1 loop
264
                                                        curl_state_low(NONCE_OFFSET + NONCE_LENGTH - INTERN_NONCE_LENGTH + I) <= expand(i_binary_nonce(I));
265
                                                        curl_state_high(NONCE_OFFSET + NONCE_LENGTH - INTERN_NONCE_LENGTH + I) <= not expand(i_binary_nonce(I));
266 4 microengin
                                                end loop;
267
 
268
                                                -- initialize round-counter
269
                                                round := NUMBER_OF_ROUNDS;
270
 
271
                                                state := 10;
272
                                        when 10 =>      -- do the curl hash round without any copying needed
273 5 microengin
                                                if round = 1 then
274
                                                        state := 16;
275
                                                end if;
276 4 microengin
                                                for I in 0 to STATE_LENGTH-1 loop
277
                                                        alpha(I) := curl_state_low(index_table(I));
278
                                                        beta(I) := curl_state_high(index_table(I));
279
                                                        gamma(I) := curl_state_high(index_table(I+1));
280
 
281
                                                        delta(I) := (alpha(I) or (not gamma(I))) and (curl_state_low(index_table(I+1)) xor beta(I));
282
 
283
                                                        curl_state_low(I) <= not delta(I);
284
                                                        curl_state_high(I) <= (alpha(I) xor gamma(I)) or delta(I);
285
                                                end loop;
286
                                                round := round - 1;
287
                                        when 16 =>  -- find out which solution - if any
288 5 microengin
                                                imask := (others => '0');
289
 
290
                                                -- transform "vertical" trits to "horizontal" bits
291
                                                -- and compare with min weight magnitude mask
292 4 microengin
                                                for I in 0 to PARALLEL-1 loop
293 5 microengin
                                                        tmp_weight_magnitude(I) := (others => '0');
294 4 microengin
                                                        for J in 0 to BITS_MIN_WEIGHT_MAGINUTE_MAX-1 loop
295 5 microengin
                                                                tmp_weight_magnitude(I)(J) := curl_state_low(HASH_LENGTH - 1 - J)(I) and curl_state_high(HASH_LENGTH - 1 - J)(I);
296 4 microengin
                                                        end loop;
297 5 microengin
                                                        tmp_weight_magnitude(I) := tmp_weight_magnitude(I) and i_min_weight_magnitude; -- only consider used bits
298
                                                        if tmp_weight_magnitude(I) = i_min_weight_magnitude then
299
                                                                imask(I) := '1';
300
                                                        end if;
301 4 microengin
                                                end loop;
302 5 microengin
                                                state := 17;
303
                                        when 17 =>
304
                                                if unsigned(imask) /= 0 then
305
                                                        state := 30;
306
                                                elsif i_binary_nonce = x"ffffffff" then
307
                                                        state := 31;
308 4 microengin
                                                else
309 5 microengin
                                                        i_binary_nonce := i_binary_nonce + 1;
310
                                                        state := 8;
311 4 microengin
                                                end if;
312
                                        when 30 =>
313
                                                flag_found <= '1';
314
                                                state := 0;
315 5 microengin
                                        when 31 =>
316
                                                flag_overflow <= '1';
317
                                                state := 0;
318 4 microengin
                                        when others =>
319
                                                state := 0;
320
                                end case;
321
                        end if;
322
                end if;
323
        end process;
324
end behv;

powered by: WebSVN 2.1.0

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