-
Notifications
You must be signed in to change notification settings - Fork 1
/
r1cs.rs
179 lines (155 loc) · 5.93 KB
/
r1cs.rs
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
//! This module contains the implementation of Rank-1 Constraint System (R1CS).
//! It consists of three matrices: left, right, and output, each of which is a vector of vectors.
//! The R1CS is satisfied if the Hadamard product of left and right matrices times solution witness
//! is equal to the output matrix times solution witness.
//!
//! Here, you need to implement the function checking whether the R1CS is satisfied by the witness.
use crate::{finite_field::Fp, linear_algebra::{Matrix, Vector}};
/// Structure representing general R1CS. It consists of three matrices:
/// left, right, and output, each of which is a vector of vectors
pub struct R1CS<const WITNESS_SIZE: usize, const CONSTRAINT_NUM: usize> {
left_matrix: Matrix<WITNESS_SIZE, CONSTRAINT_NUM>,
right_matrix: Matrix<WITNESS_SIZE, CONSTRAINT_NUM>,
output_matrix: Matrix<WITNESS_SIZE, CONSTRAINT_NUM>,
}
impl<const WITNESS_SIZE: usize, const CONSTRAINT_NUM: usize> R1CS<WITNESS_SIZE, CONSTRAINT_NUM> {
/// Creates a new R1CS instance from three matrices
pub fn new(
left_matrix: Matrix<WITNESS_SIZE, CONSTRAINT_NUM>,
right_matrix: Matrix<WITNESS_SIZE, CONSTRAINT_NUM>,
output_matrix: Matrix<WITNESS_SIZE, CONSTRAINT_NUM>,
) -> Self {
R1CS {
left_matrix,
right_matrix,
output_matrix,
}
}
/// Checks whether specified witness satisfies the R1CS
pub fn is_satisfied(&self, witness: &Vector<WITNESS_SIZE>) -> bool {
assert_eq!(witness.get(0), Fp::from(1), "first element of witness must be 1!");
// TODO: Implement R1CS satisfaction check here!
unimplemented!("Implement R1CS satisfaction check!")
}
/// Checks whether the j-th R1CS constraint is satisfied by the witness
pub fn is_constraint_satisfied(&self, witness: &Vector<WITNESS_SIZE>, constraint_id: usize) -> bool {
assert_eq!(witness.get(0), Fp::from(1), "first element of witness must be 1!");
assert!(constraint_id < CONSTRAINT_NUM, "invalid constraint id!");
// TODO: Implement R1CS constraint satisfaction check here!
unimplemented!("Implement R1CS constraint satisfaction check!")
}
}
/// Tests below create a toy R1CS to check the circuit satisfiability
/// C(x1, x2, x3) = x1*x2*x3 + (1-x1)(x2+x3) for x2, x3 in Fp and x1 in {0,1}.
#[cfg(test)]
mod tests {
use super::*;
use crate::finite_field::Fp;
const WITNESS_SIZE: usize = 7;
const CONSTRAINT_NUM: usize = 4;
fn create_toy_r1cs() -> R1CS<WITNESS_SIZE, CONSTRAINT_NUM> {
let zero = Fp::from(0);
let one = Fp::from(1);
let left_matrix = Matrix::new([
Vector::new([zero, zero, one, zero, zero, zero, zero]),
Vector::new([zero, zero, zero, one, zero, zero, zero]),
Vector::new([zero, zero, one, zero, zero, zero, zero]),
Vector::new([one, zero, -one, zero, zero, zero, zero]),
]);
let right_matrix = Matrix::new([
Vector::new([zero, zero, one, zero, zero, zero, zero]),
Vector::new([zero, zero, zero, zero, one, zero, zero]),
Vector::new([zero, zero, zero, zero, zero, one, zero]),
Vector::new([zero, zero, zero, one, one, zero, zero]),
]);
let output_matrix = Matrix::new([
Vector::new([zero, zero, one, zero, zero, zero, zero]),
Vector::new([zero, zero, zero, zero, zero, one, zero]),
Vector::new([zero, zero, zero, zero, zero, zero, one]),
Vector::new([zero, one, zero, zero, zero, zero, -one]),
]);
R1CS::new(left_matrix, right_matrix, output_matrix)
}
#[test]
fn test_toy_r1cs_valid_witness_1() {
let toy_r1cs = create_toy_r1cs();
let valid_witness = Vector::new([
Fp::from(1),
Fp::from(12),
Fp::from(1),
Fp::from(3),
Fp::from(4),
Fp::from(12),
Fp::from(12),
]);
assert!(
toy_r1cs.is_satisfied(&valid_witness),
"valid witness failed!"
);
}
#[test]
fn test_toy_r1cs_valid_witness_2() {
let toy_r1cs = create_toy_r1cs();
let valid_witness = Vector::new([
Fp::from(1),
Fp::from(7),
Fp::from(0),
Fp::from(3),
Fp::from(4),
Fp::from(12),
Fp::from(0),
]);
assert!(
toy_r1cs.is_satisfied(&valid_witness),
"valid witness failed!"
);
}
#[test]
fn test_toy_r1cs_invalid_witness() {
let toy_r1cs = create_toy_r1cs();
let invalid_witness = Vector::new([
Fp::from(1),
Fp::from(12),
Fp::from(0),
Fp::from(3),
Fp::from(4),
Fp::from(12),
Fp::from(12),
]);
assert!(
!toy_r1cs.is_satisfied(&invalid_witness),
"invalid witness passed!"
);
}
#[test]
fn test_toy_r1cs_constraints() {
let toy_r1cs = create_toy_r1cs();
let invalid_witness = Vector::new([
Fp::from(1),
Fp::from(12),
Fp::from(0),
Fp::from(3),
Fp::from(4),
Fp::from(12),
Fp::from(12),
]);
// Here, the first two constraints should be satisfied
// while the last two should not be satisfied
assert!(
toy_r1cs.is_constraint_satisfied(&invalid_witness, 0),
"correct constraint is not satisfied!"
);
assert!(
toy_r1cs.is_constraint_satisfied(&invalid_witness, 1),
"correct constraint is not satisfied!"
);
assert!(
!toy_r1cs.is_constraint_satisfied(&invalid_witness, 2),
"incorrect constraint is satisfied!"
);
assert!(
!toy_r1cs.is_constraint_satisfied(&invalid_witness, 3),
"incorrect constraint is satisfied!"
);
}
}