1use std::{
2 borrow::Borrow,
3 cmp::{max, min},
4};
5
6use crate::{
7 gates::{
8 flex_gate::GateInstructions,
9 range::{RangeChip, RangeInstructions},
10 },
11 utils::ScalarField,
12 AssignedValue, Context,
13 QuantumCell::Constant,
14};
15
16use itertools::Itertools;
17
18mod bytes;
19mod primitives;
20
21pub use bytes::*;
22pub use primitives::*;
23
24#[cfg(test)]
26pub mod tests;
27
28type RawAssignedValues<F> = Vec<AssignedValue<F>>;
29
30const BITS_PER_BYTE: usize = 8;
31
32#[derive(Clone, Debug)]
43pub struct SafeType<F: ScalarField, const BYTES_PER_ELE: usize, const TOTAL_BITS: usize> {
44 value: RawAssignedValues<F>,
46}
47
48impl<F: ScalarField, const BYTES_PER_ELE: usize, const TOTAL_BITS: usize>
49 SafeType<F, BYTES_PER_ELE, TOTAL_BITS>
50{
51 pub const BYTES_PER_ELE: usize = BYTES_PER_ELE;
53 pub const TOTAL_BITS: usize = TOTAL_BITS;
55 pub const VALUE_LENGTH: usize = TOTAL_BITS.div_ceil(BYTES_PER_ELE * BITS_PER_BYTE);
57
58 pub fn bits_per_ele() -> usize {
60 min(TOTAL_BITS, BYTES_PER_ELE * BITS_PER_BYTE)
61 }
62
63 fn new(raw_values: RawAssignedValues<F>) -> Self {
65 assert!(raw_values.len() == Self::VALUE_LENGTH, "Invalid raw values length");
66 Self { value: raw_values }
67 }
68
69 pub fn value(&self) -> &[AssignedValue<F>] {
71 &self.value
72 }
73}
74
75impl<F: ScalarField, const BYTES_PER_ELE: usize, const TOTAL_BITS: usize> AsRef<[AssignedValue<F>]>
76 for SafeType<F, BYTES_PER_ELE, TOTAL_BITS>
77{
78 fn as_ref(&self) -> &[AssignedValue<F>] {
79 self.value()
80 }
81}
82
83impl<F: ScalarField, const TOTAL_BITS: usize> TryFrom<Vec<SafeByte<F>>>
84 for SafeType<F, 1, TOTAL_BITS>
85{
86 type Error = String;
87
88 fn try_from(value: Vec<SafeByte<F>>) -> Result<Self, Self::Error> {
89 if value.len() * 8 != TOTAL_BITS {
90 return Err("Invalid length".to_owned());
91 }
92 Ok(Self::new(value.into_iter().map(|b| b.0).collect::<Vec<_>>()))
93 }
94}
95
96pub type SafeAddress<F> = SafeType<F, 1, 160>;
98pub type SafeBytes32<F> = SafeType<F, 1, 256>;
100
101pub struct SafeTypeChip<'a, F: ScalarField> {
103 range_chip: &'a RangeChip<F>,
104}
105
106impl<'a, F: ScalarField> SafeTypeChip<'a, F> {
107 pub fn new(range_chip: &'a RangeChip<F>) -> Self {
109 Self { range_chip }
110 }
111
112 pub fn raw_bytes_to<const BYTES_PER_ELE: usize, const TOTAL_BITS: usize>(
116 &self,
117 ctx: &mut Context<F>,
118 inputs: RawAssignedValues<F>,
119 ) -> SafeType<F, BYTES_PER_ELE, TOTAL_BITS> {
120 let element_bits = SafeType::<F, BYTES_PER_ELE, TOTAL_BITS>::bits_per_ele();
121 let bits = TOTAL_BITS;
122 assert!(
123 inputs.len() * BITS_PER_BYTE == max(bits, BITS_PER_BYTE),
124 "number of bits doesn't match"
125 );
126 self.add_bytes_constraints(ctx, &inputs, bits);
127 if bits == 1 || element_bits == BITS_PER_BYTE {
129 return SafeType::<F, BYTES_PER_ELE, TOTAL_BITS>::new(inputs);
130 };
131 assert!(
132 element_bits <= F::CAPACITY as usize,
133 "packed SafeType element exceeds native field capacity"
134 );
135
136 let byte_base = (0..BYTES_PER_ELE)
137 .map(|i| Constant(self.range_chip.gate.pow_of_two[i * BITS_PER_BYTE]))
138 .collect::<Vec<_>>();
139 let value = inputs
140 .chunks(BYTES_PER_ELE)
141 .map(|chunk| {
142 self.range_chip.gate.inner_product(
143 ctx,
144 chunk.to_vec(),
145 byte_base[..chunk.len()].to_vec(),
146 )
147 })
148 .collect::<Vec<_>>();
149 SafeType::<F, BYTES_PER_ELE, TOTAL_BITS>::new(value)
150 }
151
152 pub fn unsafe_to_safe_type<const BYTES_PER_ELE: usize, const TOTAL_BITS: usize>(
155 inputs: RawAssignedValues<F>,
156 ) -> SafeType<F, BYTES_PER_ELE, TOTAL_BITS> {
157 assert_eq!(inputs.len(), SafeType::<F, BYTES_PER_ELE, TOTAL_BITS>::VALUE_LENGTH);
158 SafeType::<F, BYTES_PER_ELE, TOTAL_BITS>::new(inputs)
159 }
160
161 pub fn assert_bool(&self, ctx: &mut Context<F>, input: AssignedValue<F>) -> SafeBool<F> {
163 self.range_chip.gate().assert_bit(ctx, input);
164 SafeBool(input)
165 }
166
167 pub fn load_bool(&self, ctx: &mut Context<F>, input: bool) -> SafeBool<F> {
169 let input = ctx.load_witness(F::from(input));
170 self.assert_bool(ctx, input)
171 }
172
173 pub fn unsafe_to_bool(input: AssignedValue<F>) -> SafeBool<F> {
176 SafeBool(input)
177 }
178
179 pub fn assert_byte(&self, ctx: &mut Context<F>, input: AssignedValue<F>) -> SafeByte<F> {
181 self.range_chip.range_check(ctx, input, BITS_PER_BYTE);
182 SafeByte(input)
183 }
184
185 pub fn load_byte(&self, ctx: &mut Context<F>, input: u8) -> SafeByte<F> {
187 let input = ctx.load_witness(F::from(input as u64));
188 self.assert_byte(ctx, input)
189 }
190
191 pub fn unsafe_to_byte(input: AssignedValue<F>) -> SafeByte<F> {
194 SafeByte(input)
195 }
196
197 pub fn unsafe_to_var_len_bytes<const MAX_LEN: usize>(
200 inputs: [AssignedValue<F>; MAX_LEN],
201 len: AssignedValue<F>,
202 ) -> VarLenBytes<F, MAX_LEN> {
203 VarLenBytes::<F, MAX_LEN>::new(inputs.map(|input| Self::unsafe_to_byte(input)), len)
204 }
205
206 pub fn unsafe_to_var_len_bytes_vec(
209 inputs: RawAssignedValues<F>,
210 len: AssignedValue<F>,
211 max_len: usize,
212 ) -> VarLenBytesVec<F> {
213 VarLenBytesVec::<F>::new(
214 inputs.iter().map(|input| Self::unsafe_to_byte(*input)).collect_vec(),
215 len,
216 max_len,
217 )
218 }
219
220 pub fn unsafe_to_fix_len_bytes<const MAX_LEN: usize>(
223 inputs: [AssignedValue<F>; MAX_LEN],
224 ) -> FixLenBytes<F, MAX_LEN> {
225 FixLenBytes::<F, MAX_LEN>::new(inputs.map(|input| Self::unsafe_to_byte(input)))
226 }
227
228 pub fn unsafe_to_fix_len_bytes_vec(
231 inputs: RawAssignedValues<F>,
232 len: usize,
233 ) -> FixLenBytesVec<F> {
234 FixLenBytesVec::<F>::new(
235 inputs.into_iter().map(|input| Self::unsafe_to_byte(input)).collect_vec(),
236 len,
237 )
238 }
239
240 pub fn raw_to_var_len_bytes<const MAX_LEN: usize>(
250 &self,
251 ctx: &mut Context<F>,
252 inputs: [AssignedValue<F>; MAX_LEN],
253 len: AssignedValue<F>,
254 ) -> VarLenBytes<F, MAX_LEN> {
255 self.range_chip.check_less_than_safe(ctx, len, MAX_LEN as u64 + 1);
256 VarLenBytes::<F, MAX_LEN>::new(inputs.map(|input| self.assert_byte(ctx, input)), len)
257 }
258
259 pub fn raw_to_var_len_bytes_vec(
269 &self,
270 ctx: &mut Context<F>,
271 inputs: RawAssignedValues<F>,
272 len: AssignedValue<F>,
273 max_len: usize,
274 ) -> VarLenBytesVec<F> {
275 self.range_chip.check_less_than_safe(ctx, len, max_len as u64 + 1);
276 VarLenBytesVec::<F>::new(
277 inputs.iter().map(|input| self.assert_byte(ctx, *input)).collect_vec(),
278 len,
279 max_len,
280 )
281 }
282
283 pub fn raw_to_fix_len_bytes<const LEN: usize>(
288 &self,
289 ctx: &mut Context<F>,
290 inputs: [AssignedValue<F>; LEN],
291 ) -> FixLenBytes<F, LEN> {
292 FixLenBytes::<F, LEN>::new(inputs.map(|input| self.assert_byte(ctx, input)))
293 }
294
295 pub fn raw_to_fix_len_bytes_vec(
300 &self,
301 ctx: &mut Context<F>,
302 inputs: RawAssignedValues<F>,
303 len: usize,
304 ) -> FixLenBytesVec<F> {
305 FixLenBytesVec::<F>::new(
306 inputs.into_iter().map(|input| self.assert_byte(ctx, input)).collect_vec(),
307 len,
308 )
309 }
310
311 fn add_bytes_constraints(
313 &self,
314 ctx: &mut Context<F>,
315 inputs: &RawAssignedValues<F>,
316 bits: usize,
317 ) {
318 let mut bits_left = bits;
319 for input in inputs {
320 let num_bit = min(bits_left, BITS_PER_BYTE);
321 self.range_chip.range_check(ctx, *input, num_bit);
322 bits_left -= num_bit;
323 }
324 }
325
326 }