vrf/
message.rs

1use ark_ff::{One, SquareRootField, Zero};
2
3use ledger::{proofs::transaction::legacy_input::to_bits, ToInputs};
4use mina_curves::pasta::curves::pallas::Pallas as CurvePoint;
5use mina_p2p_messages::v2::EpochSeed;
6use o1_utils::FieldHelpers;
7use poseidon::hash::{params::MINA_VRF_MESSAGE, Inputs};
8use serde::{Deserialize, Serialize};
9
10use super::{BaseField, VrfError, VrfResult};
11
12const LEDGER_DEPTH: usize = 35;
13
14#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
15pub struct VrfMessage {
16    global_slot: u32,
17    epoch_seed: EpochSeed,
18    delegator_index: u64,
19}
20
21impl VrfMessage {
22    pub fn new(global_slot: u32, epoch_seed: EpochSeed, delegator_index: u64) -> Self {
23        Self {
24            global_slot,
25            epoch_seed,
26            delegator_index,
27        }
28    }
29
30    pub fn hash(&self) -> BaseField {
31        self.hash_with_param(&MINA_VRF_MESSAGE)
32    }
33
34    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)?;
44        let projection_point_y = BaseField::one();
45        let conic_c = three;
46        let u_over_2 = BaseField::one();
47        let u = two;
48
49        let t = self.hash();
50
51        // field to conic
52        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;
56        let conic_y = projection_point_y - (s * t);
57
58        // conic to s
59        let v = (conic_z / conic_y) - u_over_2;
60        let y = conic_y;
61
62        // s to v
63        let x1 = v;
64        let x2 = -(u + v);
65        let x3 = u + (y * y);
66
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
81        for x in [x1, x2, x3] {
82            if let Some(y) = get_y(x) {
83                return Ok(CurvePoint::new(x, y, false));
84            }
85        }
86
87        Err(VrfError::ToGroupError(t))
88    }
89}
90
91impl ToInputs for VrfMessage {
92    fn to_inputs(&self, inputs: &mut Inputs) {
93        let epoch_seed = match self.epoch_seed.to_field() {
94            Ok(epoch_seed) => epoch_seed,
95            Err(_) => {
96                // TODO: Return an error somehow
97                mina_curves::pasta::Fp::zero()
98            }
99        };
100        inputs.append_field(epoch_seed);
101        inputs.append_u32(self.global_slot);
102        for bit in to_bits::<_, LEDGER_DEPTH>(self.delegator_index) {
103            inputs.append_bool(bit);
104        }
105    }
106}