如何在gnark中实现对可正负明文整数的>=0校验?
在Gnark中实现整数>=0的校验逻辑
由于Gnark仅处理无符号有限域整数,原明文负数会被模域阶p转换为p - |x|形式的大正数,无法直接用常规比较判断原数是否非负。同时api.Select的第一个参数必须是布尔变量(仅0或1),这是触发assertIsBoolean错误的原因。以下是适配Gnark的解决方案:
核心思路
域阶p是一个大奇数,原明文正数在无符号域中直接等于自身,且必然小于p/2;原明文负数模p后的值为p - |x|,必然大于p/2。因此可以通过判断变量与p/2的大小关系,反向推导原数是否非负。
具体实现代码
首先获取当前曲线的域阶并计算其一半:
import ( "math/big" "github.com/consensys/gnark/frontend" ) func YourCircuit(api frontend.API) error { // 定义变量(假设已声明val, postcheck, bitpostcheck为[10]frontend.Variable) val := [10]frontend.Variable{/* 初始化输入 */} var postcheck [10]frontend.Variable var bitpostcheck [10]frontend.Variable // 获取当前电路使用的有限域阶 p := api.Compiler().Field().Params().Fr.Modulus() // 计算域阶的一半(p为奇数,直接整除2即可) pDiv2 := new(big.Int).Div(p, big.NewInt(2)) pDiv2Var := frontend.Variable(pDiv2) for i := 0; i < 10; i++ { // api.Cmp(a, b)返回1当a >= b,返回0当a < b // 原正数在域中 < p/2,所以cmpResult为0;原负数模后 >= p/2,cmpResult为1 cmpResult := api.Cmp(val[i], pDiv2Var) // 取反得到isNonNegative:1表示原数>=0,0表示原数<0 isNonNegative := api.Sub(1, cmpResult) // 使用布尔变量作为Select的条件参数,符合Gnark要求 postcheck[i] = api.Select(isNonNegative, val[i], frontend.Variable(0)) // bitpostcheck直接复用isNonNegative即可,无需重复Select bitpostcheck[i] = isNonNegative } return nil }
关键说明
- 确保输入的原整数绝对值不超过
p/2:这是该逻辑成立的前提,若原数绝对值超过p/2,负数模p后可能小于p/2,导致判断错误。ZK电路设计中通常会通过约束限制输入范围,避免这种情况。 isNonNegative是严格布尔变量:通过api.Sub(1, api.Cmp(...))得到的结果只能是0或1,完全符合api.Select对条件参数的要求,不会触发assertIsBoolean错误。
内容的提问来源于stack exchange,提问作者stateless
相关产品推荐
相关产品推荐

