mina_tree/proofs/public_input/
scalar_challenge.rs

1use std::array::IntoIter;
2
3use ark_ff::{BigInteger256, Field};
4
5use crate::proofs::{field::FieldWitness, transaction::endos};
6
7#[derive(Clone, Debug)]
8pub struct ScalarChallenge {
9    pub inner: [u64; 2],
10}
11
12impl<F: FieldWitness> From<F> for ScalarChallenge {
13    fn from(value: F) -> Self {
14        let bigint: BigInteger256 = value.into();
15        let bigint = bigint.to_64x4();
16        Self::new(bigint[0], bigint[1])
17    }
18}
19
20impl From<[u64; 2]> for ScalarChallenge {
21    fn from(value: [u64; 2]) -> Self {
22        Self::new(value[0], value[1])
23    }
24}
25
26impl From<Vec<u64>> for ScalarChallenge {
27    fn from(value: Vec<u64>) -> Self {
28        Self::new(value[0], value[1])
29    }
30}
31
32struct ScalarChallengeBitsIterator {
33    inner: IntoIter<bool, 128>,
34}
35
36impl Iterator for ScalarChallengeBitsIterator {
37    type Item = (bool, bool);
38
39    fn next(&mut self) -> Option<Self::Item> {
40        let second = self.inner.next()?;
41        let first = self.inner.next()?;
42        Some((first, second))
43    }
44}
45
46impl ScalarChallenge {
47    pub fn new(a: u64, b: u64) -> Self {
48        Self { inner: [a, b] }
49    }
50
51    pub fn dummy() -> Self {
52        Self::new(1, 1)
53    }
54
55    fn iter_bits(&self) -> ScalarChallengeBitsIterator {
56        let a: u128 = self.inner[0] as u128;
57        let b: u128 = self.inner[1] as u128;
58        let num: u128 = (a | (b << 64)).reverse_bits();
59
60        let mut bits = [false; 128];
61        for (index, bit) in bits.iter_mut().enumerate() {
62            *bit = ((num >> index) & 1) != 0;
63        }
64
65        ScalarChallengeBitsIterator {
66            inner: bits.into_iter(),
67        }
68    }
69
70    /// Implemention of `to_field_constant`
71    /// <https://github.com/MinaProtocol/mina/blob/32a91613c388a71f875581ad72276e762242f802/src/lib/pickles/scalar_challenge.ml#L139>
72    pub fn to_field<F>(&self, endo: &F) -> F
73    where
74        F: Field + From<i32>,
75    {
76        let mut a: F = 2.into();
77        let mut b: F = 2.into();
78        let one: F = 1.into();
79        let neg_one: F = -one;
80
81        for (first, second) in self.iter_bits() {
82            let s = if first { one } else { neg_one };
83
84            a += a;
85            b += b;
86
87            if second {
88                a += s;
89            } else {
90                b += s;
91            }
92        }
93
94        (a * endo) + b
95    }
96
97    pub fn array_to_fields<F: FieldWitness, const N: usize>(array: &[F; N]) -> [F; N] {
98        let (_, endo) = endos::<F::Scalar>();
99        array.each_ref().map(|v| Self::from(*v).to_field(&endo))
100    }
101
102    pub fn limbs_to_field<F: FieldWitness>(limbs: &[u64; 2]) -> F {
103        let (_, endo) = endos::<F::Scalar>();
104        Self::from(*limbs).to_field(&endo)
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use crate::util::FpExt;
111
112    use super::*;
113
114    use mina_curves::pasta::{Fp, Fq};
115
116    #[cfg(target_family = "wasm")]
117    use wasm_bindgen_test::wasm_bindgen_test as test;
118
119    #[test]
120    fn test_fp_challenges() {
121        #[rustfmt::skip]
122        let scalar_challenges = [
123            ScalarChallenge::new(-6073566958339139610i64 as u64, -2081966045668129095i64 as u64),
124            ScalarChallenge::new(-7959424372843801919i64 as u64,4324727692349798413i64 as u64),
125            ScalarChallenge::new(5281407247363008654i64 as u64,-341126770839524452i64 as u64),
126            ScalarChallenge::new(-8793505104561934341i64 as u64,1149061412269814663i64 as u64),
127            ScalarChallenge::new(-6319682980234921909i64 as u64,-2993470668064492538i64 as u64),
128            ScalarChallenge::new(-4632520420895617322i64 as u64,-1043277042477928353i64 as u64),
129            ScalarChallenge::new(-6520172058534332359i64 as u64,-6056327257651418415i64 as u64),
130            ScalarChallenge::new(2243596438622148941i64 as u64,2765464070332650197i64 as u64),
131            ScalarChallenge::new(2003371658010473514i64 as u64,-4740690826649485901i64 as u64),
132            ScalarChallenge::new(4360179541971010175i64 as u64,-1774460476906845353i64 as u64),
133            ScalarChallenge::new(1218693385180536706i64 as u64,7371465240007863116i64 as u64),
134            ScalarChallenge::new(-4074108557518982675i64 as u64,-1941843029663935209i64 as u64),
135            ScalarChallenge::new(-443524479034963553i64 as u64,-6709701916849696870i64 as u64),
136            ScalarChallenge::new(-8471733636946508646i64 as u64,-7855667751781032417i64 as u64),
137            ScalarChallenge::new(-4458439752495496649i64 as u64,5085686095541820097i64 as u64),
138            ScalarChallenge::new(7895667244538374865i64 as u64,-7599583809327744882i64 as u64),
139        ];
140
141        let (_, endo) = crate::proofs::transaction::endos::<Fq>();
142
143        let challenges: Vec<_> = scalar_challenges
144            .iter()
145            .rev()
146            .map(|s| s.to_field(&endo).to_decimal())
147            .collect();
148
149        const OCAML_RESULTS: &[&str] = &[
150            "7064008822864728398858417698649153554618393735019982159700213736571223036821",
151            "21281073930096202884976340572605376014917627927607000098124963387126671667405",
152            "20034221077127088921131022285724504665904750595809121027858777196941115095595",
153            "18497339512896533967070595151637618702096421683793996188803218728257093313954",
154            "26091707259541979535386026279646546924481219402460945255985587200333895442426",
155            "26000802478877378291818950871303958371690312575800175603275158984631747112314",
156            "3542775955255721718735057551619208290322691095579511881465771193916627523656",
157            "26082193213255146858325625064941365409422644280364303832412501842706109482352",
158            "14045706980484410694469015017617110793948725477238650483822693423475791735584",
159            "19471582594431150457263082825199126200392919902939760347730982393598455884567",
160            "1326396224493213224809637465524487722432218763470273737330947122279510339127",
161            "17485742224041066720858261709734580297392897788368828400728418930917070940077",
162            "11369682275649236437578679786208728227049581168916414391705587421204991504471",
163            "5558430160842950378525019782179979114837605858253956740879954326712738838869",
164            "17514922848108718369845316737207968652832912751889238861905018424256428652733",
165            "11088960946452242729814251490831984807138805895197664788816609458265399565988",
166        ];
167
168        assert_eq!(challenges, OCAML_RESULTS);
169    }
170
171    #[test]
172    fn test_fq_challenges() {
173        #[rustfmt::skip]
174        let scalar_challenges = [
175            ScalarChallenge::new(7486980280913238963i64 as u64,4173194488927267133i64 as u64),
176            ScalarChallenge::new(-8437921285878338178i64 as u64,-2241273202573544127i64 as u64),
177            ScalarChallenge::new(7651331705457292674i64 as u64,-3583141513394030281i64 as u64),
178            ScalarChallenge::new(-3464302417307075879i64 as u64,-436261906098457727i64 as u64),
179            ScalarChallenge::new(8255044994932440761i64 as u64,5640094314955753085i64 as u64),
180            ScalarChallenge::new(-2513734760972484960i64 as u64,1161566061253204655i64 as u64),
181            ScalarChallenge::new(7525998242613288472i64 as u64,3436443803216159028i64 as u64),
182            ScalarChallenge::new(6809231383204761158i64 as u64,-1877195934091894696i64 as u64),
183            ScalarChallenge::new(-2746520749286704399i64 as u64,-3783224604272248786i64 as u64),
184            ScalarChallenge::new(-36686536733916892i64 as u64,-7835584350097226223i64 as u64),
185            ScalarChallenge::new(-487486487490201322i64 as u64,2756145684490201109i64 as u64),
186            ScalarChallenge::new(-2928903316653004982i64 as u64,346819656816504982i64 as u64),
187            ScalarChallenge::new(-6510054999844554738i64 as u64,5242613218253829938i64 as u64),
188            ScalarChallenge::new(-9192160905410203809i64 as u64,9069127704639200224i64 as u64),
189            ScalarChallenge::new(-1805085648820294365i64 as u64,4705625510417283644i64 as u64),
190        ];
191
192        let (_, endo) = crate::proofs::transaction::endos::<Fp>();
193
194        let challenges: Vec<_> = scalar_challenges
195            .iter()
196            .map(|s| s.to_field(&endo).to_decimal())
197            .collect();
198
199        const OCAML_RESULTS: &[&str] = &[
200            "18930573265662216159442494814184247548231007813972071269603851935535469568681",
201            "13262618632343563854609319990042165233884668386778849308201250967495466297892",
202            "3280133380740312520798484208652485449441154026649408650609268816997503996596",
203            "5974304366701279384657274575561097681967365179758505920855016184604375547845",
204            "3661423464518527108104215048163162714022670481055215775284279432335542360947",
205            "28186039308015693212526267835091480366420716733534501029059512929488448172803",
206            "2928242866467619037394221722592602237395615492823915494722307192257841920053",
207            "7996242790950647686981276345325562931441969146107262270102737887450525547679",
208            "21300612581975001967226090647975097001166598554510871181982133469971233105666",
209            "20608125931317303080428446946426401578478104508733856541747380631345253223759",
210            "20544136014497620836884335380316800592936676638960436539103183677666423950244",
211            "18427567011408397204090055018472561464711254957456387310196545464234121256500",
212            "17571157148266047799767015777008435938200309464425419775013145733714886071865",
213            "9174651000781852149559362347943707955252174789399970369305126738373271491014",
214            "2598585929268909637848366187420073930931414900720607825745008437243507445619",
215        ];
216
217        assert_eq!(challenges, OCAML_RESULTS);
218    }
219}