mithril_stm/circuits/halo2/off_circuit/
utils.rs1use ff::{Field, PrimeField};
2use num_bigint::BigUint;
3use num_integer::Integer;
4use num_traits::{Num, One, Zero};
5use subtle::{Choice, ConstantTimeEq};
6
7use crate::circuits::halo2::constants::EDWARDS_D;
8use crate::circuits::halo2::types::{
9 Jubjub, JubjubAffine, JubjubBase, JubjubScalar, JubjubSubgroup,
10};
11
12pub fn get_coordinates(point: JubjubSubgroup) -> (JubjubBase, JubjubBase) {
13 let extended: Jubjub = point.into(); let affine: JubjubAffine = extended.into(); let x = affine.get_u(); let y = affine.get_v(); (x, y)
18}
19
20pub fn jubjub_base_to_scalar(x: JubjubBase) -> JubjubScalar {
21 let bytes = x.to_bytes_le();
22 JubjubScalar::from_raw([
23 u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
24 u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
25 u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
26 u64::from_le_bytes(bytes[24..32].try_into().unwrap()),
27 ])
28}
29
30pub fn jubjub_base_from_le_bytes(bytes: &[u8]) -> JubjubBase {
31 assert_eq!(bytes.len(), 32);
32 JubjubBase::from_raw([
33 u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
34 u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
35 u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
36 u64::from_le_bytes(bytes[24..32].try_into().unwrap()),
37 ])
38}
39
40pub fn is_on_curve(u: JubjubBase, v: JubjubBase) -> Choice {
41 let u2 = u.square();
42 let v2 = v.square();
43
44 let lhs = v2 - u2;
46
47 let rhs = JubjubBase::ONE + EDWARDS_D * u2 * v2;
49
50 lhs.ct_eq(&rhs)
52}
53
54pub fn big_to_limbs(nb_limbs: u32, base: &BigUint, value: &BigUint) -> Vec<BigUint> {
58 let mut output = vec![];
59 let mut q = (*value).clone();
60 let mut r;
61 while output.len() < nb_limbs as usize {
62 (q, r) = q.div_rem(base);
63 output.push(r.clone());
64 }
65 if !BigUint::is_zero(&q) {
66 panic!(
67 "big_to_limbs: {} cannot be expressed in base {} with {} limbs",
68 value, base, nb_limbs
69 )
70 };
71 output
72}
73
74pub fn modulus<F: PrimeField>() -> BigUint {
75 BigUint::from_str_radix(&F::MODULUS[2..], 16).unwrap()
76}
77
78pub fn big_to_fe<F: PrimeField>(e: BigUint) -> F {
79 let modulus = modulus::<F>();
80 let e = e % modulus;
81 F::from_str_vartime(&e.to_str_radix(10)[..]).unwrap()
82}
83
84pub fn fe_to_big<F: PrimeField>(fe: F) -> BigUint {
85 BigUint::from_bytes_le(fe.to_repr().as_ref())
86}
87
88pub fn decompose<F: PrimeField>(value: &F, limb_bits: usize) -> Vec<F> {
89 let value_big = BigUint::from_bytes_le(value.to_repr().as_ref());
90 let nb_limbs = value_big.bits().div_ceil(limb_bits as u64) as u32;
91 big_to_limbs(nb_limbs, &(BigUint::from(1u8) << limb_bits), &value_big)
92 .into_iter()
93 .map(big_to_fe::<F>)
94 .collect()
95}
96
97pub fn split<F: PrimeField>(value: &F, num_bits: u32) -> (F, F) {
98 let value_big = BigUint::from_bytes_le(value.to_repr().as_ref());
99 let lower_mask = (BigUint::one() << num_bits) - BigUint::one(); let lower_big = value_big.clone() & &lower_mask;
101 let upper_big = value_big >> num_bits;
102 let lower = big_to_fe::<F>(lower_big);
103 let upper = big_to_fe::<F>(upper_big);
104 (lower, upper)
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110 use rand_core::OsRng;
111
112 #[test]
113 fn test_decompose() {
114 let ran = JubjubBase::random(&mut OsRng);
115 let limb_bits = 85;
116 let limbs = decompose(&ran, limb_bits);
117 assert_eq!(limbs.len(), 3);
118
119 let mut reconstructed = JubjubBase::ZERO;
120 let base = JubjubBase::from_u128(1_u128 << limb_bits);
121 for (i, limb) in limbs.iter().enumerate() {
122 reconstructed += base.pow_vartime([i as u64]) * limb;
123 }
124 assert_eq!(
125 reconstructed.ct_eq(&ran).unwrap_u8(),
126 1,
127 "Decomposition failed!"
128 );
129 }
130
131 #[test]
132 fn test_split() {
133 let ran = JubjubBase::random(&mut OsRng);
134 let num_bits = 120;
135 let (lower, upper) = split(&ran, num_bits);
136
137 let base = JubjubBase::from_u128(1_u128 << num_bits);
138 let reconstructed = lower + base * upper;
139 assert_eq!(
140 reconstructed.ct_eq(&ran).unwrap_u8(),
141 1,
142 "Splitting failed!"
143 );
144 }
145
146 #[test]
147 fn test_bytes() {
148 let ran = JubjubBase::random(&mut OsRng);
149 let bytes = ran.to_bytes_le();
150
151 let base = jubjub_base_from_le_bytes(&bytes);
152 assert_eq!(ran, base);
153 }
154}