Line data Source code
1 : #include "./fd_poseidon.h"
2 : #include "fd_poseidon_params.c"
3 :
4 : /* Poseidon internals */
5 :
6 : static inline void
7 : fd_poseidon_apply_ark( fd_bn254_scalar_t state[],
8 : ulong const width,
9 : fd_poseidon_par_t const * params,
10 1029921 : ulong round ) {
11 7402218 : for( ulong i=0; i<width; i++ ) {
12 6372297 : fd_bn254_scalar_add( &state[i], &state[i], ¶ms->ark[ round * width + i ] );
13 6372297 : }
14 1029921 : }
15 :
16 : static inline void
17 : fd_poseidon_apply_sbox_full( fd_bn254_scalar_t state[],
18 1029921 : ulong const width ) {
19 : /* Compute s[i]^5 */
20 2664234 : for( ulong i=0; i<width; i++ ) {
21 1634313 : fd_bn254_scalar_t t[1];
22 1634313 : fd_bn254_scalar_sqr( t, &state[i] ); /* t = s^2 */
23 1634313 : fd_bn254_scalar_sqr( t, t ); /* t = s^4 */
24 1634313 : fd_bn254_scalar_mul( &state[i], &state[i], t ); /* s = s^5 */
25 1634313 : }
26 1029921 : }
27 :
28 : static inline void
29 909105 : fd_poseidon_apply_sbox_partial( fd_bn254_scalar_t state[] ) {
30 : /* Compute s[0]^5 */
31 909105 : fd_poseidon_apply_sbox_full( state, 1 );
32 909105 : }
33 :
34 : static inline void
35 : fd_poseidon_apply_mds( fd_bn254_scalar_t state[],
36 : ulong const width,
37 1029921 : fd_poseidon_par_t const * params ) {
38 1029921 : fd_bn254_scalar_t x[FD_POSEIDON_MAX_WIDTH+1] = { 0 };
39 : /* Vector-matrix multiplication (state vector times mds matrix) */
40 7402218 : for( ulong i=0; i<width; i++ ) {
41 61839546 : for( ulong j=0; j<width; j++ ) {
42 55467249 : fd_bn254_scalar_t t[1];
43 55467249 : fd_bn254_scalar_mul( t, &state[j], ¶ms->mds[ i * width + j ] );
44 55467249 : fd_bn254_scalar_add( &x[i], &x[i], t );
45 55467249 : }
46 6372297 : }
47 7402218 : for( ulong i=0; i<width; i++ ) {
48 6372297 : state[i] = x[i];
49 6372297 : }
50 1029921 : }
51 :
52 : static inline void
53 : fd_poseidon_get_params( fd_poseidon_par_t * params,
54 15102 : ulong const width ) {
55 15102 : #define FD_POSEIDON_GET_PARAMS(w) case (w): \
56 15102 : params->ark = (fd_bn254_scalar_t *)fd_poseidon_ark_## w; \
57 15102 : params->mds = (fd_bn254_scalar_t *)fd_poseidon_mds_## w; \
58 15102 : break
59 :
60 15102 : switch( width ) {
61 3015 : FD_POSEIDON_GET_PARAMS(2);
62 3024 : FD_POSEIDON_GET_PARAMS(3);
63 6 : FD_POSEIDON_GET_PARAMS(4);
64 3006 : FD_POSEIDON_GET_PARAMS(5);
65 6 : FD_POSEIDON_GET_PARAMS(6);
66 3006 : FD_POSEIDON_GET_PARAMS(7);
67 6 : FD_POSEIDON_GET_PARAMS(8);
68 6 : FD_POSEIDON_GET_PARAMS(9);
69 6 : FD_POSEIDON_GET_PARAMS(10);
70 6 : FD_POSEIDON_GET_PARAMS(11);
71 6 : FD_POSEIDON_GET_PARAMS(12);
72 15102 : FD_POSEIDON_GET_PARAMS(13);
73 15102 : }
74 15102 : #undef FD_POSEIDON_GET_PARAMS
75 15102 : }
76 :
77 : /* Poseidon interface */
78 :
79 : fd_poseidon_t *
80 : fd_poseidon_init( fd_poseidon_t * pos,
81 15105 : int const big_endian ) {
82 15105 : if( FD_UNLIKELY( pos==NULL ) ) {
83 0 : return NULL;
84 0 : }
85 15105 : pos->big_endian = big_endian;
86 15105 : pos->cnt = 0UL;
87 15105 : fd_memset( pos->state, 0, sizeof(pos->state) );
88 15105 : return pos;
89 15105 : }
90 :
91 : fd_poseidon_t *
92 : fd_poseidon_append( fd_poseidon_t * pos,
93 : uchar const * data,
94 : ulong sz,
95 75552 : int enforce_padding ) {
96 75552 : if( FD_UNLIKELY( pos==NULL ) ) {
97 0 : return NULL;
98 0 : }
99 75552 : if( FD_UNLIKELY( pos->cnt >= FD_POSEIDON_MAX_WIDTH ) ) {
100 0 : return NULL;
101 0 : }
102 75552 : if( FD_UNLIKELY( enforce_padding && sz!=32UL ) ) {
103 3 : return NULL;
104 3 : }
105 : /* Empty input and non-field are errors. Short element is extended with 0s. */
106 75549 : if( FD_UNLIKELY( sz==0 || sz>32UL ) ) {
107 0 : return NULL;
108 0 : }
109 :
110 : /* Handle endianness */
111 75549 : fd_bn254_scalar_t cur[1] = { 0 };
112 75549 : fd_memcpy( cur->buf + (32-sz)*(pos->big_endian?1:0), data, sz );
113 75549 : if( pos->big_endian ) {
114 75537 : fd_uint256_bswap( cur, cur );
115 75537 : }
116 :
117 75549 : if( FD_UNLIKELY( !fd_bn254_scalar_validate( cur ) ) ) {
118 0 : return NULL;
119 0 : }
120 75549 : pos->cnt++;
121 75549 : fd_bn254_scalar_to_mont( &pos->state[ pos->cnt ], cur );
122 :
123 75549 : return pos;
124 75549 : }
125 :
126 : uchar *
127 : fd_poseidon_fini( fd_poseidon_t * pos,
128 15102 : uchar hash[ FD_POSEIDON_HASH_SZ ] ) {
129 15102 : if( FD_UNLIKELY( pos==NULL ) ) {
130 0 : return NULL;
131 0 : }
132 15102 : if( FD_UNLIKELY( !pos->cnt ) ) {
133 0 : return NULL;
134 0 : }
135 15102 : const ulong width = pos->cnt+1;
136 15102 : fd_poseidon_par_t params[1] = { 0 };
137 15102 : fd_poseidon_get_params( params, width );
138 15102 : if( FD_UNLIKELY( !params->ark || !params->mds ) ) {
139 0 : return NULL;
140 0 : }
141 :
142 15102 : const ulong PARTIAL_ROUNDS[] = { 56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68 };
143 15102 : const ulong partial_rounds = PARTIAL_ROUNDS[ pos->cnt-1 ];
144 15102 : const ulong full_rounds = 8;
145 15102 : const ulong half_rounds = full_rounds / 2;
146 15102 : const ulong all_rounds = full_rounds + partial_rounds;
147 :
148 15102 : ulong round=0;
149 75510 : for (; round<half_rounds; round++ ) {
150 60408 : fd_poseidon_apply_ark ( pos->state, width, params, round );
151 60408 : fd_poseidon_apply_sbox_full ( pos->state, width );
152 60408 : fd_poseidon_apply_mds ( pos->state, width, params );
153 60408 : }
154 :
155 924207 : for (; round<half_rounds+partial_rounds; round++ ) {
156 909105 : fd_poseidon_apply_ark ( pos->state, width, params, round );
157 909105 : fd_poseidon_apply_sbox_partial( pos->state );
158 909105 : fd_poseidon_apply_mds ( pos->state, width, params );
159 909105 : }
160 :
161 75510 : for (; round<all_rounds; round++ ) {
162 60408 : fd_poseidon_apply_ark ( pos->state, width, params, round );
163 60408 : fd_poseidon_apply_sbox_full ( pos->state, width );
164 60408 : fd_poseidon_apply_mds ( pos->state, width, params );
165 60408 : }
166 :
167 : /* Directly convert scalar into return hash buffer - hash MUST be FD_UINT256_ALIGNED */
168 15102 : fd_bn254_scalar_t scalar_hash[1];
169 15102 : fd_bn254_scalar_from_mont( scalar_hash, &pos->state[0] );
170 15102 : if( pos->big_endian ) {
171 15093 : fd_uint256_bswap( scalar_hash, scalar_hash );
172 15093 : }
173 15102 : fd_memcpy( hash, scalar_hash, 32 );
174 15102 : return hash;
175 15102 : }
|