two.hoon 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716
  1. /= ztd-one /common/ztd/one
  2. => ztd-one
  3. ~% %ext-field ..belt ~
  4. :: math-ext: arithmetic for elements and polynomials over the extension field.
  5. |_ deg=_`@`3 :: field extension degree
  6. :: finite field arithmetic
  7. +| %felt-math
  8. ::
  9. :: +deg-to-irp:
  10. ++ deg-to-irp
  11. ^- (map @ bpoly)
  12. %- ~(gas by *(map @ bpoly))
  13. :~ [1 (init-bpoly ~[0 1])]
  14. [2 (init-bpoly ~[2 18.446.744.069.414.584.320 1])]
  15. [3 (init-bpoly ~[1 18.446.744.069.414.584.320 0 1])]
  16. ==
  17. ::
  18. ++ f0 0x1.0000.0000.0000.0000.0000.0000.0000.0000.0000.0000.0000.0000
  19. ++ f1 0x1.0000.0000.0000.0000.0000.0000.0000.0000.0000.0000.0000.0001
  20. ::
  21. :: +lift: the unique lift of a base field element into an extension field
  22. ++ lift
  23. |= =belt
  24. ~+
  25. ^- felt
  26. %- frep
  27. :- belt
  28. (reap (dec deg) 0)
  29. ::
  30. ++ drop
  31. |= =felt
  32. ^- belt
  33. :: inverse of lift
  34. :: (lift 7) => <felt ~[7 0 0 0]>
  35. :: (snag 0 <felt ~[7 0 0 0]>) => 7
  36. (snag 0 (felt-to-list felt))
  37. ::
  38. ++ felt-to-list
  39. |= fel=felt
  40. ^- (list belt)
  41. (bpoly-to-list [deg fel])
  42. ::
  43. ::
  44. :: +fat: is the atom a felt?
  45. ++ fat
  46. ~/ %fat
  47. |= a=@
  48. ^- ?
  49. ~+
  50. =/ v (rip 6 a)
  51. ?& =((lent v) +(deg))
  52. (levy v based)
  53. ==
  54. ::
  55. :: +frip: field rip - rip a felt into a list of belts
  56. ++ frip
  57. ~/ %frip
  58. |= a=felt
  59. ^- (list belt)
  60. ~+
  61. ?> (fat a)
  62. (bpoly-to-list [deg a])
  63. ::
  64. :: +frep: inverse of frip; list of belts are rep'd to a felt
  65. ++ frep
  66. ~/ %frep
  67. |= x=(list belt)
  68. ^- felt
  69. ~+
  70. ?> =((lent x) deg)
  71. ?> (levy x based)
  72. dat:(init-bpoly x)
  73. ::
  74. :: +fadd: field addition
  75. ++ fadd
  76. ~/ %fadd
  77. |: [a=`felt`(lift 0) b=`felt`(lift 0)]
  78. ~+
  79. ~| a
  80. ?> (fat a)
  81. ~| b
  82. ?> (fat b)
  83. %- frep
  84. (zip (frip a) (frip b) badd)
  85. ::
  86. :: +fneg: field negation
  87. ++ fneg
  88. ~/ %fneg
  89. |: a=`felt`(lift 0)
  90. ~+
  91. ?> (fat a)
  92. %- frep
  93. (turn (frip a) bneg)
  94. ::
  95. :: +fsub: field subtraction
  96. ++ fsub
  97. ~/ %fsub
  98. |: [a=`felt`(lift 0) b=`felt`(lift 0)]
  99. ^- felt
  100. ~+
  101. (fadd a (fneg b))
  102. ::
  103. ++ fmul-naive
  104. ~/ %fmul-naive
  105. |: [a=`felt`(lift 1) b=`felt`(lift 1)]
  106. ^- felt
  107. ~+
  108. ~| `@ux`a
  109. ?> (fat a)
  110. ~| `@ux`b
  111. ?> (fat b)
  112. =/ result-poly
  113. %- bpoly-to-list
  114. %+ bpmod
  115. (bpmul deg^a deg^b)
  116. (~(got by deg-to-irp) deg)
  117. %- frep
  118. %+ bzero-extend result-poly
  119. (sub deg (lent result-poly))
  120. ::
  121. ::
  122. :: +fmul: field multiplication
  123. ::
  124. :: Multiply field extension elements and reduce by using the algebraic identities of the basis
  125. :: vectors.
  126. ::
  127. :: We are reducing mod x^3-x+1. So,
  128. :: x^3-x+1=0
  129. :: => x^3 = x-1
  130. :: => x^4 = x^2-x
  131. ::
  132. :: So,
  133. :: (a0+a1x+a2x^2)*(b0+b1x+b2x^2)
  134. :: = a0b0 + [a0b1+a1b0]x + [a0b2+a1b1+a2b0]x^2 + [a1b2+a2b1]x^3 + a2b2x^4
  135. ::
  136. :: Substituting the reductions above we get
  137. ::
  138. :: (a0+a1x+a2x^2)*(b0+b1x+b2x^2)
  139. :: = a0b0 + [a0b1+a1b0]x + [a0b2+a1b1+a2b0]x^2 + [a1b2+a2b1](x-1) + a2b2(x^2-x)
  140. ::
  141. :: = [a0b0-a1b2-a2b1] + [a0b1+a1b0+a1b2+a2b1-a2b2]x + [a0b2+a1b1+a2b0+a2b2]x^2.
  142. ::
  143. :: And finally we use the karatsuba trick to reduce multiplications.
  144. ::
  145. ++ fmul
  146. ~/ %fmul
  147. |: [a=`felt`(lift 1) b=`felt`(lift 1)]
  148. ^- felt
  149. ~+
  150. ~| `@ux`a
  151. ?> (fat a)
  152. ~| `@ux`b
  153. ?> (fat b)
  154. =/ a [3 a]
  155. =/ b [3 b]
  156. =/ a0=belt (~(snag bop a) 0)
  157. =/ a1=belt (~(snag bop a) 1)
  158. =/ a2=belt (~(snag bop a) 2)
  159. =/ b0=belt (~(snag bop b) 0)
  160. =/ b1=belt (~(snag bop b) 1)
  161. =/ b2=belt (~(snag bop b) 2)
  162. ::
  163. =/ a0b0 (bmul a0 b0)
  164. =/ a1b1 (bmul a1 b1)
  165. =/ a2b2 (bmul a2 b2)
  166. =/ a0b1-a1b0 (bsub (bsub (bmul (badd a0 a1) (badd b0 b1)) a0b0) a1b1)
  167. =/ a1b2-a2b1 (bsub (bsub (bmul (badd a1 a2) (badd b1 b2)) a1b1) a2b2)
  168. =/ a0b2-a2b0 (bsub (bsub (bmul (badd a0 a2) (badd b0 b2)) a0b0) a2b2)
  169. %- frep
  170. :~ (bsub a0b0 a1b2-a2b1)
  171. (bsub (badd a0b1-a1b0 a1b2-a2b1) a2b2)
  172. :(badd a0b2-a2b0 a1b1 a2b2)
  173. ==
  174. ::
  175. :: +finv: field inversion
  176. ++ finv
  177. ~/ %finv
  178. |: a=`felt`(lift 1)
  179. ^- felt
  180. ~+
  181. ?> (fat a)
  182. ?< =(a (lift 0))
  183. =/ egcd=[d=bpoly u=bpoly v=bpoly]
  184. %+ bpegcd
  185. (~(got by deg-to-irp) deg)
  186. deg^a
  187. =/ d (bpoly-to-list d.egcd)
  188. =/ u (bpoly-to-list u.egcd)
  189. =/ v (bpoly-to-list v.egcd)
  190. ?> =((bdegree d) 0)
  191. ?< ?=(~ d)
  192. =/ result-poly
  193. %- bpoly-to-list
  194. (bpscal (binv i.d) v.egcd)
  195. %- frep
  196. %+ bzero-extend result-poly
  197. (sub deg (lent result-poly))
  198. ::
  199. :: +mass-inversion: inverts list of elements by cleverly performing only a single inversion
  200. ++ mass-inversion
  201. ~/ %mass-inversion
  202. |= lis=(list felt)
  203. ^- (list felt)
  204. |^
  205. =/ all-prods (accumulate-products lis)
  206. ?< ?=(~ all-prods)
  207. =. lis (flop lis)
  208. =/ acc (finv i.all-prods)
  209. =/ prods t.all-prods
  210. =| invs=(list felt)
  211. |-
  212. ?~ prods
  213. [acc invs]
  214. ?< ?=(~ lis)
  215. %= $
  216. lis t.lis
  217. prods t.prods
  218. acc (fmul acc i.lis)
  219. invs [(fmul acc i.prods) invs]
  220. ==
  221. ++ accumulate-products
  222. |= lis=(list felt)
  223. ^- (list felt)
  224. =| res=(list felt)
  225. =/ acc (lift 1)
  226. |-
  227. ?~ lis
  228. res
  229. ?: =(i.lis (lift 0))
  230. ~| "Cannot invert 0!"
  231. !!
  232. =/ new (fmul acc i.lis)
  233. $(acc new, res [new res], lis t.lis)
  234. --
  235. ::
  236. :: +fdiv: division of field elements
  237. ++ fdiv
  238. ~/ %fdiv
  239. |: [a=`felt`(lift 1) b=`felt`(lift 1)]
  240. ^- felt
  241. ~+
  242. (fmul a (finv b))
  243. ::
  244. :: +fpow: field power; computes x^n
  245. ++ fpow
  246. ~/ %fpow
  247. |: [x=`felt`(lift 1) n=`@`0]
  248. ^- felt
  249. ~+
  250. ?> (fat x)
  251. ~? (gte (met 3 n) (met 3 (lift 0))) "fpow: n is wayy too high and is likely a felt by accident."
  252. %. [(lift 1) x n]
  253. |= [y=felt x=felt n=@]
  254. ^- felt
  255. ?> (fat y)
  256. ?: =(n 0)
  257. y
  258. :: parity flag
  259. =/ f=@ (end 0 n)
  260. ?: =(0 f)
  261. $(x (fmul x x), n (rsh 0 n))
  262. $(y (fmul y x), x (fmul x x), n (rsh 0 n))
  263. ::
  264. :: +bpeval-lift: evaluate a bpoly at a felt
  265. ++ bpeval-lift
  266. ~/ %bpeval-lift
  267. |: [bp=`bpoly`one-bpoly x=`felt`(lift 1)]
  268. ^- felt
  269. ~+
  270. ?: (bp-is-zero bp) (lift 0)
  271. ?: =(len.bp 1) (lift (~(snag bop bp) 0))
  272. =/ p ~(to-poly bop bp)
  273. =. p (flop p)
  274. =/ res=@ (lift 0)
  275. |-
  276. ?~ p !!
  277. ?~ t.p
  278. (fadd (fmul res x) (lift i.p))
  279. :: based on p(x) = (...((a_n)x + a_{n-1})x + a_{n-2})x + ... )
  280. $(res (fadd (fmul res x) (lift i.p)), p t.p)
  281. ::
  282. :: general field polynomial methods and math
  283. +| %fpoly-math
  284. ::
  285. ::
  286. ++ fop ~(ops array-op 3)
  287. ::
  288. :: +fpadd: field polynomial addition
  289. ++ fpadd
  290. ~/ %fpadd
  291. |: [fp=`fpoly`zero-fpoly fq=`fpoly`zero-fpoly]
  292. ^- fpoly
  293. ?> &(!=(len.fp 0) !=(len.fq 0))
  294. =/ p ~(to-poly fop fp)
  295. =/ q ~(to-poly fop fq)
  296. =/ lp (lent p)
  297. =/ lq (lent q)
  298. =/ m (max lp lq)
  299. =: p (weld p (reap (sub m lp) (lift 0)))
  300. q (weld q (reap (sub m lq) (lift 0)))
  301. ==
  302. %- init-fpoly
  303. (zip p q fadd)
  304. ::
  305. :: +fpneg: additive inverse of a field polynomial
  306. ++ fpneg
  307. ~/ %fpneg
  308. |: fp=`fpoly`zero-fpoly
  309. ^- fpoly
  310. ?> !=(len.fp 0)
  311. ~+
  312. =/ p ~(to-poly fop fp)
  313. %- init-fpoly
  314. (turn p fneg)
  315. ::
  316. :: fpscal: scale a polynomial by a field element
  317. ++ fpscal
  318. ~/ %fpscal
  319. |: [c=`felt`(lift 1) fp=`fpoly`one-fpoly]
  320. ^- fpoly
  321. ~+
  322. =/ p ~(to-poly fop fp)
  323. %- init-fpoly
  324. %+ turn
  325. p
  326. (cury fmul c)
  327. ::
  328. :: +fpsub: field polynomial subtraction
  329. ++ fpsub
  330. ~/ %fpsub
  331. |: [p=`fpoly`zero-fpoly q=`fpoly`zero-fpoly]
  332. ^- fpoly
  333. ~+
  334. ?> &(!=(len.p 0) !=(len.q 0))
  335. (fpadd p (fpneg q))
  336. ::
  337. ++ fp-is-zero
  338. ~/ %fp-is-zero
  339. |= p=fpoly
  340. ^- ?
  341. ~+
  342. =. p (fpcan p)
  343. |(=(len.p 0) =(p zero-fpoly))
  344. ::
  345. ++ fp-is-one
  346. ~/ %fp-is-one
  347. |= p=fpoly
  348. ^- ?
  349. ~+
  350. =. p (fpcan p)
  351. &(=(len.p 1) =((~(snag fop p) 0) (lift 1)))
  352. ::
  353. :: f(x)=0
  354. ++ zero-fpoly
  355. ~+
  356. ^- fpoly
  357. (init-fpoly ~[(lift 0)])
  358. ::
  359. :: f(x)=1
  360. ++ one-fpoly
  361. ~+
  362. ^- fpoly
  363. (init-fpoly ~[(lift 1)])
  364. ::
  365. :: f(x)=x
  366. ++ id-fpoly
  367. ~+
  368. ^- fpoly
  369. (init-fpoly ~[(lift 0) (lift 1)])
  370. ::
  371. :: +init-fpoly: transforms a list of felts into its fpoly equivalent
  372. ++ init-fpoly
  373. ~/ %init-fpoly
  374. |= poly=(list felt)
  375. ^- fpoly
  376. ?~ poly [0 (lift 0)]
  377. array:(init-mary poly)
  378. ::
  379. :: +fcan: gives the canonical leading-zero-stripped representation of p(x)
  380. ++ fcan
  381. |= p=poly
  382. ^- poly
  383. =. p (flop p)
  384. |-
  385. ?~ p
  386. ~
  387. ?: =(i.p (lift 0))
  388. $(p t.p)
  389. (flop p)
  390. ::
  391. ++ fpcan
  392. |= fp=fpoly
  393. ^- fpoly
  394. =/ p ~(to-poly fop fp)
  395. (init-fpoly (fcan p))
  396. ::
  397. :: +fdegree: computes the degree of a polynomial
  398. ++ fdegree
  399. |= p=poly
  400. ^- @
  401. =/ cp=poly (fcan p)
  402. ?~ cp 0
  403. (dec (lent cp))
  404. ::
  405. :: +fzero-extend: make the zero coefficients for powers of x higher than deg(p) explicit
  406. ++ fzero-extend
  407. |= [p=poly much=@]
  408. ^- poly
  409. (weld p (reap much (lift 0)))
  410. ::
  411. ++ lift-to-fpoly
  412. ~/ %lift-to-fpoly
  413. |= poly=(list belt)
  414. ^- fpoly
  415. ?> (levy poly based)
  416. (init-fpoly (turn poly lift))
  417. ::
  418. ++ fpoly-to-list
  419. ~/ %fpoly-to-list
  420. |= fp=fpoly
  421. ^- (list felt)
  422. ~| "len.fp must not be 0"
  423. ?> !=(len.fp 0)
  424. (mary-to-list [3 fp])
  425. ::
  426. :: +bpoly-to-fpoly: lift a bpoly to an fpoly
  427. ++ bpoly-to-fpoly
  428. ~/ %bpoly-to-fpoly
  429. |= bp=bpoly
  430. ^- fpoly
  431. (lift-to-fpoly ~(to-poly bop bp))
  432. ::
  433. :: +fpoly-from-dat
  434. ::
  435. :: given a dat=@ux, compute the length using met and return an fpoly
  436. ++ fpoly-from-dat
  437. |= dat=@ux
  438. ^- fpoly
  439. [(div (dec (met 6 dat)) 3) dat]
  440. ::
  441. :: +fp-ntt: number theoretic transform for fpolys based on anatomy of a stark
  442. ++ fp-ntt
  443. ~/ %fp-ntt
  444. |= [fp=fpoly root=felt]
  445. ^- fpoly
  446. ~+
  447. ?: =(len.fp 1)
  448. fp
  449. =/ half (div len.fp 2)
  450. ?> =((fpow root len.fp) (lift 1))
  451. ?< =((fpow root half) (lift 1))
  452. =/ odds
  453. %+ fp-ntt
  454. %- init-fpoly
  455. %+ murn (range len.fp)
  456. |= i=@
  457. ?: =(0 (mod i 2))
  458. ~
  459. `(~(snag fop fp) i)
  460. (fmul root root)
  461. =/ evens
  462. %+ fp-ntt
  463. %- init-fpoly
  464. %+ murn (range len.fp)
  465. |= i=@
  466. ?: =(1 (mod i 2))
  467. ~
  468. `(~(snag fop fp) i)
  469. (fmul root root)
  470. %- init-fpoly
  471. %+ turn (range len.fp)
  472. |= i=@
  473. %+ fadd (~(snag fop evens) (mod i half))
  474. %+ fmul (fpow root i)
  475. (~(snag fop odds) (mod i half))
  476. ::
  477. :: +bp-ntt: ntt over base field
  478. ++ bp-ntt
  479. ~/ %bp-ntt
  480. |= [bp=bpoly root=belt]
  481. ^- bpoly
  482. ~+
  483. ?: =(len.bp 1)
  484. bp
  485. =/ half (div len.bp 2)
  486. ?> =((bpow root len.bp) 1)
  487. ?< =((bpow root half) 1)
  488. =/ odds
  489. %+ bp-ntt
  490. %- init-bpoly
  491. %+ murn (range len.bp)
  492. |= i=@
  493. ?: =(0 (mod i 2))
  494. ~
  495. `(~(snag bop bp) i)
  496. (bmul root root)
  497. =/ evens
  498. %+ bp-ntt
  499. %- init-bpoly
  500. %+ murn (range len.bp)
  501. |= i=@
  502. ?: =(1 (mod i 2))
  503. ~
  504. `(~(snag bop bp) i)
  505. (bmul root root)
  506. %- init-bpoly
  507. %+ turn (range len.bp)
  508. |= i=@
  509. %+ badd (~(snag bop evens) (mod i half))
  510. %+ bmul (bpow root i)
  511. (~(snag bop odds) (mod i half))
  512. ::
  513. :: +fp-fft: Discrete Fourier Transform (DFT) with Fast Fourier Transform (FFT) algorithm
  514. ++ fp-fft
  515. ~/ %fp-fft
  516. |= p=fpoly
  517. ^- fpoly
  518. ~+
  519. ~| "fft: must have power-of-2-many coefficients."
  520. ?> =(0 (dis len.p (dec len.p)))
  521. (fp-ntt p (lift (ordered-root len.p)))
  522. ::
  523. :: +fp-ifft: Inverse DFT with FFT algorithm
  524. ++ fp-ifft
  525. ~/ %ifft
  526. |= p=fpoly
  527. ^- fpoly
  528. ~+
  529. ~| "ifft: must have power-of-2-many coefficients."
  530. ?> =((dis len.p (dec len.p)) 0)
  531. %+ fpscal (lift (binv len.p))
  532. (fp-ntt p (lift (binv (ordered-root len.p))))
  533. ::
  534. :: +bp-fft: fft over base field
  535. ++ bp-fft
  536. ~/ %bp-fft
  537. |= p=bpoly
  538. ^- bpoly
  539. ~+
  540. ~| "bp-fft: must have power-of-2-many coefficients."
  541. ?> =(0 (dis len.p (dec len.p)))
  542. (bp-ntt p (ordered-root len.p))
  543. ::
  544. :: +bp-ifft: ifft over base field
  545. ++ bp-ifft
  546. ~/ %bp-ifft
  547. |= p=bpoly
  548. ^- bpoly
  549. ~+
  550. ~| "bp-ifft: must have power-of-2-many coefficients."
  551. ?> =((dis len.p (dec len.p)) 0)
  552. %+ bpscal (binv len.p)
  553. (bp-ntt p (binv (ordered-root len.p)))
  554. ::
  555. :: +fpmul-naive: high school polynomial multiplication
  556. ++ fpmul-naive
  557. ~/ %fpmul-naive
  558. |= [fp=fpoly fq=fpoly]
  559. ^- fpoly
  560. ~+
  561. =/ p ~(to-poly fop fp)
  562. =/ q ~(to-poly fop fq)
  563. %- init-fpoly
  564. ?: ?|(=(~ p) =(~ q))
  565. ~
  566. =/ v=(list felt)
  567. %- weld
  568. :_ p
  569. (reap (dec (lent q)) (lift 0))
  570. =/ w=(list felt) (flop q)
  571. =| prod=poly
  572. |-
  573. ?~ v
  574. (flop prod)
  575. %= $
  576. v t.v
  577. ::
  578. prod
  579. :_ prod
  580. %. [v w]
  581. :: computes a "dot product" (actually a bilinear form that just looks like
  582. :: one) of v and w by implicitly zero-extending if lengths unequal we
  583. :: don't actually zero-extend to save a constant time factor
  584. |= [v=(list felt) w=(list felt)]
  585. ^- felt
  586. =/ dot=felt (lift 0)
  587. |-
  588. ?: ?|(?=(~ v) ?=(~ w))
  589. dot
  590. $(v t.v, w t.w, dot (fadd dot (fmul i.v i.w)))
  591. ==
  592. ::
  593. :: +fpmul-fast: polynomial multiplication with fft
  594. ++ fpmul-fast
  595. ~/ %fpmul-fast
  596. |= [fp=fpoly fq=fpoly]
  597. ^- fpoly
  598. ~+
  599. =: fp (fpcan fp)
  600. fq (fpcan fq)
  601. ==
  602. ?: ?|(=(fp zero-fpoly) =(fq zero-fpoly))
  603. zero-fpoly
  604. =* deg-p len.fp
  605. =* deg-q len.fq
  606. =/ deg-prod (bex (xeb (dec (add deg-p deg-q))))
  607. %- fpcan
  608. %- fp-ifft
  609. %+ %~ zip fop
  610. (fp-fft (~(zero-extend fop fp) (sub deg-prod deg-p)))
  611. (fp-fft (~(zero-extend fop fq) (sub deg-prod deg-q)))
  612. fmul
  613. ::
  614. :: +fpmul: polynomial multiplication
  615. ++ fpmul
  616. ~/ %fpmul
  617. |: [fp=`fpoly`one-fpoly fq=`fpoly`one-fpoly]
  618. ^- fpoly
  619. ~+
  620. ?: |(=(len.fp 0) =(len.fq 0))
  621. (init-fpoly ~[(lift 0)])
  622. =/ p ~(to-poly fop fp)
  623. =/ q ~(to-poly fop fq)
  624. ?: (lth (add (fdegree p) (fdegree q)) 8)
  625. (fpmul-naive fp fq)
  626. (fpmul-fast fp fq)
  627. ::
  628. :: fppow: compute (p(x))^k
  629. ++ fppow
  630. ~/ %fppow
  631. |= [fp=fpoly k=@]
  632. ^- fpoly
  633. ~+
  634. ?> !=(len.fp 0)
  635. %. [(init-fpoly ~[(lift 1)]) fp k]
  636. |= [q=fpoly p=fpoly k=@]
  637. ?: =(k 0)
  638. q
  639. =/ f=@ (end 0 k)
  640. ?: =(f 0)
  641. %_ $
  642. p (fpmul p p)
  643. k (rsh 0 k)
  644. ==
  645. %_ $
  646. q (fpmul q p)
  647. p (fpmul p p)
  648. k (rsh 0 k)
  649. ==
  650. ::
  651. :: +fp-hadamard
  652. ::
  653. :: Hadamard product of two fpolys. This is just a fancy name for pointwise multiplication.
  654. ++ fp-hadamard
  655. ~/ %fp-hadamard
  656. |: [fp=`fpoly`one-fpoly fq=`fpoly`one-fpoly]
  657. ^- fpoly
  658. =: fp (fpcan fp)
  659. fq (fpcan fq)
  660. ==
  661. ?: |((fp-is-zero fp) (fp-is-zero fq)) zero-fpoly
  662. ?: (fp-is-one fp) fq
  663. ?: (fp-is-one fq) fp
  664. ?: |(=(len.fp 0) =(len.fq 0)) zero-fpoly
  665. (~(zip fop fp) fq fmul)
  666. ::
  667. :: +fp-hadamard-pow
  668. ::
  669. :: Hadamard product with itself n times
  670. ++ fp-hadamard-pow
  671. ~/ %fp-hadamard-pow
  672. |: [fa=`fpoly`one-fpoly n=`@`0]
  673. ^- fpoly
  674. ?: =(n 0) one-fpoly
  675. ?: =(n 1) fa
  676. %+ roll (range n)
  677. |= [i=@ acc=_one-fpoly]
  678. ?: =(i 0) fa
  679. (fp-hadamard acc fa)
  680. ::
  681. :: fpdvr
  682. ++ fpdvr
  683. ~/ %fpdvr
  684. |: [fa=`fpoly`one-fpoly fb=`fpoly`one-fpoly]
  685. ^- [q=fpoly r=fpoly]
  686. ~+
  687. ?> &(!=(len.fa 0) !=(len.fb 0))
  688. =/ a ~(to-poly fop fa)
  689. =/ b ~(to-poly fop fb)
  690. =^ rem b
  691. :- (flop (fcan a))
  692. (flop (fcan b))
  693. ~| "Cannot divide by the zero polynomial."
  694. ?< ?=(~ b)
  695. =/ db (dec (lent b))
  696. ?: =(db 0)
  697. :_ (init-fpoly ~)
  698. (fpscal (finv i.b) fa)
  699. =| quot=poly
  700. |-
  701. ?: (lth (fdegree (flop rem)) db)
  702. :- (init-fpoly quot)
  703. %- init-fpoly
  704. (fcan (flop rem))
  705. ?< ?=(~ rem)
  706. =/ new-coeff (fdiv i.rem i.b)
  707. =/ new-rem
  708. %~ to-poly fop
  709. %+ fpsub
  710. (init-fpoly rem)
  711. (fpscal new-coeff (init-fpoly b))
  712. ?< ?=(~ new-rem)
  713. %= $
  714. quot [new-coeff quot]
  715. rem t.new-rem
  716. ==
  717. ::
  718. :: +fpdiv: polynomial division
  719. ::
  720. :: Quasilinear algo, faster than naive. Based on the formula
  721. :: rev(p/q) = rev(q)^{-1} rev(p) mod x^{deg(p) - deg(q) + 1}.
  722. :: Why?: we can compute rev(f)^{-1} mod x^l quickly.
  723. ++ fpdiv
  724. ~/ %fpdiv
  725. |: [p=`fpoly`one-fpoly q=`fpoly`one-fpoly]
  726. ^- fpoly
  727. ~+
  728. ?> &(!=(len.p 0) !=(len.q 0))
  729. |^
  730. =: p (fpcan p)
  731. q (fpcan q)
  732. ==
  733. ?: (fp-is-zero q)
  734. ~| "Cannot divide by the zero polynomial!"
  735. !!
  736. ?: (fp-is-zero p)
  737. zero-fpoly
  738. =/ [c=felt f=fpoly] (con-mon p)
  739. =/ [d=felt g=fpoly] (con-mon q)
  740. =/ lead=felt (fdiv c d)
  741. =/ rf=fpoly ~(flop fop f)
  742. =/ rg=fpoly ~(flop fop g)
  743. =/ df=@ (fdegree ~(to-poly fop f))
  744. =/ dg=@ (fdegree ~(to-poly fop g))
  745. ?: (lth df dg)
  746. zero-fpoly
  747. =/ dq=@ (sub df dg)
  748. %+ fpscal
  749. lead
  750. %~ flop fop
  751. %. +(dq)
  752. %~ scag fop
  753. (fpmul (pinv-mod-x-to +(dq) rg) rf)
  754. ::
  755. :: +pinv-mod-x-to: computes p^{-1} mod x^l
  756. ++ pinv-mod-x-to
  757. |= [l=@ p=fpoly]
  758. ^- fpoly
  759. (~(scag fop (hensel-lift-inverse p (xeb l))) l)
  760. ::
  761. :: +hensel-lift-inverse: if p_0 = 1, compute p^{-1} mod x^{2^l} (l = level parameter below)
  762. ::
  763. :: Given a(x) such that p(x)a(x) = 1 mod x^{2^i}, then a*p = 1 + x^{2^i}s(x) (see s below).
  764. :: Letting t(x) = -a(x)*s(x) mod x^{2^i}, then p's inverse modulo x^{2^{i+1}} is
  765. :: a(x) + x^{2^i}t(x)
  766. ++ hensel-lift-inverse
  767. |= [p=fpoly level=@]
  768. ^- fpoly
  769. ~| "Polynomial must have constant term equal to 1."
  770. ?> =(~(head fop p) (lift 1))
  771. :: since p_0 = 1, 1 is p's inverse mod x (x = x^{2^0})
  772. =/ inv=fpoly one-fpoly
  773. :: have solution for level i, i.e. mod x^{2^i}, bootstrapping to next level
  774. =/ i=@ 0
  775. |-
  776. ?: =(i level)
  777. inv
  778. =/ bex-i=@ (bex i)
  779. =/ s (~(slag fop (fpmul p inv)) bex-i)
  780. =/ t (~(scag fop (fpmul (fpscal (lift (bneg 1)) inv) s)) bex-i)
  781. $(i +(i), inv (fpadd inv (pmul-by-x-to bex-i t)))
  782. ::
  783. :: pmul-by-x-to: multiply by x to the power l
  784. ++ pmul-by-x-to
  785. |= [l=@ p=fpoly]
  786. ^- fpoly
  787. %. p
  788. ~(weld fop (init-fpoly (reap l (lift 0))))
  789. ::
  790. :: con-mon: split p(x)!=0 uniquely into c*f(x) where c is constant f monic
  791. ++ con-mon
  792. |= fp=fpoly
  793. ^- [felt fpoly]
  794. ~+
  795. =. fp ~(flop fop (fpcan fp))
  796. ~| "Cannot accept the zero polynomial!"
  797. ?< =(zero-fpoly fp)
  798. :- ~(head fop fp)
  799. %~ flop fop
  800. (fpscal (finv ~(head fop fp)) fp)
  801. --
  802. ::
  803. :: fpmod: f(x) mod g(x), gives remainder r of f/g
  804. ++ fpmod
  805. ~/ %fpmod
  806. |: [f=`fpoly`one-fpoly g=`fpoly`one-fpoly]
  807. ^- fpoly
  808. ~+
  809. :: f - g*q, stripped of leading zeroes
  810. %- fpcan
  811. (fpsub f (fpmul g (fpdiv f g)))
  812. ::
  813. :: fpeval: evaluate a polynomial with Horner's method.
  814. ++ fpeval
  815. ~/ %fpeval
  816. |: [fp=`fpoly`one-fpoly x=`felt`(lift 1)]
  817. ^- felt
  818. ~+
  819. ?: (fp-is-zero fp) (lift 0)
  820. ?: =(len.fp 1) (~(snag fop fp) 0)
  821. =/ p ~(to-poly fop fp)
  822. =. p (flop p)
  823. =/ res=@ (lift 0)
  824. |-
  825. ?~ p !!
  826. ?~ t.p
  827. (fadd (fmul res x) i.p)
  828. :: based on p(x) = (...((a_n)x + a_{n-1})x + a_{n-2})x + ... )
  829. $(res (fadd (fmul res x) i.p), p t.p)
  830. ::
  831. :: +fpcompose: given fpolys P(X) and Q(X), compute P(Q(X))
  832. ++ fpcompose
  833. ~/ %fpcompose
  834. |: [p=`fpoly`zero-fpoly q=`fpoly`zero-fpoly]
  835. ^- fpoly
  836. ~+
  837. =. p (fpcan p)
  838. =. q (fpcan q)
  839. ?: |((fp-is-zero p) (fp-is-zero q)) zero-fpoly
  840. =- -<
  841. %+ roll (range len.p)
  842. |= [n=@ acc=_zero-fpoly q-pow=_one-fpoly]
  843. :_ (fpmul q-pow q)
  844. %+ fpadd acc
  845. (fpscal (~(snag fop p) n) q-pow)
  846. ::
  847. :: construct the constant fpoly f(X)=c
  848. ++ fp-c
  849. |= c=felt
  850. ^- fpoly
  851. ~+
  852. (init-fpoly ~[c])
  853. ::
  854. :: +fp-decompose
  855. ::
  856. :: given a polynomial f(X) of degree at most D*N, decompose into D polynomials
  857. :: {h_i(X) : 0 <= i < D} each of degree at most N such that
  858. ::
  859. :: f(X) = h_0(X^D) + X*h_1(X^D) + X^2*h_2(X^D) + ... + X^{D-1}*h_{D-1}(X^D)
  860. ::
  861. :: This is just a generalization of splitting a polynomial into even and odd terms
  862. :: as the FFT does.
  863. :: h_i(X) is the terms whose degree is congruent to i modulo D.
  864. ::
  865. :: Passing in d=2 will split into even and odd terms.
  866. ::
  867. ++ fp-decompose
  868. ~/ %fp-decompose
  869. |= [p=_one-fpoly d=@]
  870. ^- (list fpoly)
  871. =/ total-deg=@ (fdegree (fpoly-to-list p))
  872. =/ deg=@
  873. =/ dvr (dvr total-deg d)
  874. ?:(=(q.dvr 0) p.dvr (add p.dvr 1))
  875. =/ acc=(list (list felt)) (reap d ~)
  876. =-
  877. %+ turn -
  878. |= poly=(list felt)
  879. ?~ poly zero-fpoly
  880. (init-fpoly (flop poly))
  881. %+ roll (range (add 1 deg))
  882. |= [i=@ acc=_acc]
  883. %+ iturn acc
  884. |= [n=@ l=(list felt)]
  885. =/ idx (add (mul i d) n)
  886. ?: (gth idx total-deg) l
  887. [(~(snag fop p) idx) l]
  888. ::
  889. :: +fp-decomposition-eval
  890. ::
  891. :: given a decomposition created by +fp-decompose, evaluate it.
  892. ::
  893. :: input:
  894. :: n=number of pieces,
  895. :: {h_i(X): 0 <= i < n }
  896. :: c=felt (evaluation point)
  897. ::
  898. :: output:
  899. :: h_0(c^n) + X*h_1(c^n) + X^2*h_2(c^n) + ... + x^{n-1)}*h_{n-1}(x^n)
  900. ::
  901. ++ fp-decomposition-eval
  902. |= [n=@ polys=(list fpoly) eval-point=felt]
  903. ^- felt
  904. =/ c (fpow eval-point n)
  905. %^ zip-roll (range n) polys
  906. |= [[i=@ poly=fpoly] acc=_(lift 0)]
  907. (fadd acc (fmul (fpow eval-point i) (fpeval poly c)))
  908. ::
  909. :: specialized fpoly manipulations mostly used by the prover
  910. +| %prover-math
  911. :: codeword: compute a Reed-Solomon codeword, i.e. evaluate a poly on a domain
  912. ++ codeword
  913. ~/ %codeword
  914. |= [fp=fpoly fdomain=fpoly]
  915. ^- fpoly
  916. ?: =(fdomain zero-fpoly)
  917. fdomain
  918. ?: =(1 len.fdomain)
  919. (init-fpoly (fpeval fp ~(head fop fdomain))^~)
  920. =/ half (div len.fdomain 2)
  921. =/ lef-zerofier (zerofier (~(scag fop fdomain) half))
  922. =/ rig-zerofier (zerofier (~(slag fop fdomain) half))
  923. =/ lef
  924. $(fp (fpmod fp lef-zerofier), fdomain (~(scag fop fdomain) half))
  925. =/ rig
  926. $(fp (fpmod fp rig-zerofier), fdomain (~(slag fop fdomain) half))
  927. (~(weld fop lef) rig)
  928. ::
  929. ++ zerofier
  930. ~/ %zerofier
  931. |= fdomain=fpoly
  932. ^- fpoly
  933. ~+
  934. ?: =(fdomain zero-fpoly)
  935. fdomain
  936. ?: =(1 len.fdomain)
  937. %- init-fpoly
  938. [(fneg ~(head fop fdomain)) (lift 1) ~]
  939. =/ half (div len.fdomain 2)
  940. =/ lef $(fdomain (~(scag fop fdomain) half))
  941. =/ rig $(fdomain (~(slag fop fdomain) half))
  942. (fpmul lef rig)
  943. ::
  944. :: interpolate: compute the poly of minimal degree which evaluates to values on domain
  945. ++ interpolate
  946. ~/ %interpolate
  947. |= [fdomain=fpoly fvalues=fpoly]
  948. ^- fpoly
  949. ~+
  950. ?> =(len.fdomain len.fvalues)
  951. ?: =(fdomain zero-fpoly)
  952. fdomain
  953. ?: =(1 len.fdomain) fvalues
  954. =/ half (div len.fdomain 2)
  955. =/ half-1 (~(scag fop fdomain) half)
  956. =/ half-2 (~(slag fop fdomain) half)
  957. =/ lef-zerofier (zerofier half-1)
  958. =/ rig-zerofier (zerofier half-2)
  959. =/ lef-offset (codeword rig-zerofier half-1)
  960. =/ rig-offset (codeword lef-zerofier half-2)
  961. =/ lef-target
  962. %+ ~(zip fop (~(scag fop fvalues) half))
  963. lef-offset
  964. fdiv
  965. =/ rig-target
  966. %+ ~(zip fop (~(slag fop fvalues) half))
  967. rig-offset
  968. fdiv
  969. =/ lef-interpolant
  970. $(fdomain half-1, fvalues lef-target)
  971. =/ rig-interpolant
  972. $(fdomain half-2, fvalues rig-target)
  973. %+ fpadd
  974. (fpmul lef-interpolant rig-zerofier)
  975. (fpmul rig-interpolant lef-zerofier)
  976. ::
  977. ++ test-colinearity
  978. |= points=(list (pair felt felt))
  979. ^- ?
  980. ?< ?|(?=(~ points) ?=(~ t.points))
  981. =* x0 p.i.points
  982. =* y0 q.i.points
  983. =* x1 p.i.t.points
  984. =* y1 q.i.t.points
  985. ~| "x-coordinates must be distinct"
  986. ?< =(x0 x1)
  987. =/ line=fpoly
  988. (interpolate (init-fpoly ~[x0 x1]) (init-fpoly ~[y0 y1]))
  989. =/ bool=? %.y
  990. =/ iter t.t.points
  991. |-
  992. ?~ iter
  993. bool
  994. %= $
  995. iter t.iter
  996. bool ?& bool
  997. =((fpeval line p.i.iter) q.i.iter)
  998. ==
  999. ==
  1000. :: +shift: produces the polynomial q(x) such that p(c*x) = q(x), i.e. q_i = (p_i)*(c^i)
  1001. ::
  1002. :: Usecase:
  1003. :: If p is a polynomial you want to evaluate on coset cH of subgroup H, then you can
  1004. :: instead evaluate q on H. The value of q on h is that of p on ch: q(h) = p(ch).
  1005. ++ shift
  1006. ~/ %shift
  1007. |: [fp=`fpoly`one-fpoly c=`felt`(lift 1)]
  1008. ^- fpoly
  1009. =/ p ~(to-poly fop fp)
  1010. =/ power=felt (lift 1)
  1011. =| q=poly
  1012. |-
  1013. ?~ p
  1014. (init-fpoly (flop q))
  1015. $(q [(fmul i.p power) q], power (fmul power c), p t.p)
  1016. ::
  1017. ++ bp-shift
  1018. ~/ %bp-shift
  1019. |: [bp=`bpoly`one-bpoly c=`belt`1]
  1020. ^- bpoly
  1021. =/ p ~(to-poly bop bp)
  1022. =/ power=belt 1
  1023. =| q=poly
  1024. |-
  1025. ?~ p
  1026. (init-bpoly (flop q))
  1027. $(q [(bmul i.p power) q], power (bmul power c), p t.p)
  1028. ::
  1029. ::
  1030. :: +shift-by-unity
  1031. ::
  1032. :: compose a polynomial in eval form over a root of unity with a power of that root of unity. It just
  1033. :: has to shift the vector to the left by pow steps and wrap back to the right.
  1034. ++ shift-by-unity
  1035. ~/ %shift-by-unity
  1036. |= [fp=fpoly n=@]
  1037. ^- fpoly
  1038. ?: |(=(len.fp 0) =(len.fp 1)) fp
  1039. (~(weld fop (~(slag fop fp) n)) (~(scag fop fp) n))
  1040. ::
  1041. ++ bp-shift-by-unity
  1042. ~/ %bp-shift-by-unity
  1043. |= [bp=bpoly n=@]
  1044. ^- bpoly
  1045. ?: |(=(len.bp 0) =(len.bp 1)) bp
  1046. (~(weld bop (~(slag bop bp) n)) (~(scag bop bp) n))
  1047. ::
  1048. ++ turn-coseword
  1049. ~/ %turn-coseword
  1050. |= [polys=mary offset=belt order=@]
  1051. ^- mary
  1052. %- zing-bpolys
  1053. %+ turn (range len.array.polys)
  1054. |= i=@
  1055. =/ bp=bpoly (~(snag-as-bpoly ave polys) i)
  1056. (bp-coseword bp offset order)
  1057. ::
  1058. :: +coseword: fast evaluation on a coset of a binary subgroup
  1059. ::
  1060. :: Portmanteau of coset and codeword. If we want to evaluate a polynomial p on a coset of
  1061. :: a subgroup H, this is the same as evaluating the shifted polynomial q on H. If H is
  1062. :: generated by a binary root of unity, this evaluation is the same as an FFT.
  1063. :: NOTE: the polynomial being evaluated should have length less than the size of H.
  1064. :: This is because an FFT of a polynomial uses a root of unity of order the power of 2
  1065. :: which is larger than the length of the polynomial.
  1066. :: NOTE: 'order' is the size of H. It suffices for this single number to be our proxy for
  1067. :: H because there is a unique subgroup of this size. (Follows from the fact that F* is cyclic.)
  1068. ++ coseword
  1069. ~/ %coseword
  1070. |= [p=fpoly offset=felt order=@]
  1071. ^- fpoly
  1072. ~| "Order must be a power of 2."
  1073. ?> =((dis order (dec order)) 0)
  1074. %- fp-fft
  1075. %- ~(zero-extend fop (shift p offset))
  1076. (sub order len.p)
  1077. ::
  1078. :: +bp-coseword: coseword over base field
  1079. ++ bp-coseword
  1080. ~/ %bp-coseword
  1081. |= [p=bpoly offset=belt order=@]
  1082. ^- bpoly
  1083. ~| "Order must be a power of 2."
  1084. ?> =((dis order (dec order)) 0)
  1085. %- bp-fft
  1086. %- ~(zero-extend bop (bp-shift p offset))
  1087. (sub order len.p)
  1088. ::
  1089. :: +intercosate: interpolate a polynomial taking particular values over a binary subgroup coset
  1090. ::
  1091. :: Returns a polynomial p satisfying p(c*w^i) = v_i where w generates a cyclic subgroup of
  1092. :: binary order. This is accomplished by first obtaining q = (ifft values), which satisfies
  1093. :: q(w^i) = v_i. This is equivalent to q(c^{-1}*(c*w^i)) = v_i so comparing to our desired
  1094. :: equation we want p(x) = q(c^{-1}*x); i.e. we need to shift q by c^{-1}.
  1095. ++ intercosate
  1096. ~/ %intercosate
  1097. |= [offset=felt order=@ values=fpoly]
  1098. ^- fpoly
  1099. ~+
  1100. :: order = |H| is a power of 2
  1101. ?> =((dis order (dec order)) 0)
  1102. :: number of values should match the number of points in the coset
  1103. ?> =(len.values order)
  1104. (shift (fp-ifft values) (finv offset))
  1105. ::
  1106. ++ bp-intercosate
  1107. ~/ %bp-intercosate
  1108. |= [offset=belt order=@ values=bpoly]
  1109. ^- bpoly
  1110. ~+
  1111. :: order = |H| is a power of 2
  1112. ?> =((dis order (dec order)) 0)
  1113. :: number of values should match the number of points in the coset
  1114. ?> =(len.values order)
  1115. =/ ifft (bp-ifft values)
  1116. (bp-shift (bp-ifft values) (binv offset))
  1117. ::
  1118. ::
  1119. ++ interpolate-table
  1120. ~/ %interpolate-table
  1121. |= [table=mary domain-len=@]
  1122. ^- mary
  1123. =/ trace=mary (transpose-bpolys table)
  1124. %- zing-bpolys
  1125. %+ turn (range len.array.trace)
  1126. |= col=@
  1127. ^- bpoly
  1128. =/ values-old=bpoly (~(snag-as-bpoly ave trace) col)
  1129. =/ values (~(zero-extend bop values-old) (sub domain-len len.values-old))
  1130. ?> =(len.values domain-len)
  1131. ?> =((dis domain-len (dec domain-len)) 0)
  1132. (bp-intercosate 1 domain-len values)
  1133. ::
  1134. ::
  1135. ++ mp-to-mega
  1136. ~% %mp-to-mega + ~
  1137. |%
  1138. :: type of a term
  1139. +$ mega-typ ?(%var %rnd %dyn %con %com)
  1140. ::
  1141. :: bit flags for type of term
  1142. :: constant: just a belt constant term
  1143. +$ con-id %0
  1144. :: variable: index is index of variable
  1145. +$ var-id %1
  1146. :: challenge: index is index in challenge list
  1147. +$ rnd-id %2
  1148. :: dynamic terminal: index is index in dynamic list
  1149. +$ dyn-id %3
  1150. :: composition: index of result of previous evaluation
  1151. +$ com-id %4
  1152. ::
  1153. :: bit length of type
  1154. ++ typ-len 3
  1155. :: bit length of index
  1156. ++ idx-len 10
  1157. :: bit length of exponent
  1158. ++ exp-len 30
  1159. ::
  1160. :: one term inside a monomial. fits in a direct atom.
  1161. +$ mega-term @ux
  1162. ::
  1163. ++ mega
  1164. |_ term=mega-term
  1165. :: retrieve type of terminal
  1166. ++ typ
  1167. ^- mega-typ
  1168. ?+ (cut 0 [0 typ-len] term) !!
  1169. con-id %con
  1170. var-id %var
  1171. rnd-id %rnd
  1172. dyn-id %dyn
  1173. com-id %com
  1174. ==
  1175. ::
  1176. :: retrieve index of terminal
  1177. ++ idx
  1178. ^- @ud
  1179. (cut 0 [typ-len idx-len] term)
  1180. ::
  1181. :: retrieve exponent of terminal
  1182. ++ exp
  1183. ^- @ud
  1184. (cut 0 [(add typ-len idx-len) exp-len] term)
  1185. ::
  1186. --
  1187. ::
  1188. :: assemble a mega term out of a (type, index, exponent) triple
  1189. ++ form-mega
  1190. |= [typ=mega-typ idx=@ exp=@ud]
  1191. ^- mega-term
  1192. ?> (lte (met 0 idx) idx-len)
  1193. ?> (lte (met 0 exp) exp-len)
  1194. =/ t=@
  1195. ?- typ
  1196. %con *con-id
  1197. %var *var-id
  1198. %rnd *rnd-id
  1199. %dyn *dyn-id
  1200. %com *com-id
  1201. ==
  1202. (can 0 ~[[typ-len t] [idx-len idx] [exp-len exp]])
  1203. ::
  1204. :: dissable a term into its (type, index, exponent) triple
  1205. ++ brek
  1206. |= ter=mega-term
  1207. ^- [mega-typ @ @ud]
  1208. :+ ~(typ mega ter)
  1209. ~(idx mega ter)
  1210. ~(exp mega ter)
  1211. ::
  1212. :: +mp-is-constant: is mp a constant polynomial
  1213. ++ mp-is-constant
  1214. |= mp=mp-mega
  1215. ^- ?
  1216. |^
  1217. %+ levy ~(tap by mp)
  1218. |= [k=bpoly v=belt]
  1219. (is-monomial-constant k)
  1220. ::
  1221. ++ is-monomial-constant
  1222. |= monomial=bpoly
  1223. ^- ?
  1224. %- levy
  1225. :_ same
  1226. %+ turn (range len.monomial)
  1227. |= i=@
  1228. ^- ?
  1229. =/ ter (~(snag bop monomial) i)
  1230. !?=(%var ~(typ mega ter))
  1231. --
  1232. ::
  1233. :: print out an mp-mega
  1234. ++ print-mega
  1235. |= mp=mp-mega
  1236. ^- tape
  1237. %- zing
  1238. =- (flop acc)
  1239. %+ roll ~(tap by mp)
  1240. |= [[k=bpoly v=belt] first=? acc=(list tape)]
  1241. =/ plus ?:(first "" " + ")
  1242. =/ coeff ?:(=(1 v) "" "{(scow %ud v)}*")
  1243. =; str=tape
  1244. :+ %.n
  1245. :(weld plus coeff str)
  1246. acc
  1247. %- zing
  1248. =- (flop acc)
  1249. %+ roll (range len.k)
  1250. |= [i=@ first=? acc=(list tape)]
  1251. =/ times=tape ?:(first "" "*")
  1252. =/ ter (~(snag bop k) i)
  1253. =/ exp
  1254. ?: =(1 ~(exp mega ter))
  1255. ""
  1256. "^{(scow %ud ~(exp mega ter))}"
  1257. :- %.n
  1258. :_ acc
  1259. ;: weld
  1260. times
  1261. (trip ~(typ mega ter))
  1262. (scow %ud ~(idx mega ter))
  1263. exp
  1264. ==
  1265. ::
  1266. ::
  1267. :: f(x0, x1, ..., xn) = r[i] where r is a result from a previous computation
  1268. ++ mp-com
  1269. |= i=@
  1270. ^- mp-mega
  1271. ~+
  1272. (my [[(init-bpoly ~[(form-mega %com i 1)]) 1] ~])
  1273. ::
  1274. ::
  1275. :: f(x0, x1, ..., xn) = c where c is a belt constant
  1276. ++ mp-c
  1277. |= c=belt
  1278. ^- mp-mega
  1279. ~+
  1280. ?> (based c)
  1281. ?: =(c 0)
  1282. ~
  1283. (my [[zero-bpoly c] ~])
  1284. ::
  1285. :: f(x0, x1, ..., x0)=xi where i is the argument
  1286. ++ mp-var
  1287. |= which-variable=@
  1288. ^- mp-mega
  1289. ~+
  1290. (my [[(init-bpoly ~[(form-mega %var which-variable 1)]) 1] ~])
  1291. ::
  1292. :: f(x0, x1, ..., x0) = d where d is the value of the dynamic terminal
  1293. :: with index dyn
  1294. ++ mp-dyn
  1295. |= dyn=@
  1296. ^- mp-mega
  1297. ~+
  1298. (my [[(init-bpoly ~[(form-mega %dyn dyn 1)]) 1] ~])
  1299. ::
  1300. :: f(x0, x1, ..., x0) = r where r is a random challenge with index rnd
  1301. ++ mp-chal
  1302. |= rnd=@
  1303. ^- mp-mega
  1304. ~+
  1305. (my [[(init-bpoly ~[(form-mega %rnd rnd 1)]) 1] ~])
  1306. ::
  1307. ++ mpadd
  1308. ~/ %mpadd
  1309. |= [f=mp-mega g=mp-mega]
  1310. ^- mp-mega
  1311. ?: =(~ f)
  1312. g
  1313. ?: =(~ g)
  1314. f
  1315. %+ roll ~(tap by g)
  1316. |= [[gk=bpoly gv=belt] res=_f]
  1317. =/ fv (~(get by f) gk)
  1318. ?~ fv
  1319. (~(put by res) gk gv)
  1320. (~(put by res) gk (badd u.fv gv))
  1321. ::
  1322. ++ mpsub
  1323. ~/ %mpsub
  1324. |= [f=mp-mega g=mp-mega]
  1325. ^- mp-mega
  1326. ?: =(~ f)
  1327. (~(run by g) bneg)
  1328. ?: =(~ g)
  1329. f
  1330. %+ roll ~(tap by g)
  1331. |= [[gk=bpoly gv=belt] res=_f]
  1332. =/ fv (~(get by f) gk)
  1333. ?~ fv
  1334. (~(put by res) gk (bneg gv))
  1335. (~(put by res) gk (bsub u.fv gv))
  1336. ::
  1337. ++ mpscal
  1338. ~/ %mpsub
  1339. |= [c=belt f=mp-mega]
  1340. ^- mp-mega
  1341. ?: =(0 c)
  1342. ~
  1343. ?: =(~ f)
  1344. f
  1345. (~(run by f) (curr bmul c))
  1346. ::
  1347. ++ mpmul
  1348. ~/ %mpmul
  1349. |= [f=mp-mega g=mp-mega]
  1350. ^- mp-mega
  1351. |^
  1352. ?: |(=(~ f) =(~ g))
  1353. ~
  1354. %+ roll ~(tap by f)
  1355. |= [[fk=bpoly fv=belt] acc=(map bpoly belt)]
  1356. %+ roll ~(tap by g)
  1357. |= [[gk=bpoly gv=belt] acc=_acc]
  1358. =/ key (mul-key fk gk)
  1359. =/ val (bmul fv gv)
  1360. =/ lookup (~(get by acc) key)
  1361. ?~ lookup
  1362. (~(put by acc) key val)
  1363. (~(put by acc) key (badd u.lookup val))
  1364. ::
  1365. ++ mul-key
  1366. |= [f=bpoly g=bpoly]
  1367. ^- bpoly
  1368. ?: (bp-is-zero f)
  1369. g
  1370. ?: (bp-is-zero g)
  1371. f
  1372. =/ f-map
  1373. %- ~(gas by *(map [mega-typ @] @ud))
  1374. %+ turn (range len.f)
  1375. |= i=@
  1376. =/ ter (~(snag bop f) i)
  1377. :- [~(typ mega ter) ~(idx mega ter)]
  1378. ~(exp mega ter)
  1379. =; acc-map=(map [mega-typ @] @ud)
  1380. %- init-bpoly
  1381. %+ turn ~(tap by acc-map)
  1382. |= [[typ=mega-typ idx=@] exp=@ud]
  1383. (form-mega typ idx exp)
  1384. %+ roll (range len.g)
  1385. |= [j=@ acc=_f-map]
  1386. =/ ter (~(snag bop g) j)
  1387. =/ exp (~(get by acc) [~(typ mega ter) ~(idx mega ter)])
  1388. ?~ exp
  1389. (~(put by acc) [~(typ mega ter) ~(idx mega ter)] ~(exp mega ter))
  1390. (~(put by acc) [~(typ mega ter) ~(idx mega ter)] (add ~(exp mega ter) u.exp))
  1391. ::
  1392. --
  1393. ::
  1394. ++ mp-degree
  1395. |= [f=mp-mega com-map=(map @ @)]
  1396. ^- @ud
  1397. %- roll
  1398. :_ max
  1399. %+ turn ~(tap by f)
  1400. |= [k=bpoly v=belt]
  1401. ^- @ud
  1402. ?: =(v 0)
  1403. 0
  1404. %+ roll (range len.k)
  1405. |= [i=@ deg=@ud]
  1406. =/ ter (~(snag bop k) i)
  1407. =/ [typ=mega-typ idx=@ exp=@ud] (brek ter)
  1408. ?+ typ deg
  1409. %var
  1410. (add deg exp)
  1411. ::
  1412. %com
  1413. =/ dep-deg (~(got by com-map) idx)
  1414. %+ add
  1415. deg
  1416. (mul dep-deg exp)
  1417. ==
  1418. ::
  1419. ++ mpeval
  1420. ~/ %mpeval
  1421. |= $: field=?(%ext %base)
  1422. mp=mp-mega
  1423. args=bpoly :: can be bpoly or fpoly
  1424. chal-map=(map @ belt)
  1425. dyns=bpoly
  1426. com-map=(map @ elt)
  1427. ==
  1428. ^- elt
  1429. =/ add-op ?:(=(field %base) badd fadd)
  1430. =/ mul-op ?:(=(field %base) bmul fmul)
  1431. =/ pow-op ?:(=(field %base) bpow fpow)
  1432. =/ aop-door ?:(=(field %base) bop fop)
  1433. =/ lift-op ?:(=(field %base) |=(v=@ `@ux`v) lift)
  1434. =/ init-zero=@ux (lift-op 0)
  1435. =/ init-one=@ux (lift-op 1)
  1436. ?: =(~ mp)
  1437. init-zero
  1438. %+ roll ~(tap by mp)
  1439. |= [[k=bpoly v=belt] acc=_init-zero]
  1440. =/ coeff=@ux (lift-op v)
  1441. ?: =(init-zero coeff)
  1442. acc
  1443. %+ add-op acc
  1444. %+ mul-op coeff
  1445. %+ roll (range len.k)
  1446. |= [i=@ res=_init-one]
  1447. ?: =(init-zero res)
  1448. init-zero
  1449. %+ mul-op res
  1450. =/ ter (~(snag bop k) i)
  1451. =/ [typ=mega-typ idx=@ exp=@ud] (brek ter)
  1452. ?- typ
  1453. %var
  1454. %+ pow-op
  1455. (~(snag aop-door args) idx)
  1456. exp
  1457. ::
  1458. %rnd
  1459. %+ pow-op
  1460. (lift-op (~(got by chal-map) idx))
  1461. exp
  1462. ::
  1463. %dyn
  1464. %+ pow-op
  1465. (lift-op (~(snag bop dyns) idx))
  1466. exp
  1467. ::
  1468. %con
  1469. init-one
  1470. ::
  1471. %com
  1472. %+ pow-op
  1473. (~(got by com-map) idx)
  1474. exp
  1475. ==
  1476. --
  1477. ::
  1478. ++ mp-degree-mega
  1479. |= [f=mp-mega com-map=(map @ @)]
  1480. ^- @
  1481. (mp-degree:mp-to-mega f com-map)
  1482. ::
  1483. ++ mp-degree-ultra
  1484. |= f=mp-ultra
  1485. ^- (list @)
  1486. ?- -.f
  1487. %mega
  1488. :~ (mp-degree-mega +.f ~)
  1489. ==
  1490. ::
  1491. %comp
  1492. =; com-degs=(map @ @)
  1493. %+ turn
  1494. com.f
  1495. |= mp=mp-mega
  1496. (mp-degree-mega mp com-degs)
  1497. %+ roll
  1498. (range (lent dep.f))
  1499. |= [i=@ acc=(map @ @)]
  1500. =/ mp (snag i dep.f)
  1501. %- ~(put by acc)
  1502. :- i
  1503. (mp-degree-mega mp ~)
  1504. ==
  1505. ::
  1506. :: +mp-to-graph: multipoly arithmetic in the mp-graph representation
  1507. ::
  1508. :: you can usually convert mpoly arithmetic into mp-graph arithmetic by
  1509. :: writing =, mp-to-graph and leaving everything else the same.
  1510. ++ mp-to-graph
  1511. ~% %mp-to-graph + ~
  1512. |%
  1513. ++ make-variable
  1514. |= which-variable=@
  1515. ^- mp-graph
  1516. [%var +<]
  1517. ::
  1518. ++ inv
  1519. |= a=mp-graph
  1520. ^- mp-graph
  1521. [%inv a]
  1522. ::
  1523. ++ neg
  1524. |= a=mp-graph
  1525. ^- mp-graph
  1526. [%neg a]
  1527. ::
  1528. ++ mpadd
  1529. |= [a=mp-graph b=mp-graph]
  1530. ^- mp-graph
  1531. [%addl ~[a b]]
  1532. ::
  1533. ++ mpsub
  1534. |= [a=mp-graph b=mp-graph]
  1535. ^- mp-graph
  1536. [%addl ~[a [%scal (bneg 1) b]]]
  1537. ::
  1538. ++ mpmul
  1539. |= [a=mp-graph b=mp-graph]
  1540. ^- mp-graph
  1541. [%mul +<]
  1542. ::
  1543. ++ mppow
  1544. |= [a=mp-graph n=@ud]
  1545. ^- mp-graph
  1546. [%pow +<]
  1547. ::
  1548. ++ mpscal
  1549. |= [c=belt f=mp-graph]
  1550. ^- mp-graph
  1551. [%scal +<]
  1552. ::
  1553. ++ mp-c
  1554. |= a=belt
  1555. ^- mp-graph
  1556. [%con a]
  1557. ::
  1558. ++ mp-cb
  1559. |= a=belt
  1560. ^- mp-graph
  1561. [%con a]
  1562. ::
  1563. ++ mp-dyn
  1564. |= d=term
  1565. ^- mp-graph
  1566. [%dyn d]
  1567. ::
  1568. --
  1569. ::
  1570. ++ mpeval-mega
  1571. ~/ %mpeval-mega
  1572. |= $: field=?(%ext %base)
  1573. p=mp-mega
  1574. args=bpoly :: can be bpoly or fpoly
  1575. chal-map=(map @ belt)
  1576. dyns=bpoly
  1577. com-map=(map @ elt)
  1578. ==
  1579. ^- elt
  1580. (mpeval:mp-to-mega +<)
  1581. ::
  1582. ++ mpeval-ultra
  1583. ~/ %mpeval-ultra
  1584. |= $: field=?(%ext %base)
  1585. p=mp-ultra
  1586. args=bpoly :: can be bpoly or fpoly
  1587. chal-map=(map @ belt)
  1588. dyns=bpoly
  1589. ==
  1590. ^- (list elt)
  1591. ?- -.p
  1592. %mega
  1593. :~ (mpeval-mega field +.p args chal-map dyns ~)
  1594. ==
  1595. ::
  1596. %comp
  1597. =; com-map=(map @ elt)
  1598. %+ turn
  1599. com.p
  1600. |= mp=mp-mega
  1601. (mpeval-mega field mp args chal-map dyns com-map)
  1602. %+ roll
  1603. (range (lent dep.p))
  1604. |= [i=@ acc=(map @ elt)]
  1605. =/ mp (snag i dep.p)
  1606. %- ~(put by acc)
  1607. :- i
  1608. (mpeval-mega field mp args chal-map dyns ~)
  1609. ==
  1610. ::
  1611. ::
  1612. :: +mp-substitute-ultra
  1613. ::
  1614. :: Handles substitution for %mega and %comp mp-ultra cases. If the multi-poly is a
  1615. :: single mp-mega constraint, we just call mp-substitute-mega on it. On the other hand
  1616. :: if it is a composition, we must first evaluate its dependencies, collating the
  1617. :: indexed results in a map. We then pass the map in as input when we substitute
  1618. :: the actual computation.
  1619. ::
  1620. ++ mp-substitute-ultra
  1621. ~/ %mp-substitute-ultra
  1622. |= [p=mp-ultra trace-evals=bpoly height=@ chal-map=(map @ belt) dyns=bpoly]
  1623. ^- (list bpoly)
  1624. ?- -.p
  1625. %mega
  1626. :~ (mp-substitute-mega +.p trace-evals height chal-map dyns ~)
  1627. ==
  1628. ::
  1629. %comp
  1630. =; com-map=(map @ bpoly)
  1631. %+ turn
  1632. com.p
  1633. |= mp=mp-mega
  1634. (mp-substitute-mega mp trace-evals height chal-map dyns com-map)
  1635. ::
  1636. :: Materialize the dependencies and label them based on order
  1637. %+ roll
  1638. (range (lent dep.p))
  1639. |= [i=@ acc=(map @ bpoly)]
  1640. =/ mp=mp-mega (snag i dep.p)
  1641. %- ~(put by acc)
  1642. :- i
  1643. (mp-substitute-mega mp trace-evals height chal-map dyns ~)
  1644. ==
  1645. ::
  1646. :: +mp-substitute-mega: Given a multipoly: sub in the chals, dyns, vars, and composition dependencies:
  1647. ::
  1648. :: For vars, the trace polys: ~[p0(t) p1(t) ... ] are in eval form and we substitute pi(t) for xi.
  1649. ::
  1650. :: The key insight is that multiplication is much faster on polynomials in eval form instead of
  1651. :: coefficient form. Calling bpmul will do ntt's on the arguments and an ifft on the result
  1652. :: over and over again. Instead we precompute the ntts for all the polynomials and those
  1653. :: are the arguments to substitute. Since they're already in the correct form we just compute
  1654. :: hadamard products on them, sum up all the terms, and do an ifft to get the result.
  1655. ::
  1656. :: Another optimization is that the polynomials in eval form must be the length of the degree
  1657. :: of the final product. Since the max degree of the constraints is 4 (this method has this
  1658. :: constraint degree hardcoded for optimization purposes and must be changed by hand
  1659. :: if the constraint degree changes), the vectors must be 4*n where n is the height.
  1660. ::
  1661. ++ mp-substitute-mega
  1662. ~/ %mp-substitute-mega
  1663. |= [p=mp-mega trace-evals=bpoly height=@ chal-map=(map @ belt) dyns=bpoly com-map=(map @ bpoly)]
  1664. ^- bpoly
  1665. %+ roll ~(tap by p)
  1666. |= [[k=bpoly v=belt] acc=_zero-bpoly]
  1667. =/ [poly=bpoly len=@] [trace-evals (mul 4 height)]
  1668. =/ ones=bpoly (init-bpoly (reap len 1))
  1669. ?: =(v 0) acc
  1670. %+ bpadd acc
  1671. %+ bpscal v
  1672. %+ roll (range len.k)
  1673. |= [i=@ acc=_ones]
  1674. ^- bpoly
  1675. =/ ter (~(snag bop k) i)
  1676. =/ [typ=mega-typ:mp-to-mega idx=@ exp=@ud]
  1677. (brek:mp-to-mega ter)
  1678. ?- typ
  1679. %var
  1680. =/ var=bpoly (~(swag bop poly) (mul idx len) len)
  1681. %+ roll (range exp)
  1682. |= [i=@ power=_acc]
  1683. (bp-hadamard power var)
  1684. ::
  1685. %rnd
  1686. =/ rnd (~(got by chal-map) idx)
  1687. (bpscal (bpow rnd exp) acc)
  1688. ::
  1689. %dyn
  1690. =/ dyn (~(snag bop dyns) idx)
  1691. (bpscal (bpow dyn exp) acc)
  1692. ::
  1693. %con
  1694. acc
  1695. ::
  1696. %com
  1697. =/ com=bpoly (~(got by com-map) idx)
  1698. %+ roll (range exp)
  1699. |= [i=@ power=_acc]
  1700. (bp-hadamard power com)
  1701. ==
  1702. ::
  1703. :: ++ fpdiv-test
  1704. :: |= [p=poly q=poly]
  1705. :: ^- ?
  1706. :: =(-:(fpdvr p q) (fpdiv p q))
  1707. :: ::
  1708. :: ++ fpdvr-test
  1709. :: |= [a=poly b=poly]
  1710. :: ^- ?
  1711. :: =/ [q=poly r=poly] (fpdvr a b)
  1712. :: ?& =(a (fpadd (fpmul-naive b q) r))
  1713. :: (lth (degree r) (degree b))
  1714. :: ==
  1715. ::
  1716. -- ::ext-field