use nebu::Goldilocks;
use super::{reg_t, reg_t1, select_matrix, CONST_IDX, Z_LEN};
use crate::types::{CCSInstance, SparseMatrix};
fn neg_one() -> Goldilocks {
Goldilocks::ZERO - Goldilocks::ONE
}
pub fn build_step_ccs(pattern_tag: u8) -> CCSInstance {
match pattern_tag {
1 => pattern_quote(),
2 => pattern_compose(),
3 => pattern_cons(),
4 => pattern_branch(),
5 => pattern_add(),
6 => pattern_sub(),
7 => pattern_mul(),
8 => pattern_inv(),
9 => pattern_eq(),
0 => pattern_axis(),
10 => pattern_lt(),
11 => pattern_xor(),
12 => pattern_and(),
13 => pattern_not(),
14 => pattern_shl(),
15 => pattern_hash(),
16 => pattern_call(),
17 => pattern_look_inline(),
_ => trivial_ccs(),
}
}
pub fn trivial_ccs() -> CCSInstance {
CCSInstance {
matrices: vec![],
multisets: vec![],
coeffs: vec![],
num_rows: 1,
num_cols: Z_LEN,
}
}
fn build_ccs(matrices: Vec<SparseMatrix>, terms: Vec<(Vec<usize>, Goldilocks)>) -> CCSInstance {
let (multisets, coeffs): (Vec<_>, Vec<_>) = terms.into_iter().unzip();
let num_cols = matrices.first().map_or(Z_LEN, |m| m.cols);
CCSInstance {
matrices,
multisets,
coeffs,
num_rows: 1,
num_cols,
}
}
fn pattern_quote() -> CCSInstance {
let m_r5_t1 = select_matrix(reg_t1(5)); let m_r4_t = select_matrix(reg_t(4)); build_ccs(
vec![m_r5_t1, m_r4_t],
vec![
(vec![0], Goldilocks::ONE), (vec![1], neg_one()), ],
)
}
fn pattern_compose() -> CCSInstance {
let m_r5_t1 = select_matrix(reg_t1(5));
let m_r3_t = select_matrix(reg_t(3));
build_ccs(
vec![m_r5_t1, m_r3_t],
vec![
(vec![0], Goldilocks::ONE),
(vec![1], neg_one()),
],
)
}
fn pattern_cons() -> CCSInstance {
let m_r5_t1 = select_matrix(reg_t1(5));
let m_r3_t = select_matrix(reg_t(3));
build_ccs(
vec![m_r5_t1, m_r3_t],
vec![
(vec![0], Goldilocks::ONE),
(vec![1], neg_one()),
],
)
}
fn pattern_branch() -> CCSInstance {
let m_r5_t1 = select_matrix(reg_t1(5));
let m_r6_t = select_matrix(reg_t(6));
let m_r8_t_a = select_matrix(reg_t(8));
let m_r6_t_dup = select_matrix(reg_t(6));
let m_r8_t_b = select_matrix(reg_t(8));
let m_r4_t = select_matrix(reg_t(4));
CCSInstance {
matrices: vec![m_r5_t1, m_r6_t, m_r8_t_a, m_r6_t_dup, m_r8_t_b, m_r4_t],
multisets: vec![
vec![0], vec![1], vec![2, 3], vec![4, 5], ],
coeffs: vec![
Goldilocks::ONE,
neg_one(),
Goldilocks::ONE,
neg_one(),
],
num_rows: 1,
num_cols: Z_LEN,
}
}
fn pattern_add() -> CCSInstance {
let m_r5_t1 = select_matrix(reg_t1(5)); let m_r3_t = select_matrix(reg_t(3)); let m_r4_t = select_matrix(reg_t(4)); build_ccs(
vec![m_r5_t1, m_r3_t, m_r4_t],
vec![
(vec![0], Goldilocks::ONE), (vec![1], neg_one()), (vec![2], neg_one()), ],
)
}
fn pattern_sub() -> CCSInstance {
let m_r5_t1 = select_matrix(reg_t1(5));
let m_r3_t = select_matrix(reg_t(3));
let m_r4_t = select_matrix(reg_t(4));
build_ccs(
vec![m_r5_t1, m_r3_t, m_r4_t],
vec![
(vec![0], Goldilocks::ONE), (vec![1], neg_one()), (vec![2], Goldilocks::ONE), ],
)
}
fn pattern_mul() -> CCSInstance {
let m_r5_t1 = select_matrix(reg_t1(5));
let m_r3_t = select_matrix(reg_t(3));
let m_r4_t = select_matrix(reg_t(4));
build_ccs(
vec![m_r5_t1, m_r3_t, m_r4_t],
vec![
(vec![0], Goldilocks::ONE), (vec![1, 2], neg_one()), ],
)
}
fn pattern_inv() -> CCSInstance {
let m_r5_t1 = select_matrix(reg_t1(5));
let m_r3_t = select_matrix(reg_t(3));
let m_const = select_matrix(CONST_IDX);
build_ccs(
vec![m_r5_t1, m_r3_t, m_const],
vec![
(vec![0, 1], Goldilocks::ONE), (vec![2], neg_one()), ],
)
}
fn pattern_eq() -> CCSInstance {
let mut mr3_2r = SparseMatrix::new(2, Z_LEN);
let mut mr4_2r = SparseMatrix::new(2, Z_LEN);
let mut mr8_2r = SparseMatrix::new(2, Z_LEN);
let mut mr9_2r = SparseMatrix::new(2, Z_LEN);
let mut mr5_2r = SparseMatrix::new(2, Z_LEN);
let mut mc_2r = SparseMatrix::new(2, Z_LEN);
mr3_2r.set(0, reg_t(3), Goldilocks::ONE);
mr4_2r.set(0, reg_t(4), Goldilocks::ONE);
mr8_2r.set(0, reg_t(8), Goldilocks::ONE);
mr8_2r.set(1, reg_t(8), Goldilocks::ONE); mr9_2r.set(0, reg_t(9), Goldilocks::ONE);
mr9_2r.set(1, reg_t(9), Goldilocks::ONE);
mr5_2r.set(1, reg_t1(5), Goldilocks::ONE);
mc_2r.set(1, CONST_IDX, Goldilocks::ONE);
CCSInstance {
matrices: vec![mr3_2r, mr4_2r, mr8_2r, mr9_2r, mr5_2r, mc_2r],
multisets: vec![
vec![0, 2], vec![1, 2], vec![3], vec![4], vec![5], vec![3], ],
coeffs: vec![
Goldilocks::ONE, neg_one(), neg_one(), Goldilocks::ONE, neg_one(), Goldilocks::ONE, ],
num_rows: 2,
num_cols: Z_LEN,
}
}
fn pattern_axis() -> CCSInstance {
let m_r9 = select_matrix(reg_t(9)); let m_r8 = select_matrix(reg_t(8)); let m_c = select_matrix(CONST_IDX); build_ccs(
vec![m_r9, m_r8, m_c],
vec![
(vec![0], Goldilocks::ONE), (vec![1], neg_one()), (vec![2], Goldilocks::ONE), ],
)
}
fn pattern_lt() -> CCSInstance {
let m_ak = select_matrix(reg_t(10)); build_ccs(
vec![m_ak],
vec![
(vec![0, 0], Goldilocks::ONE), (vec![0], neg_one()), ],
)
}
fn pattern_xor() -> CCSInstance {
let m_ak = select_matrix(reg_t(10));
let m_bk = select_matrix(reg_t(11));
let m_ck = select_matrix(reg_t(12));
let neg_two = Goldilocks::ZERO - Goldilocks::new(2);
build_ccs(
vec![m_ak, m_bk, m_ck],
vec![
(vec![0], Goldilocks::ONE), (vec![1], Goldilocks::ONE), (vec![0, 1], neg_two), (vec![2], neg_one()), ],
)
}
fn pattern_and() -> CCSInstance {
let m_ak = select_matrix(reg_t(10));
let m_bk = select_matrix(reg_t(11));
let m_ck = select_matrix(reg_t(12));
build_ccs(
vec![m_ak, m_bk, m_ck],
vec![
(vec![0, 1], Goldilocks::ONE), (vec![2], neg_one()), ],
)
}
fn pattern_not() -> CCSInstance {
let m_ak = select_matrix(reg_t(10)); let m_ck = select_matrix(reg_t(12)); let m_const = select_matrix(CONST_IDX); build_ccs(
vec![m_ak, m_ck, m_const],
vec![
(vec![0], Goldilocks::ONE), (vec![1], Goldilocks::ONE), (vec![2], neg_one()), ],
)
}
fn pattern_shl() -> CCSInstance {
let m_ck = select_matrix(reg_t(12)); let m_src = select_matrix(reg_t(11)); build_ccs(
vec![m_ck, m_src],
vec![
(vec![0], Goldilocks::ONE), (vec![1], neg_one()), ],
)
}
fn pattern_hash() -> CCSInstance {
let m_r14_t1 = select_matrix(reg_t1(14)); let m_r14_t = select_matrix(reg_t(14)); let m_const = select_matrix(CONST_IDX); build_ccs(
vec![m_r14_t1, m_r14_t, m_const],
vec![
(vec![0], Goldilocks::ONE), (vec![1], neg_one()), (vec![2], neg_one()), ],
)
}
fn pattern_call() -> CCSInstance {
let m_r6 = select_matrix(reg_t(6)); build_ccs(
vec![m_r6],
vec![
(vec![0], Goldilocks::ONE), ],
)
}
fn pattern_look_inline() -> CCSInstance {
trivial_ccs()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ccs::{reg_t, reg_t1, CONST_IDX, Z_LEN};
use crate::types::{CCSWitness};
fn make_z(vals: &[(usize, u64)]) -> Vec<Goldilocks> {
let mut z = vec![Goldilocks::ZERO; Z_LEN];
z[CONST_IDX] = Goldilocks::ONE;
for &(idx, v) in vals {
z[idx] = Goldilocks::new(v);
}
z
}
#[test]
fn pattern_axis_budget_decrement() {
let z = make_z(&[(reg_t(8), 10), (reg_t(9), 9)]);
assert!(pattern_axis().is_satisfied_by(&CCSWitness { z }));
let z = make_z(&[(reg_t(8), 10), (reg_t(9), 8)]);
assert!(!pattern_axis().is_satisfied_by(&CCSWitness { z }));
}
#[test]
fn pattern_add_satisfying_witness() {
let z = make_z(&[(reg_t(3), 5), (reg_t(4), 3), (reg_t1(5), 8)]);
let ccs = pattern_add();
assert!(ccs.is_satisfied_by(&CCSWitness { z }));
}
#[test]
fn pattern_add_wrong_witness() {
let z = make_z(&[(reg_t(3), 5), (reg_t(4), 3), (reg_t1(5), 7)]);
let ccs = pattern_add();
assert!(!ccs.is_satisfied_by(&CCSWitness { z }));
}
#[test]
fn pattern_sub_satisfying_witness() {
let z = make_z(&[(reg_t(3), 7), (reg_t(4), 2), (reg_t1(5), 5)]);
let ccs = pattern_sub();
assert!(ccs.is_satisfied_by(&CCSWitness { z }));
}
#[test]
fn pattern_mul_satisfying_witness() {
let z = make_z(&[(reg_t(3), 6), (reg_t(4), 7), (reg_t1(5), 42)]);
let ccs = pattern_mul();
assert!(ccs.is_satisfied_by(&CCSWitness { z }));
}
#[test]
fn pattern_mul_wrong_witness() {
let z = make_z(&[(reg_t(3), 6), (reg_t(4), 7), (reg_t1(5), 43)]);
let ccs = pattern_mul();
assert!(!ccs.is_satisfied_by(&CCSWitness { z }));
}
#[test]
fn pattern_lt_bit_validity_accepts_bits() {
let z = make_z(&[(reg_t(10), 0)]);
assert!(pattern_lt().is_satisfied_by(&CCSWitness { z }));
let z = make_z(&[(reg_t(10), 1)]);
assert!(pattern_lt().is_satisfied_by(&CCSWitness { z }));
}
#[test]
fn pattern_lt_bit_validity_rejects_non_bit() {
let z = make_z(&[(reg_t(10), 2)]);
assert!(!pattern_lt().is_satisfied_by(&CCSWitness { z }));
}
#[test]
fn pattern_xor_gadget_satisfying() {
let z = make_z(&[(reg_t(10), 1), (reg_t(11), 0), (reg_t(12), 1)]);
assert!(pattern_xor().is_satisfied_by(&CCSWitness { z }));
let z = make_z(&[(reg_t(10), 1), (reg_t(11), 1), (reg_t(12), 0)]);
assert!(pattern_xor().is_satisfied_by(&CCSWitness { z }));
let z = make_z(&[(reg_t(10), 1), (reg_t(11), 0), (reg_t(12), 0)]);
assert!(!pattern_xor().is_satisfied_by(&CCSWitness { z }));
}
#[test]
fn pattern_and_gadget_satisfying() {
let z = make_z(&[(reg_t(10), 1), (reg_t(11), 1), (reg_t(12), 1)]);
assert!(pattern_and().is_satisfied_by(&CCSWitness { z }));
let z = make_z(&[(reg_t(10), 1), (reg_t(11), 0), (reg_t(12), 0)]);
assert!(pattern_and().is_satisfied_by(&CCSWitness { z }));
let z = make_z(&[(reg_t(10), 1), (reg_t(11), 1), (reg_t(12), 0)]);
assert!(!pattern_and().is_satisfied_by(&CCSWitness { z }));
}
#[test]
fn pattern_not_bit_gadget() {
let z = make_z(&[(reg_t(10), 0), (reg_t(12), 1)]);
assert!(pattern_not().is_satisfied_by(&CCSWitness { z }));
let z = make_z(&[(reg_t(10), 1), (reg_t(12), 0)]);
assert!(pattern_not().is_satisfied_by(&CCSWitness { z }));
let z = make_z(&[(reg_t(10), 1), (reg_t(12), 1)]);
assert!(!pattern_not().is_satisfied_by(&CCSWitness { z }));
}
#[test]
fn pattern_shl_src_bit_propagation() {
let z = make_z(&[(reg_t(11), 1), (reg_t(12), 1)]);
assert!(pattern_shl().is_satisfied_by(&CCSWitness { z }));
let z = make_z(&[(reg_t(11), 0), (reg_t(12), 1)]);
assert!(!pattern_shl().is_satisfied_by(&CCSWitness { z }));
}
#[test]
fn pattern_hash_round_counter_increments() {
let z = make_z(&[(reg_t(14), 5), (reg_t1(14), 6)]);
assert!(pattern_hash().is_satisfied_by(&CCSWitness { z }));
let z = make_z(&[(reg_t(14), 5), (reg_t1(14), 7)]);
assert!(!pattern_hash().is_satisfied_by(&CCSWitness { z }));
}
#[test]
fn pattern_call_result_must_be_zero() {
let z = make_z(&[(reg_t(6), 0)]);
assert!(pattern_call().is_satisfied_by(&CCSWitness { z }));
let z = make_z(&[(reg_t(6), 1)]);
assert!(!pattern_call().is_satisfied_by(&CCSWitness { z }));
}
}