Function seec::secret::low_depth_reduce

source ·
pub fn low_depth_reduce<F, Idx: GateIdx>(
    shares: impl IntoIterator<Item = Secret<BooleanGmw, Idx>>,
    f: F
) -> Option<Secret<BooleanGmw, Idx>>
where F: FnMut(Secret<BooleanGmw, Idx>, Secret<BooleanGmw, Idx>) -> Secret<BooleanGmw, Idx>,
Expand description

Reduce the slice of Secrets with the provided operation. The operation can be a closure or simply one of the operations implemented on Secrets, like BitAnd.
The circuit will be constructed such that the depth is minimal.

let inputs = inputs::<DefaultIdx>(23);
low_depth_reduce(inputs, std::ops::BitAnd::bitand)
    .unwrap()
    .output();
// It is important that the Gate and Idx type of the circuit match up with those of the
// Secrets, as otherwise an empty circuit will be returned
let and_tree: Circuit<bool, BooleanGate, DefaultIdx> = CircuitBuilder::global_into_circuit();
assert_eq!(and_tree.interactive_count(), 22)
Examples found in repository?
crates/seec/examples/sub_circuits.rs (line 13)
12
13
14
15
16
17
18
19
fn and_sc(input: &[Secret]) -> Secret {
    low_depth_reduce(input.iter().cloned(), ops::BitAnd::bitand).expect("Empty input")
}

#[sub_circuit]
fn or_sc(input: &[Secret]) -> Secret {
    low_depth_reduce(input.iter().cloned(), ops::BitOr::bitor).expect("Empty input")
}
More examples
Hide additional examples
crates/seec/examples/privmail_sc.rs (line 162)
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
fn comparison_circuit(keyword: &[[Secret; 8]], target_text: &[[Secret; 8]]) -> Secret {
    const CHARACTER_BIT_LEN: usize = 6; // Follows from the special PrivMail encoding
    let splitted_keyword: Vec<_> = keyword
        .iter()
        .flat_map(|c| c.iter().take(CHARACTER_BIT_LEN).cloned())
        .collect();
    let splitted_text: Vec<_> = target_text
        .iter()
        .flat_map(|c| c.iter().take(CHARACTER_BIT_LEN).cloned())
        .collect();

    let res: Vec<_> = splitted_keyword
        .into_iter()
        .zip(splitted_text)
        .map(|(k, t)| !(k ^ t))
        .collect();

    low_depth_reduce(res, ops::BitAnd::bitand).expect("Empty input")
}

#[sub_circuit]
fn or_sc(input: &[Secret]) -> Secret {
    low_depth_reduce(input.to_owned(), ops::BitOr::bitor)
        .unwrap_or_else(|| Secret::from_const(0, false))
}
crates/seec/examples/privmail.rs (line 143)
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
fn create_search_circuit(keyword: &[[Secret; 8]], target_text: &[[Secret; 8]]) -> Secret {
    /*
     * Calculate the number of positions we need to compare. E.g., if search_keyword
     * is "key" and target_text is "target", we must do 4 comparison:
     *
     * target , target , target , target
     * ^^^       ^^^       ^^^       ^^^
     * key       key       key       key
     */
    let num_positions = target_text.len() - keyword.len() + 1;
    let search_results_per_position: Vec<_> = (0..num_positions)
        .map(|k| create_comparison_circuit(keyword, target_text, k))
        .collect();

    let result_bits = search_results_per_position.into_iter().map(|result| {
        debug!("AND reduce for {} bits", result.len());
        low_depth_reduce(result, ops::BitAnd::bitand).expect("Reduce returned None")
    });
    // Finally, use OR tree to get the final answer of whether any of the comparisons was a match
    low_depth_reduce(result_bits, ops::BitOr::bitor).expect("Reduce returned None")
}