Skip to content

Commit ba467d3

Browse files
authored
chore(rln): update dependencies and refactor code for compatibility (#291)
While publishing the release on crate io it turned out that we can't use libraries without a version as it was for arc-circom. During the upgrade to the new version it was also discovered that it is possible to speed up input preparation for witness calculator by 4 times by switching from bigint to Fr: ![image](https://github.com/user-attachments/assets/53962387-308b-4aae-8af2-dbd0d3f62369) it was also checked that it is also possible to use iden3 as a sub-module instead of copying code, but benchmarks showed that the new iden3 version with u256 calculations and subsequent conversion of the result to Fr is slower than the current implementation: ![image](https://github.com/user-attachments/assets/f950f089-b66a-4a13-a86f-f391caf32b4f) ---- - Updated dependencies to their latest versions, including ark-ff, ark-bn254, ark-std, and others to 0.5.0. - Refactored circuit and iden3calc modules to use Fr instead of BigInt for better type consistency. - Improved utility functions for type conversions between Fr and U256. - Adjusted Cargo.toml files for rln and utils to reflect new dependency versions and features. - Enhanced documentation and comments for clarity on changes made. This update ensures compatibility with the latest versions of the Ark framework and improves overall code quality.
1 parent ffd5851 commit ba467d3

File tree

9 files changed

+671
-421
lines changed

9 files changed

+671
-421
lines changed

Cargo.lock

Lines changed: 589 additions & 325 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rln/Cargo.toml

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,21 @@ bench = false
1515
# This flag disable cargo doctests, i.e. testing example code-snippets in documentation
1616
doctest = false
1717

18-
1918
[dependencies]
2019
# ZKP Generation
21-
ark-ec = { version = "=0.4.2", default-features = false }
22-
ark-ff = { version = "=0.4.2", default-features = false, features = ["asm"] }
23-
ark-std = { version = "=0.4.0", default-features = false }
24-
ark-bn254 = { version = "=0.4.0" }
25-
ark-groth16 = { version = "=0.4.0", features = [
20+
ark-bn254 = { version = "0.5.0", features = ["std"] }
21+
ark-ff = { version = "0.5.0", features = ["std", "asm"] }
22+
ark-serialize = { version = "0.5.0", features = ["derive"] }
23+
ark-ec = { version = "0.5.0", default-features = false }
24+
ark-std = { version = "0.5.0", default-features = false }
25+
ark-groth16 = { version = "0.5.0", features = [
2626
"parallel",
2727
], default-features = false }
28-
ark-relations = { version = "=0.4.0", default-features = false, features = [
28+
ark-relations = { version = "0.5.0", default-features = false, features = [
2929
"std",
3030
] }
31-
ark-serialize = { version = "=0.4.2", default-features = false }
32-
# v0.5.0 use all other ark 0.5.0 versions and they are not compatible with current code.
33-
# master branch contains commit with compatible version
34-
ark-circom = { git = "https://github.com/gakonst/ark-circom.git", rev = "7f80002" }
31+
ark-circom = { version = "0.5.0" }
32+
ark-r1cs-std = { version = "0.5.0" }
3533

3634
# error handling
3735
color-eyre = "0.6.2"
@@ -40,34 +38,28 @@ thiserror = "2.0.11"
4038
# utilities
4139
byteorder = "1.4.3"
4240
cfg-if = "1.0"
43-
num-bigint = { version = "0.4.3", default-features = false, features = [
41+
num-bigint = { version = "0.4.6", default-features = false, features = [
4442
"rand",
4543
] }
4644
num-traits = "0.2.19"
4745
once_cell = "1.19.0"
4846
lazy_static = "1.4.0"
4947
rand = "0.8.5"
5048
rand_chacha = "0.3.1"
51-
ruint = { version = "1.10.0", features = [
52-
"rand",
53-
"serde",
54-
"ark-ff-04",
55-
"num-bigint",
56-
] }
49+
ruint = { version = "1.12.4", features = ["rand", "serde", "ark-ff-04"] }
5750
tiny-keccak = { version = "2.0.2", features = ["keccak"] }
58-
utils = { package = "zerokit_utils", path = "../utils/", default-features = false }
59-
51+
utils = { package = "zerokit_utils", version = "0.5.2", path = "../utils/", default-features = false }
6052

6153
# serialization
6254
prost = "0.13.1"
63-
serde_json = "1.0.138"
64-
serde = { version = "1.0.217", features = ["derive"] }
55+
serde_json = "1.0"
56+
serde = { version = "1.0", features = ["derive"] }
6557

6658
document-features = { version = "=0.2.10", optional = true }
6759

6860
[dev-dependencies]
69-
sled = "=0.34.7"
70-
criterion = { version = "=0.4.0", features = ["html_reports"] }
61+
sled = "0.34.7"
62+
criterion = { version = "0.4.0", features = ["html_reports"] }
7163

7264
[features]
7365
default = ["parallel", "pmtree-ft"]

rln/src/circuit.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// This crate provides interfaces for the zero-knowledge circuit and keys
22

3-
use crate::iden3calc::calc_witness;
43
use ::lazy_static::lazy_static;
54
use ark_bn254::{
65
Bn254, Fq as ArkFq, Fq2 as ArkFq2, Fr as ArkFr, G1Affine as ArkG1Affine,
@@ -10,7 +9,8 @@ use ark_groth16::{ProvingKey, VerifyingKey};
109
use ark_relations::r1cs::ConstraintMatrices;
1110
use cfg_if::cfg_if;
1211
use color_eyre::{Report, Result};
13-
use num_bigint::BigInt;
12+
13+
use crate::iden3calc::calc_witness;
1414

1515
#[cfg(feature = "arkzkey")]
1616
use {
@@ -97,7 +97,7 @@ pub fn check_vk_from_zkey(verifying_key: VerifyingKey<Curve>) -> Result<()> {
9797
}
9898
}
9999

100-
pub fn calculate_rln_witness<I: IntoIterator<Item = (String, Vec<BigInt>)>>(
100+
pub fn calculate_rln_witness<I: IntoIterator<Item = (String, Vec<Fr>)>>(
101101
inputs: I,
102102
graph_data: &[u8],
103103
) -> Vec<Fr> {

rln/src/iden3calc.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,22 @@ pub mod graph;
55
pub mod proto;
66
pub mod storage;
77

8-
use ark_bn254::Fr;
9-
use graph::Node;
10-
use num_bigint::BigInt;
118
use ruint::aliases::U256;
129
use std::collections::HashMap;
1310
use storage::deserialize_witnesscalc_graph;
1411

12+
use crate::circuit::Fr;
13+
use graph::{fr_to_u256, Node};
14+
1515
pub type InputSignalsInfo = HashMap<String, (usize, usize)>;
1616

17-
pub fn calc_witness<I: IntoIterator<Item = (String, Vec<BigInt>)>>(
17+
pub fn calc_witness<I: IntoIterator<Item = (String, Vec<Fr>)>>(
1818
inputs: I,
1919
graph_data: &[u8],
2020
) -> Vec<Fr> {
2121
let inputs: HashMap<String, Vec<U256>> = inputs
2222
.into_iter()
23-
.map(|(key, value)| (key, value.iter().map(|v| U256::from(v)).collect()))
23+
.map(|(key, value)| (key, value.iter().map(fr_to_u256).collect()))
2424
.collect();
2525

2626
let (nodes, signals, input_mapping): (Vec<Node>, Vec<usize>, InputSignalsInfo) =

rln/src/iden3calc/graph.rs

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
11
// This file is based on the code by iden3. Its preimage can be found here:
22
// https://github.com/iden3/circom-witnesscalc/blob/5cb365b6e4d9052ecc69d4567fcf5bc061c20e94/src/graph.rs
33

4-
use crate::iden3calc::proto;
5-
use ark_bn254::Fr;
64
use ark_ff::{BigInt, BigInteger, One, PrimeField, Zero};
5+
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate};
76
use rand::Rng;
8-
use ruint::aliases::U256;
7+
use ruint::{aliases::U256, uint};
98
use serde::{Deserialize, Serialize};
10-
use std::cmp::Ordering;
11-
use std::error::Error;
12-
use std::ops::{BitOr, BitXor, Deref};
139
use std::{
10+
cmp::Ordering,
1411
collections::HashMap,
15-
ops::{BitAnd, Shl, Shr},
12+
error::Error,
13+
ops::{BitAnd, BitOr, BitXor, Deref, Shl, Shr},
1614
};
1715

18-
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate};
19-
use ruint::uint;
16+
use crate::circuit::Fr;
17+
use crate::iden3calc::proto;
2018

2119
pub const M: U256 =
2220
uint!(21888242871839275222246405745257275088548364400416034343698204186575808495617_U256);
@@ -40,6 +38,16 @@ where
4038
a.map_err(serde::de::Error::custom)
4139
}
4240

41+
#[inline(always)]
42+
pub fn fr_to_u256(x: &Fr) -> U256 {
43+
U256::from_limbs(x.into_bigint().0)
44+
}
45+
46+
#[inline(always)]
47+
pub fn u256_to_fr(x: &U256) -> Fr {
48+
Fr::from_bigint(BigInt::new(x.into_limbs())).expect("Failed to convert U256 to Fr")
49+
}
50+
4351
#[derive(Hash, PartialEq, Eq, Debug, Clone, Copy, Serialize, Deserialize)]
4452
pub enum Operation {
4553
Mul,
@@ -125,14 +133,18 @@ impl Operation {
125133
if b.is_zero() {
126134
Fr::zero()
127135
} else {
128-
Fr::new((Into::<U256>::into(a) / Into::<U256>::into(b)).into())
136+
let a_u256 = fr_to_u256(&a);
137+
let b_u256 = fr_to_u256(&b);
138+
u256_to_fr(&(a_u256 / b_u256))
129139
}
130140
}
131141
Mod => {
132142
if b.is_zero() {
133143
Fr::zero()
134144
} else {
135-
Fr::new((Into::<U256>::into(a) % Into::<U256>::into(b)).into())
145+
let a_u256 = fr_to_u256(&a);
146+
let b_u256 = fr_to_u256(&b);
147+
u256_to_fr(&(a_u256 % b_u256))
136148
}
137149
}
138150
Eq => match a.cmp(&b) {
@@ -143,10 +155,10 @@ impl Operation {
143155
Ordering::Equal => Fr::zero(),
144156
_ => Fr::one(),
145157
},
146-
Lt => Fr::new(u_lt(&a.into(), &b.into()).into()),
147-
Gt => Fr::new(u_gt(&a.into(), &b.into()).into()),
148-
Leq => Fr::new(u_lte(&a.into(), &b.into()).into()),
149-
Geq => Fr::new(u_gte(&a.into(), &b.into()).into()),
158+
Lt => u256_to_fr(&u_lt(&fr_to_u256(&a), &fr_to_u256(&b))),
159+
Gt => u256_to_fr(&u_gt(&fr_to_u256(&a), &fr_to_u256(&b))),
160+
Leq => u256_to_fr(&u_lte(&fr_to_u256(&a), &fr_to_u256(&b))),
161+
Geq => u256_to_fr(&u_gte(&fr_to_u256(&a), &fr_to_u256(&b))),
150162
Land => {
151163
if a.is_zero() || b.is_zero() {
152164
Fr::zero()
@@ -415,9 +427,9 @@ pub fn evaluate(nodes: &[Node], inputs: &[U256], outputs: &[usize]) -> Vec<Fr> {
415427
let mut values = Vec::with_capacity(nodes.len());
416428
for &node in nodes.iter() {
417429
let value = match node {
418-
Node::Constant(c) => Fr::new(c.into()),
430+
Node::Constant(c) => u256_to_fr(&c),
419431
Node::MontConstant(c) => c,
420-
Node::Input(i) => Fr::new(inputs[i].into()),
432+
Node::Input(i) => u256_to_fr(&inputs[i]),
421433
Node::Op(op, a, b) => op.eval_fr(values[a], values[b]),
422434
Node::UnoOp(op, a) => op.eval_fr(values[a]),
423435
Node::TresOp(op, a, b, c) => op.eval_fr(values[a], values[b], values[c]),
@@ -633,7 +645,7 @@ pub fn montgomery_form(nodes: &mut [Node]) {
633645
use Node::*;
634646
use Operation::*;
635647
match node {
636-
Constant(c) => *node = MontConstant(Fr::new((*c).into())),
648+
Constant(c) => *node = MontConstant(u256_to_fr(c)),
637649
MontConstant(..) => (),
638650
Input(..) => (),
639651
Op(
@@ -659,10 +671,8 @@ fn shl(a: Fr, b: Fr) -> Fr {
659671
}
660672

661673
let n = b.into_bigint().0[0] as u32;
662-
663-
let mut a = a.into_bigint();
664-
a.muln(n);
665-
Fr::from_bigint(a).unwrap()
674+
let a = a.into_bigint();
675+
Fr::from_bigint(a << n).unwrap()
666676
}
667677

668678
fn shr(a: Fr, b: Fr) -> Fr {

rln/src/iden3calc/storage.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
// This file is based on the code by iden3. Its preimage can be found here:
22
// https://github.com/iden3/circom-witnesscalc/blob/5cb365b6e4d9052ecc69d4567fcf5bc061c20e94/src/storage.rs
33

4-
use crate::iden3calc::{
5-
graph,
6-
graph::{Operation, TresOperation, UnoOperation},
7-
proto, InputSignalsInfo,
8-
};
94
use ark_bn254::Fr;
105
use ark_ff::PrimeField;
116
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
127
use prost::Message;
138
use std::io::{Read, Write};
149

10+
use crate::iden3calc::{
11+
graph,
12+
graph::{Operation, TresOperation, UnoOperation},
13+
proto, InputSignalsInfo,
14+
};
15+
1516
// format of the wtns.graph file:
1617
// + magic line: wtns.graph.001
1718
// + 4 bytes unsigned LE 32-bit integer: number of nodes

rln/src/protocol.rs

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// This crate collects all the underlying primitives used to implement RLN
22

3+
use ark_bn254::Fr;
34
use ark_circom::CircomReduction;
45
use ark_groth16::{prepare_verifying_key, Groth16, Proof as ArkProof, ProvingKey, VerifyingKey};
5-
use ark_relations::r1cs::ConstraintMatrices;
6-
use ark_relations::r1cs::SynthesisError;
6+
use ark_relations::r1cs::{ConstraintMatrices, SynthesisError};
77
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
88
use ark_std::{rand::thread_rng, UniformRand};
99
use color_eyre::{Report, Result};
@@ -16,9 +16,8 @@ use std::time::Instant;
1616
use thiserror::Error;
1717
use tiny_keccak::{Hasher as _, Keccak};
1818

19-
use crate::circuit::{calculate_rln_witness, Curve, Fr};
20-
use crate::hashers::hash_to_field;
21-
use crate::hashers::poseidon_hash;
19+
use crate::circuit::{calculate_rln_witness, Curve};
20+
use crate::hashers::{hash_to_field, poseidon_hash};
2221
use crate::poseidon_tree::*;
2322
use crate::public::RLN_IDENTIFIER;
2423
use crate::utils::*;
@@ -606,40 +605,23 @@ pub fn generate_proof_with_witness(
606605
/// Returns an error if `rln_witness.message_id` is not within `rln_witness.user_message_limit`.
607606
pub fn inputs_for_witness_calculation(
608607
rln_witness: &RLNWitnessInput,
609-
) -> Result<[(&str, Vec<BigInt>); 7]> {
608+
) -> Result<[(&str, Vec<Fr>); 7]> {
610609
message_id_range_check(&rln_witness.message_id, &rln_witness.user_message_limit)?;
611610

612-
// We convert the path indexes to field elements
613-
// TODO: check if necessary
614-
let mut path_elements = Vec::new();
615-
616-
for v in rln_witness.path_elements.iter() {
617-
path_elements.push(to_bigint(v)?);
618-
}
619-
620-
let mut identity_path_index = Vec::new();
611+
let mut identity_path_index = Vec::with_capacity(rln_witness.identity_path_index.len());
621612
rln_witness
622613
.identity_path_index
623614
.iter()
624-
.for_each(|v| identity_path_index.push(BigInt::from(*v)));
615+
.for_each(|v| identity_path_index.push(Fr::from(*v)));
625616

626617
Ok([
627-
(
628-
"identitySecret",
629-
vec![to_bigint(&rln_witness.identity_secret)?],
630-
),
631-
(
632-
"userMessageLimit",
633-
vec![to_bigint(&rln_witness.user_message_limit)?],
634-
),
635-
("messageId", vec![to_bigint(&rln_witness.message_id)?]),
636-
("pathElements", path_elements),
618+
("identitySecret", vec![rln_witness.identity_secret]),
619+
("userMessageLimit", vec![rln_witness.user_message_limit]),
620+
("messageId", vec![rln_witness.message_id]),
621+
("pathElements", rln_witness.path_elements.clone()),
637622
("identityPathIndex", identity_path_index),
638-
("x", vec![to_bigint(&rln_witness.x)?]),
639-
(
640-
"externalNullifier",
641-
vec![to_bigint(&rln_witness.external_nullifier)?],
642-
),
623+
("x", vec![rln_witness.x]),
624+
("externalNullifier", vec![rln_witness.external_nullifier]),
643625
])
644626
}
645627

rln/src/utils.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
// This crate provides cross-module useful utilities (mainly type conversions) not necessarily specific to RLN
22

3-
use crate::circuit::Fr;
43
use ark_ff::PrimeField;
54
use color_eyre::{Report, Result};
65
use num_bigint::{BigInt, BigUint};
76
use num_traits::Num;
87
use serde_json::json;
98
use std::io::Cursor;
109

10+
use crate::circuit::Fr;
11+
1112
#[inline(always)]
1213
pub fn to_bigint(el: &Fr) -> Result<BigInt> {
1314
Ok(BigUint::from(*el).into())

utils/Cargo.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "zerokit_utils"
3-
version = "0.5.1"
3+
version = "0.5.2"
44
edition = "2021"
55
license = "MIT OR Apache-2.0"
66
description = "Various utilities for Zerokit"
@@ -12,19 +12,19 @@ repository = "https://github.com/vacp2p/zerokit"
1212
bench = false
1313

1414
[dependencies]
15-
ark-ff = { version = "=0.4.2", default-features = false, features = ["asm"] }
16-
num-bigint = { version = "0.4.3", default-features = false, features = [
15+
ark-ff = { version = "0.5.0", features = ["asm"] }
16+
num-bigint = { version = "0.4.6", default-features = false, features = [
1717
"rand",
1818
] }
1919
color-eyre = "0.6.2"
2020
pmtree = { package = "vacp2p_pmtree", version = "=2.0.2", optional = true }
21-
sled = "=0.34.7"
21+
sled = "0.34.7"
2222
serde = "1.0"
2323
lazy_static = "1.4.0"
2424
hex = "0.4"
2525

2626
[dev-dependencies]
27-
ark-bn254 = "=0.4.0"
27+
ark-bn254 = { version = "0.5.0", features = ["std"] }
2828
num-traits = "0.2.19"
2929
hex-literal = "0.3.4"
3030
tiny-keccak = { version = "2.0.2", features = ["keccak"] }

0 commit comments

Comments
 (0)