use ff::PrimeFieldBits; use halo2::{ circuit::{Cell, Layouter, Region}, plonk::{Advice, Column, Error, Permutation}, }; use pasta_curves::arithmetic::FieldExt; use std::array; use std::convert::TryInto; pub(crate) mod cond_swap; pub(crate) mod enable_flag; pub(crate) mod lookup_range_check; pub(crate) mod plonk; /// A variable representing a field element. #[derive(Copy, Clone, Debug)] pub struct CellValue { cell: Cell, value: Option, } pub trait Var: Copy + Clone + std::fmt::Debug { fn new(cell: Cell, value: Option) -> Self; fn cell(&self) -> Cell; fn value(&self) -> Option; } impl Var for CellValue { fn new(cell: Cell, value: Option) -> Self { Self { cell, value } } fn cell(&self) -> Cell { self.cell } fn value(&self) -> Option { self.value } } pub trait UtilitiesInstructions { type Var: Var; fn load_private( &self, mut layouter: impl Layouter, column: Column, value: Option, ) -> Result { layouter.assign_region( || "load private", |mut region| { let cell = region.assign_advice( || "load private", column, 0, || value.ok_or(Error::SynthesisError), )?; Ok(Var::new(cell, value)) }, ) } } /// Assigns a cell at a specific offset within the given region, constraining it /// to the same value as another cell (which may be in any region). /// /// Returns an error if either `column` or `copy` is not within `perm`. pub fn copy( region: &mut Region<'_, F>, annotation: A, column: Column, offset: usize, copy: &CellValue, perm: &Permutation, ) -> Result, Error> where A: Fn() -> AR, AR: Into, { let cell = region.assign_advice(annotation, column, offset, || { copy.value.ok_or(Error::SynthesisError) })?; region.constrain_equal(perm, cell, copy.cell)?; Ok(CellValue::new(cell, copy.value)) } pub fn transpose_option_array( option_array: Option<[T; LEN]>, ) -> [Option; LEN] { let mut ret = [None; LEN]; if let Some(arr) = option_array { for (entry, value) in ret.iter_mut().zip(array::IntoIter::new(arr)) { *entry = Some(value); } } ret } /// Subsets a field element to a specified bitrange (little-endian) pub fn bitrange_subset( field_elem: F, bitrange: std::ops::Range, ) -> F { assert!(bitrange.end <= F::NUM_BITS as usize); let bits: Vec = field_elem .to_le_bits() .iter() .by_val() .skip(bitrange.start) .take(bitrange.end - bitrange.start) .chain(std::iter::repeat(false)) .take(256) .collect(); let bytearray: Vec = bits .chunks_exact(8) .map(|byte| byte.iter().rev().fold(0u8, |acc, bit| acc * 2 + *bit as u8)) .collect(); F::from_bytes(&bytearray.try_into().unwrap()).unwrap() }