1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
use p3_field::PrimeField32;
use serde::{Deserialize, Serialize};
use super::ByteOpcode;
/// A byte lookup event.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct ByteLookupEvent {
/// The shard number, used for byte lookup table.
pub shard: u32,
// The channel multiplicity identifier.
pub channel: u32,
/// The opcode of the operation.
pub opcode: ByteOpcode,
/// The first output operand.
pub a1: u32,
/// The second output operand.
pub a2: u32,
/// The first input operand.
pub b: u32,
/// The second input operand.
pub c: u32,
}
/// A type that can record byte lookup events.
pub trait ByteRecord {
/// Adds a new `ByteLookupEvent` to the record.
fn add_byte_lookup_event(&mut self, blu_event: ByteLookupEvent);
/// Adds a list of `ByteLookupEvent`s to the record.
#[inline]
fn add_byte_lookup_events(&mut self, blu_events: Vec<ByteLookupEvent>) {
for blu_event in blu_events.into_iter() {
self.add_byte_lookup_event(blu_event);
}
}
/// Adds a `ByteLookupEvent` to verify `a` and `b are indeed bytes to the shard.
fn add_u8_range_check(&mut self, shard: u32, channel: u32, a: u8, b: u8) {
self.add_byte_lookup_event(ByteLookupEvent {
shard,
channel,
opcode: ByteOpcode::U8Range,
a1: 0,
a2: 0,
b: a as u32,
c: b as u32,
});
}
/// Adds a `ByteLookupEvent` to verify `a` is indeed u16.
fn add_u16_range_check(&mut self, shard: u32, channel: u32, a: u32) {
self.add_byte_lookup_event(ByteLookupEvent {
shard,
channel,
opcode: ByteOpcode::U16Range,
a1: a,
a2: 0,
b: 0,
c: 0,
});
}
/// Adds `ByteLookupEvent`s to verify that all the bytes in the input slice are indeed bytes.
fn add_u8_range_checks(&mut self, shard: u32, channel: u32, bytes: &[u8]) {
let mut index = 0;
while index + 1 < bytes.len() {
self.add_u8_range_check(shard, channel, bytes[index], bytes[index + 1]);
index += 2;
}
if index < bytes.len() {
// If the input slice's length is odd, we need to add a check for the last byte.
self.add_u8_range_check(shard, channel, bytes[index], 0);
}
}
/// Adds `ByteLookupEvent`s to verify that all the field elements in the input slice are indeed
/// bytes.
fn add_u8_range_checks_field<F: PrimeField32>(
&mut self,
shard: u32,
channel: u32,
field_values: &[F],
) {
self.add_u8_range_checks(
shard,
channel,
&field_values
.iter()
.map(|x| x.as_canonical_u32() as u8)
.collect::<Vec<_>>(),
);
}
/// Adds `ByteLookupEvent`s to verify that all the bytes in the input slice are indeed bytes.
fn add_u16_range_checks(&mut self, shard: u32, channel: u32, ls: &[u32]) {
ls.iter()
.for_each(|x| self.add_u16_range_check(shard, channel, *x));
}
/// Adds a `ByteLookupEvent` to compute the bitwise OR of the two input values.
fn lookup_or(&mut self, shard: u32, channel: u32, b: u8, c: u8) {
self.add_byte_lookup_event(ByteLookupEvent {
shard,
channel,
opcode: ByteOpcode::OR,
a1: (b | c) as u32,
a2: 0,
b: b as u32,
c: c as u32,
});
}
}
impl ByteLookupEvent {
/// Creates a new `ByteLookupEvent`.
#[inline(always)]
pub fn new(
shard: u32,
channel: u32,
opcode: ByteOpcode,
a1: u32,
a2: u32,
b: u32,
c: u32,
) -> Self {
Self {
shard,
channel,
opcode,
a1,
a2,
b,
c,
}
}
}
impl ByteRecord for Vec<ByteLookupEvent> {
fn add_byte_lookup_event(&mut self, blu_event: ByteLookupEvent) {
self.push(blu_event);
}
}