Skip to content

Commit c6dbdd3

Browse files
committed
tweak(vrf): Optimize to_group by avoiding the recomputation of constants
1 parent f5c17bb commit c6dbdd3

File tree

1 file changed

+48
-29
lines changed

1 file changed

+48
-29
lines changed

vrf/src/message.rs

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::sync::OnceLock;
2+
13
use ark_ff::{One, SquareRootField, Zero};
24

35
use ledger::{proofs::transaction::legacy_input::to_bits, ToInputs};
@@ -18,6 +20,26 @@ pub struct VrfMessage {
1820
delegator_index: u64,
1921
}
2022

23+
struct CachedFields {
24+
two: BaseField,
25+
three: BaseField,
26+
five: BaseField,
27+
projection_point_z: BaseField,
28+
// Add other fields here that might benefit from caching
29+
}
30+
31+
static CACHED_FIELDS: OnceLock<CachedFields> = OnceLock::new();
32+
33+
#[inline(always)]
34+
fn get_y(x: BaseField, five: BaseField) -> Option<BaseField> {
35+
let mut res = x;
36+
res *= &x; // x^2
37+
res += BaseField::zero(); // x^2 + A x
38+
res *= &x; // x^3 + A x
39+
res += five; // x^3 + A x + B
40+
res.sqrt()
41+
}
42+
2143
impl VrfMessage {
2244
pub fn new(global_slot: u32, epoch_seed: EpochSeed, delegator_index: u64) -> Self {
2345
Self {
@@ -32,27 +54,38 @@ impl VrfMessage {
3254
}
3355

3456
pub fn to_group(&self) -> VrfResult<CurvePoint> {
35-
// helpers
36-
let two = BaseField::one() + BaseField::one();
37-
let three = two + BaseField::one();
38-
39-
// params, according to ocaml
40-
let mut projection_point_z_bytes =
41-
hex::decode("1AF731EC3CA2D77CC5D13EDC8C9A0A77978CB5F4FBFCC470B5983F5B6336DB69")?;
42-
projection_point_z_bytes.reverse();
43-
let projection_point_z = BaseField::from_bytes(&projection_point_z_bytes)?;
57+
let cached = CACHED_FIELDS.get_or_init(|| {
58+
let one = BaseField::one();
59+
let two = one + one;
60+
let three = two + one;
61+
let five = three + two;
62+
63+
let projection_point_z_bytes =
64+
hex::decode("1AF731EC3CA2D77CC5D13EDC8C9A0A77978CB5F4FBFCC470B5983F5B6336DB69")
65+
.expect("Failed to decode hex string");
66+
let projection_point_z = BaseField::from_bytes(&projection_point_z_bytes)
67+
.expect("Failed to convert bytes to BaseField");
68+
69+
CachedFields {
70+
two,
71+
three,
72+
five,
73+
projection_point_z,
74+
}
75+
});
76+
4477
let projection_point_y = BaseField::one();
45-
let conic_c = three;
78+
let conic_c = cached.three;
4679
let u_over_2 = BaseField::one();
47-
let u = two;
80+
let u = cached.two;
4881

4982
let t = self.hash();
5083

5184
// field to conic
5285
let ct = conic_c * t;
53-
let s =
54-
two * ((ct * projection_point_y) + projection_point_z) / ((ct * t) + BaseField::one());
55-
let conic_z = projection_point_z - s;
86+
let s = cached.two * ((ct * projection_point_y) + cached.projection_point_z)
87+
/ ((ct * t) + BaseField::one());
88+
let conic_z = cached.projection_point_z - s;
5689
let conic_y = projection_point_y - (s * t);
5790

5891
// conic to s
@@ -64,22 +97,8 @@ impl VrfMessage {
6497
let x2 = -(u + v);
6598
let x3 = u + (y * y);
6699

67-
let get_y = |x: BaseField| -> Option<BaseField> {
68-
let five = BaseField::one()
69-
+ BaseField::one()
70-
+ BaseField::one()
71-
+ BaseField::one()
72-
+ BaseField::one();
73-
let mut res = x;
74-
res *= &x; // x^2
75-
res += BaseField::zero(); // x^2 + A x
76-
res *= &x; // x^3 + A x
77-
res += five; // x^3 + A x + B
78-
res.sqrt()
79-
};
80-
81100
for x in [x1, x2, x3] {
82-
if let Some(y) = get_y(x) {
101+
if let Some(y) = get_y(x, cached.five) {
83102
return Ok(CurvePoint::new(x, y, false));
84103
}
85104
}

0 commit comments

Comments
 (0)