From d35c96f05400e63871af8c2f1a3925b5d69ed654 Mon Sep 17 00:00:00 2001 From: jotabulacios <45471455+jotabulacios@users.noreply.github.com> Date: Mon, 11 Nov 2024 15:49:44 -0300 Subject: [PATCH] Add Rescue Prime Optimized (#930) * first commit * first draft, save work * first working commit, passes all tests. Save work * save work * save work * fixed padding, now all test pass * refactor * more refactor * added precomputed values for 160 security level * fix typos * fix clippy and wasm * add std feature when needed * save work, refactor and solved some comments * save work * move Mds enum and removed commented code * remove unnecessary match * removed commented code --------- Co-authored-by: Diego K <43053772+diegokingston@users.noreply.github.com> --- crypto/Cargo.toml | 14 +- crypto/src/hash/mod.rs | 1 + crypto/src/hash/rescue_prime/mod.rs | 11 + crypto/src/hash/rescue_prime/parameters.rs | 963 ++++++++++++++++++ .../rescue_prime/rescue_prime_optimized.rs | 815 +++++++++++++++ crypto/src/hash/rescue_prime/utils.rs | 78 ++ 6 files changed, 1876 insertions(+), 6 deletions(-) create mode 100644 crypto/src/hash/rescue_prime/mod.rs create mode 100644 crypto/src/hash/rescue_prime/parameters.rs create mode 100644 crypto/src/hash/rescue_prime/rescue_prime_optimized.rs create mode 100644 crypto/src/hash/rescue_prime/utils.rs diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml index 72efea7ee..45ec2caa6 100644 --- a/crypto/Cargo.toml +++ b/crypto/Cargo.toml @@ -11,9 +11,11 @@ license.workspace = true lambdaworks-math = { workspace = true, features = ["alloc"] } sha3 = { version = "0.10", default-features = false } sha2 = { version = "0.10", default-features = false } - # Optional -serde = { version = "1.0", default-features = false, features = ["derive", "alloc"], optional = true } +serde = { version = "1.0", default-features = false, features = [ + "derive", + "alloc", +], optional = true } rayon = { version = "1.8.0", optional = true } [dev-dependencies] @@ -40,9 +42,9 @@ name = "iai_merkle" harness = false [[bench]] -name= "criterion_poseidon" -harness=false +name = "criterion_poseidon" +harness = false [[bench]] -name= "criterion_pedersen" -harness=false +name = "criterion_pedersen" +harness = false diff --git a/crypto/src/hash/mod.rs b/crypto/src/hash/mod.rs index 630903112..ad9e21a1c 100644 --- a/crypto/src/hash/mod.rs +++ b/crypto/src/hash/mod.rs @@ -2,4 +2,5 @@ pub mod hash_to_field; pub mod monolith; pub mod pedersen; pub mod poseidon; +pub mod rescue_prime; pub mod sha3; diff --git a/crypto/src/hash/rescue_prime/mod.rs b/crypto/src/hash/rescue_prime/mod.rs new file mode 100644 index 000000000..c68be4b8a --- /dev/null +++ b/crypto/src/hash/rescue_prime/mod.rs @@ -0,0 +1,11 @@ +mod parameters; +mod rescue_prime_optimized; +mod utils; + +pub use rescue_prime_optimized::MdsMethod; +pub use rescue_prime_optimized::RescuePrimeOptimized; + +use lambdaworks_math::field::element::FieldElement; +use lambdaworks_math::field::fields::u64_goldilocks_field::Goldilocks64Field; + +pub type Fp = FieldElement; diff --git a/crypto/src/hash/rescue_prime/parameters.rs b/crypto/src/hash/rescue_prime/parameters.rs new file mode 100644 index 000000000..d091d8962 --- /dev/null +++ b/crypto/src/hash/rescue_prime/parameters.rs @@ -0,0 +1,963 @@ +use super::Fp; +pub const ALPHA: u64 = 7; +pub const ALPHA_INV: u64 = 10540996611094048183; + +// Constants obtained using the paper implementation in Sage +// https://github.com/ASDiscreteMathematics/rpo/tree/master/reference_implementation + +// Constants for the 128-bit security level +pub const MDS_VECTOR_128: [Fp; 12] = [ + Fp::const_from_raw(7), + Fp::const_from_raw(23), + Fp::const_from_raw(8), + Fp::const_from_raw(26), + Fp::const_from_raw(13), + Fp::const_from_raw(10), + Fp::const_from_raw(9), + Fp::const_from_raw(7), + Fp::const_from_raw(6), + Fp::const_from_raw(22), + Fp::const_from_raw(21), + Fp::const_from_raw(8), +]; +pub const ROUND_CONSTANTS_128: [Fp; 168] = [ + Fp::const_from_raw(5789762306288267392), + Fp::const_from_raw(6522564764413701783), + Fp::const_from_raw(17809893479458208203), + Fp::const_from_raw(107145243989736508), + Fp::const_from_raw(6388978042437517382), + Fp::const_from_raw(15844067734406016715), + Fp::const_from_raw(9975000513555218239), + Fp::const_from_raw(3344984123768313364), + Fp::const_from_raw(9959189626657347191), + Fp::const_from_raw(12960773468763563665), + Fp::const_from_raw(9602914297752488475), + Fp::const_from_raw(16657542370200465908), + Fp::const_from_raw(6077062762357204287), + Fp::const_from_raw(15277620170502011191), + Fp::const_from_raw(5358738125714196705), + Fp::const_from_raw(14233283787297595718), + Fp::const_from_raw(13792579614346651365), + Fp::const_from_raw(11614812331536767105), + Fp::const_from_raw(14871063686742261166), + Fp::const_from_raw(10148237148793043499), + Fp::const_from_raw(4457428952329675767), + Fp::const_from_raw(15590786458219172475), + Fp::const_from_raw(10063319113072092615), + Fp::const_from_raw(14200078843431360086), + Fp::const_from_raw(12987190162843096997), + Fp::const_from_raw(653957632802705281), + Fp::const_from_raw(4441654670647621225), + Fp::const_from_raw(4038207883745915761), + Fp::const_from_raw(5613464648874830118), + Fp::const_from_raw(13222989726778338773), + Fp::const_from_raw(3037761201230264149), + Fp::const_from_raw(16683759727265180203), + Fp::const_from_raw(8337364536491240715), + Fp::const_from_raw(3227397518293416448), + Fp::const_from_raw(8110510111539674682), + Fp::const_from_raw(2872078294163232137), + Fp::const_from_raw(6202948458916099932), + Fp::const_from_raw(17690140365333231091), + Fp::const_from_raw(3595001575307484651), + Fp::const_from_raw(373995945117666487), + Fp::const_from_raw(1235734395091296013), + Fp::const_from_raw(14172757457833931602), + Fp::const_from_raw(707573103686350224), + Fp::const_from_raw(15453217512188187135), + Fp::const_from_raw(219777875004506018), + Fp::const_from_raw(17876696346199469008), + Fp::const_from_raw(17731621626449383378), + Fp::const_from_raw(2897136237748376248), + Fp::const_from_raw(18072785500942327487), + Fp::const_from_raw(6200974112677013481), + Fp::const_from_raw(17682092219085884187), + Fp::const_from_raw(10599526828986756440), + Fp::const_from_raw(975003873302957338), + Fp::const_from_raw(8264241093196931281), + Fp::const_from_raw(10065763900435475170), + Fp::const_from_raw(2181131744534710197), + Fp::const_from_raw(6317303992309418647), + Fp::const_from_raw(1401440938888741532), + Fp::const_from_raw(8884468225181997494), + Fp::const_from_raw(13066900325715521532), + Fp::const_from_raw(8023374565629191455), + Fp::const_from_raw(15013690343205953430), + Fp::const_from_raw(4485500052507912973), + Fp::const_from_raw(12489737547229155153), + Fp::const_from_raw(9500452585969030576), + Fp::const_from_raw(2054001340201038870), + Fp::const_from_raw(12420704059284934186), + Fp::const_from_raw(355990932618543755), + Fp::const_from_raw(9071225051243523860), + Fp::const_from_raw(12766199826003448536), + Fp::const_from_raw(9045979173463556963), + Fp::const_from_raw(12934431667190679898), + Fp::const_from_raw(5674685213610121970), + Fp::const_from_raw(5759084860419474071), + Fp::const_from_raw(13943282657648897737), + Fp::const_from_raw(1352748651966375394), + Fp::const_from_raw(17110913224029905221), + Fp::const_from_raw(1003883795902368422), + Fp::const_from_raw(4141870621881018291), + Fp::const_from_raw(8121410972417424656), + Fp::const_from_raw(14300518605864919529), + Fp::const_from_raw(13712227150607670181), + Fp::const_from_raw(17021852944633065291), + Fp::const_from_raw(6252096473787587650), + Fp::const_from_raw(18389244934624494276), + Fp::const_from_raw(16731736864863925227), + Fp::const_from_raw(4440209734760478192), + Fp::const_from_raw(17208448209698888938), + Fp::const_from_raw(8739495587021565984), + Fp::const_from_raw(17000774922218161967), + Fp::const_from_raw(13533282547195532087), + Fp::const_from_raw(525402848358706231), + Fp::const_from_raw(16987541523062161972), + Fp::const_from_raw(5466806524462797102), + Fp::const_from_raw(14512769585918244983), + Fp::const_from_raw(10973956031244051118), + Fp::const_from_raw(4887609836208846458), + Fp::const_from_raw(3027115137917284492), + Fp::const_from_raw(9595098600469470675), + Fp::const_from_raw(10528569829048484079), + Fp::const_from_raw(7864689113198939815), + Fp::const_from_raw(17533723827845969040), + Fp::const_from_raw(5781638039037710951), + Fp::const_from_raw(17024078752430719006), + Fp::const_from_raw(109659393484013511), + Fp::const_from_raw(7158933660534805869), + Fp::const_from_raw(2955076958026921730), + Fp::const_from_raw(7433723648458773977), + Fp::const_from_raw(6982293561042362913), + Fp::const_from_raw(14065426295947720331), + Fp::const_from_raw(16451845770444974180), + Fp::const_from_raw(7139138592091306727), + Fp::const_from_raw(9012006439959783127), + Fp::const_from_raw(14619614108529063361), + Fp::const_from_raw(1394813199588124371), + Fp::const_from_raw(4635111139507788575), + Fp::const_from_raw(16217473952264203365), + Fp::const_from_raw(10782018226466330683), + Fp::const_from_raw(6844229992533662050), + Fp::const_from_raw(7446486531695178711), + Fp::const_from_raw(16308865189192447297), + Fp::const_from_raw(11977192855656444890), + Fp::const_from_raw(12532242556065780287), + Fp::const_from_raw(14594890931430968898), + Fp::const_from_raw(7291784239689209784), + Fp::const_from_raw(5514718540551361949), + Fp::const_from_raw(10025733853830934803), + Fp::const_from_raw(7293794580341021693), + Fp::const_from_raw(6728552937464861756), + Fp::const_from_raw(6332385040983343262), + Fp::const_from_raw(13277683694236792804), + Fp::const_from_raw(2600778905124452676), + Fp::const_from_raw(3736792340494631448), + Fp::const_from_raw(577852220195055341), + Fp::const_from_raw(6689998335515779805), + Fp::const_from_raw(13886063479078013492), + Fp::const_from_raw(14358505101923202168), + Fp::const_from_raw(7744142531772274164), + Fp::const_from_raw(16135070735728404443), + Fp::const_from_raw(12290902521256031137), + Fp::const_from_raw(12059913662657709804), + Fp::const_from_raw(16456018495793751911), + Fp::const_from_raw(4571485474751953524), + Fp::const_from_raw(17200392109565783176), + Fp::const_from_raw(7123075680859040534), + Fp::const_from_raw(1034205548717903090), + Fp::const_from_raw(7717824418247931797), + Fp::const_from_raw(3019070937878604058), + Fp::const_from_raw(11403792746066867460), + Fp::const_from_raw(10280580802233112374), + Fp::const_from_raw(337153209462421218), + Fp::const_from_raw(13333398568519923717), + Fp::const_from_raw(3596153696935337464), + Fp::const_from_raw(8104208463525993784), + Fp::const_from_raw(14345062289456085693), + Fp::const_from_raw(17036731477169661256), + Fp::const_from_raw(17130398059294018733), + Fp::const_from_raw(519782857322261988), + Fp::const_from_raw(9625384390925085478), + Fp::const_from_raw(1664893052631119222), + Fp::const_from_raw(7629576092524553570), + Fp::const_from_raw(3485239601103661425), + Fp::const_from_raw(9755891797164033838), + Fp::const_from_raw(15218148195153269027), + Fp::const_from_raw(16460604813734957368), + Fp::const_from_raw(9643968136937729763), + Fp::const_from_raw(3611348709641382851), + Fp::const_from_raw(18256379591337759196), +]; + +pub const MDS_MATRIX_128: [[Fp; 12]; 12] = [ + [ + Fp::const_from_raw(7), + Fp::const_from_raw(23), + Fp::const_from_raw(8), + Fp::const_from_raw(26), + Fp::const_from_raw(13), + Fp::const_from_raw(10), + Fp::const_from_raw(9), + Fp::const_from_raw(7), + Fp::const_from_raw(6), + Fp::const_from_raw(22), + Fp::const_from_raw(21), + Fp::const_from_raw(8), + ], + [ + Fp::const_from_raw(8), + Fp::const_from_raw(7), + Fp::const_from_raw(23), + Fp::const_from_raw(8), + Fp::const_from_raw(26), + Fp::const_from_raw(13), + Fp::const_from_raw(10), + Fp::const_from_raw(9), + Fp::const_from_raw(7), + Fp::const_from_raw(6), + Fp::const_from_raw(22), + Fp::const_from_raw(21), + ], + [ + Fp::const_from_raw(21), + Fp::const_from_raw(8), + Fp::const_from_raw(7), + Fp::const_from_raw(23), + Fp::const_from_raw(8), + Fp::const_from_raw(26), + Fp::const_from_raw(13), + Fp::const_from_raw(10), + Fp::const_from_raw(9), + Fp::const_from_raw(7), + Fp::const_from_raw(6), + Fp::const_from_raw(22), + ], + [ + Fp::const_from_raw(22), + Fp::const_from_raw(21), + Fp::const_from_raw(8), + Fp::const_from_raw(7), + Fp::const_from_raw(23), + Fp::const_from_raw(8), + Fp::const_from_raw(26), + Fp::const_from_raw(13), + Fp::const_from_raw(10), + Fp::const_from_raw(9), + Fp::const_from_raw(7), + Fp::const_from_raw(6), + ], + [ + Fp::const_from_raw(6), + Fp::const_from_raw(22), + Fp::const_from_raw(21), + Fp::const_from_raw(8), + Fp::const_from_raw(7), + Fp::const_from_raw(23), + Fp::const_from_raw(8), + Fp::const_from_raw(26), + Fp::const_from_raw(13), + Fp::const_from_raw(10), + Fp::const_from_raw(9), + Fp::const_from_raw(7), + ], + [ + Fp::const_from_raw(7), + Fp::const_from_raw(6), + Fp::const_from_raw(22), + Fp::const_from_raw(21), + Fp::const_from_raw(8), + Fp::const_from_raw(7), + Fp::const_from_raw(23), + Fp::const_from_raw(8), + Fp::const_from_raw(26), + Fp::const_from_raw(13), + Fp::const_from_raw(10), + Fp::const_from_raw(9), + ], + [ + Fp::const_from_raw(9), + Fp::const_from_raw(7), + Fp::const_from_raw(6), + Fp::const_from_raw(22), + Fp::const_from_raw(21), + Fp::const_from_raw(8), + Fp::const_from_raw(7), + Fp::const_from_raw(23), + Fp::const_from_raw(8), + Fp::const_from_raw(26), + Fp::const_from_raw(13), + Fp::const_from_raw(10), + ], + [ + Fp::const_from_raw(10), + Fp::const_from_raw(9), + Fp::const_from_raw(7), + Fp::const_from_raw(6), + Fp::const_from_raw(22), + Fp::const_from_raw(21), + Fp::const_from_raw(8), + Fp::const_from_raw(7), + Fp::const_from_raw(23), + Fp::const_from_raw(8), + Fp::const_from_raw(26), + Fp::const_from_raw(13), + ], + [ + Fp::const_from_raw(13), + Fp::const_from_raw(10), + Fp::const_from_raw(9), + Fp::const_from_raw(7), + Fp::const_from_raw(6), + Fp::const_from_raw(22), + Fp::const_from_raw(21), + Fp::const_from_raw(8), + Fp::const_from_raw(7), + Fp::const_from_raw(23), + Fp::const_from_raw(8), + Fp::const_from_raw(26), + ], + [ + Fp::const_from_raw(26), + Fp::const_from_raw(13), + Fp::const_from_raw(10), + Fp::const_from_raw(9), + Fp::const_from_raw(7), + Fp::const_from_raw(6), + Fp::const_from_raw(22), + Fp::const_from_raw(21), + Fp::const_from_raw(8), + Fp::const_from_raw(7), + Fp::const_from_raw(23), + Fp::const_from_raw(8), + ], + [ + Fp::const_from_raw(8), + Fp::const_from_raw(26), + Fp::const_from_raw(13), + Fp::const_from_raw(10), + Fp::const_from_raw(9), + Fp::const_from_raw(7), + Fp::const_from_raw(6), + Fp::const_from_raw(22), + Fp::const_from_raw(21), + Fp::const_from_raw(8), + Fp::const_from_raw(7), + Fp::const_from_raw(23), + ], + [ + Fp::const_from_raw(23), + Fp::const_from_raw(8), + Fp::const_from_raw(26), + Fp::const_from_raw(13), + Fp::const_from_raw(10), + Fp::const_from_raw(9), + Fp::const_from_raw(7), + Fp::const_from_raw(6), + Fp::const_from_raw(22), + Fp::const_from_raw(21), + Fp::const_from_raw(8), + Fp::const_from_raw(7), + ], +]; + +// Constants for the 160-bit security level + +pub const MDS_VECTOR_160: [Fp; 16] = [ + Fp::const_from_raw(256), + Fp::const_from_raw(2), + Fp::const_from_raw(1073741824), + Fp::const_from_raw(2048), + Fp::const_from_raw(16777216), + Fp::const_from_raw(128), + Fp::const_from_raw(8), + Fp::const_from_raw(16), + Fp::const_from_raw(524288), + Fp::const_from_raw(4194304), + Fp::const_from_raw(1), + Fp::const_from_raw(268435456), + Fp::const_from_raw(1), + Fp::const_from_raw(1024), + Fp::const_from_raw(2), + Fp::const_from_raw(8192), +]; + +pub const ROUND_CONSTANTS_160: [Fp; 224] = [ + Fp::const_from_raw(1965335827333385572), + Fp::const_from_raw(13386940263093285890), + Fp::const_from_raw(2676433512518024499), + Fp::const_from_raw(3265387569419834752), + Fp::const_from_raw(1983410871005483133), + Fp::const_from_raw(9697282293408698131), + Fp::const_from_raw(1272774544215511539), + Fp::const_from_raw(8206289606243220511), + Fp::const_from_raw(1290391036756663400), + Fp::const_from_raw(18219831014774660739), + Fp::const_from_raw(9691367064095402927), + Fp::const_from_raw(1323942862844130786), + Fp::const_from_raw(15151407902520044968), + Fp::const_from_raw(3367241195349533752), + Fp::const_from_raw(4045613938354522492), + Fp::const_from_raw(8414577515806306591), + Fp::const_from_raw(12735791373473705278), + Fp::const_from_raw(3301196190123345788), + Fp::const_from_raw(4934538150586227609), + Fp::const_from_raw(3817643842607407527), + Fp::const_from_raw(13416431558822898318), + Fp::const_from_raw(5832629091408730901), + Fp::const_from_raw(3362368740314001033), + Fp::const_from_raw(11092906639494490385), + Fp::const_from_raw(6071859273097876791), + Fp::const_from_raw(10161425034618716356), + Fp::const_from_raw(7152209120756903545), + Fp::const_from_raw(16380870469663741149), + Fp::const_from_raw(3952136951542576078), + Fp::const_from_raw(17537441052343611097), + Fp::const_from_raw(11551242553047556263), + Fp::const_from_raw(10106900133850428740), + Fp::const_from_raw(11416650542216810040), + Fp::const_from_raw(11422270812969046329), + Fp::const_from_raw(8866991719313052084), + Fp::const_from_raw(11055863001411088108), + Fp::const_from_raw(6180770262849183127), + Fp::const_from_raw(15065904341621422463), + Fp::const_from_raw(6379231142859676194), + Fp::const_from_raw(12898133478008807755), + Fp::const_from_raw(17022976567648776965), + Fp::const_from_raw(9092326911543756291), + Fp::const_from_raw(6030122978628466915), + Fp::const_from_raw(9597034755157312926), + Fp::const_from_raw(994741965321505508), + Fp::const_from_raw(7556490651023083151), + Fp::const_from_raw(13471961853484783473), + Fp::const_from_raw(5530500298270693480), + Fp::const_from_raw(3138602747749119790), + Fp::const_from_raw(14959768162492908516), + Fp::const_from_raw(9134218270579160311), + Fp::const_from_raw(11526344086740032769), + Fp::const_from_raw(18056157006815181954), + Fp::const_from_raw(6800589288408907691), + Fp::const_from_raw(15936640138392473876), + Fp::const_from_raw(2300163192580995689), + Fp::const_from_raw(4526841916921293676), + Fp::const_from_raw(7195881155996340935), + Fp::const_from_raw(2785483023916634674), + Fp::const_from_raw(15081468567893261932), + Fp::const_from_raw(6614707290651872269), + Fp::const_from_raw(13681365294828420351), + Fp::const_from_raw(10664658542323360702), + Fp::const_from_raw(10084964797450915045), + Fp::const_from_raw(4845198022119750202), + Fp::const_from_raw(2607866667643628253), + Fp::const_from_raw(5208104371714885253), + Fp::const_from_raw(12959011109386888563), + Fp::const_from_raw(4000466944391262442), + Fp::const_from_raw(17728719744160665330), + Fp::const_from_raw(7150641948246037689), + Fp::const_from_raw(9776810486328380322), + Fp::const_from_raw(8402715679168885485), + Fp::const_from_raw(3121448252217290414), + Fp::const_from_raw(17436789549778885163), + Fp::const_from_raw(15165907014487612788), + Fp::const_from_raw(11269595316481578714), + Fp::const_from_raw(9914651255870961898), + Fp::const_from_raw(12689101348845299684), + Fp::const_from_raw(11975655653136929369), + Fp::const_from_raw(7372192115875804252), + Fp::const_from_raw(374526648312709133), + Fp::const_from_raw(5985220408386061330), + Fp::const_from_raw(7185802228951619536), + Fp::const_from_raw(1399294693953396201), + Fp::const_from_raw(3261364014951657316), + Fp::const_from_raw(12077409443637692420), + Fp::const_from_raw(9673650825325087603), + Fp::const_from_raw(5569045552142119082), + Fp::const_from_raw(17617312550416673451), + Fp::const_from_raw(6211450796053144311), + Fp::const_from_raw(11274862073326008409), + Fp::const_from_raw(18367233290057731659), + Fp::const_from_raw(13198876392118957255), + Fp::const_from_raw(13272050586507026767), + Fp::const_from_raw(13010781901687851463), + Fp::const_from_raw(11176896862794321170), + Fp::const_from_raw(6638609153583434674), + Fp::const_from_raw(14505835809704498565), + Fp::const_from_raw(17581684280975726513), + Fp::const_from_raw(699795237352602006), + Fp::const_from_raw(9944038704239459812), + Fp::const_from_raw(8047212797227008956), + Fp::const_from_raw(1395744870455664103), + Fp::const_from_raw(18357515964980248812), + Fp::const_from_raw(9097466431298056431), + Fp::const_from_raw(14710664890151992774), + Fp::const_from_raw(6629781383077611287), + Fp::const_from_raw(17573797615501516970), + Fp::const_from_raw(12347664633647440814), + Fp::const_from_raw(11021709264172808686), + Fp::const_from_raw(10955032358008028206), + Fp::const_from_raw(12827014260928926472), + Fp::const_from_raw(14274600229400487385), + Fp::const_from_raw(12031986599882032134), + Fp::const_from_raw(16154104676212634613), + Fp::const_from_raw(18132152994017433356), + Fp::const_from_raw(15441239634310983499), + Fp::const_from_raw(10976597099491887044), + Fp::const_from_raw(3707145841124002094), + Fp::const_from_raw(8720928559638383045), + Fp::const_from_raw(16336200500310468906), + Fp::const_from_raw(6210805750383775651), + Fp::const_from_raw(7719884621977079797), + Fp::const_from_raw(11449042012956416425), + Fp::const_from_raw(9075619080551251971), + Fp::const_from_raw(617668424765806231), + Fp::const_from_raw(12270348236411784037), + Fp::const_from_raw(6186113401837024523), + Fp::const_from_raw(15458192282022704662), + Fp::const_from_raw(3533646002027882636), + Fp::const_from_raw(7323750725122298699), + Fp::const_from_raw(17370102587019252090), + Fp::const_from_raw(1740987243995377904), + Fp::const_from_raw(10219908189144498973), + Fp::const_from_raw(1822464913426161699), + Fp::const_from_raw(13340330593340428766), + Fp::const_from_raw(11476413915876641735), + Fp::const_from_raw(10301877462024259119), + Fp::const_from_raw(17003473479205724655), + Fp::const_from_raw(10899885430087119072), + Fp::const_from_raw(2161571014943847810), + Fp::const_from_raw(10337649388059569402), + Fp::const_from_raw(1627927149280118935), + Fp::const_from_raw(981019442244479500), + Fp::const_from_raw(8080861373146567887), + Fp::const_from_raw(8033636340692269807), + Fp::const_from_raw(1747076424940820198), + Fp::const_from_raw(15430102639810276278), + Fp::const_from_raw(9286420248392647962), + Fp::const_from_raw(11497964697936588530), + Fp::const_from_raw(17639509337065865628), + Fp::const_from_raw(2160917583540985983), + Fp::const_from_raw(6735220140815683510), + Fp::const_from_raw(6183237619116523957), + Fp::const_from_raw(13347893983048485379), + Fp::const_from_raw(4087545433624195113), + Fp::const_from_raw(11701648626105993864), + Fp::const_from_raw(11913677089736238784), + Fp::const_from_raw(271004950317860287), + Fp::const_from_raw(11794070108002091165), + Fp::const_from_raw(15639064309077629849), + Fp::const_from_raw(16481734838884572560), + Fp::const_from_raw(3932918848577657311), + Fp::const_from_raw(16327200574281469287), + Fp::const_from_raw(7060041503065075033), + Fp::const_from_raw(4892761442718320741), + Fp::const_from_raw(8255275116206368067), + Fp::const_from_raw(14957838536671021552), + Fp::const_from_raw(14493715972468567436), + Fp::const_from_raw(7463718209809697261), + Fp::const_from_raw(3440982266989812843), + Fp::const_from_raw(2354199421703013492), + Fp::const_from_raw(2321628279578256047), + Fp::const_from_raw(3746041501354899488), + Fp::const_from_raw(11186576936873825301), + Fp::const_from_raw(15218587616061641074), + Fp::const_from_raw(11844784525417523222), + Fp::const_from_raw(7998727848169056055), + Fp::const_from_raw(7948968711630609066), + Fp::const_from_raw(11805042600408037937), + Fp::const_from_raw(18172588443872800894), + Fp::const_from_raw(13092373363317372568), + Fp::const_from_raw(2169983441195298580), + Fp::const_from_raw(1499680808057735775), + Fp::const_from_raw(7077486803310915643), + Fp::const_from_raw(743612288630452727), + Fp::const_from_raw(11665426394426065172), + Fp::const_from_raw(15533499373769144802), + Fp::const_from_raw(14249183160150274240), + Fp::const_from_raw(13792290235996127743), + Fp::const_from_raw(4995017088228886738), + Fp::const_from_raw(9763845271226970122), + Fp::const_from_raw(1727820159257625458), + Fp::const_from_raw(9681902124347643227), + Fp::const_from_raw(11327574568051933160), + Fp::const_from_raw(10627429556158481577), + Fp::const_from_raw(13984143774797145216), + Fp::const_from_raw(17082059622058840713), + Fp::const_from_raw(16264233536802058333), + Fp::const_from_raw(10077962488096645822), + Fp::const_from_raw(5057253598123536060), + Fp::const_from_raw(2301672207952647376), + Fp::const_from_raw(17506877517896521554), + Fp::const_from_raw(14583366393971011156), + Fp::const_from_raw(6226877164823354372), + Fp::const_from_raw(2260055134098203623), + Fp::const_from_raw(12945296184826522120), + Fp::const_from_raw(15417698598606677168), + Fp::const_from_raw(7447949755934804788), + Fp::const_from_raw(8017843736725863212), + Fp::const_from_raw(1003688007091182795), + Fp::const_from_raw(8935767355090348282), + Fp::const_from_raw(793319158990348431), + Fp::const_from_raw(4437923789992338287), + Fp::const_from_raw(7869978205237541489), + Fp::const_from_raw(9039403419111053092), + Fp::const_from_raw(3845065612997771849), + Fp::const_from_raw(15179573672801872590), + Fp::const_from_raw(2879645310341005490), + Fp::const_from_raw(4421001170561580576), + Fp::const_from_raw(7614461260369642079), + Fp::const_from_raw(10869617590371203777), + Fp::const_from_raw(4582902440098948914), +]; + +pub const MDS_MATRIX_160: [[Fp; 16]; 16] = [ + [ + Fp::const_from_raw(256), + Fp::const_from_raw(2), + Fp::const_from_raw(1073741824), + Fp::const_from_raw(2048), + Fp::const_from_raw(16777216), + Fp::const_from_raw(128), + Fp::const_from_raw(8), + Fp::const_from_raw(16), + Fp::const_from_raw(524288), + Fp::const_from_raw(4194304), + Fp::const_from_raw(1), + Fp::const_from_raw(268435456), + Fp::const_from_raw(1), + Fp::const_from_raw(1024), + Fp::const_from_raw(2), + Fp::const_from_raw(8192), + ], + [ + Fp::const_from_raw(8192), + Fp::const_from_raw(256), + Fp::const_from_raw(2), + Fp::const_from_raw(1073741824), + Fp::const_from_raw(2048), + Fp::const_from_raw(16777216), + Fp::const_from_raw(128), + Fp::const_from_raw(8), + Fp::const_from_raw(16), + Fp::const_from_raw(524288), + Fp::const_from_raw(4194304), + Fp::const_from_raw(1), + Fp::const_from_raw(268435456), + Fp::const_from_raw(1), + Fp::const_from_raw(1024), + Fp::const_from_raw(2), + ], + [ + Fp::const_from_raw(2), + Fp::const_from_raw(8192), + Fp::const_from_raw(256), + Fp::const_from_raw(2), + Fp::const_from_raw(1073741824), + Fp::const_from_raw(2048), + Fp::const_from_raw(16777216), + Fp::const_from_raw(128), + Fp::const_from_raw(8), + Fp::const_from_raw(16), + Fp::const_from_raw(524288), + Fp::const_from_raw(4194304), + Fp::const_from_raw(1), + Fp::const_from_raw(268435456), + Fp::const_from_raw(1), + Fp::const_from_raw(1024), + ], + [ + Fp::const_from_raw(1024), + Fp::const_from_raw(2), + Fp::const_from_raw(8192), + Fp::const_from_raw(256), + Fp::const_from_raw(2), + Fp::const_from_raw(1073741824), + Fp::const_from_raw(2048), + Fp::const_from_raw(16777216), + Fp::const_from_raw(128), + Fp::const_from_raw(8), + Fp::const_from_raw(16), + Fp::const_from_raw(524288), + Fp::const_from_raw(4194304), + Fp::const_from_raw(1), + Fp::const_from_raw(268435456), + Fp::const_from_raw(1), + ], + [ + Fp::const_from_raw(1), + Fp::const_from_raw(1024), + Fp::const_from_raw(2), + Fp::const_from_raw(8192), + Fp::const_from_raw(256), + Fp::const_from_raw(2), + Fp::const_from_raw(1073741824), + Fp::const_from_raw(2048), + Fp::const_from_raw(16777216), + Fp::const_from_raw(128), + Fp::const_from_raw(8), + Fp::const_from_raw(16), + Fp::const_from_raw(524288), + Fp::const_from_raw(4194304), + Fp::const_from_raw(1), + Fp::const_from_raw(268435456), + ], + [ + Fp::const_from_raw(268435456), + Fp::const_from_raw(1), + Fp::const_from_raw(1024), + Fp::const_from_raw(2), + Fp::const_from_raw(8192), + Fp::const_from_raw(256), + Fp::const_from_raw(2), + Fp::const_from_raw(1073741824), + Fp::const_from_raw(2048), + Fp::const_from_raw(16777216), + Fp::const_from_raw(128), + Fp::const_from_raw(8), + Fp::const_from_raw(16), + Fp::const_from_raw(524288), + Fp::const_from_raw(4194304), + Fp::const_from_raw(1), + ], + [ + Fp::const_from_raw(1), + Fp::const_from_raw(268435456), + Fp::const_from_raw(1), + Fp::const_from_raw(1024), + Fp::const_from_raw(2), + Fp::const_from_raw(8192), + Fp::const_from_raw(256), + Fp::const_from_raw(2), + Fp::const_from_raw(1073741824), + Fp::const_from_raw(2048), + Fp::const_from_raw(16777216), + Fp::const_from_raw(128), + Fp::const_from_raw(8), + Fp::const_from_raw(16), + Fp::const_from_raw(524288), + Fp::const_from_raw(4194304), + ], + [ + Fp::const_from_raw(4194304), + Fp::const_from_raw(1), + Fp::const_from_raw(268435456), + Fp::const_from_raw(1), + Fp::const_from_raw(1024), + Fp::const_from_raw(2), + Fp::const_from_raw(8192), + Fp::const_from_raw(256), + Fp::const_from_raw(2), + Fp::const_from_raw(1073741824), + Fp::const_from_raw(2048), + Fp::const_from_raw(16777216), + Fp::const_from_raw(128), + Fp::const_from_raw(8), + Fp::const_from_raw(16), + Fp::const_from_raw(524288), + ], + [ + Fp::const_from_raw(524288), + Fp::const_from_raw(4194304), + Fp::const_from_raw(1), + Fp::const_from_raw(268435456), + Fp::const_from_raw(1), + Fp::const_from_raw(1024), + Fp::const_from_raw(2), + Fp::const_from_raw(8192), + Fp::const_from_raw(256), + Fp::const_from_raw(2), + Fp::const_from_raw(1073741824), + Fp::const_from_raw(2048), + Fp::const_from_raw(16777216), + Fp::const_from_raw(128), + Fp::const_from_raw(8), + Fp::const_from_raw(16), + ], + [ + Fp::const_from_raw(16), + Fp::const_from_raw(524288), + Fp::const_from_raw(4194304), + Fp::const_from_raw(1), + Fp::const_from_raw(268435456), + Fp::const_from_raw(1), + Fp::const_from_raw(1024), + Fp::const_from_raw(2), + Fp::const_from_raw(8192), + Fp::const_from_raw(256), + Fp::const_from_raw(2), + Fp::const_from_raw(1073741824), + Fp::const_from_raw(2048), + Fp::const_from_raw(16777216), + Fp::const_from_raw(128), + Fp::const_from_raw(8), + ], + [ + Fp::const_from_raw(8), + Fp::const_from_raw(16), + Fp::const_from_raw(524288), + Fp::const_from_raw(4194304), + Fp::const_from_raw(1), + Fp::const_from_raw(268435456), + Fp::const_from_raw(1), + Fp::const_from_raw(1024), + Fp::const_from_raw(2), + Fp::const_from_raw(8192), + Fp::const_from_raw(256), + Fp::const_from_raw(2), + Fp::const_from_raw(1073741824), + Fp::const_from_raw(2048), + Fp::const_from_raw(16777216), + Fp::const_from_raw(128), + ], + [ + Fp::const_from_raw(128), + Fp::const_from_raw(8), + Fp::const_from_raw(16), + Fp::const_from_raw(524288), + Fp::const_from_raw(4194304), + Fp::const_from_raw(1), + Fp::const_from_raw(268435456), + Fp::const_from_raw(1), + Fp::const_from_raw(1024), + Fp::const_from_raw(2), + Fp::const_from_raw(8192), + Fp::const_from_raw(256), + Fp::const_from_raw(2), + Fp::const_from_raw(1073741824), + Fp::const_from_raw(2048), + Fp::const_from_raw(16777216), + ], + [ + Fp::const_from_raw(16777216), + Fp::const_from_raw(128), + Fp::const_from_raw(8), + Fp::const_from_raw(16), + Fp::const_from_raw(524288), + Fp::const_from_raw(4194304), + Fp::const_from_raw(1), + Fp::const_from_raw(268435456), + Fp::const_from_raw(1), + Fp::const_from_raw(1024), + Fp::const_from_raw(2), + Fp::const_from_raw(8192), + Fp::const_from_raw(256), + Fp::const_from_raw(2), + Fp::const_from_raw(1073741824), + Fp::const_from_raw(2048), + ], + [ + Fp::const_from_raw(2048), + Fp::const_from_raw(16777216), + Fp::const_from_raw(128), + Fp::const_from_raw(8), + Fp::const_from_raw(16), + Fp::const_from_raw(524288), + Fp::const_from_raw(4194304), + Fp::const_from_raw(1), + Fp::const_from_raw(268435456), + Fp::const_from_raw(1), + Fp::const_from_raw(1024), + Fp::const_from_raw(2), + Fp::const_from_raw(8192), + Fp::const_from_raw(256), + Fp::const_from_raw(2), + Fp::const_from_raw(1073741824), + ], + [ + Fp::const_from_raw(1073741824), + Fp::const_from_raw(2048), + Fp::const_from_raw(16777216), + Fp::const_from_raw(128), + Fp::const_from_raw(8), + Fp::const_from_raw(16), + Fp::const_from_raw(524288), + Fp::const_from_raw(4194304), + Fp::const_from_raw(1), + Fp::const_from_raw(268435456), + Fp::const_from_raw(1), + Fp::const_from_raw(1024), + Fp::const_from_raw(2), + Fp::const_from_raw(8192), + Fp::const_from_raw(256), + Fp::const_from_raw(2), + ], + [ + Fp::const_from_raw(2), + Fp::const_from_raw(1073741824), + Fp::const_from_raw(2048), + Fp::const_from_raw(16777216), + Fp::const_from_raw(128), + Fp::const_from_raw(8), + Fp::const_from_raw(16), + Fp::const_from_raw(524288), + Fp::const_from_raw(4194304), + Fp::const_from_raw(1), + Fp::const_from_raw(268435456), + Fp::const_from_raw(1), + Fp::const_from_raw(1024), + Fp::const_from_raw(2), + Fp::const_from_raw(8192), + Fp::const_from_raw(256), + ], +]; + +#[derive(Clone)] +pub enum SecurityLevel { + Sec128, + Sec160, +} + +pub fn get_state_size(security_level: &SecurityLevel) -> usize { + match security_level { + SecurityLevel::Sec128 => 12, + SecurityLevel::Sec160 => 16, + } +} + +pub fn get_capacity(security_level: &SecurityLevel) -> usize { + match security_level { + SecurityLevel::Sec128 => 4, + SecurityLevel::Sec160 => 6, + } +} + +pub fn get_round_constants(level: &SecurityLevel) -> &'static [Fp] { + match level { + SecurityLevel::Sec128 => &ROUND_CONSTANTS_128, + SecurityLevel::Sec160 => &ROUND_CONSTANTS_160, + } +} + +pub enum MdsVector { + Mds128([Fp; 12]), + Mds160([Fp; 16]), +} + +pub fn get_mds_vector(level: SecurityLevel) -> MdsVector { + match level { + SecurityLevel::Sec128 => MdsVector::Mds128(MDS_VECTOR_128), + SecurityLevel::Sec160 => MdsVector::Mds160(MDS_VECTOR_160), + } +} + +#[allow(clippy::large_enum_variant)] +pub enum MdsMatrix { + Mds128([[Fp; 12]; 12]), + Mds160([[Fp; 16]; 16]), +} + +pub fn get_mds_matrix(level: &SecurityLevel) -> MdsMatrix { + match level { + SecurityLevel::Sec128 => MdsMatrix::Mds128(MDS_MATRIX_128), + SecurityLevel::Sec160 => MdsMatrix::Mds160(MDS_MATRIX_160), + } +} + +impl MdsVector { + pub fn as_slice(&self) -> &[Fp] { + match self { + MdsVector::Mds128(ref vec) => vec, + MdsVector::Mds160(ref vec) => vec, + } + } +} diff --git a/crypto/src/hash/rescue_prime/rescue_prime_optimized.rs b/crypto/src/hash/rescue_prime/rescue_prime_optimized.rs new file mode 100644 index 000000000..6ecf86f2b --- /dev/null +++ b/crypto/src/hash/rescue_prime/rescue_prime_optimized.rs @@ -0,0 +1,815 @@ +use super::parameters::*; +use super::utils::*; +use super::Fp; +use crate::alloc::vec::Vec; +use core::iter; +use lambdaworks_math::field::errors::FieldError; + +// Implementation of the Rescue Prime Optimized hash function. +// https://eprint.iacr.org/2022/1577 +// https://github.com/ASDiscreteMathematics/rpo/tree/master/reference_implementation +// It supports two security levels: 128-bit and 160-bit. Depending on the security level chosen +// the integer parameters are set accordingly. + +// For the Security level (λ) of 128 bits we have: +// Number of rounds (N): 7 +// State size (m): 12 +// Rate (r): 8 +// Capacity (c): 4 + +// For the Security level (λ) of 160 bits we have: +// Number of rounds (N): 7 +// State size (m): 16 +// Rate (r): 10 +// Capacity (c): 6 + +// In the paper, the authors use a number of rounds equal to 7 as a trade-off between security and performance. +// The number of rounds can be increased to 8 or 9 to achieve a higher level of security at the cost of performance. +const NUM_FULL_ROUNDS: usize = 7; + +pub struct RescuePrimeOptimized { + /// State width of the hash function. + m: usize, + /// Capacity of the sponge. + capacity: usize, + /// Rate of the sponge. + rate: usize, + /// Precomputed round constants used in the permutation. + round_constants: &'static [Fp], + /// MDS matrix used in the permutation. + mds_matrix: Vec>, + /// MDS vector used for optimizing matrix multiplication. + mds_vector: MdsVector, + /// Method used for applying the MDS matrix. + mds_method: MdsMethod, +} + +impl Default for RescuePrimeOptimized { + fn default() -> Self { + Self::new(SecurityLevel::Sec128, MdsMethod::MatrixMultiplication).unwrap() + } +} + +impl RescuePrimeOptimized { + /// Creates a new instance of `RescuePrimeOptimized` with corresponding Security level and the specified MDS method. + pub fn new(security_level: SecurityLevel, mds_method: MdsMethod) -> Result { + let m = get_state_size(&security_level); + let capacity = get_capacity(&security_level); + let rate = m - capacity; + let mds_matrix = get_mds_matrix(&security_level); + let round_constants = get_round_constants(&security_level); + let mds_vector = get_mds_vector(security_level); + Ok(Self { + m, + capacity, + rate, + round_constants, + mds_matrix: match mds_matrix { + MdsMatrix::Mds128(matrix) => matrix.iter().map(|&row| row.to_vec()).collect(), + MdsMatrix::Mds160(matrix) => matrix.iter().map(|&row| row.to_vec()).collect(), + }, + mds_vector, + mds_method, + }) + } + + /// Applies the inverse S-box to the state. + pub fn apply_inverse_sbox(state: &mut [Fp]) { + for x in state.iter_mut() { + *x = x.pow(ALPHA_INV); + } + } + + /// Applies the S-box to the state. + pub fn apply_sbox(state: &mut [Fp]) { + for x in state.iter_mut() { + *x = x.pow(ALPHA); + } + } + + /// Performs MDS matrix-vector multiplication. + fn mds_matrix_vector_multiplication(&self, state: &[Fp]) -> Vec { + let m = state.len(); + let mut new_state = vec![Fp::zero(); m]; + + for (i, new_value) in new_state.iter_mut().enumerate() { + for (j, state_value) in state.iter().enumerate() { + *new_value += self.mds_matrix[i][j] * state_value; + } + } + + new_state + } + + /// Performs MDS using Number Theoretic Transform. + fn mds_ntt(&self, state: &[Fp]) -> Result, FieldError> { + let m = state.len(); + let omega = if m == 12 { + Fp::from(281474976645120u64) + } else { + Fp::from(17293822564807737345u64) + }; + let mds_vector = self.mds_vector.as_slice(); + + let mds_ntt = ntt(mds_vector, omega); + let state_rev: Vec = iter::once(state[0]) + .chain(state[1..].iter().rev().cloned()) + .collect(); + let state_ntt = ntt(&state_rev, omega); + + let mut product_ntt = vec![Fp::zero(); m]; + for i in 0..m { + product_ntt[i] = mds_ntt[i] * state_ntt[i]; + } + + let omega_inv = omega.inv()?; + let result = intt(&product_ntt, omega_inv)?; + + Ok(iter::once(result[0]) + .chain(result[1..].iter().rev().cloned()) + .collect()) + } + + /// Performs MDS using the Karatsuba algorithm. + fn mds_karatsuba(&self, state: &[Fp]) -> Vec { + let m = state.len(); + let mds_vector = self.mds_vector.as_slice(); + let mds_rev: Vec = iter::once(mds_vector[0]) + .chain(mds_vector[1..].iter().rev().cloned()) + .collect(); + + let conv = karatsuba(&mds_rev, state); + + let mut result = vec![Fp::zero(); m]; + result[..m].copy_from_slice(&conv[..m]); + for i in m..conv.len() { + result[i - m] += conv[i]; + } + + result + } + + /// Applies the MDS transformation to the state. + fn apply_mds(&self, state: &mut [Fp]) -> Result<(), FieldError> { + let new_state = match self.mds_method { + MdsMethod::MatrixMultiplication => self.mds_matrix_vector_multiplication(state), + MdsMethod::Ntt => self.mds_ntt(state)?, + MdsMethod::Karatsuba => self.mds_karatsuba(state), + }; + state.copy_from_slice(&new_state); + Ok(()) + } + + /// Adds the round constants to the state. + fn add_round_constants(&self, state: &mut [Fp], round: usize) { + let m = self.m; + let round_constants = &self.round_constants[round * 2 * m..]; + + state + .iter_mut() + .zip(round_constants.iter()) + .take(m) + .for_each(|(state_elem, &constant)| { + *state_elem += constant; + }); + } + + /// Adds the second set of round constants to the state. + fn add_round_constants_second(&self, state: &mut [Fp], round: usize) { + let m = self.m; + let round_constants = &self.round_constants[round * 2 * m + m..]; + + state + .iter_mut() + .zip(round_constants.iter()) + .take(m) + .for_each(|(state_elem, &constant)| { + *state_elem += constant; + }); + } + + /// Performs the full permutation on the state. + pub fn permutation(&self, state: &mut [Fp]) { + let num_rounds = NUM_FULL_ROUNDS; + for round in 0..num_rounds { + let _ = self.apply_mds(state); + self.add_round_constants(state, round); + Self::apply_sbox(state); + let _ = self.apply_mds(state); + self.add_round_constants_second(state, round); + Self::apply_inverse_sbox(state); + } + } + + /// Hashes an input sequence of field elements. + pub fn hash(&self, input_sequence: &[Fp]) -> Vec { + let mut state = vec![Fp::zero(); self.m]; + let input_len = input_sequence.len(); + if input_len % self.rate != 0 { + state[0] = Fp::one(); + } + let num_full_chunks = input_len / self.rate; + for i in 0..num_full_chunks { + let chunk = &input_sequence[i * self.rate..(i + 1) * self.rate]; + state[self.capacity..(self.rate + self.capacity)].copy_from_slice(&chunk[..self.rate]); + self.permutation(&mut state); + } + let last_chunk_size = input_len % self.rate; + if last_chunk_size != 0 { + let mut last_chunk = vec![Fp::zero(); self.rate]; + for j in 0..last_chunk_size { + last_chunk[j] = input_sequence[num_full_chunks * self.rate + j]; + } + last_chunk[last_chunk_size] = Fp::one(); + state[self.capacity..(self.rate + self.capacity)] + .copy_from_slice(&last_chunk[..self.rate]); + self.permutation(&mut state); + } + + state[self.capacity..self.capacity + self.rate / 2].to_vec() + } + + /// Hashes an input sequence of bytes. + pub fn hash_bytes(&self, input: &[u8]) -> Vec { + let field_elements = bytes_to_field_elements(input); + self.hash(&field_elements) + } +} +#[derive(Clone)] +pub enum MdsMethod { + /// Use standard matrix multiplication. + MatrixMultiplication, + /// Use Number Theoretic Transform for multiplication. + Ntt, + /// Use Karatsuba algorithm for multiplication. + Karatsuba, +} +#[cfg(test)] +mod tests { + use super::*; + use rand::rngs::StdRng; + use rand::{Rng, SeedableRng}; + + // Values obtained from the Sage implemenstation in + // https://github.com/ASDiscreteMathematics/rpo/tree/master/reference_implementation + pub const EXPECTED_128: [[Fp; 4]; 19] = [ + [ + Fp::const_from_raw(1502364727743950833u64), + Fp::const_from_raw(5880949717274681448u64), + Fp::const_from_raw(162790463902224431u64), + Fp::const_from_raw(6901340476773664264u64), + ], + [ + Fp::const_from_raw(7478710183745780580u64), + Fp::const_from_raw(3308077307559720969u64), + Fp::const_from_raw(3383561985796182409u64), + Fp::const_from_raw(17205078494700259815u64), + ], + [ + Fp::const_from_raw(17439912364295172999u64), + Fp::const_from_raw(17979156346142712171u64), + Fp::const_from_raw(8280795511427637894u64), + Fp::const_from_raw(9349844417834368814u64), + ], + [ + Fp::const_from_raw(5105868198472766874u64), + Fp::const_from_raw(13090564195691924742u64), + Fp::const_from_raw(1058904296915798891u64), + Fp::const_from_raw(18379501748825152268u64), + ], + [ + Fp::const_from_raw(9133662113608941286u64), + Fp::const_from_raw(12096627591905525991u64), + Fp::const_from_raw(14963426595993304047u64), + Fp::const_from_raw(13290205840019973377u64), + ], + [ + Fp::const_from_raw(3134262397541159485u64), + Fp::const_from_raw(10106105871979362399u64), + Fp::const_from_raw(138768814855329459u64), + Fp::const_from_raw(15044809212457404677u64), + ], + [ + Fp::const_from_raw(162696376578462826u64), + Fp::const_from_raw(4991300494838863586u64), + Fp::const_from_raw(660346084748120605u64), + Fp::const_from_raw(13179389528641752698u64), + ], + [ + Fp::const_from_raw(2242391899857912644u64), + Fp::const_from_raw(12689382052053305418u64), + Fp::const_from_raw(235236990017815546u64), + Fp::const_from_raw(5046143039268215739u64), + ], + [ + Fp::const_from_raw(9585630502158073976u64), + Fp::const_from_raw(1310051013427303477u64), + Fp::const_from_raw(7491921222636097758u64), + Fp::const_from_raw(9417501558995216762u64), + ], + [ + Fp::const_from_raw(1994394001720334744u64), + Fp::const_from_raw(10866209900885216467u64), + Fp::const_from_raw(13836092831163031683u64), + Fp::const_from_raw(10814636682252756697u64), + ], + [ + Fp::const_from_raw(17486854790732826405u64), + Fp::const_from_raw(17376549265955727562u64), + Fp::const_from_raw(2371059831956435003u64), + Fp::const_from_raw(17585704935858006533u64), + ], + [ + Fp::const_from_raw(11368277489137713825u64), + Fp::const_from_raw(3906270146963049287u64), + Fp::const_from_raw(10236262408213059745u64), + Fp::const_from_raw(78552867005814007u64), + ], + [ + Fp::const_from_raw(17899847381280262181u64), + Fp::const_from_raw(14717912805498651446u64), + Fp::const_from_raw(10769146203951775298u64), + Fp::const_from_raw(2774289833490417856u64), + ], + [ + Fp::const_from_raw(3794717687462954368u64), + Fp::const_from_raw(4386865643074822822u64), + Fp::const_from_raw(8854162840275334305u64), + Fp::const_from_raw(7129983987107225269u64), + ], + [ + Fp::const_from_raw(7244773535611633983u64), + Fp::const_from_raw(19359923075859320u64), + Fp::const_from_raw(10898655967774994333u64), + Fp::const_from_raw(9319339563065736480u64), + ], + [ + Fp::const_from_raw(4935426252518736883u64), + Fp::const_from_raw(12584230452580950419u64), + Fp::const_from_raw(8762518969632303998u64), + Fp::const_from_raw(18159875708229758073u64), + ], + [ + Fp::const_from_raw(14871230873837295931u64), + Fp::const_from_raw(11225255908868362971u64), + Fp::const_from_raw(18100987641405432308u64), + Fp::const_from_raw(1559244340089644233u64), + ], + [ + Fp::const_from_raw(8348203744950016968u64), + Fp::const_from_raw(4041411241960726733u64), + Fp::const_from_raw(17584743399305468057u64), + Fp::const_from_raw(16836952610803537051u64), + ], + [ + Fp::const_from_raw(16139797453633030050u64), + Fp::const_from_raw(1090233424040889412u64), + Fp::const_from_raw(10770255347785669036u64), + Fp::const_from_raw(16982398877290254028u64), + ], + ]; + + pub const EXPECTED_160: [[Fp; 5]; 19] = [ + [ + Fp::const_from_raw(4766737105427868572), + Fp::const_from_raw(7538777753317835226), + Fp::const_from_raw(13644171984579649606), + Fp::const_from_raw(6748107971891460622), + Fp::const_from_raw(3480072938342119934), + ], + [ + Fp::const_from_raw(6277287777617382937), + Fp::const_from_raw(5688033921803605355), + Fp::const_from_raw(1104978478612014217), + Fp::const_from_raw(973672476085279574), + Fp::const_from_raw(7883652116413797779), + ], + [ + Fp::const_from_raw(3071553803427093579), + Fp::const_from_raw(12239501990998925662), + Fp::const_from_raw(14411295652479845526), + Fp::const_from_raw(5735407824213194294), + Fp::const_from_raw(6714816738691504270), + ], + [ + Fp::const_from_raw(4455998568145007624), + Fp::const_from_raw(18218360213084301612), + Fp::const_from_raw(8963555484142424669), + Fp::const_from_raw(13451196299356019287), + Fp::const_from_raw(660967320761434775), + ], + [ + Fp::const_from_raw(7894041400531553560), + Fp::const_from_raw(3138084719322472990), + Fp::const_from_raw(15017675162298246509), + Fp::const_from_raw(12340633143623038238), + Fp::const_from_raw(3710158928968726190), + ], + [ + Fp::const_from_raw(18345924309197503617), + Fp::const_from_raw(6448668044176965096), + Fp::const_from_raw(5891298758878861437), + Fp::const_from_raw(18404292940273103487), + Fp::const_from_raw(399715742058360811), + ], + [ + Fp::const_from_raw(4293522863608749708), + Fp::const_from_raw(11352999694211746044), + Fp::const_from_raw(15850245073570756600), + Fp::const_from_raw(1206950096837096206), + Fp::const_from_raw(6945598368659615878), + ], + [ + Fp::const_from_raw(1339949574743034442), + Fp::const_from_raw(5967452101017112419), + Fp::const_from_raw(824612579975542151), + Fp::const_from_raw(3327557828938393394), + Fp::const_from_raw(14113149399665697150), + ], + [ + Fp::const_from_raw(3540904694808418824), + Fp::const_from_raw(5951416386790014715), + Fp::const_from_raw(13859113410786779774), + Fp::const_from_raw(17205554479494520251), + Fp::const_from_raw(7359323608260195110), + ], + [ + Fp::const_from_raw(7504301802792161339), + Fp::const_from_raw(12879743137663115497), + Fp::const_from_raw(17245986604042562042), + Fp::const_from_raw(8175050867418132561), + Fp::const_from_raw(1063965910664731268), + ], + [ + Fp::const_from_raw(18267475461736255602), + Fp::const_from_raw(4481864641736940956), + Fp::const_from_raw(11260039501101148638), + Fp::const_from_raw(7529970948767692955), + Fp::const_from_raw(4177810888704753150), + ], + [ + Fp::const_from_raw(16604116128892623566), + Fp::const_from_raw(1520851983040290492), + Fp::const_from_raw(9361704524730297620), + Fp::const_from_raw(7447748879766268839), + Fp::const_from_raw(10834422028571028806), + ], + [ + Fp::const_from_raw(243957224918814907), + Fp::const_from_raw(9966149007214472697), + Fp::const_from_raw(18130816682404489504), + Fp::const_from_raw(3814760895598122151), + Fp::const_from_raw(862573500652233787), + ], + [ + Fp::const_from_raw(13414343823130474877), + Fp::const_from_raw(1002887112060795246), + Fp::const_from_raw(16685735965176892618), + Fp::const_from_raw(16172309857128312555), + Fp::const_from_raw(5158081519803147178), + ], + [ + Fp::const_from_raw(14614132925482133961), + Fp::const_from_raw(7618082792229868740), + Fp::const_from_raw(1881720834768448253), + Fp::const_from_raw(11508391877383996679), + Fp::const_from_raw(5348386073072413261), + ], + [ + Fp::const_from_raw(6268111131988518030), + Fp::const_from_raw(17920308297240232909), + Fp::const_from_raw(17719152474870950965), + Fp::const_from_raw(14857432101092580778), + Fp::const_from_raw(5708937553833180778), + ], + [ + Fp::const_from_raw(11597726741964198121), + Fp::const_from_raw(1568026444559423552), + Fp::const_from_raw(3233218961458461983), + Fp::const_from_raw(9700509409081014876), + Fp::const_from_raw(7989061413164577390), + ], + [ + Fp::const_from_raw(11180580619692834182), + Fp::const_from_raw(16871004730930134181), + Fp::const_from_raw(17810700669516829599), + Fp::const_from_raw(13679692060051982328), + Fp::const_from_raw(10386085719330760064), + ], + [ + Fp::const_from_raw(6222872143719551583), + Fp::const_from_raw(3842704143974291265), + Fp::const_from_raw(18311432727968603639), + Fp::const_from_raw(12278517700025439333), + Fp::const_from_raw(7011953052853282225), + ], + ]; + fn rand_field_element(rng: &mut R) -> Fp { + Fp::from(rng.gen::()) + } + + #[test] + fn test_apply_sbox() { + let mut rng = StdRng::seed_from_u64(1); + let rescue = + RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::MatrixMultiplication) + .unwrap(); + let mut state: Vec = (0..rescue.m) + .map(|_| rand_field_element(&mut rng)) + .collect(); + + let mut expected = state.clone(); + expected.iter_mut().for_each(|v| *v = v.pow(ALPHA)); + + RescuePrimeOptimized::apply_sbox(&mut state); + assert_eq!(expected, state); + } + + #[test] + fn test_apply_inverse_sbox() { + let mut rng = StdRng::seed_from_u64(2); + let rescue = + RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::MatrixMultiplication) + .unwrap(); + let mut state: Vec = (0..rescue.m) + .map(|_| rand_field_element(&mut rng)) + .collect(); + + let mut expected = state.clone(); + expected.iter_mut().for_each(|v| *v = v.pow(ALPHA_INV)); + + RescuePrimeOptimized::apply_inverse_sbox(&mut state); + assert_eq!(expected, state); + } + + #[test] + fn test_mds_matrix_multiplication() { + let mut rng = StdRng::seed_from_u64(3); + let rescue = + RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::MatrixMultiplication) + .unwrap(); + let state: Vec = (0..rescue.m) + .map(|_| rand_field_element(&mut rng)) + .collect(); + + let expected_state = rescue.mds_matrix_vector_multiplication(&state); + let mut computed_state = state.clone(); + let _ = rescue.apply_mds(&mut computed_state); + + assert_eq!(expected_state, computed_state); + } + + #[test] + fn test_mds_ntt() { + let mut rng = StdRng::seed_from_u64(4); + let rescue_ntt = RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::Ntt).unwrap(); + let state: Vec = (0..rescue_ntt.m) + .map(|_| rand_field_element(&mut rng)) + .collect(); + + let expected_state = rescue_ntt.mds_ntt(&state).unwrap(); + let mut computed_state = state.clone(); + let _ = rescue_ntt.apply_mds(&mut computed_state); + + assert_eq!(expected_state, computed_state); + } + + #[test] + fn test_mds_karatsuba() { + let mut rng = StdRng::seed_from_u64(5); + let rescue_karatsuba = + RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::Karatsuba).unwrap(); + let state: Vec = (0..rescue_karatsuba.m) + .map(|_| rand_field_element(&mut rng)) + .collect(); + + let expected_state = rescue_karatsuba.mds_karatsuba(&state); + let mut computed_state = state.clone(); + let _ = rescue_karatsuba.apply_mds(&mut computed_state); + + assert_eq!(expected_state, computed_state); + } + + #[test] + fn test_add_round_constants() { + let mut rng = StdRng::seed_from_u64(6); + let rescue = + RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::MatrixMultiplication) + .unwrap(); + let mut state: Vec = (0..rescue.m) + .map(|_| rand_field_element(&mut rng)) + .collect(); + + let round = 0; + let expected_state = state + .iter() + .enumerate() + .map(|(i, &x)| x + rescue.round_constants[round * 2 * rescue.m + i]) + .collect::>(); + + rescue.add_round_constants(&mut state, round); + + assert_eq!(expected_state, state); + } + + #[test] + fn test_permutation() { + let mut rng = StdRng::seed_from_u64(7); + let rescue = + RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::MatrixMultiplication) + .unwrap(); + let mut state: Vec = (0..rescue.m) + .map(|_| rand_field_element(&mut rng)) + .collect(); + + let expected_state = { + let mut temp_state = state.clone(); + for round in 0..7 { + let _ = rescue.apply_mds(&mut temp_state); + rescue.add_round_constants(&mut temp_state, round); + RescuePrimeOptimized::apply_sbox(&mut temp_state); + let _ = rescue.apply_mds(&mut temp_state); + rescue.add_round_constants_second(&mut temp_state, round); + RescuePrimeOptimized::apply_inverse_sbox(&mut temp_state); + } + temp_state + }; + + rescue.permutation(&mut state); + + assert_eq!(expected_state, state); + } + + #[test] + fn test_hash_single_chunk() { + let rescue = + RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::MatrixMultiplication) + .unwrap(); + let input_sequence: Vec = (0..8).map(Fp::from).collect(); + let hash_output = rescue.hash(&input_sequence); + + assert_eq!(hash_output.len(), 4); + } + + #[test] + fn test_hash_multiple_chunks() { + let rescue = + RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::MatrixMultiplication) + .unwrap(); + let input_sequence: Vec = (0..16).map(Fp::from).collect(); // Two chunks of size 8 + let hash_output = rescue.hash(&input_sequence); + + assert_eq!(hash_output.len(), 4); + } + + #[test] + fn test_hash_with_padding() { + let rescue = + RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::MatrixMultiplication) + .unwrap(); + let input_sequence: Vec = (0..5).map(Fp::from).collect(); + let hash_output = rescue.hash(&input_sequence); + assert_eq!(hash_output.len(), 4); + } + #[test] + // test ported from https://github.com/0xPolygonMiden/crypto/blob/main/src/hash/rescue/rpo/tests.rs + fn hash_padding() { + let rescue = + RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::MatrixMultiplication) + .unwrap(); + + let input1 = vec![1u8, 2, 3]; + let input2 = vec![1u8, 2, 3, 0]; + let hash1 = rescue.hash_bytes(&input1); + let hash2 = rescue.hash_bytes(&input2); + assert_ne!(hash1, hash2); + + let input1 = vec![1_u8, 2, 3, 4, 5, 6]; + let input2 = vec![1_u8, 2, 3, 4, 5, 6, 0]; + let hash1 = rescue.hash_bytes(&input1); + let hash2 = rescue.hash_bytes(&input2); + assert_ne!(hash1, hash2); + + let input1 = vec![1_u8, 2, 3, 4, 5, 6, 7, 0, 0]; + let input2 = vec![1_u8, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0]; + let hash1 = rescue.hash_bytes(&input1); + let hash2 = rescue.hash_bytes(&input2); + assert_ne!(hash1, hash2); + } + #[cfg(feature = "std")] + #[test] + fn sponge_zeroes_collision() { + let rescue = + RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::MatrixMultiplication) + .unwrap(); + + let mut zeroes = Vec::new(); + let mut hashes = std::collections::HashSet::new(); + + for _ in 0..255 { + let hash = rescue.hash(&zeroes); + assert!(hashes.insert(hash)); + zeroes.push(Fp::zero()); + } + } + #[test] + fn test_hash_bytes() { + let rescue = + RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::MatrixMultiplication) + .unwrap(); + let input_bytes = b"Rescue Prime Optimized"; + let hash_output = rescue.hash_bytes(input_bytes); + + assert_eq!(hash_output.len(), 4); + } + + #[test] + fn test_mds_methods_consistency() { + let rescue_matrix = + RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::MatrixMultiplication) + .unwrap(); + let rescue_ntt = RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::Ntt).unwrap(); + let rescue_karatsuba = + RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::Karatsuba).unwrap(); + + let input = vec![ + Fp::from(1u64), + Fp::from(2u64), + Fp::from(3u64), + Fp::from(4u64), + Fp::from(5u64), + Fp::from(6u64), + Fp::from(7u64), + Fp::from(8u64), + Fp::from(9u64), + ]; + + let hash_matrix = rescue_matrix.hash(&input); + let hash_ntt = rescue_ntt.hash(&input); + let hash_karatsuba = rescue_karatsuba.hash(&input); + + assert_eq!(hash_matrix, hash_ntt); + assert_eq!(hash_ntt, hash_karatsuba); + } + + #[test] + fn test_hash_vectors_128() { + let rescue = + RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::MatrixMultiplication) + .unwrap(); + let elements: Vec = (0..19).map(Fp::from).collect(); + + EXPECTED_128.iter().enumerate().for_each(|(i, expected)| { + let input = elements.iter().take(i + 1); + let hash_output = rescue.hash(input.cloned().collect::>().as_slice()); + + assert_eq!( + hash_output, + *expected, + "Hash mismatch for input length {}", + i + 1 + ); + }); + } + #[test] + fn test_hash_vector_160() { + let rescue = + RescuePrimeOptimized::new(SecurityLevel::Sec160, MdsMethod::MatrixMultiplication) + .unwrap(); + let elements: Vec = (0..19).map(Fp::from).collect(); + + EXPECTED_160.iter().enumerate().for_each(|(i, expected)| { + let input = elements.iter().take(i + 1); + let hash_output = rescue.hash(input.cloned().collect::>().as_slice()); + + assert_eq!( + hash_output, + *expected, + "Hash mismatch for input length {}", + i + 1 + ); + }); + } + #[cfg(feature = "std")] + #[test] + fn test_hash_example_and_print() { + let rescue = RescuePrimeOptimized::new(SecurityLevel::Sec128, MdsMethod::Ntt).unwrap(); + + let input = b"Hello there"; + + let hash_result = rescue.hash_bytes(input); + + println!("Input: {:?}", input); + println!("Hash result:"); + for (i, value) in hash_result.iter().enumerate() { + println!(" {}: {}", i, value); + } + + println!("Hash as u64 values:"); + for value in hash_result.iter() { + print!("{}, ", value.value()); + } + println!(); + assert_eq!(hash_result.len(), 4); + } +} diff --git a/crypto/src/hash/rescue_prime/utils.rs b/crypto/src/hash/rescue_prime/utils.rs new file mode 100644 index 000000000..ba17341bc --- /dev/null +++ b/crypto/src/hash/rescue_prime/utils.rs @@ -0,0 +1,78 @@ +use super::Fp; +use alloc::vec::Vec; +use lambdaworks_math::field::errors::FieldError; + +// Auxiliary algorithms based on the reference implementation in Sage +// https://github.com/ASDiscreteMathematics/rpo/tree/master/reference_implementation + +pub fn bytes_to_field_elements(input: &[u8]) -> Vec { + input + .chunks(7) + .map(|chunk| { + let mut buf = [0u8; 8]; + buf[..chunk.len()].copy_from_slice(chunk); + if chunk.len() < 7 { + buf[chunk.len()] = 1; + } + let value = u64::from_le_bytes(buf); + Fp::from(value) + }) + .collect() +} + +pub fn ntt(input: &[Fp], omega: Fp) -> Vec { + (0..input.len()) + .map(|i| { + input.iter().enumerate().fold(Fp::zero(), |acc, (j, val)| { + acc + *val * omega.pow((i * j) as u64) + }) + }) + .collect() +} + +pub fn intt(input: &[Fp], omega_inv: Fp) -> Result, FieldError> { + let n = input.len() as u64; + let inv_n = Fp::from(n).inv()?; + let transformed = ntt(input, omega_inv); + Ok(transformed.into_iter().map(|val| val * inv_n).collect()) +} + +pub fn karatsuba(lhs: &[Fp], rhs: &[Fp]) -> Vec { + let n = lhs.len(); + if n <= 32 { + let mut result = vec![Fp::zero(); 2 * n - 1]; + lhs.iter().enumerate().for_each(|(i, &lhs_val)| { + rhs.iter().enumerate().for_each(|(j, &rhs_val)| { + result[i + j] += lhs_val * rhs_val; + }); + }); + return result; + } + + let half = n / 2; + let (lhs_low, lhs_high) = lhs.split_at(half); + let (rhs_low, rhs_high) = rhs.split_at(half); + + let z0 = karatsuba(lhs_low, rhs_low); + let z2 = karatsuba(lhs_high, rhs_high); + + let lhs_sum: Vec = lhs_low.iter().zip(lhs_high).map(|(a, b)| *a + *b).collect(); + let rhs_sum: Vec = rhs_low.iter().zip(rhs_high).map(|(a, b)| *a + *b).collect(); + + let z1 = karatsuba(&lhs_sum, &rhs_sum); + + let mut result = vec![Fp::zero(); 2 * n - 1]; + + z0.iter().enumerate().for_each(|(i, &val)| result[i] = val); + z2.iter() + .enumerate() + .for_each(|(i, &val)| result[i + 2 * half] = val); + + z1.iter().enumerate().for_each(|(i, &val)| { + result[i + half] += val + - z0.get(i).cloned().unwrap_or(Fp::zero()) + - z2.get(i).cloned().unwrap_or(Fp::zero()); + }); + + result +}