gnarkの使いかた
zk-SNARKsの標準的なライブラリを用意してくれている。回路の設定は自分で決める模様
一般的に、modの世界の計算が定義されるようなので暗号学的署名とかが回路に定義されるみたい
例えば、以下のようにYはpublicに宣言されている。
code:go
type MyCircuit struct {
C myComponent
Y frontend.Variable gnark:",public"
}
type myComponent struct {
X frontend.Variable
}
func (circuit *MyCircuit) Define(curveID ecc.ID, cs *frontend.ConstraintSystem) error {
// ... see Cicuit API section
}
code:go
func Define(curveID ecc.ID, cs *frontend.ConstraintSystem) error
curveIDはコンパイル時に挿入され、楕円曲線に応じて異なるコードパスを処理します(たとえば、MiMCのようなハッシュ関数にはcurveIDに応じてバリエーションがあります) csは、制約を定義するときに操作するルートオブジェクトです。
例えば、三次方程式$ x^3+x+5=yの解を知っていることを証明するには
$ x×xを書くために$ x² := cs.Mul(x, x) を使う
code:go
x3 := cs.Mul(circuit.X, circuit.X, circuit.X)
cs.AssertIsEqual(circuit.Y, cs.Add(x3, circuit.X, 5))
みたいな感じ
命令型のプログラミング言語では、条件分岐はif文やelse文を使います。しかし、回路を定義するための宣言型APIでは、これはうまく変換できません。なぜなら、frontend.Compileメソッドの出力は、さまざまな分岐を符号化しなければならない算術表現だからです。
gnarkは、Prologのような言語に似たcs.Select(...)APIを提供します。
意味わからん
frontend.Compileメソッドは、高水準プログラムを受け取り、それを単純な数学形式の一連の制約に変換します。
つまり、回路の計算だけ書いておけばcompileでいい感じにしてくれる
gnark APIを使ってどんな回路でも書くことができる
重要な点は、制約のすべての構成要素(変数、入力、定数)は、特性pの有限体Fpに存在するということです。
合理的な数の制約を含む回路を書くためには、回路の変数が住む場と制約システムが推論する場が同じになるように、Fp上で作業することが重要です。
一方、r≠pのFrに存在する変数を推論する回路は、pの場でのmodulo rの算術をエミュレートするために必要な代数的制約のために、高い制約数を持っています。
最後に、回路内の制約の数は限られており、任意に大きな回路を書くことはできません。例えば、BN254でGroth16を使用した場合、~250Mの制約を超えることはできません。