even_bits.rs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. use std::{marker::PhantomData, ops::Deref};
  2. use halo2_proofs::{
  3. arithmetic::FieldExt,
  4. circuit::{AssignedCell, Chip, Layouter, Region},
  5. plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector, TableColumn},
  6. poly::Rotation,
  7. };
  8. /// Chip state is stored in a config struct. This is generated by the
  9. /// chip during configuration, and then stored inside the chip
  10. #[derive(Clone, Debug)]
  11. pub struct EvenBitsConfig {
  12. advice: [Column<Advice>; 2],
  13. even_bits: TableColumn,
  14. s_decompose: Selector,
  15. }
  16. impl EvenBitsConfig {
  17. pub fn load_private<F: FieldExt>(
  18. &self,
  19. mut layouter: impl Layouter<F>,
  20. value: Option<F>,
  21. ) -> Result<AssignedCell<F, F>, Error> {
  22. layouter.assign_region(
  23. || "load private",
  24. |mut region| {
  25. region.assign_advice(
  26. || "private input",
  27. self.advice[0],
  28. 0,
  29. || value.ok_or(Error::Synthesis),
  30. )
  31. },
  32. )
  33. }
  34. }
  35. #[derive(Clone, Debug)]
  36. pub struct EvenBitsChip<F: FieldExt, const WORD_BITS: u32> {
  37. config: EvenBitsConfig,
  38. _marker: PhantomData<F>,
  39. }
  40. impl<F: FieldExt, const WORD_BITS: u32> Chip<F> for EvenBitsChip<F, WORD_BITS> {
  41. type Config = EvenBitsConfig;
  42. type Loaded = ();
  43. fn config(&self) -> &Self::Config {
  44. &self.config
  45. }
  46. fn loaded(&self) -> &Self::Loaded {
  47. &()
  48. }
  49. }
  50. impl<F: FieldExt, const WORD_BITS: u32> EvenBitsChip<F, WORD_BITS> {
  51. pub fn construct(config: <Self as Chip<F>>::Config) -> Self {
  52. Self { config, _marker: PhantomData }
  53. }
  54. pub fn configure(meta: &mut ConstraintSystem<F>) -> <Self as Chip<F>>::Config {
  55. let advice = [meta.advice_column(), meta.advice_column()];
  56. for column in &advice {
  57. meta.enable_equality(*column);
  58. }
  59. let s_decompose = meta.complex_selector();
  60. let even_bits = meta.lookup_table_column();
  61. meta.create_gate("decompose", |meta| {
  62. let lhs = meta.query_advice(advice[0], Rotation::cur());
  63. let rhs = meta.query_advice(advice[1], Rotation::cur());
  64. let out = meta.query_advice(advice[0], Rotation::next());
  65. let s_decompose = meta.query_selector(s_decompose);
  66. // Finally, we return the polynomial expressions that constrain this gate.
  67. // For our multiplication gate, we only need a single polynomial constraint.
  68. //
  69. // The polynomial expressions returned from `create_gate` will be
  70. // constrained by the proving system to equal zero.
  71. vec![s_decompose * (lhs + Expression::Constant(F::from(2)) * rhs - out)]
  72. });
  73. let _ = meta.lookup(|meta| {
  74. let lookup = meta.query_selector(s_decompose);
  75. let a = meta.query_advice(advice[0], Rotation::cur());
  76. vec![(lookup * a, even_bits)]
  77. });
  78. let _ = meta.lookup(|meta| {
  79. let lookup = meta.query_selector(s_decompose);
  80. let b = meta.query_advice(advice[1], Rotation::cur());
  81. vec![(lookup * b, even_bits)]
  82. });
  83. EvenBitsConfig { advice, even_bits, s_decompose }
  84. }
  85. // Allocates all even bits in a table for the word size WORD_BITS.
  86. // `2^(WORD_BITS/2)` rows of the constraint system
  87. pub fn alloc_table(&self, layouter: &mut impl Layouter<F>) -> Result<(), Error> {
  88. layouter.assign_table(
  89. || "even bits table",
  90. |mut table| {
  91. for i in 0..2usize.pow(WORD_BITS / 2) {
  92. table.assign_cell(
  93. || format!("even_bits row {}", i),
  94. self.config.even_bits,
  95. i,
  96. || Ok(F::from(even_bits_at(i) as u64)),
  97. )?;
  98. }
  99. Ok(())
  100. },
  101. )
  102. }
  103. }
  104. fn even_bits_at(mut i: usize) -> usize {
  105. let mut r = 0;
  106. let mut c = 0;
  107. while i != 0 {
  108. let lower_bit = i % 2;
  109. r += lower_bit * 4usize.pow(c);
  110. i >>= 1;
  111. c += 1;
  112. }
  113. r
  114. }
  115. /// A newtype of a field element containing only bits that were in the
  116. /// even position of the decomposed element.
  117. /// All odd bits will be zero.
  118. #[derive(Clone, Copy, Debug)]
  119. pub struct EvenBits<W>(pub W);
  120. impl<W> Deref for EvenBits<W> {
  121. type Target = W;
  122. fn deref(&self) -> &Self::Target {
  123. &self.0
  124. }
  125. }
  126. /// A newtype of a field element containing only bits thet were in the
  127. /// odd position of the decomposed element.
  128. /// All odd bits will be right shifted by 1 into even positions.
  129. /// All odd bits will be zero.
  130. #[derive(Clone, Copy, Debug)]
  131. pub struct OddBits<W>(pub W);
  132. impl<W> Deref for OddBits<W> {
  133. type Target = W;
  134. fn deref(&self) -> &Self::Target {
  135. &self.0
  136. }
  137. }
  138. pub trait EvenBitsLookup<F: FieldExt>: Chip<F> {
  139. type Word;
  140. #[allow(clippy::type_complexity)]
  141. fn decompose(
  142. &self,
  143. layouter: impl Layouter<F>,
  144. c: Self::Word,
  145. ) -> Result<(EvenBits<Self::Word>, OddBits<Self::Word>), Error>;
  146. }
  147. impl<F: FieldExt, const WORD_BITS: u32> EvenBitsLookup<F> for EvenBitsChip<F, WORD_BITS> {
  148. type Word = AssignedCell<F, F>;
  149. fn decompose(
  150. &self,
  151. mut layouter: impl Layouter<F>,
  152. c: Self::Word,
  153. ) -> Result<(EvenBits<Self::Word>, OddBits<Self::Word>), Error> {
  154. let config = self.config();
  155. layouter.assign_region(
  156. || "decompose",
  157. |mut region: Region<'_, F>| {
  158. config.s_decompose.enable(&mut region, 0)?;
  159. let o_eo = c.value().cloned().map(decompose);
  160. let e_cell = region
  161. .assign_advice(
  162. || "even bits",
  163. config.advice[0],
  164. 0,
  165. || o_eo.map(|eo| *eo.0).ok_or(Error::Synthesis),
  166. )
  167. .map(EvenBits)?;
  168. let o_cell = region
  169. .assign_advice(
  170. || "odd bits",
  171. config.advice[1],
  172. 0,
  173. || o_eo.map(|eo| *eo.1).ok_or(Error::Synthesis),
  174. )
  175. .map(OddBits)?;
  176. c.copy_advice(|| "out", &mut region, config.advice[0], 1)?;
  177. Ok((e_cell, o_cell))
  178. },
  179. )
  180. }
  181. }
  182. fn decompose<F: FieldExt>(word: F) -> (EvenBits<F>, OddBits<F>) {
  183. assert!(word <= F::from_u128(u128::MAX));
  184. let mut even_only = word.to_repr();
  185. even_only.as_mut().iter_mut().for_each(|bits| {
  186. *bits &= 0b01010101;
  187. });
  188. let mut odd_only = word.to_repr();
  189. odd_only.as_mut().iter_mut().for_each(|bits| {
  190. *bits &= 0b10101010;
  191. });
  192. let even_only = EvenBits(F::from_repr(even_only).unwrap());
  193. let odd_only = F::from_repr(odd_only).unwrap();
  194. let odds_in_even = OddBits(F::from_u128(odd_only.get_lower_128() >> 1));
  195. (even_only, odds_in_even)
  196. }
  197. #[cfg(test)]
  198. mod tests {
  199. use super::*;
  200. #[test]
  201. fn even_bits_at_test() {
  202. assert_eq!(0b0, even_bits_at(0));
  203. assert_eq!(0b1, even_bits_at(1));
  204. assert_eq!(0b100, even_bits_at(2));
  205. assert_eq!(0b101, even_bits_at(3));
  206. }
  207. #[test]
  208. fn decompose_even_odd_test() {
  209. use pasta_curves::pallas;
  210. let odds = 0xAAAA;
  211. let evens = 0x5555;
  212. let (e, o) = decompose(pallas::Base::from_u128(odds));
  213. assert_eq!(e.get_lower_128(), 0);
  214. assert_eq!(o.get_lower_128(), odds >> 1);
  215. let (e, o) = decompose(pallas::Base::from_u128(evens));
  216. assert_eq!(e.get_lower_128(), evens);
  217. assert_eq!(o.get_lower_128(), 0);
  218. }
  219. }