diff --git a/.gitmodules b/.gitmodules index b7cb5924..e47105ca 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,3 @@ -[submodule "rln/vendor/rln"] - path = rln/vendor/rln - ignore = dirty - url = https://github.com/Rate-Limiting-Nullifier/rln_circuits.git [submodule "semaphore/vendor/semaphore"] path = semaphore/vendor/semaphore ignore = dirty diff --git a/rln-wasm/tests/rln-wasm.rs b/rln-wasm/tests/rln-wasm.rs index 7be4e025..a4f29a84 100644 --- a/rln-wasm/tests/rln-wasm.rs +++ b/rln-wasm/tests/rln-wasm.rs @@ -3,8 +3,9 @@ #[cfg(test)] mod tests { use js_sys::{BigInt as JsBigInt, Object, Uint8Array}; - use rln::circuit::TEST_TREE_HEIGHT; - use rln::utils::normalize_usize; + use rln::circuit::{Fr, TEST_TREE_HEIGHT}; + use rln::hashers::{hash_to_field, poseidon_hash}; + use rln::utils::{bytes_le_to_fr, fr_to_bytes_le, normalize_usize}; use rln_wasm::*; use wasm_bindgen::{prelude::*, JsValue}; use wasm_bindgen_test::wasm_bindgen_test; @@ -33,26 +34,40 @@ mod tests { // Creating membership key let mem_keys = wasm_key_gen(rln_instance).unwrap(); - let idkey = mem_keys.subarray(0, 32); - let idcommitment = mem_keys.subarray(32, 64); - - // Insert PK - wasm_set_next_leaf(rln_instance, idcommitment).unwrap(); + let id_key = mem_keys.subarray(0, 32); + let id_commitment = mem_keys.subarray(32, 64); // Prepare the message - let signal = "Hello World".as_bytes(); - - // Setting up the epoch (With 0s for the test) - let epoch = Uint8Array::new_with_length(32); - epoch.fill(0, 0, 32); + let signal = b"Hello World"; let identity_index: usize = 0; + // Setting up the epoch and rln_identifier + let epoch = hash_to_field(b"test-epoch"); + let rln_identifier = hash_to_field(b"test-rln-identifier"); + + let external_nullifier = poseidon_hash(&[epoch, rln_identifier]); + let external_nullifier = fr_to_bytes_le(&external_nullifier); + + let user_message_limit = Fr::from(100); + let message_id = fr_to_bytes_le(&Fr::from(0)); + + let (id_commitment_fr, _) = bytes_le_to_fr(&id_commitment.to_vec()[..]); + let rate_commitment = poseidon_hash(&[id_commitment_fr, user_message_limit]); + + // Insert PK + wasm_set_next_leaf( + rln_instance, + Uint8Array::from(fr_to_bytes_le(&rate_commitment).as_slice()), + ) + .unwrap(); // Serializing the message let mut serialized_vec: Vec = Vec::new(); - serialized_vec.append(&mut idkey.to_vec()); + serialized_vec.append(&mut id_key.to_vec()); serialized_vec.append(&mut normalize_usize(identity_index)); - serialized_vec.append(&mut epoch.to_vec()); + serialized_vec.append(&mut fr_to_bytes_le(&user_message_limit).to_vec()); + serialized_vec.append(&mut message_id.to_vec()); + serialized_vec.append(&mut external_nullifier.to_vec()); serialized_vec.append(&mut normalize_usize(signal.len())); serialized_vec.append(&mut signal.to_vec()); let serialized_message = Uint8Array::from(&serialized_vec[..]); @@ -112,7 +127,6 @@ mod tests { #[wasm_bindgen_test] fn test_metadata() { let tree_height = TEST_TREE_HEIGHT; - let circom_path = format!("../rln/resources/tree_height_{TEST_TREE_HEIGHT}/rln.wasm"); let zkey_path = format!("../rln/resources/tree_height_{TEST_TREE_HEIGHT}/rln_final.zkey"); let vk_path = format!("../rln/resources/tree_height_{TEST_TREE_HEIGHT}/verification_key.json"); @@ -122,7 +136,6 @@ mod tests { // Creating an instance of RLN let rln_instance = wasm_new(tree_height, zkey, vk).unwrap(); - let test_metadata = Uint8Array::new(&JsValue::from_str("test")); // Inserting random metadata wasm_set_metadata(rln_instance, test_metadata.clone()).unwrap(); diff --git a/rln/README.md b/rln/README.md index f25470f7..fe6ae2b2 100644 --- a/rln/README.md +++ b/rln/README.md @@ -56,7 +56,7 @@ However, if `N` is too big, this might require a bigger Powers of Tau ceremony t In such case we refer to the official [Circom documentation](https://docs.circom.io/getting-started/proving-circuits/#powers-of-tau) for instructions on how to run an appropriate Powers of Tau ceremony and Phase 2 in order to compile the desired circuit. -Currently, the `rln` module comes with three [pre-compiled](https://github.com/vacp2p/zerokit/tree/master/rln/resources) RLN circuits having Merkle tree of height `15`, `19` and `20`, respectively. +Currently, the `rln` module comes with 2 [pre-compiled](https://github.com/vacp2p/zerokit/tree/master/rln/resources) RLN circuits having Merkle tree of height `20` and `32`, respectively. ## Getting started @@ -102,18 +102,20 @@ let mut buffer = Cursor::new(Vec::::new()); rln.key_gen(&mut buffer).unwrap(); // We deserialize the keygen output to obtain -// the identiy_secret and id_commitment +// the identity_secret and id_commitment let (identity_secret_hash, id_commitment) = deserialize_identity_pair(buffer.into_inner()); ``` -### Add ID commitment to the RLN Merkle tree +### Add Rate commitment to the RLN Merkle tree ```rust // We define the tree index where id_commitment will be added let id_index = 10; +let user_message_limit = 10; // We serialize id_commitment and pass it to set_leaf -let mut buffer = Cursor::new(serialize_field_element(id_commitment)); +let rate_commitment = poseidon_hash(&[id_commitment, user_message_limit]); +let mut buffer = Cursor::new(serialize_field_element(rate_commitment)); rln.set_leaf(id_index, &mut buffer).unwrap(); ``` @@ -141,11 +143,11 @@ let signal = b"RLN is awesome"; We prepare the input to the proof generation routine. -Input buffer is serialized as `[ identity_key | id_index | epoch | signal_len | signal ]`. +Input buffer is serialized as `[ identity_key | id_index | epoch | rln_identifier | user_message_limit | message_id | signal_len | signal ]`. ```rust // We prepare input to the proof generation routine -let proof_input = prepare_prove_input(identity_secret_hash, id_index, epoch, signal); +let proof_input = prepare_prove_input(identity_secret_hash, id_index, epoch, rln_identifier, user_message_limit, message_id, signal); ``` We are now ready to generate a RLN ZK proof along with the _public outputs_ of the ZK circuit evaluation. diff --git a/rln/resources/tree_height_15/rln.wasm b/rln/resources/tree_height_15/rln.wasm deleted file mode 100644 index dbbfb652..00000000 Binary files a/rln/resources/tree_height_15/rln.wasm and /dev/null differ diff --git a/rln/resources/tree_height_15/rln_final.zkey b/rln/resources/tree_height_15/rln_final.zkey deleted file mode 100644 index 89a7c381..00000000 Binary files a/rln/resources/tree_height_15/rln_final.zkey and /dev/null differ diff --git a/rln/resources/tree_height_15/verification_key.json b/rln/resources/tree_height_15/verification_key.json deleted file mode 100644 index e4bb03c8..00000000 --- a/rln/resources/tree_height_15/verification_key.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "protocol": "groth16", - "curve": "bn128", - "nPublic": 6, - "vk_alpha_1": [ - "20124996762962216725442980738609010303800849578410091356605067053491763969391", - "9118593021526896828671519912099489027245924097793322973632351264852174143923", - "1" - ], - "vk_beta_2": [ - [ - "4693952934005375501364248788849686435240706020501681709396105298107971354382", - "14346958885444710485362620645446987998958218205939139994511461437152241966681" - ], - [ - "16851772916911573982706166384196538392731905827088356034885868448550849804972", - "823612331030938060799959717749043047845343400798220427319188951998582076532" - ], - [ - "1", - "0" - ] - ], - "vk_gamma_2": [ - [ - "10857046999023057135944570762232829481370756359578518086990519993285655852781", - "11559732032986387107991004021392285783925812861821192530917403151452391805634" - ], - [ - "8495653923123431417604973247489272438418190587263600148770280649306958101930", - "4082367875863433681332203403145435568316851327593401208105741076214120093531" - ], - [ - "1", - "0" - ] - ], - "vk_delta_2": [ - [ - "1361919643088555407518565462732544232965454074504004321739078395285189557133", - "20823246840633598579879223919854294301857184404415306521912631074982696570306" - ], - [ - "7088590198103342249937795923142619828109070290720888704402714617857746884833", - "8191367139632195506244169264298620546181137131063303219908889318280111188437" - ], - [ - "1", - "0" - ] - ], - "vk_alphabeta_12": [ - [ - [ - "12608968655665301215455851857466367636344427685631271961542642719683786103711", - "9849575605876329747382930567422916152871921500826003490242628251047652318086" - ], - [ - "6322029441245076030714726551623552073612922718416871603535535085523083939021", - "8700115492541474338049149013125102281865518624059015445617546140629435818912" - ], - [ - "10674973475340072635573101639867487770811074181475255667220644196793546640210", - "2926286967251299230490668407790788696102889214647256022788211245826267484824" - ] - ], - [ - [ - "9660441540778523475944706619139394922744328902833875392144658911530830074820", - "19548113127774514328631808547691096362144426239827206966690021428110281506546" - ], - [ - "1870837942477655969123169532603615788122896469891695773961478956740992497097", - "12536105729661705698805725105036536744930776470051238187456307227425796690780" - ], - [ - "21811903352654147452884857281720047789720483752548991551595462057142824037334", - "19021616763967199151052893283384285352200445499680068407023236283004353578353" - ] - ] - ], - "IC": [ - [ - "17643142412395322664866141827318671249236739056291610144830020671604112279111", - "13273439661778801509295280274403992505521239023074387826870538372514206268318", - "1" - ], - [ - "12325966053136615826793633393742326952102053533176311103856731330114882211366", - "6439956820140153832120005353467272867287237423425778281905068783317736451260", - "1" - ], - [ - "20405310272367450124741832665322768131899487413829191383721623069139009993137", - "21336772016824870564600007750206596010566056069977718959140462128560786193566", - "1" - ], - [ - "4007669092231576644992949839487535590075070172447826102934640178940614212519", - "7597503385395289202372182678960254605827199004598882158153019657732525465207", - "1" - ], - [ - "4545695279389338758267531646940033299700127241196839077811942492841603458462", - "6635771967009274882904456432128877995932122611166121203658485990305433499873", - "1" - ], - [ - "7876954805169515500747828488548350352651069599547377092970620945851311591012", - "7571431725691513008054581132582771105743462534789373657638701712901679323321", - "1" - ], - [ - "5563973122249220346301217166900152021860462617567141574881706390202619333219", - "5147729144109676590873823097632042430451708874867871369293332620382492068692", - "1" - ] - ] -} \ No newline at end of file diff --git a/rln/resources/tree_height_19/rln.wasm b/rln/resources/tree_height_19/rln.wasm deleted file mode 100644 index 0d3da9a7..00000000 Binary files a/rln/resources/tree_height_19/rln.wasm and /dev/null differ diff --git a/rln/resources/tree_height_19/rln_final.zkey b/rln/resources/tree_height_19/rln_final.zkey deleted file mode 100644 index de38bad1..00000000 Binary files a/rln/resources/tree_height_19/rln_final.zkey and /dev/null differ diff --git a/rln/resources/tree_height_19/verification_key.json b/rln/resources/tree_height_19/verification_key.json deleted file mode 100644 index 48455a56..00000000 --- a/rln/resources/tree_height_19/verification_key.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "protocol": "groth16", - "curve": "bn128", - "nPublic": 6, - "vk_alpha_1": [ - "20124996762962216725442980738609010303800849578410091356605067053491763969391", - "9118593021526896828671519912099489027245924097793322973632351264852174143923", - "1" - ], - "vk_beta_2": [ - [ - "4693952934005375501364248788849686435240706020501681709396105298107971354382", - "14346958885444710485362620645446987998958218205939139994511461437152241966681" - ], - [ - "16851772916911573982706166384196538392731905827088356034885868448550849804972", - "823612331030938060799959717749043047845343400798220427319188951998582076532" - ], - [ - "1", - "0" - ] - ], - "vk_gamma_2": [ - [ - "10857046999023057135944570762232829481370756359578518086990519993285655852781", - "11559732032986387107991004021392285783925812861821192530917403151452391805634" - ], - [ - "8495653923123431417604973247489272438418190587263600148770280649306958101930", - "4082367875863433681332203403145435568316851327593401208105741076214120093531" - ], - [ - "1", - "0" - ] - ], - "vk_delta_2": [ - [ - "16125279975606773676640811113051624654121459921695914044301154938920321009721", - "14844345250267029614093295465313288254479124604567709177260777529651293576873" - ], - [ - "20349277326920398483890518242229158117668855310237215044647746783223259766294", - "19338776107510040969200058390413661029003750817172740054990168933780935479540" - ], - [ - "1", - "0" - ] - ], - "vk_alphabeta_12": [ - [ - [ - "12608968655665301215455851857466367636344427685631271961542642719683786103711", - "9849575605876329747382930567422916152871921500826003490242628251047652318086" - ], - [ - "6322029441245076030714726551623552073612922718416871603535535085523083939021", - "8700115492541474338049149013125102281865518624059015445617546140629435818912" - ], - [ - "10674973475340072635573101639867487770811074181475255667220644196793546640210", - "2926286967251299230490668407790788696102889214647256022788211245826267484824" - ] - ], - [ - [ - "9660441540778523475944706619139394922744328902833875392144658911530830074820", - "19548113127774514328631808547691096362144426239827206966690021428110281506546" - ], - [ - "1870837942477655969123169532603615788122896469891695773961478956740992497097", - "12536105729661705698805725105036536744930776470051238187456307227425796690780" - ], - [ - "21811903352654147452884857281720047789720483752548991551595462057142824037334", - "19021616763967199151052893283384285352200445499680068407023236283004353578353" - ] - ] - ], - "IC": [ - [ - "5645604624116784480262312750033349186912223090668673154853165165224747369512", - "5656337658385597582701340925622307146226708710361427687425735166776477641124", - "1" - ], - [ - "8216930132302312821663833393171053651364962198587857550991047765311607638330", - "19934865864074163318938688021560358348660709566570123384268356491416384822148", - "1" - ], - [ - "11046959016591768534564223076484566731774575511709349452804727872479525392631", - "9401797690410912638766111919371607085248054251975419812613989999345815833269", - "1" - ], - [ - "13216594148914395028254776738842380005944817065680915990743659996725367876414", - "11541283802841111343960351782994043892623551381569479006737253908665900144087", - "1" - ], - [ - "6957074593219251760608960101283708711892008557897337713430173510328411964571", - "21673833055087220750009279957462375662312260098732685145862504142183400549467", - "1" - ], - [ - "20795071270535109448604057031148356571036039566776607847840379441839742201050", - "21654952744643117202636583766828639581880877547772465264383291983528268115687", - "1" - ], - [ - "19143058772755719660075704757531991493801758701561469885274062297246796623789", - "3996020163280925980543600106196205910576345230982361007978823537163123181007", - "1" - ] - ] -} \ No newline at end of file diff --git a/rln/resources/tree_height_20/rln.wasm b/rln/resources/tree_height_20/rln.wasm index 04aaeef7..0d190033 100644 Binary files a/rln/resources/tree_height_20/rln.wasm and b/rln/resources/tree_height_20/rln.wasm differ diff --git a/rln/resources/tree_height_20/rln_final.zkey b/rln/resources/tree_height_20/rln_final.zkey index c6cc7d49..0318efa5 100644 Binary files a/rln/resources/tree_height_20/rln_final.zkey and b/rln/resources/tree_height_20/rln_final.zkey differ diff --git a/rln/resources/tree_height_20/verification_key.json b/rln/resources/tree_height_20/verification_key.json index 5974ffb0..7bdc62ae 100644 --- a/rln/resources/tree_height_20/verification_key.json +++ b/rln/resources/tree_height_20/verification_key.json @@ -1,20 +1,20 @@ { "protocol": "groth16", "curve": "bn128", - "nPublic": 6, + "nPublic": 5, "vk_alpha_1": [ - "20124996762962216725442980738609010303800849578410091356605067053491763969391", - "9118593021526896828671519912099489027245924097793322973632351264852174143923", + "20491192805390485299153009773594534940189261866228447918068658471970481763042", + "9383485363053290200918347156157836566562967994039712273449902621266178545958", "1" ], "vk_beta_2": [ [ - "4693952934005375501364248788849686435240706020501681709396105298107971354382", - "14346958885444710485362620645446987998958218205939139994511461437152241966681" + "6375614351688725206403948262868962793625744043794305715222011528459656738731", + "4252822878758300859123897981450591353533073413197771768651442665752259397132" ], [ - "16851772916911573982706166384196538392731905827088356034885868448550849804972", - "823612331030938060799959717749043047845343400798220427319188951998582076532" + "10505242626370262277552901082094356697409835680220590971873171140371331206856", + "21847035105528745403288232691147584728191162732299865338377159692350059136679" ], [ "1", @@ -37,12 +37,12 @@ ], "vk_delta_2": [ [ - "8353516066399360694538747105302262515182301251524941126222712285088022964076", - "9329524012539638256356482961742014315122377605267454801030953882967973561832" + "6832692771504397957590360708759281700999118750809760982970136159661838520508", + "13468886275581916448704001206191042468244128660792047667708868998914217226607" ], [ - "16805391589556134376869247619848130874761233086443465978238468412168162326401", - "10111259694977636294287802909665108497237922060047080343914303287629927847739" + "14994740931449791291635382287837232766460012379707446516704013722977810183046", + "9922411474443524470273139351326464261786154815141265104663214568321167583711" ], [ "1", @@ -52,67 +52,62 @@ "vk_alphabeta_12": [ [ [ - "12608968655665301215455851857466367636344427685631271961542642719683786103711", - "9849575605876329747382930567422916152871921500826003490242628251047652318086" + "2029413683389138792403550203267699914886160938906632433982220835551125967885", + "21072700047562757817161031222997517981543347628379360635925549008442030252106" ], [ - "6322029441245076030714726551623552073612922718416871603535535085523083939021", - "8700115492541474338049149013125102281865518624059015445617546140629435818912" + "5940354580057074848093997050200682056184807770593307860589430076672439820312", + "12156638873931618554171829126792193045421052652279363021382169897324752428276" ], [ - "10674973475340072635573101639867487770811074181475255667220644196793546640210", - "2926286967251299230490668407790788696102889214647256022788211245826267484824" + "7898200236362823042373859371574133993780991612861777490112507062703164551277", + "7074218545237549455313236346927434013100842096812539264420499035217050630853" ] ], [ [ - "9660441540778523475944706619139394922744328902833875392144658911530830074820", - "19548113127774514328631808547691096362144426239827206966690021428110281506546" + "7077479683546002997211712695946002074877511277312570035766170199895071832130", + "10093483419865920389913245021038182291233451549023025229112148274109565435465" ], [ - "1870837942477655969123169532603615788122896469891695773961478956740992497097", - "12536105729661705698805725105036536744930776470051238187456307227425796690780" + "4595479056700221319381530156280926371456704509942304414423590385166031118820", + "19831328484489333784475432780421641293929726139240675179672856274388269393268" ], [ - "21811903352654147452884857281720047789720483752548991551595462057142824037334", - "19021616763967199151052893283384285352200445499680068407023236283004353578353" + "11934129596455521040620786944827826205713621633706285934057045369193958244500", + "8037395052364110730298837004334506829870972346962140206007064471173334027475" ] ] ], "IC": [ [ - "11992897507809711711025355300535923222599547639134311050809253678876341466909", - "17181525095924075896332561978747020491074338784673526378866503154966799128110", + "4920513730204767532050733107749276406754520419375654722016092399980613788208", + "10950491564509418434657706642388934308456795265036074733953533582377584967294", "1" ], [ - "17018665030246167677911144513385572506766200776123272044534328594850561667818", - "18601114175490465275436712413925513066546725461375425769709566180981674884464", + "6815064660695497986531118446154820702646540722664044216580897159556261271171", + "17838140936832571103329556013529166877877534025488014783346458943575275015438", "1" ], [ - "18799470100699658367834559797874857804183288553462108031963980039244731716542", - "13064227487174191981628537974951887429496059857753101852163607049188825592007", + "16364982450206976302246609763791333525052810246590359380676749324389440643932", + "17092624338100676284548565502349491320314889021833923882585524649862570629227", "1" ], [ - "17432501889058124609368103715904104425610382063762621017593209214189134571156", - "13406815149699834788256141097399354592751313348962590382887503595131085938635", + "3679639231485547795420532910726924727560917141402837495597760107842698404034", + "16213191511474848247596810551723578773353083440353745908057321946068926848382", "1" ], [ - "10320964835612716439094703312987075811498239445882526576970512041988148264481", - "9024164961646353611176283204118089412001502110138072989569118393359029324867", + "9215428431027260354679105025212521481930206886203677270216204485256690813172", + "934602510541226149881779979217731465262250233587980565969044391353665291792", "1" ], [ - "718355081067365548229685160476620267257521491773976402837645005858953849298", - "14635482993933988261008156660773180150752190597753512086153001683711587601974", - "1" - ], - [ - "11777720285956632126519898515392071627539405001940313098390150593689568177535", - "8483603647274280691250972408211651407952870456587066148445913156086740744515", + "8935861545794299876685457331391349387048184820319250771243971382360441890897", + "4993459033694759724715904486381952906869986989682015547152342336961693234616", "1" ] ] diff --git a/rln/resources/tree_height_32/rln.wasm b/rln/resources/tree_height_32/rln.wasm new file mode 100644 index 00000000..94901cb2 Binary files /dev/null and b/rln/resources/tree_height_32/rln.wasm differ diff --git a/rln/resources/tree_height_32/rln_final.zkey b/rln/resources/tree_height_32/rln_final.zkey new file mode 100644 index 00000000..44e08f92 Binary files /dev/null and b/rln/resources/tree_height_32/rln_final.zkey differ diff --git a/rln/resources/tree_height_32/verification_key.json b/rln/resources/tree_height_32/verification_key.json new file mode 100644 index 00000000..67877066 --- /dev/null +++ b/rln/resources/tree_height_32/verification_key.json @@ -0,0 +1,114 @@ +{ + "protocol": "groth16", + "curve": "bn128", + "nPublic": 5, + "vk_alpha_1": [ + "20491192805390485299153009773594534940189261866228447918068658471970481763042", + "9383485363053290200918347156157836566562967994039712273449902621266178545958", + "1" + ], + "vk_beta_2": [ + [ + "6375614351688725206403948262868962793625744043794305715222011528459656738731", + "4252822878758300859123897981450591353533073413197771768651442665752259397132" + ], + [ + "10505242626370262277552901082094356697409835680220590971873171140371331206856", + "21847035105528745403288232691147584728191162732299865338377159692350059136679" + ], + [ + "1", + "0" + ] + ], + "vk_gamma_2": [ + [ + "10857046999023057135944570762232829481370756359578518086990519993285655852781", + "11559732032986387107991004021392285783925812861821192530917403151452391805634" + ], + [ + "8495653923123431417604973247489272438418190587263600148770280649306958101930", + "4082367875863433681332203403145435568316851327593401208105741076214120093531" + ], + [ + "1", + "0" + ] + ], + "vk_delta_2": [ + [ + "3689226096868373144622340732612563195789744807442014147637039988348252818659", + "18947459102520510468597269280688700807407684209892273827108603062925288762423" + ], + [ + "5816405977664254142436796931495067997250259145480168934320978750042633353708", + "14555486789839131710516067578112557185806110684461247253491378577062852578892" + ], + [ + "1", + "0" + ] + ], + "vk_alphabeta_12": [ + [ + [ + "2029413683389138792403550203267699914886160938906632433982220835551125967885", + "21072700047562757817161031222997517981543347628379360635925549008442030252106" + ], + [ + "5940354580057074848093997050200682056184807770593307860589430076672439820312", + "12156638873931618554171829126792193045421052652279363021382169897324752428276" + ], + [ + "7898200236362823042373859371574133993780991612861777490112507062703164551277", + "7074218545237549455313236346927434013100842096812539264420499035217050630853" + ] + ], + [ + [ + "7077479683546002997211712695946002074877511277312570035766170199895071832130", + "10093483419865920389913245021038182291233451549023025229112148274109565435465" + ], + [ + "4595479056700221319381530156280926371456704509942304414423590385166031118820", + "19831328484489333784475432780421641293929726139240675179672856274388269393268" + ], + [ + "11934129596455521040620786944827826205713621633706285934057045369193958244500", + "8037395052364110730298837004334506829870972346962140206007064471173334027475" + ] + ] + ], + "IC": [ + [ + "5412646265162057015134786739992128493053406364679846617542694915593022919217", + "9665511386935901867415947590751330959748921059696950821222365265700369811120", + "1" + ], + [ + "4294362651275803035824711662252687124584574009834787359330648404293309808795", + "1861758671717754835450145961645465880215655915164196594175485865489885224285", + "1" + ], + [ + "1911114017568107170522785254288953144010421698038439931935418407428234018676", + "13761363892532562822351086117281964648116890138564516558345965908415019790129", + "1" + ], + [ + "16312980235585837964428386585067529342038135099260965575497230302984635878053", + "20286500347141875536561618770383759234192052027362539966911091298688849002783", + "1" + ], + [ + "21038649368092225315431823433752123495654049075935052064397443455654061176031", + "6976971039866104284556300526186000690370678593992968176463280189048347216392", + "1" + ], + [ + "971745799362951123575710699973701411260115357326598060711339429906895409324", + "12959821343398475313407440786226277845673045139874184400082186049649123071798", + "1" + ] + ] +} \ No newline at end of file diff --git a/rln/src/circuit.rs b/rln/src/circuit.rs index 22e75922..de7b29c0 100644 --- a/rln/src/circuit.rs +++ b/rln/src/circuit.rs @@ -30,12 +30,11 @@ const VK_FILENAME: &str = "verification_key.json"; const WASM_FILENAME: &str = "rln.wasm"; // These parameters are used for tests -// Note that the circuit and keys in TEST_RESOURCES_FOLDER are compiled for Merkle trees of height 15, 19 and 20 +// Note that the circuit and keys in TEST_RESOURCES_FOLDER are compiled for Merkle trees of height 20 & 32 // Changing these parameters to other values than these defaults will cause zkSNARK proof verification to fail -pub const TEST_PARAMETERS_INDEX: usize = 2; -pub const TEST_TREE_HEIGHT: usize = [15, 19, 20][TEST_PARAMETERS_INDEX]; -pub const TEST_RESOURCES_FOLDER: &str = - ["tree_height_15", "tree_height_19", "tree_height_20"][TEST_PARAMETERS_INDEX]; +pub const TEST_PARAMETERS_INDEX: usize = 0; +pub const TEST_TREE_HEIGHT: usize = [20, 32][TEST_PARAMETERS_INDEX]; +pub const TEST_RESOURCES_FOLDER: &str = ["tree_height_20", "tree_height_32"][TEST_PARAMETERS_INDEX]; #[cfg(not(target_arch = "wasm32"))] static RESOURCES_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/resources"); diff --git a/rln/src/protocol.rs b/rln/src/protocol.rs index f460fad3..cc1aa8b8 100644 --- a/rln/src/protocol.rs +++ b/rln/src/protocol.rs @@ -32,11 +32,12 @@ use utils::{ZerokitMerkleProof, ZerokitMerkleTree}; #[derive(Debug, PartialEq)] pub struct RLNWitnessInput { identity_secret: Fr, + user_message_limit: Fr, + message_id: Fr, path_elements: Vec, identity_path_index: Vec, x: Fr, - epoch: Fr, - rln_identifier: Fr, + external_nullifier: Fr, } #[derive(Debug, PartialEq)] @@ -47,8 +48,7 @@ pub struct RLNProofValues { pub root: Fr, // Public Inputs: pub x: Fr, - pub epoch: Fr, - pub rln_identifier: Fr, + pub external_nullifier: Fr, } pub fn serialize_field_element(element: Fr) -> Vec { @@ -90,25 +90,46 @@ pub fn deserialize_identity_tuple(serialized: Vec) -> (Fr, Fr, Fr, Fr) { ) } +/// Serializes witness +/// +/// # Errors +/// +/// Returns an error if `rln_witness.message_id` is not within `rln_witness.user_message_limit`. pub fn serialize_witness(rln_witness: &RLNWitnessInput) -> Result> { + message_id_range_check(&rln_witness.message_id, &rln_witness.user_message_limit)?; + let mut serialized: Vec = Vec::new(); serialized.append(&mut fr_to_bytes_le(&rln_witness.identity_secret)); + serialized.append(&mut fr_to_bytes_le(&rln_witness.user_message_limit)); + serialized.append(&mut fr_to_bytes_le(&rln_witness.message_id)); serialized.append(&mut vec_fr_to_bytes_le(&rln_witness.path_elements)?); serialized.append(&mut vec_u8_to_bytes_le(&rln_witness.identity_path_index)?); serialized.append(&mut fr_to_bytes_le(&rln_witness.x)); - serialized.append(&mut fr_to_bytes_le(&rln_witness.epoch)); - serialized.append(&mut fr_to_bytes_le(&rln_witness.rln_identifier)); + serialized.append(&mut fr_to_bytes_le(&rln_witness.external_nullifier)); Ok(serialized) } +/// Deserializes witness +/// +/// # Errors +/// +/// Returns an error if `message_id` is not within `user_message_limit`. pub fn deserialize_witness(serialized: &[u8]) -> Result<(RLNWitnessInput, usize)> { let mut all_read: usize = 0; let (identity_secret, read) = bytes_le_to_fr(&serialized[all_read..]); all_read += read; + let (user_message_limit, read) = bytes_le_to_fr(&serialized[all_read..]); + all_read += read; + + let (message_id, read) = bytes_le_to_fr(&serialized[all_read..]); + all_read += read; + + message_id_range_check(&message_id, &user_message_limit)?; + let (path_elements, read) = bytes_le_to_vec_fr(&serialized[all_read..])?; all_read += read; @@ -118,13 +139,9 @@ pub fn deserialize_witness(serialized: &[u8]) -> Result<(RLNWitnessInput, usize) let (x, read) = bytes_le_to_fr(&serialized[all_read..]); all_read += read; - let (epoch, read) = bytes_le_to_fr(&serialized[all_read..]); - all_read += read; - - let (rln_identifier, read) = bytes_le_to_fr(&serialized[all_read..]); + let (external_nullifier, read) = bytes_le_to_fr(&serialized[all_read..]); all_read += read; - // TODO: check rln_identifier against public::RLN_IDENTIFIER if serialized.len() != all_read { return Err(Report::msg("serialized length is not equal to all_read")); } @@ -135,8 +152,9 @@ pub fn deserialize_witness(serialized: &[u8]) -> Result<(RLNWitnessInput, usize) path_elements, identity_path_index, x, - epoch, - rln_identifier, + external_nullifier, + user_message_limit, + message_id, }, all_read, )) @@ -144,7 +162,7 @@ pub fn deserialize_witness(serialized: &[u8]) -> Result<(RLNWitnessInput, usize) // This function deserializes input for kilic's rln generate_proof public API // https://github.com/kilic/rln/blob/7ac74183f8b69b399e3bc96c1ae8ab61c026dc43/src/public.rs#L148 -// input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal ] +// input_data is [ identity_secret<32> | id_index<8> | user_message_limit<32> | message_id<32> | signal_len<8> | signal ] // return value is a rln witness populated according to this information pub fn proof_inputs_to_rln_witness( tree: &mut PoseidonTree, @@ -160,7 +178,13 @@ pub fn proof_inputs_to_rln_witness( ))?; all_read += 8; - let (epoch, read) = bytes_le_to_fr(&serialized[all_read..]); + let (user_message_limit, read) = bytes_le_to_fr(&serialized[all_read..]); + all_read += read; + + let (message_id, read) = bytes_le_to_fr(&serialized[all_read..]); + all_read += read; + + let (external_nullifier, read) = bytes_le_to_fr(&serialized[all_read..]); all_read += read; let signal_len = usize::try_from(u64::from_le_bytes( @@ -176,37 +200,47 @@ pub fn proof_inputs_to_rln_witness( let x = hash_to_field(&signal); - let rln_identifier = hash_to_field(RLN_IDENTIFIER); - Ok(( RLNWitnessInput { identity_secret, path_elements, identity_path_index, + user_message_limit, + message_id, x, - epoch, - rln_identifier, + external_nullifier, }, all_read, )) } +/// Returns `RLNWitnessInput` given a file with JSON serialized values. +/// +/// # Errors +/// +/// Returns an error if `message_id` is not within `user_message_limit`. pub fn rln_witness_from_json(input_json_str: &str) -> Result { let input_json: serde_json::Value = serde_json::from_str(input_json_str).expect("JSON was not well-formatted"); - let identity_secret = str_to_fr(&input_json["identity_secret"].to_string(), 10)?; + let user_message_limit = str_to_fr(&input_json["userMessageLimit"].to_string(), 10)?; + + let message_id = str_to_fr(&input_json["messageId"].to_string(), 10)?; - let path_elements = input_json["path_elements"] + message_id_range_check(&message_id, &user_message_limit)?; + + let identity_secret = str_to_fr(&input_json["identitySecret"].to_string(), 10)?; + + let path_elements = input_json["pathElements"] .as_array() .ok_or(Report::msg("not an array"))? .iter() .map(|v| str_to_fr(&v.to_string(), 10)) .collect::>()?; - let identity_path_index_array = input_json["identity_path_index"] + let identity_path_index_array = input_json["identityPathIndex"] .as_array() - .ok_or(Report::msg("not an arrray"))?; + .ok_or(Report::msg("not an array"))?; let mut identity_path_index: Vec = vec![]; @@ -216,41 +250,46 @@ pub fn rln_witness_from_json(input_json_str: &str) -> Result { let x = str_to_fr(&input_json["x"].to_string(), 10)?; - let epoch = str_to_fr(&input_json["epoch"].to_string(), 16)?; - - let rln_identifier = str_to_fr(&input_json["rln_identifier"].to_string(), 10)?; - - // TODO: check rln_identifier against public::RLN_IDENTIFIER + let external_nullifier = str_to_fr(&input_json["externalNullifier"].to_string(), 10)?; Ok(RLNWitnessInput { identity_secret, path_elements, identity_path_index, x, - epoch, - rln_identifier, + external_nullifier, + user_message_limit, + message_id, }) } +/// Creates `RLNWitnessInput` from it's fields. +/// +/// # Errors +/// +/// Returns an error if `message_id` is not within `user_message_limit`. pub fn rln_witness_from_values( identity_secret: Fr, merkle_proof: &MerkleProof, x: Fr, - epoch: Fr, - //rln_identifier: Fr, -) -> RLNWitnessInput { + external_nullifier: Fr, + user_message_limit: Fr, + message_id: Fr, +) -> Result { + message_id_range_check(&message_id, &user_message_limit)?; + let path_elements = merkle_proof.get_path_elements(); let identity_path_index = merkle_proof.get_path_index(); - let rln_identifier = hash_to_field(RLN_IDENTIFIER); - RLNWitnessInput { + Ok(RLNWitnessInput { identity_secret, path_elements, identity_path_index, x, - epoch, - rln_identifier, - } + external_nullifier, + user_message_limit, + message_id, + }) } pub fn random_rln_witness(tree_height: usize) -> RLNWitnessInput { @@ -269,21 +308,26 @@ pub fn random_rln_witness(tree_height: usize) -> RLNWitnessInput { identity_path_index.push(rng.gen_range(0..2) as u8); } + let user_message_limit = Fr::from(100); + let message_id = Fr::from(1); + RLNWitnessInput { identity_secret, path_elements, identity_path_index, x, - epoch, - rln_identifier, + external_nullifier: poseidon_hash(&[epoch, rln_identifier]), + user_message_limit, + message_id, } } -pub fn proof_values_from_witness(rln_witness: &RLNWitnessInput) -> RLNProofValues { +pub fn proof_values_from_witness(rln_witness: &RLNWitnessInput) -> Result { + message_id_range_check(&rln_witness.message_id, &rln_witness.user_message_limit)?; + // y share - let external_nullifier = poseidon_hash(&[rln_witness.epoch, rln_witness.rln_identifier]); let a_0 = rln_witness.identity_secret; - let a_1 = poseidon_hash(&[a_0, external_nullifier]); + let a_1 = poseidon_hash(&[a_0, rln_witness.external_nullifier, rln_witness.message_id]); let y = a_0 + rln_witness.x * a_1; // Nullifier @@ -292,30 +336,28 @@ pub fn proof_values_from_witness(rln_witness: &RLNWitnessInput) -> RLNProofValue // Merkle tree root computations let root = compute_tree_root( &rln_witness.identity_secret, + &rln_witness.user_message_limit, &rln_witness.path_elements, &rln_witness.identity_path_index, - true, ); - RLNProofValues { + Ok(RLNProofValues { y, nullifier, root, x: rln_witness.x, - epoch: rln_witness.epoch, - rln_identifier: rln_witness.rln_identifier, - } + external_nullifier: rln_witness.external_nullifier, + }) } pub fn serialize_proof_values(rln_proof_values: &RLNProofValues) -> Vec { let mut serialized: Vec = Vec::new(); serialized.append(&mut fr_to_bytes_le(&rln_proof_values.root)); - serialized.append(&mut fr_to_bytes_le(&rln_proof_values.epoch)); + serialized.append(&mut fr_to_bytes_le(&rln_proof_values.external_nullifier)); serialized.append(&mut fr_to_bytes_le(&rln_proof_values.x)); serialized.append(&mut fr_to_bytes_le(&rln_proof_values.y)); serialized.append(&mut fr_to_bytes_le(&rln_proof_values.nullifier)); - serialized.append(&mut fr_to_bytes_le(&rln_proof_values.rln_identifier)); serialized } @@ -328,7 +370,7 @@ pub fn deserialize_proof_values(serialized: &[u8]) -> (RLNProofValues, usize) { let (root, read) = bytes_le_to_fr(&serialized[all_read..]); all_read += read; - let (epoch, read) = bytes_le_to_fr(&serialized[all_read..]); + let (external_nullifier, read) = bytes_le_to_fr(&serialized[all_read..]); all_read += read; let (x, read) = bytes_le_to_fr(&serialized[all_read..]); @@ -340,17 +382,13 @@ pub fn deserialize_proof_values(serialized: &[u8]) -> (RLNProofValues, usize) { let (nullifier, read) = bytes_le_to_fr(&serialized[all_read..]); all_read += read; - let (rln_identifier, read) = bytes_le_to_fr(&serialized[all_read..]); - all_read += read; - ( RLNProofValues { y, nullifier, root, x, - epoch, - rln_identifier, + external_nullifier, }, all_read, ) @@ -359,14 +397,14 @@ pub fn deserialize_proof_values(serialized: &[u8]) -> (RLNProofValues, usize) { pub fn prepare_prove_input( identity_secret: Fr, id_index: usize, - epoch: Fr, + external_nullifier: Fr, signal: &[u8], ) -> Vec { let mut serialized: Vec = Vec::new(); serialized.append(&mut fr_to_bytes_le(&identity_secret)); serialized.append(&mut normalize_usize(id_index)); - serialized.append(&mut fr_to_bytes_le(&epoch)); + serialized.append(&mut fr_to_bytes_le(&external_nullifier)); serialized.append(&mut normalize_usize(signal.len())); serialized.append(&mut signal.to_vec()); @@ -389,15 +427,13 @@ pub fn prepare_verify_input(proof_data: Vec, signal: &[u8]) -> Vec { /////////////////////////////////////////////////////// pub fn compute_tree_root( - leaf: &Fr, + identity_secret: &Fr, + user_message_limit: &Fr, path_elements: &[Fr], identity_path_index: &[u8], - hash_leaf: bool, ) -> Fr { - let mut root = *leaf; - if hash_leaf { - root = poseidon_hash(&[root]); - } + let id_commitment = poseidon_hash(&[*identity_secret]); + let mut root = poseidon_hash(&[id_commitment, *user_message_limit]); for i in 0..identity_path_index.len() { if identity_path_index[i] == 0 { @@ -488,11 +524,7 @@ pub fn extended_seeded_keygen(signal: &[u8]) -> (Fr, Fr, Fr, Fr) { ) } -pub fn compute_id_secret( - share1: (Fr, Fr), - share2: (Fr, Fr), - external_nullifier: Fr, -) -> Result { +pub fn compute_id_secret(share1: (Fr, Fr), share2: (Fr, Fr)) -> Result { // Assuming a0 is the identity secret and a1 = poseidonHash([a0, external_nullifier]), // a (x,y) share satisfies the following relation // y = a_0 + x * a_1 @@ -506,14 +538,7 @@ pub fn compute_id_secret( let a_0 = y1 - x1 * a_1; // If shares come from the same polynomial, a0 is correctly recovered and a1 = poseidonHash([a0, external_nullifier]) - let computed_a_1 = poseidon_hash(&[a_0, external_nullifier]); - - if a_1 == computed_a_1 { - // We successfully recovered the identity secret - Ok(a_0) - } else { - Err("Cannot recover identity_secret_hash from provided shares".into()) - } + Ok(a_0) } /////////////////////////////////////////////////////// @@ -594,10 +619,17 @@ pub fn generate_proof_with_witness( Ok(proof) } +/// Formats inputs for witness calculation +/// +/// # Errors +/// +/// Returns an error if `rln_witness.message_id` is not within `rln_witness.user_message_limit`. pub fn inputs_for_witness_calculation( rln_witness: &RLNWitnessInput, -) -> Result<[(&str, Vec); 6]> { - // We confert the path indexes to field elements +) -> Result<[(&str, Vec); 7]> { + message_id_range_check(&rln_witness.message_id, &rln_witness.user_message_limit)?; + + // We convert the path indexes to field elements // TODO: check if necessary let mut path_elements = Vec::new(); @@ -613,16 +645,20 @@ pub fn inputs_for_witness_calculation( Ok([ ( - "identity_secret", + "identitySecret", vec![to_bigint(&rln_witness.identity_secret)?], ), - ("path_elements", path_elements), - ("identity_path_index", identity_path_index), + ( + "userMessageLimit", + vec![to_bigint(&rln_witness.user_message_limit)?], + ), + ("messageId", vec![to_bigint(&rln_witness.message_id)?]), + ("pathElements", path_elements), + ("identityPathIndex", identity_path_index), ("x", vec![to_bigint(&rln_witness.x)?]), - ("epoch", vec![to_bigint(&rln_witness.epoch)?]), ( - "rln_identifier", - vec![to_bigint(&rln_witness.rln_identifier)?], + "externalNullifier", + vec![to_bigint(&rln_witness.external_nullifier)?], ), ]) } @@ -671,7 +707,6 @@ pub fn generate_proof( // If in debug mode, we measure and later print time take to compute proof #[cfg(debug_assertions)] let now = Instant::now(); - let proof = Groth16::<_, CircomReduction>::create_proof_with_reduction_and_matrices( &proving_key.0, r, @@ -705,8 +740,7 @@ pub fn verify_proof( proof_values.root, proof_values.nullifier, proof_values.x, - proof_values.epoch, - proof_values.rln_identifier, + proof_values.external_nullifier, ]; // Check that the proof is valid @@ -729,7 +763,13 @@ pub fn verify_proof( /// /// Returns a JSON object containing the inputs necessary to calculate /// the witness with CIRCOM on javascript +/// +/// # Errors +/// +/// Returns an error if `rln_witness.message_id` is not within `rln_witness.user_message_limit`. pub fn get_json_inputs(rln_witness: &RLNWitnessInput) -> Result { + message_id_range_check(&rln_witness.message_id, &rln_witness.user_message_limit)?; + let mut path_elements = Vec::new(); for v in rln_witness.path_elements.iter() { @@ -743,13 +783,23 @@ pub fn get_json_inputs(rln_witness: &RLNWitnessInput) -> Result Result<()> { + if message_id > user_message_limit { + return Err(color_eyre::Report::msg( + "message_id is not within user_message_limit", + )); + } + Ok(()) +} diff --git a/rln/src/public.rs b/rln/src/public.rs index 5de153a7..d779dbc3 100644 --- a/rln/src/public.rs +++ b/rln/src/public.rs @@ -238,11 +238,14 @@ impl RLN<'_> { /// // We generate a random identity secret hash and commitment pair /// let (identity_secret_hash, id_commitment) = keygen(); /// - /// // We define the tree index where id_commitment will be added + /// // We define the tree index where rate_commitment will be added /// let id_index = 10; + /// let user_message_limit = 1; /// - /// // We serialize id_commitment and pass it to set_leaf - /// let mut buffer = Cursor::new(serialize_field_element(id_commitment)); + /// let rate_commitment = poseidon_hash(&[id_commitment, user_message_limit]); + /// + /// // We serialize rate_commitment and pass it to set_leaf + /// let mut buffer = Cursor::new(serialize_field_element(rate_commitment)); /// rln.set_leaf(id_index, &mut buffer).unwrap(); /// ``` pub fn set_leaf(&mut self, index: usize, mut input_data: R) -> Result<()> { @@ -270,7 +273,7 @@ impl RLN<'_> { /// let id_index = 10; /// let mut buffer = Cursor::new(Vec::::new()); /// rln.get_leaf(id_index, &mut buffer).unwrap(); - /// let id_commitment = deserialize_field_element(&buffer.into_inner()).unwrap(); + /// let rate_commitment = deserialize_field_element(&buffer.into_inner()).unwrap(); pub fn get_leaf(&self, index: usize, mut output_data: W) -> Result<()> { // We get the leaf at input index let leaf = self.tree.get(index)?; @@ -305,7 +308,8 @@ impl RLN<'_> { /// let mut rng = thread_rng(); /// for _ in 0..no_of_leaves { /// let (_, id_commitment) = keygen(); - /// leaves.push(id_commitment); + /// let rate_commitment = poseidon_hash(&[id_commitment, 1.into()]); + /// leaves.push(rate_commitment); /// } /// /// // We add leaves in a batch into the tree @@ -366,7 +370,8 @@ impl RLN<'_> { /// let mut rng = thread_rng(); /// for _ in 0..no_of_leaves { /// let (_, id_commitment) = keygen(); - /// leaves.push(id_commitment); + /// let rate_commitment = poseidon_hash(&[id_commitment, 1.into()]); + /// leaves.push(rate_commitment); /// } /// /// let mut indices: Vec = Vec::new(); @@ -436,7 +441,8 @@ impl RLN<'_> { /// let mut rng = thread_rng(); /// for _ in 0..no_of_leaves { /// let (_, id_commitment) = keygen(); - /// leaves.push(id_commitment); + /// let rate_commitment = poseidon_hash(&[id_commitment, 1.into()]); + /// leaves.push(rate_commitment); /// } /// /// // We add leaves in a batch into the tree @@ -446,9 +452,10 @@ impl RLN<'_> { /// // We set 256 leaves starting from index 10: next_index value is now max(0, 256+10) = 266 /// /// // We set a leaf on next available index - /// // id_commitment will be set at index 266 + /// // rate_commitment will be set at index 266 /// let (_, id_commitment) = keygen(); - /// let mut buffer = Cursor::new(fr_to_bytes_le(&id_commitment)); + /// let rate_commitment = poseidon_hash(&[id_commitment, 1.into()]); + /// let mut buffer = Cursor::new(fr_to_bytes_le(&rate_commitment)); /// rln.set_next_leaf(&mut buffer).unwrap(); /// ``` pub fn set_next_leaf(&mut self, mut input_data: R) -> Result<()> { @@ -657,7 +664,7 @@ impl RLN<'_> { pub fn verify(&self, mut input_data: R) -> Result { // Input data is serialized for Curve as: // serialized_proof (compressed, 4*32 bytes) || serialized_proof_values (6*32 bytes), i.e. - // [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> ] + // [ proof<128> | root<32> | external_nullifier<32> | share_x<32> | share_y<32> | nullifier<32> ] let mut input_byte: Vec = Vec::new(); input_data.read_to_end(&mut input_byte)?; let proof = ArkProof::deserialize_compressed(&mut Cursor::new(&input_byte[..128]))?; @@ -685,9 +692,10 @@ impl RLN<'_> { /// // Generate identity pair /// let (identity_secret_hash, id_commitment) = keygen(); /// - /// // We set as leaf id_commitment after storing its index + /// // We set as leaf rate_commitment after storing its index /// let identity_index = 10; - /// let mut buffer = Cursor::new(fr_to_bytes_le(&id_commitment)); + /// let rate_commitment = poseidon_hash(&[id_commitment, 1.into()]); + /// let mut buffer = Cursor::new(fr_to_bytes_le(&rate_commitment)); /// rln.set_leaf(identity_index, &mut buffer).unwrap(); /// /// // We generate a random signal @@ -723,7 +731,7 @@ impl RLN<'_> { let mut witness_byte: Vec = Vec::new(); input_data.read_to_end(&mut witness_byte)?; let (rln_witness, _) = proof_inputs_to_rln_witness(&mut self.tree, &witness_byte)?; - let proof_values = proof_values_from_witness(&rln_witness); + let proof_values = proof_values_from_witness(&rln_witness)?; let proof = generate_proof(self.witness_calculator, &self.proving_key, &rln_witness)?; @@ -748,7 +756,7 @@ impl RLN<'_> { mut output_data: W, ) -> Result<()> { let (rln_witness, _) = deserialize_witness(&rln_witness_vec[..])?; - let proof_values = proof_values_from_witness(&rln_witness); + let proof_values = proof_values_from_witness(&rln_witness)?; let proof = generate_proof_with_witness(calculated_witness, &self.proving_key).unwrap(); @@ -804,13 +812,10 @@ impl RLN<'_> { let signal: Vec = serialized[all_read..all_read + signal_len].to_vec(); let verified = verify_proof(&self.verification_key, &proof, &proof_values)?; + let x = hash_to_field(&signal); // Consistency checks to counter proof tampering - let x = hash_to_field(&signal); - Ok(verified - && (self.tree.root() == proof_values.root) - && (x == proof_values.x) - && (proof_values.rln_identifier == hash_to_field(RLN_IDENTIFIER))) + Ok(verified && (self.tree.root() == proof_values.root) && (x == proof_values.x)) } /// Verifies a zkSNARK RLN proof against the provided proof values and a set of allowed Merkle tree roots. @@ -885,9 +890,7 @@ impl RLN<'_> { // First consistency checks to counter proof tampering let x = hash_to_field(&signal); - let partial_result = verified - && (x == proof_values.x) - && (proof_values.rln_identifier == hash_to_field(RLN_IDENTIFIER)); + let partial_result = verified && (x == proof_values.x); // We skip root validation if proof is already invalid if !partial_result { @@ -1116,15 +1119,13 @@ impl RLN<'_> { input_proof_data_1.read_to_end(&mut serialized)?; // We skip deserialization of the zk-proof at the beginning let (proof_values_1, _) = deserialize_proof_values(&serialized[128..]); - let external_nullifier_1 = - utils_poseidon_hash(&[proof_values_1.epoch, proof_values_1.rln_identifier]); + let external_nullifier_1 = proof_values_1.external_nullifier; let mut serialized: Vec = Vec::new(); input_proof_data_2.read_to_end(&mut serialized)?; // We skip deserialization of the zk-proof at the beginning let (proof_values_2, _) = deserialize_proof_values(&serialized[128..]); - let external_nullifier_2 = - utils_poseidon_hash(&[proof_values_2.epoch, proof_values_2.rln_identifier]); + let external_nullifier_2 = proof_values_2.external_nullifier; // We continue only if the proof values are for the same epoch // The idea is that proof values that go as input to this function are verified first (with zk-proof verify), hence ensuring validity of epoch and other fields. @@ -1136,12 +1137,13 @@ impl RLN<'_> { let share2 = (proof_values_2.x, proof_values_2.y); // We recover the secret - let recovered_identity_secret_hash = - compute_id_secret(share1, share2, external_nullifier_1); + let recovered_identity_secret_hash = compute_id_secret(share1, share2); // If an identity secret hash is recovered, we write it to output_data, otherwise nothing will be written. if let Ok(identity_secret_hash) = recovered_identity_secret_hash { output_data.write_all(&fr_to_bytes_le(&identity_secret_hash))?; + } else { + return Err(Report::msg("could not extract secret")); } } @@ -1625,6 +1627,123 @@ mod test { assert_eq!(root_empty, root_after_bad_set); } + fn fq_from_str(s: String) -> ark_bn254::Fq { + ark_bn254::Fq::from_str(&s).unwrap() + } + + fn g1_from_str(g1: &[String]) -> ark_bn254::G1Affine { + let x = fq_from_str(g1[0].clone()); + let y = fq_from_str(g1[1].clone()); + let z = fq_from_str(g1[2].clone()); + ark_bn254::G1Affine::from(ark_bn254::G1Projective::new(x, y, z)) + } + + fn g2_from_str(g2: &[Vec]) -> ark_bn254::G2Affine { + let c0 = fq_from_str(g2[0][0].clone()); + let c1 = fq_from_str(g2[0][1].clone()); + let x = ark_bn254::Fq2::new(c0, c1); + + let c0 = fq_from_str(g2[1][0].clone()); + let c1 = fq_from_str(g2[1][1].clone()); + let y = ark_bn254::Fq2::new(c0, c1); + + let c0 = fq_from_str(g2[2][0].clone()); + let c1 = fq_from_str(g2[2][1].clone()); + let z = ark_bn254::Fq2::new(c0, c1); + + ark_bn254::G2Affine::from(ark_bn254::G2Projective::new(x, y, z)) + } + + fn value_to_string_vec(value: &Value) -> Vec { + value + .as_array() + .unwrap() + .into_iter() + .map(|val| val.as_str().unwrap().to_string()) + .collect() + } + + #[test] + fn test_groth16_proof_hardcoded() { + let tree_height = TEST_TREE_HEIGHT; + + let input_buffer = + Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string()); + let rln = RLN::new(tree_height, input_buffer).unwrap(); + + let valid_snarkjs_proof = json!({ + "pi_a": [ + "4470527391588441860193200161084455226340491373346283552408949960585113822665", + "17066173901974939377117728437830216011764222423156801199965800887938087190121", + "1" + ], + "pi_b": [ + [ + "15972566464269406830925988363875489807783626890329856187767783138745533264635", + "14937519511565349355063307001263881540320664095110809840110097755110649950560" + ], + [ + "533488241215365262498062426054646750918758165791898421060280269581011723961", + "9035874337973494769294028746597715861635666159729389919309920308765805688602" + ], + [ + "1", + "0" + ] + ], + "pi_c": [ + "20620241453393708332486848754039748595639801912969370960546027260091108922454", + "20580342189093698831710267260567759683930279312746044733195059538431965163807", + "1" + ], + "protocol": "groth16", + "curve": "bn128" + }); + let valid_ark_proof = ArkProof { + a: g1_from_str(&value_to_string_vec(&valid_snarkjs_proof["pi_a"])), + b: g2_from_str( + &valid_snarkjs_proof["pi_b"] + .as_array() + .unwrap() + .iter() + .map(|item| value_to_string_vec(item)) + .collect::>>(), + ), + c: g1_from_str(&value_to_string_vec(&valid_snarkjs_proof["pi_c"])), + }; + + let valid_proof_values = RLNProofValues { + x: str_to_fr( + "20645213238265527935869146898028115621427162613172918400241870500502509785943", + 10, + ) + .unwrap(), + external_nullifier: str_to_fr( + "21074405743803627666274838159589343934394162804826017440941339048886754734203", + 10, + ) + .unwrap(), + y: str_to_fr( + "16401008481486069296141645075505218976370369489687327284155463920202585288271", + 10, + ) + .unwrap(), + root: str_to_fr( + "8502402278351299594663821509741133196466235670407051417832304486953898514733", + 10, + ) + .unwrap(), + nullifier: str_to_fr( + "9102791780887227194595604713537772536258726662792598131262022534710887343694", + 10, + ) + .unwrap(), + }; + + let verified = verify_proof(&rln.verification_key, &valid_ark_proof, &valid_proof_values); + assert!(verified.unwrap()); + } + #[test] // This test is similar to the one in lib, but uses only public API fn test_groth16_proof() { @@ -1636,7 +1755,7 @@ mod test { // Note: we only test Groth16 proof generation, so we ignore setting the tree in the RLN object let rln_witness = random_rln_witness(tree_height); - let proof_values = proof_values_from_witness(&rln_witness); + let proof_values = proof_values_from_witness(&rln_witness).unwrap(); // We compute a Groth16 proof let mut input_buffer = Cursor::new(serialize_witness(&rln_witness).unwrap()); @@ -1647,6 +1766,7 @@ mod test { // Before checking public verify API, we check that the (deserialized) proof generated by prove is actually valid let proof = ArkProof::deserialize_compressed(&mut Cursor::new(&serialized_proof)).unwrap(); let verified = verify_proof(&rln.verification_key, &proof, &proof_values); + // dbg!(verified.unwrap()); assert!(verified.unwrap()); // We prepare the input to prove API, consisting of serialized_proof (compressed, 4*32 bytes) || serialized_proof_values (6*32 bytes) @@ -1671,7 +1791,9 @@ mod test { let mut leaves: Vec = Vec::new(); let mut rng = thread_rng(); for _ in 0..no_of_leaves { - leaves.push(Fr::rand(&mut rng)); + let id_commitment = Fr::rand(&mut rng); + let rate_commitment = utils_poseidon_hash(&[id_commitment, Fr::from(100)]); + leaves.push(rate_commitment); } // We create a new RLN instance @@ -1686,9 +1808,11 @@ mod test { // Generate identity pair let (identity_secret_hash, id_commitment) = keygen(); - // We set as leaf id_commitment after storing its index + // We set as leaf rate_commitment after storing its index let identity_index = rln.tree.leaves_set(); - let mut buffer = Cursor::new(fr_to_bytes_le(&id_commitment)); + let user_message_limit = Fr::from(65535); + let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]); + let mut buffer = Cursor::new(fr_to_bytes_le(&rate_commitment)); rln.set_next_leaf(&mut buffer).unwrap(); // We generate a random signal @@ -1697,13 +1821,19 @@ mod test { // We generate a random epoch let epoch = hash_to_field(b"test-epoch"); + // We generate a random rln_identifier + let rln_identifier = hash_to_field(b"test-rln-identifier"); // We prepare input for generate_rln_proof API - // input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal ] let mut serialized: Vec = Vec::new(); serialized.append(&mut fr_to_bytes_le(&identity_secret_hash)); serialized.append(&mut normalize_usize(identity_index)); - serialized.append(&mut fr_to_bytes_le(&epoch)); + serialized.append(&mut fr_to_bytes_le(&user_message_limit)); + serialized.append(&mut fr_to_bytes_le(&Fr::from(1))); + serialized.append(&mut fr_to_bytes_le(&utils_poseidon_hash(&[ + epoch, + rln_identifier, + ]))); serialized.append(&mut normalize_usize(signal.len())); serialized.append(&mut signal.to_vec()); @@ -1751,9 +1881,11 @@ mod test { // Generate identity pair let (identity_secret_hash, id_commitment) = keygen(); - // We set as leaf id_commitment after storing its index + // We set as leaf rate_commitment after storing its index let identity_index = rln.tree.leaves_set(); - let mut buffer = Cursor::new(fr_to_bytes_le(&id_commitment)); + let user_message_limit = Fr::from(100); + let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]); + let mut buffer = Cursor::new(fr_to_bytes_le(&rate_commitment)); rln.set_next_leaf(&mut buffer).unwrap(); // We generate a random signal @@ -1762,13 +1894,20 @@ mod test { // We generate a random epoch let epoch = hash_to_field(b"test-epoch"); + // We generate a random rln_identifier + let rln_identifier = hash_to_field(b"test-rln-identifier"); // We prepare input for generate_rln_proof API // input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal ] let mut serialized: Vec = Vec::new(); serialized.append(&mut fr_to_bytes_le(&identity_secret_hash)); serialized.append(&mut normalize_usize(identity_index)); - serialized.append(&mut fr_to_bytes_le(&epoch)); + serialized.append(&mut fr_to_bytes_le(&user_message_limit)); + serialized.append(&mut fr_to_bytes_le(&Fr::from(1))); + serialized.append(&mut fr_to_bytes_le(&utils_poseidon_hash(&[ + epoch, + rln_identifier, + ]))); serialized.append(&mut normalize_usize(signal.len())); serialized.append(&mut signal.to_vec()); @@ -1850,22 +1989,29 @@ mod test { // We set as leaf id_commitment after storing its index let identity_index = rln.tree.leaves_set(); - let mut buffer = Cursor::new(fr_to_bytes_le(&id_commitment)); + let user_message_limit = Fr::from(100); + let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]); + let mut buffer = Cursor::new(fr_to_bytes_le(&rate_commitment)); rln.set_next_leaf(&mut buffer).unwrap(); // We generate a random signal - let mut rng = rand::thread_rng(); + let mut rng = thread_rng(); let signal: [u8; 32] = rng.gen(); // We generate a random epoch let epoch = hash_to_field(b"test-epoch"); + // We generate a random rln_identifier + let rln_identifier = hash_to_field(b"test-rln-identifier"); + let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]); // We prepare input for generate_rln_proof API - // input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal ] + // input_data is [ identity_secret<32> | id_index<8> | epoch<32> | rln_identifier<32> | user_message_limit<32> | message_id<32> | signal_len<8> | signal ] let mut serialized: Vec = Vec::new(); serialized.append(&mut fr_to_bytes_le(&identity_secret_hash)); serialized.append(&mut normalize_usize(identity_index)); - serialized.append(&mut fr_to_bytes_le(&epoch)); + serialized.append(&mut fr_to_bytes_le(&user_message_limit)); + serialized.append(&mut fr_to_bytes_le(&Fr::from(1))); + serialized.append(&mut fr_to_bytes_le(&external_nullifier)); serialized.append(&mut normalize_usize(signal.len())); serialized.append(&mut signal.to_vec()); @@ -1902,7 +2048,7 @@ mod test { .verify_with_roots(&mut input_buffer.clone(), &mut roots_buffer) .unwrap(); - assert!(verified == false); + assert_eq!(verified, false); // We get the root of the tree obtained adding one leaf per time let mut buffer = Cursor::new(Vec::::new()); @@ -1930,10 +2076,13 @@ mod test { // Generate identity pair let (identity_secret_hash, id_commitment) = keygen(); + let user_message_limit = Fr::from(100); + let message_id = Fr::from(0); + let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]); // We set as leaf id_commitment after storing its index let identity_index = rln.tree.leaves_set(); - let mut buffer = Cursor::new(fr_to_bytes_le(&id_commitment)); + let mut buffer = Cursor::new(fr_to_bytes_le(&rate_commitment)); rln.set_next_leaf(&mut buffer).unwrap(); // We generate two random signals @@ -1944,15 +2093,19 @@ mod test { // We generate a random epoch let epoch = hash_to_field(b"test-epoch"); + // We generate a random rln_identifier + let rln_identifier = hash_to_field(b"test-rln-identifier"); + let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]); // We generate two proofs using same epoch but different signals. // We prepare input for generate_rln_proof API - // input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal ] let mut serialized1: Vec = Vec::new(); serialized1.append(&mut fr_to_bytes_le(&identity_secret_hash)); serialized1.append(&mut normalize_usize(identity_index)); - serialized1.append(&mut fr_to_bytes_le(&epoch)); + serialized1.append(&mut fr_to_bytes_le(&user_message_limit)); + serialized1.append(&mut fr_to_bytes_le(&message_id)); + serialized1.append(&mut fr_to_bytes_le(&external_nullifier)); // The first part is the same for both proof input, so we clone let mut serialized2 = serialized1.clone(); @@ -2002,21 +2155,23 @@ mod test { // We generate a new identity pair let (identity_secret_hash_new, id_commitment_new) = keygen(); + let rate_commitment_new = utils_poseidon_hash(&[id_commitment_new, user_message_limit]); // We add it to the tree let identity_index_new = rln.tree.leaves_set(); - let mut buffer = Cursor::new(fr_to_bytes_le(&id_commitment_new)); + let mut buffer = Cursor::new(fr_to_bytes_le(&rate_commitment_new)); rln.set_next_leaf(&mut buffer).unwrap(); // We generate a random signals let signal3: [u8; 32] = rng.gen(); // We prepare proof input. Note that epoch is the same as before - // input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal ] let mut serialized3: Vec = Vec::new(); serialized3.append(&mut fr_to_bytes_le(&identity_secret_hash_new)); serialized3.append(&mut normalize_usize(identity_index_new)); - serialized3.append(&mut fr_to_bytes_le(&epoch)); + serialized3.append(&mut fr_to_bytes_le(&user_message_limit)); + serialized3.append(&mut fr_to_bytes_le(&message_id)); + serialized3.append(&mut fr_to_bytes_le(&external_nullifier)); serialized3.append(&mut normalize_usize(signal3.len())); serialized3.append(&mut signal3.to_vec()); @@ -2040,9 +2195,12 @@ mod test { .unwrap(); let serialized_identity_secret_hash = output_buffer.into_inner(); + let (recovered_identity_secret_hash_new, _) = + bytes_le_to_fr(&serialized_identity_secret_hash); - // We ensure that an empty value was written to output_buffer, i.e. no secret is recovered - assert!(serialized_identity_secret_hash.is_empty()); + // ensure that the recovered secret does not match with either of the + // used secrets in proof generation + assert_ne!(recovered_identity_secret_hash_new, identity_secret_hash_new); } #[test] diff --git a/rln/tests/ffi.rs b/rln/tests/ffi.rs index 8b72c2ed..f4624c48 100644 --- a/rln/tests/ffi.rs +++ b/rln/tests/ffi.rs @@ -37,7 +37,7 @@ mod test { // We first add leaves one by one specifying the index for (i, leaf) in leaves.iter().enumerate() { - // We prepare id_commitment and we set the leaf at provided index + // We prepare the rate_commitment and we set the leaf at provided index let leaf_ser = fr_to_bytes_le(&leaf); let input_buffer = &Buffer::from(leaf_ser.as_ref()); let success = set_leaf(rln_pointer, i, input_buffer); @@ -341,6 +341,7 @@ mod test { fn test_merkle_proof_ffi() { let tree_height = TEST_TREE_HEIGHT; let leaf_index = 3; + let user_message_limit = 1; // We create a RLN instance let mut rln_pointer = MaybeUninit::<*mut RLN>::uninit(); @@ -352,10 +353,12 @@ mod test { // generate identity let identity_secret_hash = hash_to_field(b"test-merkle-proof"); - let id_commitment = utils_poseidon_hash(&vec![identity_secret_hash]); + let id_commitment = utils_poseidon_hash(&[identity_secret_hash]); + let user_message_limit = Fr::from(100); + let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]); // We prepare id_commitment and we set the leaf at provided index - let leaf_ser = fr_to_bytes_le(&id_commitment); + let leaf_ser = fr_to_bytes_le(&rate_commitment); let input_buffer = &Buffer::from(leaf_ser.as_ref()); let success = set_leaf(rln_pointer, leaf_index, input_buffer); assert!(success, "set leaf call failed"); @@ -368,6 +371,21 @@ mod test { let result_data = <&[u8]>::from(&output_buffer).to_vec(); let (root, _) = bytes_le_to_fr(&result_data); + use ark_ff::BigInt; + + if TEST_TREE_HEIGHT == 20 || TEST_TREE_HEIGHT == 32 { + assert_eq!( + root, + BigInt([ + 4939322235247991215, + 5110804094006647505, + 4427606543677101242, + 910933464535675827 + ]) + .into() + ); + } + // We obtain the Merkle tree root let mut output_buffer = MaybeUninit::::uninit(); let success = get_proof(rln_pointer, leaf_index, output_buffer.as_mut_ptr()); @@ -460,8 +478,7 @@ mod test { let mut expected_identity_path_index: Vec = vec![1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - // We add the remaining elements for the case TEST_TREE_HEIGHT = 19 - if TEST_TREE_HEIGHT == 19 || TEST_TREE_HEIGHT == 20 { + if TEST_TREE_HEIGHT == 20 { expected_path_elements.append(&mut vec![ str_to_fr( "0x22f98aa9ce704152ac17354914ad73ed1167ae6596af510aa5b3649325e06c92", @@ -500,8 +517,12 @@ mod test { assert_eq!(identity_path_index, expected_identity_path_index); // We double check that the proof computed from public API is correct - let root_from_proof = - compute_tree_root(&id_commitment, &path_elements, &identity_path_index, false); + let root_from_proof = compute_tree_root( + &identity_secret_hash, + &user_message_limit, + &path_elements, + &identity_path_index, + ); assert_eq!(root, root_from_proof); } @@ -529,7 +550,7 @@ mod test { for _ in 0..sample_size { // We generate random witness instances and relative proof values let rln_witness = random_rln_witness(tree_height); - let proof_values = proof_values_from_witness(&rln_witness); + let proof_values = proof_values_from_witness(&rln_witness).unwrap(); // We prepare id_commitment and we set the leaf at provided index let rln_witness_ser = serialize_witness(&rln_witness).unwrap(); @@ -650,12 +671,15 @@ mod test { fn test_rln_proof_ffi() { let tree_height = TEST_TREE_HEIGHT; let no_of_leaves = 256; + let user_message_limit = Fr::from(65535); // We generate a vector of random leaves let mut leaves: Vec = Vec::new(); let mut rng = thread_rng(); for _ in 0..no_of_leaves { - leaves.push(Fr::rand(&mut rng)); + let id_commitment = Fr::rand(&mut rng); + let rate_commitment = utils_poseidon_hash(&[id_commitment, Fr::from(100)]); + leaves.push(rate_commitment); } // We create a RLN instance @@ -680,12 +704,7 @@ mod test { let result_data = <&[u8]>::from(&output_buffer).to_vec(); let (identity_secret_hash, read) = bytes_le_to_fr(&result_data); let (id_commitment, _) = bytes_le_to_fr(&result_data[read..].to_vec()); - - // We set as leaf id_commitment, its index would be equal to no_of_leaves - let leaf_ser = fr_to_bytes_le(&id_commitment); - let input_buffer = &Buffer::from(leaf_ser.as_ref()); - let success = set_next_leaf(rln_pointer, input_buffer); - assert!(success, "set next leaf call failed"); + let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]); let identity_index: usize = no_of_leaves; @@ -695,13 +714,30 @@ mod test { // We generate a random epoch let epoch = hash_to_field(b"test-epoch"); + let rln_identifier = hash_to_field(b"test-rln-identifier"); + let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]); + + let user_message_limit = Fr::from(100); + let message_id = Fr::from(0); + let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]); + + // We set as leaf rate_commitment, its index would be equal to no_of_leaves + let leaf_ser = fr_to_bytes_le(&rate_commitment); + let input_buffer = &Buffer::from(leaf_ser.as_ref()); + let success = set_next_leaf(rln_pointer, input_buffer); + assert!(success, "set next leaf call failed"); + + // We generate a random rln_identifier + let rln_identifier = hash_to_field(b"test-rln-identifier"); // We prepare input for generate_rln_proof API - // input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal ] + // input_data is [ identity_secret<32> | id_index<8> | user_message_limit<32> | message_id<32> | external_nullifier<32> | signal_len<8> | signal ] let mut serialized: Vec = Vec::new(); serialized.append(&mut fr_to_bytes_le(&identity_secret_hash)); serialized.append(&mut normalize_usize(identity_index)); - serialized.append(&mut fr_to_bytes_le(&epoch)); + serialized.append(&mut fr_to_bytes_le(&user_message_limit)); + serialized.append(&mut fr_to_bytes_le(&message_id)); + serialized.append(&mut fr_to_bytes_le(&external_nullifier)); serialized.append(&mut normalize_usize(signal.len())); serialized.append(&mut signal.to_vec()); @@ -735,6 +771,7 @@ mod test { // First part similar to test_rln_proof_ffi let tree_height = TEST_TREE_HEIGHT; let no_of_leaves = 256; + let user_message_limit = Fr::from(100); // We generate a vector of random leaves let mut leaves: Vec = Vec::new(); @@ -765,12 +802,7 @@ mod test { let result_data = <&[u8]>::from(&output_buffer).to_vec(); let (identity_secret_hash, read) = bytes_le_to_fr(&result_data); let (id_commitment, _) = bytes_le_to_fr(&result_data[read..].to_vec()); - - // We set as leaf id_commitment, its index would be equal to no_of_leaves - let leaf_ser = fr_to_bytes_le(&id_commitment); - let input_buffer = &Buffer::from(leaf_ser.as_ref()); - let success = set_next_leaf(rln_pointer, input_buffer); - assert!(success, "set next leaf call failed"); + let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]); let identity_index: usize = no_of_leaves; @@ -780,13 +812,27 @@ mod test { // We generate a random epoch let epoch = hash_to_field(b"test-epoch"); + let rln_identifier = hash_to_field(b"test-rln-identifier"); + let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]); + + let user_message_limit = Fr::from(100); + let message_id = Fr::from(0); + + // We set as leaf rate_commitment, its index would be equal to no_of_leaves + let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]); + let leaf_ser = fr_to_bytes_le(&rate_commitment); + let input_buffer = &Buffer::from(leaf_ser.as_ref()); + let success = set_next_leaf(rln_pointer, input_buffer); + assert!(success, "set next leaf call failed"); // We prepare input for generate_rln_proof API - // input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal ] + // input_data is [ identity_secret<32> | id_index<8> | user_message_limit<32> | message_id<32> | external_nullifier<32> | signal_len<8> | signal ] let mut serialized: Vec = Vec::new(); serialized.append(&mut fr_to_bytes_le(&identity_secret_hash)); serialized.append(&mut normalize_usize(identity_index)); - serialized.append(&mut fr_to_bytes_le(&epoch)); + serialized.append(&mut fr_to_bytes_le(&user_message_limit)); + serialized.append(&mut fr_to_bytes_le(&message_id)); + serialized.append(&mut fr_to_bytes_le(&external_nullifier)); serialized.append(&mut normalize_usize(signal.len())); serialized.append(&mut signal.to_vec()); @@ -879,8 +925,12 @@ mod test { let (identity_secret_hash, read) = bytes_le_to_fr(&result_data); let (id_commitment, _) = bytes_le_to_fr(&result_data[read..].to_vec()); - // We set as leaf id_commitment, its index would be equal to 0 since tree is empty - let leaf_ser = fr_to_bytes_le(&id_commitment); + let user_message_limit = Fr::from(100); + let message_id = Fr::from(0); + let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit]); + + // We set as leaf rate_commitment, its index would be equal to 0 since tree is empty + let leaf_ser = fr_to_bytes_le(&rate_commitment); let input_buffer = &Buffer::from(leaf_ser.as_ref()); let success = set_next_leaf(rln_pointer, input_buffer); assert!(success, "set next leaf call failed"); @@ -898,13 +948,17 @@ mod test { // We generate a random epoch let epoch = hash_to_field(b"test-epoch"); + let rln_identifier = hash_to_field(b"test-rln-identifier"); + let external_nullifier = utils_poseidon_hash(&[epoch, rln_identifier]); // We prepare input for generate_rln_proof API // input_data is [ identity_secret<32> | id_index<8> | epoch<32> | signal_len<8> | signal ] let mut serialized1: Vec = Vec::new(); serialized1.append(&mut fr_to_bytes_le(&identity_secret_hash)); serialized1.append(&mut normalize_usize(identity_index)); - serialized1.append(&mut fr_to_bytes_le(&epoch)); + serialized1.append(&mut fr_to_bytes_le(&user_message_limit)); + serialized1.append(&mut fr_to_bytes_le(&message_id)); + serialized1.append(&mut fr_to_bytes_le(&external_nullifier)); // The first part is the same for both proof input, so we clone let mut serialized2 = serialized1.clone(); @@ -966,9 +1020,10 @@ mod test { let result_data = <&[u8]>::from(&output_buffer).to_vec(); let (identity_secret_hash_new, read) = bytes_le_to_fr(&result_data); let (id_commitment_new, _) = bytes_le_to_fr(&result_data[read..].to_vec()); + let rate_commitment_new = utils_poseidon_hash(&[id_commitment_new, user_message_limit]); // We set as leaf id_commitment, its index would be equal to 1 since at 0 there is id_commitment - let leaf_ser = fr_to_bytes_le(&id_commitment_new); + let leaf_ser = fr_to_bytes_le(&rate_commitment_new); let input_buffer = &Buffer::from(leaf_ser.as_ref()); let success = set_next_leaf(rln_pointer, input_buffer); assert!(success, "set next leaf call failed"); @@ -984,7 +1039,9 @@ mod test { let mut serialized: Vec = Vec::new(); serialized.append(&mut fr_to_bytes_le(&identity_secret_hash_new)); serialized.append(&mut normalize_usize(identity_index_new)); - serialized.append(&mut fr_to_bytes_le(&epoch)); + serialized.append(&mut fr_to_bytes_le(&user_message_limit)); + serialized.append(&mut fr_to_bytes_le(&message_id)); + serialized.append(&mut fr_to_bytes_le(&external_nullifier)); serialized.append(&mut normalize_usize(signal3.len())); serialized.append(&mut signal3.to_vec()); @@ -1011,10 +1068,12 @@ mod test { assert!(success, "recover id secret call failed"); let output_buffer = unsafe { output_buffer.assume_init() }; let serialized_identity_secret_hash = <&[u8]>::from(&output_buffer).to_vec(); + let (recovered_identity_secret_hash_new, _) = + bytes_le_to_fr(&serialized_identity_secret_hash); - // We passed two shares for different secrets, so recovery should be not successful - // To check it, we ensure that recovered identity secret hash is empty - assert!(serialized_identity_secret_hash.is_empty()); + // ensure that the recovered secret does not match with either of the + // used secrets in proof generation + assert_ne!(recovered_identity_secret_hash_new, identity_secret_hash_new); } #[test] diff --git a/rln/tests/protocol.rs b/rln/tests/protocol.rs index c63c9cbc..a1b3f9bc 100644 --- a/rln/tests/protocol.rs +++ b/rln/tests/protocol.rs @@ -1,5 +1,6 @@ #[cfg(test)] mod test { + use ark_ff::BigInt; use rln::circuit::{ circom_from_folder, vk_from_folder, zkey_from_folder, Fr, TEST_RESOURCES_FOLDER, TEST_TREE_HEIGHT, @@ -13,152 +14,57 @@ mod test { type ConfigOf = ::Config; // Input generated with https://github.com/oskarth/zk-kit/commit/b6a872f7160c7c14e10a0ea40acab99cbb23c9a8 - const WITNESS_JSON_15: &str = r#" - { - "identity_secret": "12825549237505733615964533204745049909430608936689388901883576945030025938736", - "path_elements": [ - "18622655742232062119094611065896226799484910997537830749762961454045300666333", - "20590447254980891299813706518821659736846425329007960381537122689749540452732", - "7423237065226347324353380772367382631490014989348495481811164164159255474657", - "11286972368698509976183087595462810875513684078608517520839298933882497716792", - "3607627140608796879659380071776844901612302623152076817094415224584923813162", - "19712377064642672829441595136074946683621277828620209496774504837737984048981", - "20775607673010627194014556968476266066927294572720319469184847051418138353016", - "3396914609616007258851405644437304192397291162432396347162513310381425243293", - "21551820661461729022865262380882070649935529853313286572328683688269863701601", - "6573136701248752079028194407151022595060682063033565181951145966236778420039", - "12413880268183407374852357075976609371175688755676981206018884971008854919922", - "14271763308400718165336499097156975241954733520325982997864342600795471836726", - "20066985985293572387227381049700832219069292839614107140851619262827735677018", - "9394776414966240069580838672673694685292165040808226440647796406499139370960", - "11331146992410411304059858900317123658895005918277453009197229807340014528524" - ], - "identity_path_index": [ - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "x": "8143228284048792769012135629627737459844825626241842423967352803501040982", - "epoch": "0x0000005b612540fc986b42322f8cb91c2273afad58ed006fdba0c97b4b16b12f", - "rln_identifier": "11412926387081627876309792396682864042420635853496105400039841573530884328439" - } - "#; - - // Input generated with protocol::random_rln_witness - const WITNESS_JSON_19: &str = r#" - { - "identity_secret": "922538810348594125658702672067738675294669207539999802857585668079702330450", - "path_elements": [ - "16059714054680148404543504061485737353203416489071538960876865983954285286166", - "3041470753871943901334053763207316028823782848445723460227667780327106380356", - "2557297527793326315072058421057853700096944625924483912548759909801348042183", - "6677578602456189582427063963562590713054668181987223110955234085327917303436", - "2250827150965576973906150764756422151438812678308727218463995574869267980301", - "1895457427602709606993445561553433669787657053834360973759981803464906070980", - "11033689991077061346803816826729204895841441316315304395980565540264104346466", - "18588752216879570844240300406954267039026327526134910835334500497981810174976", - "19346480964028499661277403659363466542857230928032088490855656809181891953123", - "21460193770370072688835316363068413651465631481105148051902686770759127189327", - "20906347653364838502964722817589315918082261023317339146393355650507243340078", - "13466599592974387800162739317046838825289754472645703919149409009404541432954", - "9617165663598957201253074168824246164494443748556931540348223968573884172285", - "6936463137584425684797785981770877165377386163416057257854261010817156666898", - "369902028235468424790098825415813437044876310542601948037281422841675126849", - "13510969869821080499683463562609720931680005714401083864659516045615497273644", - "2567921390740781421487331055530491683313154421589525170472201828596388395736", - "14360870889466292805403568662660511177232987619663547772298178013674025998478", - "4735344599616284973799984501493858013178071155960162022656706545116168334293" - ], - "identity_path_index": [ - 1, - 0, - 1, - 0, - 1, - 1, - 0, - 0, - 1, - 1, - 1, - 0, - 0, - 0, - 1, - 0, - 1, - 1, - 0 - ], - "x": "6427050788896290028100534859169645070970780055911091444144195464808120686416", - "epoch": "0x2bd155d9f85c741044da6909d144f9cc5ce8e0d545a9ed4921b156e8b8569bab", - "rln_identifier": "2193983000213424579594329476781986065965849144986973472766961413131458022566" - } - "#; - const WITNESS_JSON_20: &str = r#" { - "identity_secret": "13732353453861280511150022598793312186188599006979552959297495195757997428306", - "path_elements": [ - "20463525608687844300981085488128968694844212760055234622292326942405619575964", - "8040856403709217901175408904825741112286158901303127670929462145501210871313", - "3776499751255585163563840252112871568402966629435152937692711318702338789837", - "19415813252626942110541463414404411443562242499365750694284604341271149125679", - "19414720788761208006634240390286942738242262010168559813148115573784354129237", - "17680594732844291740094158892269696200077963275550625226493856898849422516043", - "16009199741350632715210088346611798597033333293348807000623441780059543674510", - "18743496911007535170857676824393811326863602477260615792503039058813338644738", - "1029572792321380246989475723806770724699749375691788486434716005338938722216", - "21713138150151063186050010182615713685603650963220209951496401043119768920892", - "6713732504049401389983008178456811894856018247924860823028704114266363984580", - "2746686888799473963221285145390361693256731812094259845879519459924507786594", - "18620748467731297359505500266677881218553438497271819903304075323783392031715", - "2446201221122671119406471414204229600430018713181038717206670749886932158104", - "12037171942017611311954851302868199608036334625783560875426350283156617524597", - "21798743392351780927808323348278035105395367759688979232116905142049921734349", - "17450230289417496971557215666910229260621413088991137405744457922069827319039", - "20936854099128086256353520300046664152516566958630447858438908748907198510485", - "13513344965831154386658059617477268600255664386844920822248038939666265737046", - "15546319496880899251450021422131511560001766832580480193115646510655765306630" - - ], - "identity_path_index": [ - 0, - 1, - 0, - 0, - 1, - 1, - 0, - 0, - 1, - 1, - 0, - 0, - 0, - 1, - 0, - 1, - 1, - 0, - 0, - 0 - ], - "x": "18073935665561339809445069958310044423750771681863480888589546877024349720547", - "epoch": "0x147e4c23a43a1ddca78d94bcd28147f62ca74b3dc7e56bb0a314a954b9f0e567", - "rln_identifier": "2193983000213424579594329476781986065965849144986973472766961413131458022566" + "externalNullifier": "21074405743803627666274838159589343934394162804826017440941339048886754734203", + "identityPathIndex": [ + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0 + ], + "identitySecret": "2301650865650889795878889082892690584512243988708213561328369865554257051708", + "messageId": "1", + "pathElements": [ + "14082964758224722211945379872337797638951236517417253447686770846170014042825", + "6628418579821163687428454604867534487917867918886059133241840211975892987309", + "12745863228198753394445659605634840709296716381893463421165313830643281758511", + "56118267389743063830320351452083247040583061493621478539311100137113963555", + "3648731943306935051357703221473866306053186513730785325303257057776816073765", + "10548621390442503192989374711060717107954536293658152583621924810330521179016", + "11741160669079729961275351458682156164905457324981803454515784688429276743441", + "17165464309215350864730477596846156251863702878546777829650812432906796008534", + "18947162586829418653666557598416458949428989734998924978331450666032720066913", + "8809427088917589399897132358419395928548406347152047718919154153577297139202", + "6261460226929242970747566981077801929281729646713842579109271945192964422300", + "13871468675790284383809887052382100311103716176061564908030808887079542722597", + "10413964486611723004584705484327518190402370933255450052832412709168190985805", + "3978387560092078849178760154060822400741873818692524912249877867958842934383", + "14014915591348694328771517896715085647041518432952027841088176673715002508448", + "17680675606519345547327984724173632294904524423937145835611954334756161077843", + "17107175244885276119916848057745382329169223109661217238296871427531065458152", + "18326186549441826262593357123467931475982067066825042001499291800252145875109", + "7043961192177345916232559778383741091053414803377017307095275172896944935996", + "2807630271073553218355393059254209097448243975722083008310815929736065268921" + ], + "userMessageLimit": "100", + "x": "20645213238265527935869146898028115621427162613172918400241870500502509785943" } "#; @@ -170,7 +76,8 @@ mod test { // generate identity let identity_secret_hash = hash_to_field(b"test-merkle-proof"); - let id_commitment = poseidon_hash(&vec![identity_secret_hash]); + let id_commitment = poseidon_hash(&[identity_secret_hash]); + let rate_commitment = poseidon_hash(&[id_commitment, 100.into()]); // generate merkle tree let default_leaf = Fr::from(0); @@ -180,37 +87,21 @@ mod test { ConfigOf::::default(), ) .unwrap(); - tree.set(leaf_index, id_commitment.into()).unwrap(); + tree.set(leaf_index, rate_commitment.into()).unwrap(); // We check correct computation of the root let root = tree.root(); - if TEST_TREE_HEIGHT == 15 { + if TEST_TREE_HEIGHT == 20 || TEST_TREE_HEIGHT == 32 { assert_eq!( root, - str_to_fr( - "0x1984f2e01184aef5cb974640898a5f5c25556554e2b06d99d4841badb8b198cd", - 16 - ) - .unwrap() - ); - } else if TEST_TREE_HEIGHT == 19 { - assert_eq!( - root, - str_to_fr( - "0x219ceb53f2b1b7a6cf74e80d50d44d68ecb4a53c6cc65b25593c8d56343fb1fe", - 16 - ) - .unwrap() - ); - } else if TEST_TREE_HEIGHT == 20 { - assert_eq!( - root, - str_to_fr( - "0x21947ffd0bce0c385f876e7c97d6a42eec5b1fe935aab2f01c1f8a8cbcc356d2", - 16 - ) - .unwrap() + BigInt([ + 4939322235247991215, + 5110804094006647505, + 4427606543677101242, + 910933464535675827 + ]) + .into() ); } @@ -302,7 +193,7 @@ mod test { vec![1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // We add the remaining elements for the case TEST_TREE_HEIGHT = 20 - if TEST_TREE_HEIGHT == 19 || TEST_TREE_HEIGHT == 20 { + if TEST_TREE_HEIGHT == 20 { expected_path_elements.append(&mut vec![ str_to_fr( "0x22f98aa9ce704152ac17354914ad73ed1167ae6596af510aa5b3649325e06c92", @@ -341,7 +232,7 @@ mod test { assert_eq!(identity_path_index, expected_identity_path_index); // We check correct verification of the proof - assert!(tree.verify(&id_commitment, &merkle_proof).unwrap()); + assert!(tree.verify(&rate_commitment, &merkle_proof).unwrap()); } #[test] @@ -353,24 +244,12 @@ mod test { let builder = circom_from_folder(TEST_RESOURCES_FOLDER).unwrap(); // We compute witness from the json input example - let mut witness_json: &str = ""; - - if TEST_TREE_HEIGHT == 15 { - witness_json = WITNESS_JSON_15; - } else if TEST_TREE_HEIGHT == 19 { - witness_json = WITNESS_JSON_19; - } else if TEST_TREE_HEIGHT == 20 { - witness_json = WITNESS_JSON_20; - } - - let rln_witness = rln_witness_from_json(witness_json); - - let rln_witness_unwrapped = rln_witness.unwrap(); + let witness_json = WITNESS_JSON_20; + let rln_witness = rln_witness_from_json(witness_json).unwrap(); // Let's generate a zkSNARK proof - let proof = generate_proof(builder, &proving_key, &rln_witness_unwrapped).unwrap(); - - let proof_values = proof_values_from_witness(&rln_witness_unwrapped); + let proof = generate_proof(builder, &proving_key, &rln_witness).unwrap(); + let proof_values = proof_values_from_witness(&rln_witness).unwrap(); // Let's verify the proof let verified = verify_proof(&verification_key, &proof, &proof_values); @@ -386,6 +265,8 @@ mod test { // Generate identity pair let (identity_secret_hash, id_commitment) = keygen(); + let user_message_limit = Fr::from(100); + let rate_commitment = poseidon_hash(&[id_commitment, user_message_limit]); //// generate merkle tree let default_leaf = Fr::from(0); @@ -395,7 +276,7 @@ mod test { ConfigOf::::default(), ) .unwrap(); - tree.set(leaf_index, id_commitment.into()).unwrap(); + tree.set(leaf_index, rate_commitment.into()).unwrap(); let merkle_proof = tree.proof(leaf_index).expect("proof should exist"); @@ -404,14 +285,18 @@ mod test { // We set the remaining values to random ones let epoch = hash_to_field(b"test-epoch"); - //let rln_identifier = hash_to_field(b"test-rln-identifier"); + let rln_identifier = hash_to_field(b"test-rln-identifier"); + let external_nullifier = poseidon_hash(&[epoch, rln_identifier]); let rln_witness: RLNWitnessInput = rln_witness_from_values( identity_secret_hash, &merkle_proof, x, - epoch, /*, rln_identifier*/ - ); + external_nullifier, + user_message_limit, + Fr::from(1), + ) + .unwrap(); // We generate all relevant keys let proving_key = zkey_from_folder(TEST_RESOURCES_FOLDER).unwrap(); @@ -421,7 +306,7 @@ mod test { // Let's generate a zkSNARK proof let proof = generate_proof(builder, &proving_key, &rln_witness).unwrap(); - let proof_values = proof_values_from_witness(&rln_witness); + let proof_values = proof_values_from_witness(&rln_witness).unwrap(); // Let's verify the proof let success = verify_proof(&verification_key, &proof, &proof_values).unwrap(); @@ -432,15 +317,7 @@ mod test { #[test] fn test_witness_serialization() { // We test witness serialization - let mut witness_json: &str = ""; - - if TEST_TREE_HEIGHT == 15 { - witness_json = WITNESS_JSON_15; - } else if TEST_TREE_HEIGHT == 19 { - witness_json = WITNESS_JSON_19; - } else if TEST_TREE_HEIGHT == 20 { - witness_json = WITNESS_JSON_20; - } + let witness_json: &str = WITNESS_JSON_20; let rln_witness = rln_witness_from_json(witness_json).unwrap(); @@ -449,7 +326,7 @@ mod test { assert_eq!(rln_witness, deser); // We test Proof values serialization - let proof_values = proof_values_from_witness(&rln_witness); + let proof_values = proof_values_from_witness(&rln_witness).unwrap(); let ser = serialize_proof_values(&proof_values); let (deser, _) = deserialize_proof_values(&ser); assert_eq!(proof_values, deser); diff --git a/rln/tests/public.rs b/rln/tests/public.rs index b6ba2763..12e4566b 100644 --- a/rln/tests/public.rs +++ b/rln/tests/public.rs @@ -1,5 +1,6 @@ #[cfg(test)] mod test { + use ark_ff::BigInt; use ark_std::{rand::thread_rng, UniformRand}; use rand::Rng; use rln::circuit::{Fr, TEST_RESOURCES_FOLDER, TEST_TREE_HEIGHT}; @@ -15,6 +16,7 @@ mod test { fn test_merkle_proof() { let tree_height = TEST_TREE_HEIGHT; let leaf_index = 3; + let user_message_limit = 1; let input_buffer = Cursor::new(json!({ "resources_folder": TEST_RESOURCES_FOLDER }).to_string()); @@ -23,9 +25,10 @@ mod test { // generate identity let identity_secret_hash = hash_to_field(b"test-merkle-proof"); let id_commitment = utils_poseidon_hash(&vec![identity_secret_hash]); + let rate_commitment = utils_poseidon_hash(&[id_commitment, user_message_limit.into()]); - // We pass id_commitment as Read buffer to RLN's set_leaf - let mut buffer = Cursor::new(fr_to_bytes_le(&id_commitment)); + // We pass rate_commitment as Read buffer to RLN's set_leaf + let mut buffer = Cursor::new(fr_to_bytes_le(&rate_commitment)); rln.set_leaf(leaf_index, &mut buffer).unwrap(); // We check correct computation of the root @@ -33,25 +36,17 @@ mod test { rln.get_root(&mut buffer).unwrap(); let (root, _) = bytes_le_to_fr(&buffer.into_inner()); - if TEST_TREE_HEIGHT == 15 { - assert_eq!( - root, - str_to_fr( - "0x1984f2e01184aef5cb974640898a5f5c25556554e2b06d99d4841badb8b198cd", - 16 - ) - .unwrap() - ); - } else if TEST_TREE_HEIGHT == 19 { + if TEST_TREE_HEIGHT == 20 { assert_eq!( root, - str_to_fr( - "0x219ceb53f2b1b7a6cf74e80d50d44d68ecb4a53c6cc65b25593c8d56343fb1fe", - 16 - ) - .unwrap() + Fr::from(BigInt([ + 17110646155607829651, + 5040045984242729823, + 6965416728592533086, + 2328960363755461975 + ])) ); - } else if TEST_TREE_HEIGHT == 20 { + } else if TEST_TREE_HEIGHT == 32 { assert_eq!( root, str_to_fr( @@ -153,7 +148,7 @@ mod test { vec![1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // We add the remaining elements for the case TEST_TREE_HEIGHT = 20 - if TEST_TREE_HEIGHT == 19 || TEST_TREE_HEIGHT == 20 { + if TEST_TREE_HEIGHT == 20 || TEST_TREE_HEIGHT == 32 { expected_path_elements.append(&mut vec![ str_to_fr( "0x22f98aa9ce704152ac17354914ad73ed1167ae6596af510aa5b3649325e06c92", @@ -192,8 +187,12 @@ mod test { assert_eq!(identity_path_index, expected_identity_path_index); // We double check that the proof computed from public API is correct - let root_from_proof = - compute_tree_root(&id_commitment, &path_elements, &identity_path_index, false); + let root_from_proof = compute_tree_root( + &identity_secret_hash, + &user_message_limit.into(), + &path_elements, + &identity_path_index, + ); assert_eq!(root, root_from_proof); } diff --git a/rln/vendor/rln b/rln/vendor/rln deleted file mode 160000 index fc86ad15..00000000 --- a/rln/vendor/rln +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fc86ad156ac55b7f805b82ff98501e4eb567bcef