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
use bellperson::{ConstraintSystem, SynthesisError};
use fil_sapling_crypto::circuit::boolean::Boolean;
use fil_sapling_crypto::jubjub::JubjubEngine;
pub fn xor<E, CS>(
cs: &mut CS,
key: &[Boolean],
input: &[Boolean],
) -> Result<Vec<Boolean>, SynthesisError>
where
E: JubjubEngine,
CS: ConstraintSystem<E>,
{
let key_len = key.len();
assert_eq!(key_len, 32 * 8);
input
.iter()
.enumerate()
.map(|(i, byte)| {
Boolean::xor(
cs.namespace(|| format!("xor bit: {}", i)),
byte,
&key[i % key_len],
)
})
.collect::<Result<Vec<_>, SynthesisError>>()
}
#[cfg(test)]
mod tests {
use super::xor;
use crate::circuit::test::TestConstraintSystem;
use crate::crypto;
use crate::util::{bits_to_bytes, bytes_into_boolean_vec};
use bellperson::ConstraintSystem;
use fil_sapling_crypto::circuit::boolean::Boolean;
use paired::bls12_381::Bls12;
use rand::{Rng, SeedableRng, XorShiftRng};
#[test]
fn test_xor_input_circut() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for i in 0..10 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let key: Vec<u8> = (0..32).map(|_| rng.gen()).collect();
let data: Vec<u8> = (0..(i + 1) * 32).map(|_| rng.gen()).collect();
let key_bits: Vec<Boolean> = {
let mut cs = cs.namespace(|| "key");
bytes_into_boolean_vec(&mut cs, Some(key.as_slice()), key.len()).unwrap()
};
let data_bits: Vec<Boolean> = {
let mut cs = cs.namespace(|| "data bits");
bytes_into_boolean_vec(&mut cs, Some(data.as_slice()), data.len()).unwrap()
};
let out_bits =
xor(&mut cs, key_bits.as_slice(), data_bits.as_slice()).expect("xor failed");
assert!(cs.is_satisfied(), "constraints not satisfied");
assert_eq!(out_bits.len(), data_bits.len(), "invalid output length");
let actual = bits_to_bytes(
out_bits
.iter()
.map(|v| v.get_value().unwrap())
.collect::<Vec<bool>>()
.as_slice(),
);
let expected = crypto::xor::encode(key.as_slice(), data.as_slice()).unwrap();
assert_eq!(expected, actual, "circuit and non circuit do not match");
let roundtrip_bits = {
let mut cs = cs.namespace(|| "roundtrip");
xor(&mut cs, key_bits.as_slice(), out_bits.as_slice()).expect("xor faield")
};
let roundtrip = bits_to_bytes(
roundtrip_bits
.iter()
.map(|v| v.get_value().unwrap())
.collect::<Vec<bool>>()
.as_slice(),
);
assert_eq!(data, roundtrip, "failed to roundtrip");
}
}
}