Skip to content

Commit 5517201

Browse files
authored
Improve the prerformance of the circuits (#7)
* docs: add GitHub DKG implementations * Update documentation * Fix indexing missmatch in spec * Ensures the final key reconstruction follows the spec's requirement that PK(SS) = P(0) * Rename t to k in spec to match the implementation and fix the hashing order * Initialize performance base line * Optimize the lagrange_interpolation * Remove the redundant largrange_interpolation from compute_agg_key_from_dkg * Reduce code duplication * Little refactoring
1 parent ada0d86 commit 5517201

File tree

13 files changed

+1201
-292
lines changed

13 files changed

+1201
-292
lines changed

Makefile

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ TEST_SCRIPT := $(REPO_ROOT)/script/run.sh
99

1010
help:
1111
@echo "Makefile targets:"
12-
@echo " test Run all tests using the run_tests.sh script"
13-
@echo " help Show this help message"
12+
@echo " test Run all tests using the run_tests.sh script"
13+
@echo " instruction-compare Compare instruction counts against baseline"
14+
@echo " instruction-baseline Create new instruction count baseline"
15+
@echo " help Show this help message"
1416

1517
install-git-hooks:
1618
@ls -R ./.git/hooks > before.txt
@@ -38,4 +40,10 @@ test:
3840
fi
3941
@cd "$(REPO_ROOT)/crates/dkg" && cargo test
4042
@cd "$(REPO_ROOT)" && $(TEST_SCRIPT) $(ARGS)
43+
44+
perf-compare:
45+
@cd "$(REPO_ROOT)" && python3 script/instruction_count.py compare
46+
47+
gen-perf-baseline:
48+
@cd "$(REPO_ROOT)" && python3 script/instruction_count.py create-baseline
4149

crates/dkg/src/dkg_math.rs

Lines changed: 180 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,10 @@ pub fn lagrange_interpolation<C: Curve>(
204204
"zero secret share id",
205205
)));
206206
}
207-
let mut r = C::Point::identity();
207+
// Pre-allocate vectors for batch processing
208+
let mut terms = Vec::with_capacity(k);
209+
let mut denominators = Vec::with_capacity(k);
210+
208211
for i in 0..k {
209212
let mut b = x_vec[i];
210213
for j in 0..k {
@@ -219,32 +222,110 @@ pub fn lagrange_interpolation<C: Curve>(
219222
b.mul_assign(&v);
220223
}
221224
}
222-
let li0 = a.mul(&b.invert());
223-
let tmp = y_vec[i].mul_scalar(&li0);
224-
r = r.add(&tmp);
225+
denominators.push(b);
226+
}
227+
228+
let inv_denominators = batch_invert::<C>(&denominators);
229+
230+
for i in 0..k {
231+
let li0 = a.mul(&inv_denominators[i]);
232+
terms.push(y_vec[i].mul_scalar(&li0));
225233
}
226-
Ok(r)
234+
235+
// Batch add all terms
236+
Ok(batch_add_points::<C>(&terms))
227237
}
228238

