本文介绍了在 Circom 中如何在循环中使用组件。由于 Circom 不允许在循环中直接实例化组件,文章提供了通过预先声明组件数组并在循环内指定组件类型的方式来解决这一问题,并提供了三个实际案例:求数组最大值、检查数组是否已排序以及确保数组中所有元素都是唯一的,展示了如何在循环中有效地使用 Circom 组件,以及一些使用 circom 的小技巧。
Circom 不允许在循环中直接实例化组件。例如,编译以下代码会导致下面的错误。
include "./node_modules/circomlib/circuits/comparators.circom";
template IsSorted(n) {
signal input in[n];
for (var i = 0; i < n; i++) {
component lt = LessEqThan(252); // 这里出错
lt.in[0] <== in[0];
lt.in[1] <== in[1];
lt.out === 1;
}
}
component main = IsSorted(8);
Signal or component declaration inside While scope. Signal and component can only be defined in the initial scope or in If scopes with known condition
在 While 作用域内声明了信号或组件。信号和组件只能在初始作用域或具有已知条件的 If 作用域中定义。
解决办法是声明一个组件数组,但不指定组件类型:
pragma circom 2.1.8;
include "./node_modules/circomlib/circuits/comparators.circom";
template IsSorted(n) {
signal input in[n];
// 声明组件数组
// 但不指定组件类型
component lessThan[n];
for (var i = 0; i < n - 1; i++) {
lessThan[i] = LessEqThan(252); // 在循环中指定类型
lessThan[i].in[0] <== in[i];
lessThan[i].in[1] <== in[i+1];
lessThan[i].out === 1;
}
}
component main = IsSorted(8);
当以这种方式声明组件时,不可能像下面这样对信号进行“单行赋值”:
pragma circom 2.1.8;
include "./node_modules/circomlib/circuits/comparators.circom";
template IsSorted() {
signal input in[4];
signal leq1;
signal leq2;
signal leq3;
// 对信号进行单行赋值
leq1 <== LessEqThan(252)([in[0], in[1]]);
leq2 <== LessEqThan(252)([in[1], in[2]]);
leq3 <== LessEqThan(252)([in[2], in[3]]);
leq1 === 1;
leq2 === 1;
leq3 === 1;
}
component main = IsSorted();
在循环外,可以在单行上设置信号。然而,在循环内,我们必须用更多步骤写出赋值,就像我们在 lessThan[i] = LessEqThan(252); // 在循环中指定类型
中所做的那样。
为了说明在循环中声明组件的一个有用的例子,我们展示了如何证明 k
是一个数组的最大值。为此,我们需要约束 k
大于或等于每个其他元素,并且它等于至少一个元素。为了理解为什么等式检查是必要的,考虑一下 18 大于或等于 [7, 8, 15] 中的所有元素,但它不是该数组的最大值。
以下 Circom 代码计算数组的最大值而不生成约束。然后,它运行 n
个 GreaterEqualThan 组件来约束提议的 max
值确实是最大值,并且还使用 IsEqual 组件的数组检查是否至少有一个元素等于 k
。
include "./node_modules/c...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!