Line data Source code
1 : #ifndef HEADER_fd_src_ballet_bn254_fd_poseidon_h 2 : #define HEADER_fd_src_ballet_bn254_fd_poseidon_h 3 : 4 : /* Implementation of the Poseidon hash function over BN254 scalar field. 5 : Based on Rust light-poseidon v0.2.0: 6 : https://github.com/Lightprotocol/light-poseidon/blob/v0.2.0/light-poseidon/src/lib.rs#L377 7 : That is in turn based on Circom v2.0.x: 8 : https://github.com/iden3/circomlib/blob/v2.0.5/circuits/poseidon.circom */ 9 : 10 : #include "../fd_ballet_base.h" 11 : #include "./fd_bn254_scalar.h" 12 : 13 0 : #define FD_POSEIDON_HASH_SZ (32UL) 14 : #define FD_POSEIDON_MAX_WIDTH (12UL) 15 : 16 : /* Hash result. Actually a value in the bn254 field */ 17 : struct fd_poseidon_hash_result { 18 : uchar v[ FD_POSEIDON_HASH_SZ ]; 19 : }; 20 : typedef struct fd_poseidon_hash_result fd_poseidon_hash_result_t; 21 : 22 : struct FD_ALIGNED fd_poseidon { 23 : fd_bn254_scalar_t state[ 1+FD_POSEIDON_MAX_WIDTH ]; 24 : ulong cnt; /* How many elements have been appended total */ 25 : int big_endian; /* 0 little endian, 1 big endian */ 26 : }; 27 : typedef struct fd_poseidon fd_poseidon_t; 28 : 29 : struct fd_poseidon_par { 30 : fd_bn254_scalar_t * ark; 31 : fd_bn254_scalar_t * mds; 32 : }; 33 : typedef struct fd_poseidon_par fd_poseidon_par_t; 34 : 35 : FD_PROTOTYPES_BEGIN 36 : 37 : /* fd_poseidon_init starts a Poseidon calculation. 38 : pos is assumed to be a current local join to a Poseidon calculation 39 : state with no other concurrent operation that would modify the state 40 : while this is executing. Any preexisting state for an in-progress or 41 : recently completed calculation will be discarded. 42 : if big_endian>0 treats all inputs (append) and output (fini) as big endian, 43 : otherwise treats them all as little endian. 44 : Returns pos (on return, pos will have the state of a new in-progress 45 : calculation). */ 46 : 47 : fd_poseidon_t * 48 : fd_poseidon_init( fd_poseidon_t * pos, 49 : int const big_endian ); 50 : 51 : /* fd_poseidon_append adds sz bytes locally pointed to by data an 52 : in-progress Poseidon calculation. 53 : out is assumed to be valid (i.e. is a current local join to a Poseidon 54 : calculation state with no other concurrent operations that would modify 55 : the state while this is executing). out==NULL is ok to allow chaining: 56 : fd_poseidon_append( fd_poseidon_append( ... ) ) 57 : data points to the first of the sz bytes, and will be unmodified while 58 : this is running with no interest retained after return (data==NULL is fine if sz==0). 59 : data represents a bn254 scalar, i.e. a 256-bit bigint modulo a prime. 60 : If data is not exactly 32-byte long (sz!=32), then data is padded with 0s 61 : during conversion. 62 : Returns out on success, NULL in case of error: 63 : - if pos==NULL 64 : - if data >= modulus (including sz > 32) 65 : - if fd_poseidon_append is called more than 12 times on the same pos 66 : 67 : Note: unlike other hash functions, each call to fd_poseidon_append 68 : attempts to append a new scalar to the current state. 69 : This implementation is modeled around Rust light-poseidon, that in 70 : turn is modeled around Circom implementation. 71 : It supports hashing a max of FD_POSEIDON_MAX_WIDTH elements. */ 72 : 73 : fd_poseidon_t * 74 : fd_poseidon_append( fd_poseidon_t * pos, 75 : uchar const * data, 76 : ulong sz ); 77 : 78 : /* fd_poseidon_fini finishes a Poseidon calculation. 79 : out is assumed to be valid (i.e. is a current local join to a Poseidon 80 : calculation state with no other concurrent operations that would modify 81 : the state while this is executing). out==NULL is ok to allow chaining: 82 : fd_poseidon_fini( fd_poseidon_append( ... ) ) 83 : hash points to the first byte of a 32-byte memory region where the 84 : result of the calculation should be stored. 85 : Returns hash, or NULL if pos==NULL (on return, there will be no calculation 86 : in-progress on pos and 32-byte buffer pointed to by hash will be populated 87 : with the calculation result). */ 88 : 89 : uchar * 90 : fd_poseidon_fini( fd_poseidon_t * pos, 91 : uchar hash[ FD_POSEIDON_HASH_SZ ] ); 92 : 93 : /* Hash a series of bytes. */ 94 : static inline int 95 : fd_poseidon_hash( fd_poseidon_hash_result_t * result, 96 : uchar const * bytes, 97 : ulong bytes_len, 98 0 : int const big_endian ) { 99 0 : fd_poseidon_t pos[1]; 100 0 : fd_poseidon_init( pos, big_endian ); 101 0 : for( ulong i=0; i<bytes_len/32; i++ ) { 102 0 : fd_poseidon_append( pos, &bytes[i*32], 32 ); 103 0 : } 104 0 : return !fd_poseidon_fini( pos, fd_type_pun(result) ); 105 0 : } 106 : 107 : FD_PROTOTYPES_END 108 : 109 : #endif /* HEADER_fd_src_ballet_bn254_fd_poseidon_h */