229239
#[allow(clippy::assign_op_pattern)]
230-
pub fn agg_coefficients<C: Curve>(
231-
verification_vectors: &[Vec<C::Point>],
232-
ids: &[C::Scalar],
233-
) -> Vec<C::Point> {
234-
let mut final_cfs = Vec::new();
235-
for i in 0..verification_vectors[0].len() {
236-
let mut sum = C::Point::identity();
240+
pub fn agg_coefficients<C: Curve>(verification_vectors: &[Vec<C::Point>]) -> Vec<C::Point> {
241+
if verification_vectors.is_empty() {
242+
return Vec::new();
243+
}
244+
let num_vectors = verification_vectors.len();
245+
let vector_len = verification_vectors[0].len();
246+
247+
// Pre-allocate the result vector
248+
let mut final_cfs = Vec::with_capacity(vector_len);
249+
250+
// Batch point additions for better cache locality and performance
251+
for i in 0..vector_len {
252+
// Collect all points at position i for batch addition
253+
let mut points_to_sum = Vec::with_capacity(num_vectors);
237254
for v in verification_vectors {
238-
sum = sum.add(&v[i]);
255+
points_to_sum.push(v[i]);
239256
}
257+
258+
// Perform batched addition
259+
let sum = batch_add_points::<C>(&points_to_sum);
240260
final_cfs.push(sum);
241261
}
242-
let mut final_keys = Vec::new();
243-
for id in ids.iter() {
244-
let tmp = evaluate_polynomial::<C>(&final_cfs, id);
245-
final_keys.push(tmp);
262+
final_cfs
263+
}
264+
265+
// Optimized batch point addition function for elliptic curve operations
266+
pub fn batch_add_points<C: Curve>(points: &[C::Point]) -> C::Point {
267+
if points.is_empty() {
268+
return C::Point::identity();
269+
}
270+
271+
if points.len() == 1 {
272+
return points[0];
273+
}
274+
275+
// For small numbers of points, use sequential addition
276+
if points.len() <= 4 {
277+
let mut sum = points[0];
278+
for point in &points[1..] {
279+
sum = sum.add(point);
280+
}
281+
return sum;
282+
}
283+
284+
// For larger numbers, use a binary tree approach to reduce depth
285+
let mut current_points = points.to_vec();
286+
287+
while current_points.len() > 1 {
288+
let mut next_level = Vec::new();
289+
let mut i = 0;
290+
while i < current_points.len() {
291+
if i + 1 < current_points.len() {
292+
// Add pairs
293+
next_level.push(current_points[i].add(&current_points[i + 1]));
294+
i += 2;
295+
} else {
296+
// Handle odd element
297+
next_level.push(current_points[i]);
298+
i += 1;
299+
}
300+
}
301+
current_points = next_level;
302+
}
303+
304+
current_points[0]
305+
}
306+
307+
fn batch_invert<C: Curve>(scalars: &[C::Scalar]) -> Vec<C::Scalar> {
308+
if scalars.is_empty() {
309+
return Vec::new();
310+
}
311+
312+
let mut products = Vec::with_capacity(scalars.len());
313+
let mut current_product = C::Scalar::from_u32(1);
314+
315+
for s in scalars {
316+
current_product = current_product.mul(s);
317+
products.push(current_product);
246318
}
247-
final_keys
319+
320+
let mut inv = products[products.len() - 1].invert();
321+
let mut result = vec![C::Scalar::from_u32(0); scalars.len()];
322+
323+
for i in (1..scalars.len()).rev() {
324+
result[i] = inv.mul(&products[i - 1]);
325+
inv = inv.mul(&scalars[i]);
326+
}
327+
result[0] = inv;
328+
result
248329
}
249330

250331
#[cfg(test)]
@@ -253,40 +334,93 @@ mod tests {
253334
use crate::types::*;
254335
use bls12_381::*;
255336

337+
// Helper functions to reduce test code duplication
338+
339+
fn hex_to_bls_g1(hex_str: &str) -> BlsG1 {
340+
let pk_raw: BLSPubkeyRaw = hex::decode(hex_str).unwrap().try_into().unwrap();
341+
BlsG1 {
342+
g1: G1Affine::from_compressed(&pk_raw).into_option().unwrap(),
343+
}
344+
}
345+
346+
fn hexes_to_bls_g1s(hex_strings: &[&str]) -> Vec<BlsG1> {
347+
hex_strings.iter().map(|hex| hex_to_bls_g1(hex)).collect()
348+
}
349+
350+
fn hex_to_g1_affine(hex_str: &str) -> G1Affine {
351+
let pk_raw: BLSPubkeyRaw = hex::decode(hex_str).unwrap().try_into().unwrap();
352+
G1Affine::from_compressed(&pk_raw).into_option().unwrap()
353+
}
354+
355+
fn hex_to_g2_affine(hex_str: &str) -> G2Affine {
356+
let sig_raw: BLSSignatureRaw = hex::decode(hex_str).unwrap().try_into().unwrap();
357+
G2Affine::from_compressed(&sig_raw).into_option().unwrap()
358+
}
359+
256360
use super::*;
257361

362+
#[test]
363+
fn test_batch_invert_basic() {
364+
let scalars = vec![
365+
BlsScalar::from_u32(2),
366+
BlsScalar::from_u32(3),
367+
BlsScalar::from_u32(4),
368+
BlsScalar::from_u32(5),
369+
];
370+
371+
let inverted = batch_invert::<BlsG1Curve>(&scalars);
372+
373+
assert_eq!(scalars.len(), inverted.len());
374+
375+
for i in 0..scalars.len() {
376+
let product = scalars[i].mul(&inverted[i]);
377+
assert_eq!(product.scalar, Scalar::one());
378+
}
379+
}
380+
381+
#[test]
382+
fn test_batch_invert_empty() {
383+
let scalars: Vec<BlsScalar> = vec![];
384+
let inverted = batch_invert::<BlsG1Curve>(&scalars);
385+
assert!(inverted.is_empty());
386+
}
387+
388+
#[test]
389+
fn test_batch_invert_single() {
390+
let scalar = BlsScalar::from_u32(42);
391+
let scalars = vec![scalar];
392+
393+
let inverted = batch_invert::<BlsG1Curve>(&scalars);
394+
395+
assert_eq!(inverted.len(), 1);
396+
assert_eq!(inverted[0].scalar, scalar.invert().scalar);
397+
}
398+
258399
#[test]
259400
fn test_verify_signature() {
260401
let data = hex::decode("2f901d5cec8722e44afd59e94d0a56bf1506a72a0a60709920aad714d1a2ece0")
261402
.unwrap();
262-
let pk: BLSPubkeyRaw = hex::decode("90346f9c5f3c09d96ea02acd0220daa8459f03866ed938c798e3716e42c7e033c9a7ef66a10f83af06d5c00b508c6d0f").unwrap().try_into().unwrap();
263-
let sig:BLSSignatureRaw = hex::decode("a9c08eff13742f78f1e5929888f223b5b5b12b4836b5417c5a135cf24f4e2a4c66a6cdef91be3098b7e7a6a63903b61302e3cf2b8653101da245cf01a8d82b25debe7b18a3a2eb1778f8628fd2c59c8687f6e048a31250fbc2804c20043b8443").unwrap().try_into().unwrap();
264-
let pk = G1Affine::from_compressed(&pk).into_option().unwrap();
265-
let sig = G2Affine::from_compressed(&sig).into_option().unwrap();
403+
let pk = hex_to_g1_affine("90346f9c5f3c09d96ea02acd0220daa8459f03866ed938c798e3716e42c7e033c9a7ef66a10f83af06d5c00b508c6d0f");
404+
let sig = hex_to_g2_affine("a9c08eff13742f78f1e5929888f223b5b5b12b4836b5417c5a135cf24f4e2a4c66a6cdef91be3098b7e7a6a63903b61302e3cf2b8653101da245cf01a8d82b25debe7b18a3a2eb1778f8628fd2c59c8687f6e048a31250fbc2804c20043b8443");
266405
assert!(bls_verify(&pk, &sig, &data));
267406

268407
let invalida_data = hex::decode("00").unwrap();
269408
assert!(!bls_verify(&pk, &sig, &invalida_data));
270409

271-
let wrong_pk: BLSPubkeyRaw = hex::decode("98876a81fe982573ec5f986956bf9bf0bcb5349d95c3c8da0aefd05a49fea6215f59b0696f906547baed90ab245804e8").unwrap().try_into().unwrap();
272-
let wrong_pk = G1Affine::from_compressed(&wrong_pk).into_option().unwrap();
410+
let wrong_pk = hex_to_g1_affine("98876a81fe982573ec5f986956bf9bf0bcb5349d95c3c8da0aefd05a49fea6215f59b0696f906547baed90ab245804e8");
273411
assert!(!bls_verify(&wrong_pk, &sig, &data));
274412

275-
let bad_sig: BLSSignatureRaw = hex::decode("999e7b24bee2587d687e8f358ed10627ef57ec54935bd7a500bbbb18a57e7aa21b800f8b1f487a980d7c93918fdbd8020b66ce9a9e5788a4826e610ac937d8c2ce0ad9c0ee9a5732cf73052493e9a500cc5100a15bdbf9e5b79104db52dbf07c").unwrap().try_into().unwrap();
276-
let bad_sig = G2Affine::from_compressed(&bad_sig).into_option().unwrap();
413+
let bad_sig = hex_to_g2_affine("999e7b24bee2587d687e8f358ed10627ef57ec54935bd7a500bbbb18a57e7aa21b800f8b1f487a980d7c93918fdbd8020b66ce9a9e5788a4826e610ac937d8c2ce0ad9c0ee9a5732cf73052493e9a500cc5100a15bdbf9e5b79104db52dbf07c");
277414
assert!(!bls_verify(&pk, &bad_sig, &data))
278415
}
279416

280417
#[test]
281418
fn test_evaluate_polynomial() {
282-
let pks: Vec<BlsG1> = [
419+
let pks = hexes_to_bls_g1s(&[
283420
"92cad77a95432bc1030d81b5465cb69be672c1dd0da752230bf8112f8449b03149e7fa208a6fae460a9f0a1d5bd175e9",
284421
"98876a81fe982573ec5f986956bf9bf0bcb5349d95c3c8da0aefd05a49fea6215f59b0696f906547baed90ab245804e8",
285-
"ad2c4e5b631fbded449ede4dca2d040b9c7eae58d1e73b3050486c1ba22c15a92d9ff13c05c356f974447e4fca84864a"]
286-
.iter().map(|pk| -> BLSPubkeyRaw {
287-
hex::decode(pk).unwrap().try_into().unwrap()
288-
})
289-
.map(|pk| BlsG1{ g1: G1Affine::from_compressed(&pk).into_option().unwrap() }).collect();
422+
"ad2c4e5b631fbded449ede4dca2d040b9c7eae58d1e73b3050486c1ba22c15a92d9ff13c05c356f974447e4fca84864a",
423+
]);
290424

291425
let target = "af8e0095ecc662f65b95ce57e5bd2f8739ff93b0621a1ad53f5616538d1323ff40e6e9ddd7132298710974fe6fc0344e";
292426

@@ -299,14 +433,11 @@ mod tests {
299433

300434
#[test]
301435
fn test_evaluate_polynomial_bad_base_keys() {
302-
let pks: Vec<BlsG1> = [
436+
let pks = hexes_to_bls_g1s(&[
303437
"92cad77a95432bc1030d81b5465cb69be672c1dd0da752230bf8112f8449b03149e7fa208a6fae460a9f0a1d5bd175e9",
304438
"92cad77a95432bc1030d81b5465cb69be672c1dd0da752230bf8112f8449b03149e7fa208a6fae460a9f0a1d5bd175e9",
305-
"92cad77a95432bc1030d81b5465cb69be672c1dd0da752230bf8112f8449b03149e7fa208a6fae460a9f0a1d5bd175e9"]
306-
.iter().map(|pk| -> BLSPubkeyRaw {
307-
hex::decode(pk).unwrap().try_into().unwrap()
308-
})
309-
.map(|pk| BlsG1{ g1: G1Affine::from_compressed(&pk).into_option().unwrap() }).collect();
439+
"92cad77a95432bc1030d81b5465cb69be672c1dd0da752230bf8112f8449b03149e7fa208a6fae460a9f0a1d5bd175e9",
440+
]);
310441

311442
let target = "af8e0095ecc662f65b95ce57e5bd2f8739ff93b0621a1ad53f5616538d1323ff40e6e9ddd7132298710974fe6fc0344e";
312443

@@ -319,16 +450,13 @@ mod tests {
319450

320451
#[test]
321452
fn test_lagrange_interpolation() {
322-
let pks: Vec<BlsG1> = [
453+
let pks = hexes_to_bls_g1s(&[
323454
"8da434e68daef9af33e39ab727557a3cd86d7991cd6b545746bf92c8edec37012912cfa2292a21512bce9040a1c0e502",
324455
"a3cd061aab6013f7561978959482d79e9ca636392bc94d4bcad9cb6f90fe2cdf52100f211052f1570db0ca690b6a9903",
325456
"8cbfb6cb7af927cfe5fb17621df7036de539b7ff4aa0620cdc218d6b7fe7f2e714a96bdeddb2a0dc24867a90594427e1",
326457
"9892b390d9d3000c7bf04763006fbc617b7ba9c261fff35094aec3f43599f2c254ae667d9ba135747309b77cd02f1fbc",
327-
"b255c8a66fd1a13373537e8a4ba258f4990c141fc3c06daccda0711f5ebaffc092f0e5b0e4454e6344e2f97957be4017"]
328-
.iter().map(|pk| -> BLSPubkeyRaw {
329-
hex::decode(pk).unwrap().try_into().unwrap()
330-
})
331-
.map(|pk| BlsG1{ g1: G1Affine::from_compressed(&pk).into_option().unwrap()}).collect();
458+
"b255c8a66fd1a13373537e8a4ba258f4990c141fc3c06daccda0711f5ebaffc092f0e5b0e4454e6344e2f97957be4017",
459+
]);
332460

333461
let target = "a31d9a483703cd0da9873e5e76b4de5f7035d0a73d79b3be8667daa4fc7065a1bbb5bf77787fcf2a35bd327eecc4fa6b";
334462

@@ -347,17 +475,13 @@ mod tests {
347475

348476
#[test]
349477
fn test_lagrange_interpolation_out_of_order() {
350-
let pks: Vec<BlsG1> = [
478+
let pks = hexes_to_bls_g1s(&[
351479
"b255c8a66fd1a13373537e8a4ba258f4990c141fc3c06daccda0711f5ebaffc092f0e5b0e4454e6344e2f97957be4017",
352480
"8da434e68daef9af33e39ab727557a3cd86d7991cd6b545746bf92c8edec37012912cfa2292a21512bce9040a1c0e502",
353481
"a3cd061aab6013f7561978959482d79e9ca636392bc94d4bcad9cb6f90fe2cdf52100f211052f1570db0ca690b6a9903",
354482
"8cbfb6cb7af927cfe5fb17621df7036de539b7ff4aa0620cdc218d6b7fe7f2e714a96bdeddb2a0dc24867a90594427e1",
355483
"9892b390d9d3000c7bf04763006fbc617b7ba9c261fff35094aec3f43599f2c254ae667d9ba135747309b77cd02f1fbc",
356-
]
357-
.iter().map(|pk| -> BLSPubkeyRaw {
358-
hex::decode(pk).unwrap().try_into().unwrap()
359-
})
360-
.map(|pk| BlsG1{ g1: G1Affine::from_compressed(&pk).into_option().unwrap()}).collect();
484+
]);
361485

362486
let target = "a31d9a483703cd0da9873e5e76b4de5f7035d0a73d79b3be8667daa4fc7065a1bbb5bf77787fcf2a35bd327eecc4fa6b";
363487

@@ -376,16 +500,13 @@ mod tests {
376500

377501
#[test]
378502
fn test_lagrange_interpolation_wrong_order() {
379-
let pks: Vec<BlsG1> = [
503+
let pks = hexes_to_bls_g1s(&[
380504
"a3cd061aab6013f7561978959482d79e9ca636392bc94d4bcad9cb6f90fe2cdf52100f211052f1570db0ca690b6a9903",
381505
"8da434e68daef9af33e39ab727557a3cd86d7991cd6b545746bf92c8edec37012912cfa2292a21512bce9040a1c0e502",
382506
"8cbfb6cb7af927cfe5fb17621df7036de539b7ff4aa0620cdc218d6b7fe7f2e714a96bdeddb2a0dc24867a90594427e1",
383507
"9892b390d9d3000c7bf04763006fbc617b7ba9c261fff35094aec3f43599f2c254ae667d9ba135747309b77cd02f1fbc",
384-
"b255c8a66fd1a13373537e8a4ba258f4990c141fc3c06daccda0711f5ebaffc092f0e5b0e4454e6344e2f97957be4017"]
385-
.iter().map(|pk| -> BLSPubkeyRaw {
386-
hex::decode(pk).unwrap().try_into().unwrap()
387-
})
388-
.map(|pk| BlsG1{ g1: G1Affine::from_compressed(&pk).into_option().unwrap()}).collect();
508+
"b255c8a66fd1a13373537e8a4ba258f4990c141fc3c06daccda0711f5ebaffc092f0e5b0e4454e6344e2f97957be4017",
509+
]);
389510

390511
let target = "a31d9a483703cd0da9873e5e76b4de5f7035d0a73d79b3be8667daa4fc7065a1bbb5bf77787fcf2a35bd327eecc4fa6b";
391512

@@ -404,16 +525,13 @@ mod tests {
404525

405526
#[test]
406527
fn test_lagrange_interpolation_wrong_base_keys() {
407-
let pks: Vec<BlsG1> = [
528+
let pks = hexes_to_bls_g1s(&[
408529
"a3cd061aab6013f7561978959482d79e9ca636392bc94d4bcad9cb6f90fe2cdf52100f211052f1570db0ca690b6a9903",
409530
"a3cd061aab6013f7561978959482d79e9ca636392bc94d4bcad9cb6f90fe2cdf52100f211052f1570db0ca690b6a9903",
410531
"a3cd061aab6013f7561978959482d79e9ca636392bc94d4bcad9cb6f90fe2cdf52100f211052f1570db0ca690b6a9903",
411532
"a3cd061aab6013f7561978959482d79e9ca636392bc94d4bcad9cb6f90fe2cdf52100f211052f1570db0ca690b6a9903",
412-
"a3cd061aab6013f7561978959482d79e9ca636392bc94d4bcad9cb6f90fe2cdf52100f211052f1570db0ca690b6a9903"]
413-
.iter().map(|pk| -> BLSPubkeyRaw {
414-
hex::decode(pk).unwrap().try_into().unwrap()
415-
})
416-
.map(|pk| BlsG1{ g1: G1Affine::from_compressed(&pk).into_option().unwrap()}).collect();
533+
"a3cd061aab6013f7561978959482d79e9ca636392bc94d4bcad9cb6f90fe2cdf52100f211052f1570db0ca690b6a9903",
534+
]);
417535

418536
let target = "a31d9a483703cd0da9873e5e76b4de5f7035d0a73d79b3be8667daa4fc7065a1bbb5bf77787fcf2a35bd327eecc4fa6b";
419537

crates/dkg/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ pub use verification::{
99
};
1010

1111
pub use crypto::*;
12+
pub use dkg_math::batch_add_points;
1213
pub use types::*;

0 commit comments

Comments
 (0)