@ -1,15 +1,6 @@ |
|||
# gnark-plonky2-verifier |
|||
|
|||
# gnark-ed25519 |
|||
ed25519 implementation in Gnark |
|||
|
|||
To test: |
|||
``` |
|||
go test gnark-ed25519/edwards_curve |
|||
``` |
|||
|
|||
To build and run: |
|||
``` |
|||
go build gnark-ed25519 && ./gnark-ed25519 |
|||
To run the benchmark, |
|||
``` |
|||
|
|||
if it panics on compilation.... make vriables capitalzie |
|||
go run benchmark.go |
|||
``` |
|||
@ -1,74 +0,0 @@ |
|||
// Copyright 2020 ConsenSys AG
|
|||
//
|
|||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
// you may not use this file except in compliance with the License.
|
|||
// You may obtain a copy of the License at
|
|||
//
|
|||
// http://www.apache.org/licenses/LICENSE-2.0
|
|||
//
|
|||
// Unless required by applicable law or agreed to in writing, software
|
|||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
// See the License for the specific language governing permissions and
|
|||
// limitations under the License.
|
|||
|
|||
package main |
|||
|
|||
// import (
|
|||
// "fmt"
|
|||
// "os"
|
|||
// "github.com/consensys/gnark/frontend"
|
|||
// "github.com/consensys/gnark-crypto/ecc"
|
|||
// "github.com/consensys/gnark/frontend/cs/r1cs"
|
|||
// "github.com/consensys/gnark/backend/groth16"
|
|||
// _ "gnark-ed25519/edwards_curve"
|
|||
// _ "gnark-ed25519/sha512"
|
|||
// )
|
|||
|
|||
// // Circuit defines a simple circuit
|
|||
// // x**3 + x + 5 == y
|
|||
// type Circuit struct {
|
|||
// // struct tags on a variable is optional
|
|||
// // default uses variable name and secret visibility.
|
|||
// X frontend.Variable `gnark:"x"`
|
|||
// Y frontend.Variable `gnark:",public"`
|
|||
// }
|
|||
|
|||
// // Define declares the circuit constraints
|
|||
// // x**3 + x + 5 == y
|
|||
// func (circuit *Circuit) Define(api frontend.API) error {
|
|||
// x3 := api.Mul(circuit.X, circuit.X, circuit.X)
|
|||
// api.AssertIsEqual(circuit.Y, api.Add(x3, circuit.X, 5))
|
|||
// return nil
|
|||
// }
|
|||
|
|||
// func main() {
|
|||
// err := mainImpl()
|
|||
// if err != nil {
|
|||
// fmt.Println(err)
|
|||
// os.Exit(1)
|
|||
// }
|
|||
// }
|
|||
|
|||
// func mainImpl() error {
|
|||
// var myCircuit Circuit
|
|||
// r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &myCircuit)
|
|||
// if err != nil {
|
|||
// return err
|
|||
// }
|
|||
|
|||
// assignment := &Circuit{
|
|||
// X: "2",
|
|||
// Y: "15",
|
|||
// }
|
|||
// witness, _ := frontend.NewWitness(assignment, ecc.BN254.ScalarField())
|
|||
// publicWitness, _ := witness.Public()
|
|||
// pk, vk, err := groth16.Setup(r1cs)
|
|||
// proof, err := groth16.Prove(r1cs, pk, witness)
|
|||
// err = groth16.Verify(proof, vk, publicWitness)
|
|||
// if err != nil {
|
|||
// return err
|
|||
// }
|
|||
// fmt.Println(proof)
|
|||
// return nil
|
|||
// }
|
|||
@ -1,277 +0,0 @@ |
|||
// Copyright 2020 ConsenSys AG
|
|||
//
|
|||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
// you may not use this file except in compliance with the License.
|
|||
// You may obtain a copy of the License at
|
|||
//
|
|||
// http://www.apache.org/licenses/LICENSE-2.0
|
|||
//
|
|||
// Unless required by applicable law or agreed to in writing, software
|
|||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
// See the License for the specific language governing permissions and
|
|||
// limitations under the License.
|
|||
|
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
"gnark-ed25519/poseidon" |
|||
"math/big" |
|||
"time" |
|||
|
|||
"github.com/consensys/gnark-crypto/ecc" |
|||
"github.com/consensys/gnark/backend/groth16" |
|||
"github.com/consensys/gnark/frontend" |
|||
"github.com/consensys/gnark/frontend/cs/r1cs" |
|||
"github.com/consensys/gnark/test" |
|||
) |
|||
|
|||
// type Eddsa25519Circuit struct {
|
|||
// M []frontend.Variable
|
|||
// Pk []frontend.Variable
|
|||
// Sig []frontend.Variable
|
|||
// }
|
|||
|
|||
// func (circuit *Eddsa25519Circuit) Define(api frontend.API) error {
|
|||
// c, err := edwards_curve.New[edwards_curve.Ed25519, edwards_curve.Ed25519Scalars](api)
|
|||
// if err != nil {
|
|||
// return err
|
|||
// }
|
|||
// edwards_curve.CheckValid(c, circuit.Sig, circuit.M, circuit.Pk)
|
|||
// return nil
|
|||
// }
|
|||
|
|||
// type Sha512Circuit struct {
|
|||
// in []frontend.Variable `gnark:"in"`
|
|||
// out []frontend.Variable `gnark:"out"`
|
|||
// }
|
|||
|
|||
// func (circuit *Sha512Circuit) Define(api frontend.API) error {
|
|||
// res := sha512.Sha512(api, circuit.in)
|
|||
// if len(res) != 512 {
|
|||
// panic("bad length")
|
|||
// }
|
|||
// for i := 0; i < 512; i++ {
|
|||
// api.AssertIsEqual(res[i], circuit.out[i])
|
|||
// }
|
|||
// return nil
|
|||
// }
|
|||
|
|||
// func main() {
|
|||
// err := mainImpl()
|
|||
// if err != nil {
|
|||
// fmt.Println(err)
|
|||
// os.Exit(1)
|
|||
// }
|
|||
// }
|
|||
|
|||
// // func mainImpl() error {
|
|||
// // in := bytesToBits([]byte("Succinct Labs"))
|
|||
// // out := hexToBits("503ace098aa03f6feec1b5df0a38aee923f744a775508bc81f2b94ad139be297c2e8cd8c44af527b5d3f017a7fc929892c896604047e52e3f518924f52bff0dc")
|
|||
|
|||
// // myCircuit := Sha512Circuit{
|
|||
// // in,
|
|||
// // out,
|
|||
// // }
|
|||
// // fmt.Println(time.Now(), "compiling...")
|
|||
// // r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &myCircuit)
|
|||
// // if err != nil {
|
|||
// // return err
|
|||
// // }
|
|||
|
|||
// // assignment := &Sha512Circuit{
|
|||
// // in,
|
|||
// // out,
|
|||
// // }
|
|||
// // fmt.Println(time.Now(), "generating witness...")
|
|||
// // witness, _ := frontend.NewWitness(assignment, ecc.BN254.ScalarField())
|
|||
// // publicWitness, _ := witness.Public()
|
|||
// // fmt.Println(time.Now(), "groth setup...")
|
|||
// // pk, vk, err := groth16.Setup(r1cs)
|
|||
// // fmt.Println(time.Now(), "groth prove...")
|
|||
// // proof, err := groth16.Prove(r1cs, pk, witness)
|
|||
// // fmt.Println(time.Now(), "groth verify...")
|
|||
// // err = groth16.Verify(proof, vk, publicWitness)
|
|||
// // if err != nil {
|
|||
// // return err
|
|||
// // }
|
|||
// // fmt.Println(proof)
|
|||
// // return nil
|
|||
// // }
|
|||
|
|||
// func mainImpl() error {
|
|||
// M := "53756363696e6374204c616273"
|
|||
// Pk := "f7ec1c43f4de9d49556de87b86b26a98942cb078486fdb44de38b80864c39731"
|
|||
// Sig := "35c323757c20640a294345c89c0bfcebe3d554fdb0c7b7a0bdb72222c531b1ec849fed99a053e0f5b02dd9a25bb6eb018885526d9f583cdbde0b1e9f6329da09"
|
|||
|
|||
// myCircuit := Eddsa25519Circuit{
|
|||
// M: hexToBits(M),
|
|||
// Pk: hexToBits(Pk),
|
|||
// Sig: hexToBits(Sig),
|
|||
// }
|
|||
// fmt.Println(time.Now(), "compiling...")
|
|||
// r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &myCircuit)
|
|||
// if err != nil {
|
|||
// return err
|
|||
// }
|
|||
|
|||
// assignment := &Eddsa25519Circuit{
|
|||
// M: hexToBits(M),
|
|||
// Pk: hexToBits(Pk),
|
|||
// Sig: hexToBits(Sig),
|
|||
// }
|
|||
// fmt.Println(time.Now(), "generating witness...")
|
|||
// witness, _ := frontend.NewWitness(assignment, ecc.BN254.ScalarField())
|
|||
// publicWitness, _ := witness.Public()
|
|||
// fmt.Println(time.Now(), "groth setup...")
|
|||
// pk, vk, err := groth16.Setup(r1cs)
|
|||
// fmt.Println(time.Now(), "groth prove...")
|
|||
// proof, err := groth16.Prove(r1cs, pk, witness)
|
|||
// fmt.Println(time.Now(), "groth verify...")
|
|||
// err = groth16.Verify(proof, vk, publicWitness)
|
|||
// if err != nil {
|
|||
// return err
|
|||
// }
|
|||
// fmt.Println(proof)
|
|||
// return nil
|
|||
// }
|
|||
|
|||
// func hexToBits(h string) []frontend.Variable {
|
|||
// b, err := hex.DecodeString(h)
|
|||
// if err != nil {
|
|||
// panic(err)
|
|||
// }
|
|||
// result := make([]frontend.Variable, len(b)*8)
|
|||
// for i, v := range b {
|
|||
// for j := 0; j < 8; j++ {
|
|||
// if (v & (1 << j)) != 0 {
|
|||
// result[i*8+j] = 1
|
|||
// } else {
|
|||
// result[i*8+j] = 0
|
|||
// }
|
|||
// }
|
|||
// }
|
|||
// return result
|
|||
// }
|
|||
|
|||
// func bytesToBits(arr []byte) []frontend.Variable {
|
|||
// result := make([]frontend.Variable, len(arr)*8)
|
|||
// for i, v := range arr {
|
|||
// for j := 0; j < 8; j++ {
|
|||
// if (v & (1 << (7 - j))) != 0 {
|
|||
// result[i*8+j] = 1
|
|||
// } else {
|
|||
// result[i*8+j] = 0
|
|||
// }
|
|||
// }
|
|||
// }
|
|||
// return result
|
|||
// }
|
|||
|
|||
type PoseidonCircuit struct { |
|||
In [12]frontend.Variable |
|||
Out [12]frontend.Variable |
|||
} |
|||
|
|||
func (circuit *PoseidonCircuit) Define(api frontend.API) error { |
|||
poseidon.Poseidon(api, circuit.In, circuit.Out) |
|||
return nil |
|||
} |
|||
|
|||
func main() { |
|||
in_str := [12]string{ |
|||
"0", |
|||
"0", |
|||
"0", |
|||
"0", |
|||
"0", |
|||
"0", |
|||
"0", |
|||
"0", |
|||
"0", |
|||
"0", |
|||
"0", |
|||
"0", |
|||
} |
|||
out_str := [12]string{ |
|||
"4330397376401421145", |
|||
"14124799381142128323", |
|||
"8742572140681234676", |
|||
"14345658006221440202", |
|||
"15524073338516903644", |
|||
"5091405722150716653", |
|||
"15002163819607624508", |
|||
"2047012902665707362", |
|||
"16106391063450633726", |
|||
"4680844749859802542", |
|||
"15019775476387350140", |
|||
"1698615465718385111", |
|||
} |
|||
|
|||
var in [12]big.Int |
|||
var out [12]big.Int |
|||
for i := 0; i < 12; i++ { |
|||
n := new(big.Int) |
|||
n, _ = n.SetString(in_str[i], 10) |
|||
in[i] = *n |
|||
} |
|||
for i := 0; i < 12; i++ { |
|||
n := new(big.Int) |
|||
n, _ = n.SetString(out_str[i], 10) |
|||
out[i] = *n |
|||
} |
|||
|
|||
var _in [12]frontend.Variable |
|||
var _out [12]frontend.Variable |
|||
|
|||
for i := 0; i < 12; i++ { |
|||
_in[i] = in[i] |
|||
_out[i] = out[i] |
|||
} |
|||
|
|||
myCircuit := PoseidonCircuit{ |
|||
In: _in, |
|||
Out: _out, |
|||
} |
|||
|
|||
fmt.Println(time.Now(), "compiling...") |
|||
r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &myCircuit) |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
panic(err) |
|||
} |
|||
|
|||
assignment := &PoseidonCircuit{ |
|||
In: _in, |
|||
Out: _out, |
|||
} |
|||
|
|||
witness, _ := frontend.NewWitness(assignment, ecc.BN254.ScalarField()) |
|||
publicWitness, err := witness.Public() |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
fmt.Println(time.Now(), "groth setup...") |
|||
pk, vk, err := groth16.Setup(r1cs) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
err = test.IsSolved(&myCircuit, assignment, ecc.BN254.ScalarField()) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
fmt.Println(time.Now(), "groth prove...") |
|||
proof, err := groth16.Prove(r1cs, pk, witness) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
fmt.Println(time.Now(), "groth verify...") |
|||
|
|||
err = groth16.Verify(proof, vk, publicWitness) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
} |
|||
@ -1,297 +0,0 @@ |
|||
package edwards_curve |
|||
|
|||
|
|||
// This file is little-endian
|
|||
|
|||
import ( |
|||
"math/big" |
|||
"github.com/consensys/gnark/frontend" |
|||
"github.com/consensys/gnark/std/math/emulated" |
|||
"gnark-ed25519/sha512" |
|||
) |
|||
|
|||
|
|||
func H(api frontend.API, m []frontend.Variable) []frontend.Variable { |
|||
rawResult := sha512.Sha512(api, swapByteEndianness(m)) |
|||
sResult := swapByteEndianness(rawResult[:]) |
|||
return sResult |
|||
} |
|||
|
|||
func pow2(n uint) *big.Int { |
|||
result := big.NewInt(1) |
|||
result.Lsh(result, n) |
|||
return result |
|||
} |
|||
|
|||
type EdCurve = Curve[Ed25519, Ed25519Scalars] |
|||
type EdPoint = AffinePoint[Ed25519] |
|||
type EdCoordinate = emulated.Element[Ed25519] |
|||
type EdScalar = emulated.Element[Ed25519Scalars] |
|||
|
|||
func bits_to_scalar(c *EdCurve, s []frontend.Variable) EdCoordinate { |
|||
if len(s) != 256 { panic("bad length") } |
|||
elt := emulated.NewElement[Ed25519](0) |
|||
if len(elt.Limbs) != 4 { panic("bad length") } |
|||
i := 0 |
|||
for k := 0; k < 4; k++ { |
|||
elt.Limbs[k] = c.api.FromBinary(s[i:i+64]...) |
|||
i += 64 |
|||
} |
|||
if i != len(s) { panic("bad length") } |
|||
return elt |
|||
} |
|||
|
|||
// func bits_to_clamped_scalar(c *EdCurve, input []frontend.Variable) EdScalar {
|
|||
// if len(input) != 256 { panic("bad length") }
|
|||
// s := make([]frontend.Variable, len(input))
|
|||
// copy(s, input)
|
|||
// s[0] = 0
|
|||
// s[1] = 0
|
|||
// s[2] = 0
|
|||
// s[254] = 1
|
|||
// return bits_to_scalar[Ed25519Scalars](c, s)
|
|||
// }
|
|||
|
|||
func bits_to_element(c *EdCurve, input []frontend.Variable) EdPoint { |
|||
// L := emulated.NewElement[Ed25519Scalars](rEd25519)
|
|||
unchecked_point := decodepoint(c, input) |
|||
|
|||
// // TODO: https://github.com/warner/python-pure25519 says this check is not necessary:
|
|||
// //
|
|||
// // > This library is conservative, and performs full subgroup-membership checks on decoded
|
|||
// // > points, which adds considerable overhead. The Curve25519/Ed25519 algorithms were
|
|||
// // > designed to not require these checks, so a careful application might be able to
|
|||
// // > improve on this slightly (Ed25519 verify down to 6.2ms, DH-finish to 3.2ms).
|
|||
// c.AssertIsZero(c.ScalarMul(unchecked_point, L))
|
|||
|
|||
return unchecked_point |
|||
} |
|||
|
|||
// func publickey(c *EdCurve, seed []frontend.Variable) EdPoint {
|
|||
// if len(seed) != 32 { panic("bad length") }
|
|||
// a := bits_to_clamped_scalar(c, H(c.api, seed)[:256])
|
|||
// return c.ScalarMul(c.g, a)
|
|||
// }
|
|||
|
|||
func CheckValid(c *EdCurve, s, m, pk []frontend.Variable) { |
|||
if len(s) != 512 { panic("bad signature length") } |
|||
if len(pk) != 256 { panic("bad public key length") } |
|||
if len(m) % 8 != 0 { panic("bad message length") } |
|||
R := bits_to_element(c, s[:256]) |
|||
A := bits_to_element(c, pk) |
|||
h := H(c.api, concat(s[:256], pk, m)) |
|||
v1 := c.ScalarMulBinary(c.g, s[256:]) |
|||
v2 := c.Add(R, c.ScalarMulBinary(A, h)) |
|||
c.AssertIsEqual(v1, v2) |
|||
} |
|||
|
|||
func reverse[T interface{}](arr []T) []T { |
|||
result := make([]T, len(arr)) |
|||
for i, v := range arr { |
|||
result[len(result)-i-1] = v |
|||
} |
|||
return result |
|||
} |
|||
|
|||
func concat(args ...[]frontend.Variable) []frontend.Variable { |
|||
result := []frontend.Variable{} |
|||
for _, v := range args { |
|||
result = append(result, v...) |
|||
} |
|||
return result |
|||
} |
|||
|
|||
func decodepoint(c *EdCurve, unclamped []frontend.Variable) EdPoint { |
|||
if len(unclamped) != 256 { panic("bad length") } |
|||
|
|||
s := make([]frontend.Variable, len(unclamped)) |
|||
copy(s, unclamped) |
|||
s[255] = 0 |
|||
y := bits_to_scalar(c, s) |
|||
// unclamped = int(binascii.hexlify(s[:32][::-1]), 16)
|
|||
// clamp = (1 << 255) - 1
|
|||
// y = unclamped & clamp # clear MSB
|
|||
|
|||
x := xrecover(c, y) |
|||
// x = xrecover(y)
|
|||
|
|||
xbits := c.baseApi.ToBinary(x) |
|||
if len(xbits) != 256 { panic("bad length") } |
|||
mismatch := c.api.Xor(xbits[0], unclamped[255]) |
|||
x = c.baseApi.Select(mismatch, c.baseApi.Neg(x), x).(EdCoordinate) |
|||
// if bool(x & 1) != bool(unclamped & (1<<255)): x = Q-x
|
|||
|
|||
P := AffinePoint[Ed25519]{ |
|||
X: x, |
|||
Y: y, |
|||
} |
|||
// P = [x,y]
|
|||
|
|||
c.AssertIsOnCurve(P) |
|||
// if not isoncurve(P): raise NotOnCurve("decoding point that is not on curve")
|
|||
|
|||
return P |
|||
} |
|||
|
|||
func toValue(s EdCoordinate) *big.Int { |
|||
result := big.NewInt(0) |
|||
placeValue := big.NewInt(1) |
|||
for _, v := range s.Limbs { |
|||
q := new(big.Int).Mul(placeValue, v.(*big.Int)) |
|||
result.Add(result, q) |
|||
placeValue.Lsh(placeValue, Ed25519{}.BitsPerLimb()) |
|||
} |
|||
return result |
|||
} |
|||
|
|||
func _const(x int64) EdCoordinate { |
|||
return emulated.NewElement[Ed25519](big.NewInt(x)) |
|||
} |
|||
|
|||
// Q = 2**255 - 19
|
|||
// L = 2**252 + 27742317777372353535851937790883648493
|
|||
// def inv(x):
|
|||
// return pow(x, Q-2, Q)
|
|||
// d = -121665 * inv(121666)
|
|||
// I = pow(2,(Q-1)//4,Q)
|
|||
|
|||
func xrecover(c *EdCurve, y EdCoordinate) EdCoordinate { |
|||
Q := Ed25519{}.Modulus() |
|||
I := emulated.NewElement[Ed25519](newBigInt("2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0")) |
|||
|
|||
yy := c.baseApi.Mul(y, y) |
|||
xx := c.baseApi.Div( |
|||
c.baseApi.Sub(yy, _const(1)), |
|||
c.baseApi.Add(c.baseApi.Mul(c.d, yy), _const(1)), |
|||
).(EdCoordinate) |
|||
// xx = (y*y-1) * inv(d*y*y+1)
|
|||
|
|||
power := new(big.Int).Add(Q, big.NewInt(3)) |
|||
power.Rsh(power, 3) |
|||
x := pow(c, xx, power) |
|||
// x = pow(xx,(Q+3)//8,Q)
|
|||
|
|||
matches := c.baseApi.IsZero(c.baseApi.Sub( |
|||
c.baseApi.Mul(x, x), |
|||
xx, |
|||
)) |
|||
x = c.baseApi.Select(matches, x, c.baseApi.Mul(x, emulated.NewElement[Ed25519](I))).(EdCoordinate) |
|||
// if (x*x - xx) % Q != 0: x = (x*I) % Q
|
|||
|
|||
odd := c.baseApi.ToBinary(x)[0] |
|||
x = c.baseApi.Select(odd, c.baseApi.Neg(x), x).(EdCoordinate) |
|||
// if x % 2 != 0: x = Q-x
|
|||
|
|||
return x |
|||
} |
|||
|
|||
func pow(c *EdCurve, base EdCoordinate, exponent *big.Int) EdCoordinate { |
|||
mul := base |
|||
result := _const(1) |
|||
for exponent.Sign() > 0 { |
|||
if exponent.Bit(0) != 0 { |
|||
result = c.baseApi.Mul(result, mul).(EdCoordinate) |
|||
} |
|||
mul = c.baseApi.Mul(mul, mul).(EdCoordinate) |
|||
exponent.Rsh(exponent, 1) |
|||
} |
|||
return result |
|||
} |
|||
|
|||
func swapByteEndianness(in []frontend.Variable) []frontend.Variable { |
|||
if len(in) % 8 != 0 { panic("must be a multiple of 8 bits") } |
|||
result := make([]frontend.Variable, len(in)) |
|||
for i := 0; i < len(in); i += 8 { |
|||
for j := 0; j < 8; j++ { |
|||
result[i+j] = in[i+7-j] |
|||
} |
|||
} |
|||
return result |
|||
} |
|||
|
|||
// def checkvalid(s, m, pk):
|
|||
// if len(s) != 64: raise Exception("signature length is wrong")
|
|||
// if len(pk) != 32: raise Exception("public-key length is wrong")
|
|||
// R = bytes_to_element(s[:32])
|
|||
// A = bytes_to_element(pk)
|
|||
// S = bytes_to_scalar(s[32:])
|
|||
// h = Hint(s[:32] + pk + m)
|
|||
// v1 = Base.scalarmult(S)
|
|||
// v2 = R.add(A.scalarmult(h))
|
|||
// return v1==v2
|
|||
|
|||
// def publickey(seed):
|
|||
// # turn first half of SHA512(seed) into scalar, then into point
|
|||
// assert len(seed) == 32
|
|||
// a = bytes_to_clamped_scalar(H(seed)[:32])
|
|||
// A = Base.scalarmult(a)
|
|||
// return A.to_bytes()
|
|||
|
|||
// def bytes_to_scalar(s):
|
|||
// assert len(s) == 32, len(s)
|
|||
// return int(binascii.hexlify(s[::-1]), 16)
|
|||
|
|||
|
|||
// from pure25519.basic import (bytes_to_clamped_scalar,
|
|||
// bytes_to_scalar, scalar_to_bytes,
|
|||
// bytes_to_element, Base)
|
|||
// import hashlib, binascii
|
|||
|
|||
// def H(m):
|
|||
// return hashlib.sha512(m).digest()
|
|||
|
|||
// def Hint(m):
|
|||
// h = H(m)
|
|||
// return int(binascii.hexlify(h[::-1]), 16)
|
|||
|
|||
// def signature(m,sk,pk):
|
|||
// assert len(sk) == 32 # seed
|
|||
// assert len(pk) == 32
|
|||
// h = H(sk[:32])
|
|||
// a_bytes, inter = h[:32], h[32:]
|
|||
// a = bytes_to_clamped_scalar(a_bytes)
|
|||
// r = Hint(inter + m)
|
|||
// R = Base.scalarmult(r)
|
|||
// R_bytes = R.to_bytes()
|
|||
// S = r + Hint(R_bytes + pk + m) * a
|
|||
// return R_bytes + scalar_to_bytes(S)
|
|||
|
|||
// def checkvalid(s, m, pk):
|
|||
// if len(s) != 64: raise Exception("signature length is wrong")
|
|||
// if len(pk) != 32: raise Exception("public-key length is wrong")
|
|||
// R = bytes_to_element(s[:32])
|
|||
// A = bytes_to_element(pk)
|
|||
// S = bytes_to_scalar(s[32:])
|
|||
// h = Hint(s[:32] + pk + m)
|
|||
// v1 = Base.scalarmult(S)
|
|||
// v2 = R.add(A.scalarmult(h))
|
|||
// return v1==v2
|
|||
|
|||
// # wrappers
|
|||
|
|||
// import os
|
|||
|
|||
// def create_signing_key():
|
|||
// seed = os.urandom(32)
|
|||
// return seed
|
|||
// def create_verifying_key(signing_key):
|
|||
// return publickey(signing_key)
|
|||
|
|||
// def sign(skbytes, msg):
|
|||
// """Return just the signature, given the message and just the secret
|
|||
// key."""
|
|||
// if len(skbytes) != 32:
|
|||
// raise ValueError("Bad signing key length %d" % len(skbytes))
|
|||
// vkbytes = create_verifying_key(skbytes)
|
|||
// sig = signature(msg, skbytes, vkbytes)
|
|||
// return sig
|
|||
|
|||
// def verify(vkbytes, sig, msg):
|
|||
// if len(vkbytes) != 32:
|
|||
// raise ValueError("Bad verifying key length %d" % len(vkbytes))
|
|||
// if len(sig) != 64:
|
|||
// raise ValueError("Bad signature length %d" % len(sig))
|
|||
// rc = checkvalid(sig, msg, vkbytes)
|
|||
// if not rc:
|
|||
// raise ValueError("rc != 0", rc)
|
|||
// return True
|
|||
@ -1,65 +0,0 @@ |
|||
package edwards_curve |
|||
|
|||
import ( |
|||
"testing" |
|||
"encoding/hex" |
|||
|
|||
"github.com/consensys/gnark/frontend" |
|||
"github.com/consensys/gnark/test" |
|||
) |
|||
|
|||
type Eddsa25519Circuit struct { |
|||
m []frontend.Variable |
|||
pk []frontend.Variable |
|||
sig []frontend.Variable |
|||
} |
|||
|
|||
func (circuit *Eddsa25519Circuit) Define(api frontend.API) error { |
|||
c, err := New[Ed25519, Ed25519Scalars](api) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
CheckValid(c, circuit.sig, circuit.m, circuit.pk) |
|||
return nil |
|||
} |
|||
|
|||
func TestEddsa25519(t *testing.T) { |
|||
assert := test.NewAssert(t) |
|||
|
|||
m := "53756363696e6374204c616273" |
|||
pk := "f7ec1c43f4de9d49556de87b86b26a98942cb078486fdb44de38b80864c39731" |
|||
sig := "35c323757c20640a294345c89c0bfcebe3d554fdb0c7b7a0bdb72222c531b1ec849fed99a053e0f5b02dd9a25bb6eb018885526d9f583cdbde0b1e9f6329da09" |
|||
|
|||
circuit := Eddsa25519Circuit { |
|||
m: hexToBits(m), |
|||
pk: hexToBits(pk), |
|||
sig: hexToBits(sig), |
|||
} |
|||
witness := Eddsa25519Circuit { |
|||
m: hexToBits(m), |
|||
pk: hexToBits(pk), |
|||
sig: hexToBits(sig), |
|||
} |
|||
|
|||
err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) |
|||
assert.NoError(err) |
|||
} |
|||
|
|||
func hexToBits(h string) []frontend.Variable { |
|||
b, err := hex.DecodeString(h) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
result := make([]frontend.Variable, len(b) * 8) |
|||
for i, v := range b { |
|||
for j := 0; j < 8; j++ { |
|||
if (v & (1 << j)) != 0 { |
|||
result[i*8+j] = 1 |
|||
} else { |
|||
result[i*8+j] = 0 |
|||
} |
|||
} |
|||
} |
|||
return result |
|||
} |
|||
|
|||
@ -1,34 +0,0 @@ |
|||
package edwards_curve |
|||
|
|||
import ( |
|||
"math/big" |
|||
) |
|||
|
|||
var ( |
|||
qEd25519, rEd25519 *big.Int |
|||
) |
|||
|
|||
func init() { |
|||
// https://neuromancer.sk/std/other/Ed25519
|
|||
qEd25519 = newBigInt("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed") |
|||
rEd25519 = newBigInt("1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed") |
|||
} |
|||
|
|||
type Ed25519 struct{} |
|||
|
|||
func (fp Ed25519) NbLimbs() uint { return 4 } |
|||
func (fp Ed25519) BitsPerLimb() uint { return 64 } |
|||
func (fp Ed25519) IsPrime() bool { return true } |
|||
func (fp Ed25519) Modulus() *big.Int { return qEd25519 } |
|||
func (fp Ed25519) Generator() (*big.Int, *big.Int) { |
|||
return newBigInt("216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A"), |
|||
newBigInt("6666666666666666666666666666666666666666666666666666666666666658") |
|||
} |
|||
|
|||
type Ed25519Scalars struct{} |
|||
|
|||
func (fp Ed25519Scalars) NbLimbs() uint { return 4 } |
|||
func (fp Ed25519Scalars) BitsPerLimb() uint { return 64 } |
|||
func (fp Ed25519Scalars) IsPrime() bool { return true } |
|||
func (fp Ed25519Scalars) Modulus() *big.Int { return rEd25519 } |
|||
|
|||
@ -1,201 +0,0 @@ |
|||
package edwards_curve |
|||
|
|||
import ( |
|||
"fmt" |
|||
"math/big" |
|||
|
|||
"github.com/consensys/gnark/frontend" |
|||
"github.com/consensys/gnark/std/math/emulated" |
|||
) |
|||
|
|||
func New[T, S emulated.FieldParams](api frontend.API) (*Curve[T, S], error) { |
|||
var t T |
|||
var s S |
|||
var gxb, gyb *big.Int |
|||
var A, D *big.Int |
|||
_, is_25519_t := any(t).(Ed25519) |
|||
_, is_25519_s := any(s).(Ed25519Scalars) |
|||
if is_25519_t && is_25519_s { |
|||
// https://neuromancer.sk/std/other/Ed25519
|
|||
gxb = newBigInt("216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A") |
|||
gyb = newBigInt("6666666666666666666666666666666666666666666666666666666666666658") |
|||
A = newBigInt("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec") |
|||
D = newBigInt("52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3") |
|||
} else { |
|||
return nil, fmt.Errorf("unknown curve") |
|||
} |
|||
return newCurve[T, S]( |
|||
api, |
|||
emulated.NewElement[T](A), |
|||
emulated.NewElement[T](D), |
|||
emulated.NewElement[T](gxb), |
|||
emulated.NewElement[T](gyb)) |
|||
} |
|||
|
|||
func newBigInt(s string) *big.Int { |
|||
result, success := new(big.Int).SetString(s, 16) |
|||
if !success { |
|||
panic("invalid bigint") |
|||
} |
|||
return result |
|||
} |
|||
|
|||
// TODO: could also have a type constraint for curve parameters (fields,
|
|||
// equation and generator). But for now we don't do arbitrary curves.
|
|||
|
|||
type Curve[T, S emulated.FieldParams] struct { |
|||
a emulated.Element[T] |
|||
d emulated.Element[T] |
|||
|
|||
// api is the native api, we construct it ourselves to be sure
|
|||
api frontend.API |
|||
// baseApi is the api for point operations
|
|||
baseApi frontend.API |
|||
// scalarApi is the api for scalar operations
|
|||
scalarApi frontend.API |
|||
|
|||
g AffinePoint[T] |
|||
} |
|||
|
|||
func (c *Curve[T, S]) Generator() AffinePoint[T] { |
|||
return c.g |
|||
} |
|||
|
|||
func newCurve[T, S emulated.FieldParams](api frontend.API, a, d, Gx, Gy emulated.Element[T]) (*Curve[T, S], error) { |
|||
ba, err := emulated.NewField[T](api) |
|||
if err != nil { |
|||
return nil, fmt.Errorf("new base api: %w", err) |
|||
} |
|||
sa, err := emulated.NewField[S](api) |
|||
if err != nil { |
|||
return nil, fmt.Errorf("new scalar api: %w", err) |
|||
} |
|||
return &Curve[T, S]{ |
|||
a: a, |
|||
d: d, |
|||
api: api, |
|||
baseApi: ba, |
|||
scalarApi: sa, |
|||
g: AffinePoint[T]{ |
|||
X: Gx, |
|||
Y: Gy, |
|||
}, |
|||
}, nil |
|||
} |
|||
|
|||
type AffinePoint[T emulated.FieldParams] struct { |
|||
X, Y emulated.Element[T] |
|||
} |
|||
|
|||
func (c *Curve[T, S]) Neg(p AffinePoint[T]) AffinePoint[T] { |
|||
return AffinePoint[T]{ |
|||
X: p.X, |
|||
Y: c.baseApi.Neg(p.Y).(emulated.Element[T]), |
|||
} |
|||
} |
|||
|
|||
func (c *Curve[T, S]) AssertIsEqual(p, q AffinePoint[T]) { |
|||
c.baseApi.AssertIsEqual(p.X, q.X) |
|||
c.baseApi.AssertIsEqual(p.Y, q.Y) |
|||
} |
|||
|
|||
func (c *Curve[T, S]) AssertIsOnCurve(p AffinePoint[T]) { |
|||
xx := c.baseApi.Mul(p.X, p.X) |
|||
yy := c.baseApi.Mul(p.Y, p.Y) |
|||
axx := c.baseApi.Mul(xx, c.a) |
|||
lhs := c.baseApi.Add(axx, yy) |
|||
|
|||
dxx := c.baseApi.Mul(xx, c.d) |
|||
dxxyy := c.baseApi.Mul(dxx, yy) |
|||
rhs := c.baseApi.Add(dxxyy, 1) |
|||
|
|||
c.baseApi.AssertIsEqual(lhs, rhs) |
|||
} |
|||
|
|||
func (c *Curve[T, S]) AssertIsZero(p AffinePoint[T]) { |
|||
c.baseApi.AssertIsEqual(p.X, 0) |
|||
c.baseApi.AssertIsEqual(p.Y, 1) |
|||
} |
|||
|
|||
func (c *Curve[T, S]) Add(q, r AffinePoint[T]) AffinePoint[T] { |
|||
// u = (x1 + y1) * (x2 + y2)
|
|||
u1 := c.baseApi.Mul(q.X, c.a) |
|||
u1 = c.baseApi.Sub(q.Y, u1) |
|||
u2 := c.baseApi.Add(r.X, r.Y) |
|||
u := c.baseApi.Mul(u1, u2) |
|||
|
|||
// v0 = x1 * y2
|
|||
v0 := c.baseApi.Mul(r.Y, q.X) |
|||
|
|||
// v1 = x2 * y1
|
|||
v1 := c.baseApi.Mul(r.X, q.Y) |
|||
|
|||
// v2 = d * v0 * v1
|
|||
v2 := c.baseApi.Mul(c.d, v0, v1) |
|||
|
|||
var px, py frontend.Variable |
|||
|
|||
// x = (v0 + v1) / (1 + v2)
|
|||
px = c.baseApi.Add(v0, v1) |
|||
px = c.baseApi.DivUnchecked(px, c.baseApi.Add(1, v2)) |
|||
|
|||
// y = (u + a * v0 - v1) / (1 - v2)
|
|||
py = c.baseApi.Mul(c.a, v0) |
|||
py = c.baseApi.Sub(py, v1) |
|||
py = c.baseApi.Add(py, u) |
|||
py = c.baseApi.DivUnchecked(py, c.baseApi.Sub(1, v2)) |
|||
|
|||
return AffinePoint[T]{ |
|||
X: px.(emulated.Element[T]), |
|||
Y: py.(emulated.Element[T]), |
|||
} |
|||
} |
|||
|
|||
func (c *Curve[T, S]) Double(p AffinePoint[T]) AffinePoint[T] { |
|||
u := c.baseApi.Mul(p.X, p.Y) |
|||
v := c.baseApi.Mul(p.X, p.X) |
|||
w := c.baseApi.Mul(p.Y, p.Y) |
|||
|
|||
n1 := c.baseApi.Add(u, u) |
|||
av := c.baseApi.Mul(v, c.a) |
|||
n2 := c.baseApi.Sub(w, av) |
|||
d1 := c.baseApi.Add(w, av) |
|||
d2 := c.baseApi.Sub(2, d1) |
|||
|
|||
px := c.baseApi.DivUnchecked(n1, d1) |
|||
py := c.baseApi.DivUnchecked(n2, d2) |
|||
|
|||
return AffinePoint[T]{ |
|||
X: px.(emulated.Element[T]), |
|||
Y: py.(emulated.Element[T]), |
|||
} |
|||
} |
|||
|
|||
func (c *Curve[T, S]) Select(b frontend.Variable, p, q AffinePoint[T]) AffinePoint[T] { |
|||
x := c.baseApi.Select(b, p.X, q.X) |
|||
y := c.baseApi.Select(b, p.Y, q.Y) |
|||
return AffinePoint[T]{ |
|||
X: x.(emulated.Element[T]), |
|||
Y: y.(emulated.Element[T]), |
|||
} |
|||
} |
|||
|
|||
func (c *Curve[T, S]) ScalarMul(p AffinePoint[T], s emulated.Element[S]) AffinePoint[T] { |
|||
return c.ScalarMulBinary(p, c.scalarApi.ToBinary(s)) |
|||
} |
|||
|
|||
func (c *Curve[T, S]) ScalarMulBinary(p AffinePoint[T], sBits []frontend.Variable) AffinePoint[T] { |
|||
res := AffinePoint[T]{ |
|||
X: emulated.NewElement[T](0), |
|||
Y: emulated.NewElement[T](1), |
|||
} |
|||
acc := p |
|||
|
|||
for i := 0; i < len(sBits); i++ { |
|||
tmp := c.Add(res, acc) |
|||
res = c.Select(sBits[i], tmp, res) |
|||
acc = c.Double(acc) |
|||
} |
|||
|
|||
return res |
|||
} |
|||
@ -1,230 +0,0 @@ |
|||
package edwards_curve |
|||
|
|||
import ( |
|||
"math/big" |
|||
"testing" |
|||
|
|||
"github.com/consensys/gnark-crypto/ecc" |
|||
"github.com/consensys/gnark/frontend" |
|||
"github.com/consensys/gnark/std/math/emulated" |
|||
"github.com/consensys/gnark/test" |
|||
// "github.com/ethereum/go-ethereum/crypto/secp256k1"
|
|||
) |
|||
|
|||
type OnCurveTest[T, S emulated.FieldParams] struct { |
|||
P AffinePoint[T] |
|||
} |
|||
|
|||
func (c *OnCurveTest[T, S]) Define(api frontend.API) error { |
|||
cr, err := New[T, S](api) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
cr.AssertIsOnCurve(c.P) |
|||
return nil |
|||
} |
|||
|
|||
func TestGeneratorIsOnCurve(t *testing.T) { |
|||
assert := test.NewAssert(t) |
|||
circuit := OnCurveTest[Ed25519, Ed25519Scalars]{} |
|||
witness := OnCurveTest[Ed25519, Ed25519Scalars]{ |
|||
P: AffinePoint[Ed25519]{ |
|||
X: emulated.NewElement[Ed25519](newBigInt("216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A")), |
|||
Y: emulated.NewElement[Ed25519](newBigInt("6666666666666666666666666666666666666666666666666666666666666658")), |
|||
}, |
|||
} |
|||
err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) |
|||
assert.NoError(err) |
|||
} |
|||
|
|||
// s1*x1 + s2*x2 = y
|
|||
type MulAddTest[T, S emulated.FieldParams] struct { |
|||
X1, X2 AffinePoint[T] |
|||
S1, S2 emulated.Element[S] |
|||
Y AffinePoint[T] |
|||
} |
|||
|
|||
func (c *MulAddTest[T, S]) Define(api frontend.API) error { |
|||
cr, err := New[T, S](api) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
X1S1 := cr.ScalarMul(c.X1, c.S1) |
|||
X2S2 := cr.ScalarMul(c.X2, c.S2) |
|||
sum := cr.Add(X1S1, X2S2) |
|||
cr.AssertIsEqual(sum, c.Y) |
|||
cr.scalarApi.AssertIsEqual( |
|||
cr.scalarApi.Add(c.S1, c.S2), |
|||
emulated.NewElement[S](big.NewInt(1)), |
|||
) |
|||
return nil |
|||
} |
|||
|
|||
func TestGeneratorGeneratesCurveOfCorrectOrder(t *testing.T) { |
|||
assert := test.NewAssert(t) |
|||
Gx, Gy := Ed25519{}.Generator() |
|||
G := AffinePoint[Ed25519]{ |
|||
X: emulated.NewElement[Ed25519](Gx), |
|||
Y: emulated.NewElement[Ed25519](Gy), |
|||
} |
|||
for i := 2; i <= 3; i++ { |
|||
S1 := new(big.Int).Sub(rEd25519, big.NewInt(int64(i - 1))) |
|||
S2 := big.NewInt(int64(i)) |
|||
circuit := MulAddTest[Ed25519, Ed25519Scalars]{} |
|||
witness := MulAddTest[Ed25519, Ed25519Scalars]{ |
|||
X1: G, |
|||
X2: G, |
|||
S1: emulated.NewElement[Ed25519Scalars](S1), |
|||
S2: emulated.NewElement[Ed25519Scalars](S2), |
|||
Y: G, |
|||
} |
|||
err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) |
|||
assert.NoError(err) |
|||
} |
|||
} |
|||
|
|||
var testCurve = ecc.BN254 |
|||
|
|||
// type NegTest[T, S emulated.FieldParams] struct {
|
|||
// P, Q AffinePoint[T]
|
|||
// }
|
|||
|
|||
// func (c *NegTest[T, S]) Define(api frontend.API) error {
|
|||
// cr, err := New[T, S](api)
|
|||
// if err != nil {
|
|||
// return err
|
|||
// }
|
|||
// res := cr.Neg(c.P)
|
|||
// cr.AssertIsEqual(res, c.Q)
|
|||
// return nil
|
|||
// }
|
|||
|
|||
// func TestNeg(t *testing.T) {
|
|||
// assert := test.NewAssert(t)
|
|||
// secpCurve := secp256k1.S256()
|
|||
// yn := new(big.Int).Sub(secpCurve.P, secpCurve.Gy)
|
|||
// circuit := NegTest[emulated.Secp256k1, emulated.Secp256k1Scalars]{}
|
|||
// witness := NegTest[emulated.Secp256k1, emulated.Secp256k1Scalars]{
|
|||
// P: AffinePoint[emulated.Secp256k1]{
|
|||
// X: emulated.NewElement[emulated.Secp256k1](secpCurve.Gx),
|
|||
// Y: emulated.NewElement[emulated.Secp256k1](secpCurve.Gy),
|
|||
// },
|
|||
// Q: AffinePoint[emulated.Secp256k1]{
|
|||
// X: emulated.NewElement[emulated.Secp256k1](secpCurve.Gx),
|
|||
// Y: emulated.NewElement[emulated.Secp256k1](yn),
|
|||
// },
|
|||
// }
|
|||
// err := test.IsSolved(&circuit, &witness, testCurve.ScalarField())
|
|||
// assert.NoError(err)
|
|||
// }
|
|||
|
|||
// type AddTest[T, S emulated.FieldParams] struct {
|
|||
// P, Q, R AffinePoint[T]
|
|||
// }
|
|||
|
|||
// func (c *AddTest[T, S]) Define(api frontend.API) error {
|
|||
// cr, err := New[T, S](api)
|
|||
// if err != nil {
|
|||
// return err
|
|||
// }
|
|||
// res := cr.Add(c.P, c.Q)
|
|||
// cr.AssertIsEqual(res, c.R)
|
|||
// return nil
|
|||
// }
|
|||
|
|||
// func TestAdd(t *testing.T) {
|
|||
// assert := test.NewAssert(t)
|
|||
// secpCurve := secp256k1.S256()
|
|||
// xd, yd := secpCurve.Double(secpCurve.Gx, secpCurve.Gy)
|
|||
// xa, ya := secpCurve.Add(xd, yd, secpCurve.Gx, secpCurve.Gy)
|
|||
// circuit := AddTest[emulated.Secp256k1, emulated.Secp256k1Scalars]{}
|
|||
// witness := AddTest[emulated.Secp256k1, emulated.Secp256k1Scalars]{
|
|||
// P: AffinePoint[emulated.Secp256k1]{
|
|||
// X: emulated.NewElement[emulated.Secp256k1](secpCurve.Gx),
|
|||
// Y: emulated.NewElement[emulated.Secp256k1](secpCurve.Gy),
|
|||
// },
|
|||
// Q: AffinePoint[emulated.Secp256k1]{
|
|||
// X: emulated.NewElement[emulated.Secp256k1](xd),
|
|||
// Y: emulated.NewElement[emulated.Secp256k1](yd),
|
|||
// },
|
|||
// R: AffinePoint[emulated.Secp256k1]{
|
|||
// X: emulated.NewElement[emulated.Secp256k1](xa),
|
|||
// Y: emulated.NewElement[emulated.Secp256k1](ya),
|
|||
// },
|
|||
// }
|
|||
// err := test.IsSolved(&circuit, &witness, testCurve.ScalarField())
|
|||
// assert.NoError(err)
|
|||
// }
|
|||
|
|||
// type DoubleTest[T, S emulated.FieldParams] struct {
|
|||
// P, Q AffinePoint[T]
|
|||
// }
|
|||
|
|||
// func (c *DoubleTest[T, S]) Define(api frontend.API) error {
|
|||
// cr, err := New[T, S](api)
|
|||
// if err != nil {
|
|||
// return err
|
|||
// }
|
|||
// res := cr.Double(c.P)
|
|||
// cr.AssertIsEqual(res, c.Q)
|
|||
// return nil
|
|||
// }
|
|||
|
|||
// func TestDouble(t *testing.T) {
|
|||
// assert := test.NewAssert(t)
|
|||
// secpCurve := secp256k1.S256()
|
|||
// xd, yd := secpCurve.Double(secpCurve.Gx, secpCurve.Gy)
|
|||
// circuit := DoubleTest[emulated.Secp256k1, emulated.Secp256k1Scalars]{}
|
|||
// witness := DoubleTest[emulated.Secp256k1, emulated.Secp256k1Scalars]{
|
|||
// P: AffinePoint[emulated.Secp256k1]{
|
|||
// X: emulated.NewElement[emulated.Secp256k1](secpCurve.Gx),
|
|||
// Y: emulated.NewElement[emulated.Secp256k1](secpCurve.Gy),
|
|||
// },
|
|||
// Q: AffinePoint[emulated.Secp256k1]{
|
|||
// X: emulated.NewElement[emulated.Secp256k1](xd),
|
|||
// Y: emulated.NewElement[emulated.Secp256k1](yd),
|
|||
// },
|
|||
// }
|
|||
// err := test.IsSolved(&circuit, &witness, testCurve.ScalarField())
|
|||
// assert.NoError(err)
|
|||
// }
|
|||
|
|||
// type ScalarMulTest[T, S emulated.FieldParams] struct {
|
|||
// P, Q AffinePoint[T]
|
|||
// S emulated.Element[S]
|
|||
// }
|
|||
|
|||
// func (c *ScalarMulTest[T, S]) Define(api frontend.API) error {
|
|||
// cr, err := New[T, S](api)
|
|||
// if err != nil {
|
|||
// return err
|
|||
// }
|
|||
// res := cr.ScalarMul(c.P, c.S)
|
|||
// cr.AssertIsEqual(res, c.Q)
|
|||
// return nil
|
|||
// }
|
|||
|
|||
// func TestScalarMul(t *testing.T) {
|
|||
// assert := test.NewAssert(t)
|
|||
// secpCurve := secp256k1.S256()
|
|||
// s, ok := new(big.Int).SetString("44693544921776318736021182399461740191514036429448770306966433218654680512345", 10)
|
|||
// assert.True(ok)
|
|||
// sx, sy := secpCurve.ScalarMult(secpCurve.Gx, secpCurve.Gy, s.Bytes())
|
|||
|
|||
// circuit := ScalarMulTest[emulated.Secp256k1, emulated.Secp256k1Scalars]{}
|
|||
// witness := ScalarMulTest[emulated.Secp256k1, emulated.Secp256k1Scalars]{
|
|||
// S: emulated.NewElement[emulated.Secp256k1Scalars](s),
|
|||
// P: AffinePoint[emulated.Secp256k1]{
|
|||
// X: emulated.NewElement[emulated.Secp256k1](secpCurve.Gx),
|
|||
// Y: emulated.NewElement[emulated.Secp256k1](secpCurve.Gy),
|
|||
// },
|
|||
// Q: AffinePoint[emulated.Secp256k1]{
|
|||
// X: emulated.NewElement[emulated.Secp256k1](sx),
|
|||
// Y: emulated.NewElement[emulated.Secp256k1](sy),
|
|||
// },
|
|||
// }
|
|||
// err := test.IsSolved(&circuit, &witness, testCurve.ScalarField())
|
|||
// assert.NoError(err)
|
|||
// // _, err = frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit)
|
|||
// // assert.NoError(err)
|
|||
// }
|
|||
@ -1,94 +0,0 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
. "gnark-ed25519/field" |
|||
. "gnark-ed25519/plonky2_verifier" |
|||
"gnark-ed25519/poseidon" |
|||
"os" |
|||
"time" |
|||
|
|||
"github.com/consensys/gnark-crypto/ecc" |
|||
"github.com/consensys/gnark/backend/groth16" |
|||
"github.com/consensys/gnark/frontend" |
|||
"github.com/consensys/gnark/frontend/cs/r1cs" |
|||
) |
|||
|
|||
type BenchmarkPlonky2VerifierCircuit struct { |
|||
proofWithPis ProofWithPublicInputs |
|||
|
|||
verifierChip *VerifierChip |
|||
} |
|||
|
|||
func (circuit *BenchmarkPlonky2VerifierCircuit) Define(api frontend.API) error { |
|||
proofWithPis := DeserializeProofWithPublicInputs("./plonky2_verifier/data/fibonacci/proof_with_public_inputs.json") |
|||
commonCircuitData := DeserializeCommonCircuitData("./plonky2_verifier/data/fibonacci/common_circuit_data.json") |
|||
verifierOnlyCircuitData := DeserializeVerifierOnlyCircuitData("./plonky2_verifier/data/fibonacci/verifier_only_circuit_data.json") |
|||
|
|||
fieldAPI := NewFieldAPI(api) |
|||
qeAPI := NewQuadraticExtensionAPI(fieldAPI, commonCircuitData.DegreeBits) |
|||
hashAPI := NewHashAPI(fieldAPI) |
|||
poseidonChip := poseidon.NewPoseidonChip(api, fieldAPI) |
|||
friChip := NewFriChip(api, fieldAPI, qeAPI, hashAPI, poseidonChip, &commonCircuitData.FriParams) |
|||
plonkChip := NewPlonkChip(api, qeAPI, commonCircuitData) |
|||
circuit.verifierChip = NewVerifierChip(api, fieldAPI, qeAPI, poseidonChip, plonkChip, friChip) |
|||
|
|||
circuit.verifierChip.Verify(proofWithPis, verifierOnlyCircuitData, commonCircuitData) |
|||
|
|||
return nil |
|||
} |
|||
|
|||
func compileCircuit() frontend.CompiledConstraintSystem { |
|||
circuit := BenchmarkPlonky2VerifierCircuit{} |
|||
proofWithPis := DeserializeProofWithPublicInputs("./plonky2_verifier/data/fibonacci/proof_with_public_inputs.json") |
|||
circuit.proofWithPis = proofWithPis |
|||
|
|||
r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) |
|||
if err != nil { |
|||
fmt.Println("error in building circuit", err) |
|||
os.Exit(1) |
|||
} |
|||
|
|||
return r1cs |
|||
} |
|||
|
|||
func createProof(r1cs frontend.CompiledConstraintSystem) groth16.Proof { |
|||
proofWithPis := DeserializeProofWithPublicInputs("./plonky2_verifier/data/fibonacci/proof_with_public_inputs.json") |
|||
|
|||
// Witness
|
|||
assignment := &BenchmarkPlonky2VerifierCircuit{ |
|||
proofWithPis: proofWithPis, |
|||
} |
|||
|
|||
fmt.Println("Generating witness", time.Now()) |
|||
witness, _ := frontend.NewWitness(assignment, ecc.BN254.ScalarField()) |
|||
publicWitness, _ := witness.Public() |
|||
|
|||
fmt.Println("Running circuit setup", time.Now()) |
|||
pk, vk, err := groth16.Setup(r1cs) |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
os.Exit(1) |
|||
} |
|||
|
|||
fmt.Println("Creating proof", time.Now()) |
|||
proof, err := groth16.Prove(r1cs, pk, witness) |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
os.Exit(1) |
|||
} |
|||
fmt.Println("Verifying proof", time.Now()) |
|||
err = groth16.Verify(proof, vk, publicWitness) |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
os.Exit(1) |
|||
} |
|||
|
|||
return proof |
|||
} |
|||
|
|||
func main() { |
|||
r1cs := compileCircuit() |
|||
proof := createProof(r1cs) |
|||
fmt.Println(proof.CurveID(), time.Now()) |
|||
} |
|||
@ -1,407 +0,0 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
. "gnark-ed25519/field" |
|||
. "gnark-ed25519/plonky2_verifier" |
|||
"gnark-ed25519/poseidon" |
|||
"os" |
|||
"time" |
|||
|
|||
"github.com/consensys/gnark-crypto/ecc" |
|||
"github.com/consensys/gnark/backend/groth16" |
|||
"github.com/consensys/gnark/frontend" |
|||
"github.com/consensys/gnark/frontend/cs/r1cs" |
|||
) |
|||
|
|||
type BenchmarkLargeDummyFriCircuit struct { |
|||
zeta QuadraticExtension |
|||
openings FriOpenings |
|||
friChallenges FriChallenges |
|||
initialMerkleCaps []MerkleCap |
|||
friProof FriProof |
|||
} |
|||
|
|||
func (circuit *BenchmarkLargeDummyFriCircuit) Define(api frontend.API) error { |
|||
commonCircuitData := DeserializeCommonCircuitData("./plonky2_verifier/data/dummy_2^14_gates/common_circuit_data.json") |
|||
|
|||
field := NewFieldAPI(api) |
|||
qeAPI := NewQuadraticExtensionAPI(field, commonCircuitData.DegreeBits) |
|||
poseidonChip := poseidon.NewPoseidonChip(api, field) |
|||
friChip := NewFriChip(api, field, qeAPI, poseidonChip, &commonCircuitData.FriParams) |
|||
|
|||
friChip.VerifyFriProof( |
|||
commonCircuitData.GetFriInstance(qeAPI, circuit.zeta, commonCircuitData.DegreeBits), |
|||
circuit.openings, |
|||
&circuit.friChallenges, |
|||
circuit.initialMerkleCaps, |
|||
&circuit.friProof, |
|||
) |
|||
|
|||
return nil |
|||
} |
|||
|
|||
func compileCircuit() frontend.CompiledConstraintSystem { |
|||
fmt.Println("compiling circuit", time.Now()) |
|||
circuit := BenchmarkLargeDummyFriCircuit{} |
|||
|
|||
/* |
|||
commonCircuitData := DeserializeCommonCircuitData("./plonky2_verifier/data/dummy_2^14_gates/common_circuit_data.json") |
|||
|
|||
circuit.zeta[0] = emulated.NewElement[EmulatedField](nil) |
|||
circuit.zeta[1] = emulated.NewElement[EmulatedField](nil) |
|||
|
|||
fmt.Println("circuit zeta allocated") |
|||
|
|||
// Batch 0 has the following openings
|
|||
// Constants (config.num_constants + 1)
|
|||
// Sigmas (config.num_routed_wires)
|
|||
// Wires (config.num_wires)
|
|||
// Plonk_Z (config.num_challenges)
|
|||
// Partial Products (config.num_challenges * config.num_partial_products)
|
|||
// Quotient Polynomails (config.num_challenges * config.quotient_degree_factor)
|
|||
|
|||
// Batch 1 has the following openings
|
|||
// Plonk_Z_next (config.num_challenges)
|
|||
|
|||
circuit.openings.Batches = make([]FriOpeningBatch, 2) |
|||
|
|||
batch1Size := commonCircuitData.NumConstants + 1 + |
|||
commonCircuitData.Config.NumRoutedWires + |
|||
commonCircuitData.Config.NumWires + |
|||
commonCircuitData.Config.NumChallenges + |
|||
(commonCircuitData.Config.NumChallenges * commonCircuitData.NumPartialProducts) + |
|||
(commonCircuitData.Config.NumChallenges * commonCircuitData.QuotientDegreeFactor) |
|||
|
|||
circuit.openings.Batches[0].Values = make([]QuadraticExtension, 0) |
|||
for i := uint64(0); i < batch1Size; i++ { |
|||
circuit.openings.Batches[0].Values = append(circuit.openings.Batches[0].Values, NewEmptyQuadraticExtension()) |
|||
} |
|||
|
|||
batch2Size := commonCircuitData.Config.NumChallenges |
|||
circuit.openings.Batches[1].Values = make([]QuadraticExtension, 0) |
|||
for i := uint64(0); i < batch2Size; i++ { |
|||
circuit.openings.Batches[1].Values = append(circuit.openings.Batches[1].Values, NewEmptyQuadraticExtension()) |
|||
} |
|||
|
|||
fmt.Println("circuit openings allocated") |
|||
|
|||
circuit.friChallenges.FriAlpha = NewEmptyQuadraticExtension() |
|||
circuit.friChallenges.FriPowResponse = emulated.NewElement[EmulatedField](nil) |
|||
circuit.friChallenges.FriBetas = make([]QuadraticExtension, 0) |
|||
for i := 0; i < len(commonCircuitData.FriParams.ReductionArityBits); i++ { |
|||
circuit.friChallenges.FriBetas = append(circuit.friChallenges.FriBetas, NewEmptyQuadraticExtension()) |
|||
} |
|||
circuit.friChallenges.FriQueryIndicies = make([]F, 0) |
|||
for i := uint64(0); i < commonCircuitData.FriParams.Config.NumQueryRounds; i++ { |
|||
circuit.friChallenges.FriQueryIndicies = append(circuit.friChallenges.FriQueryIndicies, NewEmptyFieldElement()) |
|||
} |
|||
|
|||
fmt.Println("circuit challenges allocated") |
|||
|
|||
// initial merkle caps is the merkle cap for
|
|||
// the constant/sigmas, wires, partial products,
|
|||
// and quotient composite polynomial
|
|||
// The merkle cap size is 2**cap_height hashes
|
|||
numMerkleCaps := 4 |
|||
merkleCapSize := 1 << commonCircuitData.Config.FriConfig.CapHeight |
|||
circuit.initialMerkleCaps = make([]MerkleCap, 0) |
|||
for i := 0; i < numMerkleCaps; i++ { |
|||
merkleCap := make([]Hash, 0) |
|||
for j := 0; j < merkleCapSize; j++ { |
|||
merkleCap = append(merkleCap, NewEmptyHash()) |
|||
} |
|||
circuit.initialMerkleCaps = append(circuit.initialMerkleCaps, merkleCap) |
|||
} |
|||
|
|||
fmt.Println("circuit initialMerkleCaps allocated") |
|||
|
|||
// CommitPhaseMerkleCap is number of reduction_arity_bits
|
|||
// finalPoly has 2^(degreeBits - sum(arity_bits)) coefficients
|
|||
numCommitPhaseMerkleCaps := len(commonCircuitData.FriParams.ReductionArityBits) |
|||
for i := 0; i < numCommitPhaseMerkleCaps; i++ { |
|||
circuit.friProof.CommitPhaseMerkleCaps = make([]MerkleCap, 0) |
|||
merkleCap := make([]Hash, 0) |
|||
for j := 0; j < merkleCapSize; j++ { |
|||
merkleCap = append(merkleCap, NewEmptyHash()) |
|||
} |
|||
circuit.friProof.CommitPhaseMerkleCaps = append(circuit.friProof.CommitPhaseMerkleCaps, merkleCap) |
|||
} |
|||
|
|||
fmt.Println("circuit friproof CommitPhaseMerkleCaps allocated") |
|||
|
|||
friOracleInfo := commonCircuitData.FriOracles() |
|||
circuit.friProof.QueryRoundProofs = make([]FriQueryRound, 0) |
|||
for i := 0; i < int(commonCircuitData.FriParams.Config.NumQueryRounds); i++ { |
|||
|
|||
evalsProof := make([]EvalProof, 0) |
|||
// Allocation for the initial trees proof
|
|||
for j := 0; j < len(friOracleInfo); j++ { |
|||
leafSize := friOracleInfo[0].NumPolys |
|||
merkleProofLen := commonCircuitData.DegreeBits + commonCircuitData.Config.FriConfig.RateBits - commonCircuitData.Config.FriConfig.CapHeight |
|||
|
|||
evalElements := make([]F, 0) |
|||
for k := uint64(0); k < leafSize; k++ { |
|||
evalElements = append(evalElements, NewEmptyFieldElement()) |
|||
} |
|||
|
|||
merkleProofSiblings := make([]Hash, 0) |
|||
for k := uint64(0); k < merkleProofLen; k++ { |
|||
merkleProofSiblings = append(merkleProofSiblings, NewEmptyHash()) |
|||
} |
|||
|
|||
evalsProof = append( |
|||
evalsProof, |
|||
EvalProof{ |
|||
Elements: evalElements, |
|||
MerkleProof: MerkleProof{merkleProofSiblings}, |
|||
}, |
|||
) |
|||
} |
|||
|
|||
// Allocation for the steps
|
|||
steps := make([]FriQueryStep, 0) |
|||
codewordLenBits := commonCircuitData.DegreeBits + commonCircuitData.Config.FriConfig.RateBits |
|||
for j := 0; j < len(commonCircuitData.FriParams.ReductionArityBits); j++ { |
|||
arityBits := commonCircuitData.FriParams.ReductionArityBits[j] |
|||
leafSize := 1 << int(arityBits) |
|||
codewordLenBits -= arityBits |
|||
merkleProofLen := codewordLenBits - commonCircuitData.Config.FriConfig.CapHeight |
|||
|
|||
evalQEs := make([]QuadraticExtension, 0) |
|||
for k := 0; k < leafSize; k++ { |
|||
evalQEs = append(evalQEs, NewEmptyQuadraticExtension()) |
|||
} |
|||
|
|||
merkleProofSiblings := make([]Hash, 0) |
|||
for k := uint64(0); k < merkleProofLen; k++ { |
|||
merkleProofSiblings = append(merkleProofSiblings, NewEmptyHash()) |
|||
} |
|||
|
|||
steps = append( |
|||
steps, |
|||
FriQueryStep{ |
|||
Evals: evalQEs, |
|||
MerkleProof: MerkleProof{merkleProofSiblings}, |
|||
}, |
|||
) |
|||
} |
|||
|
|||
circuit.friProof.QueryRoundProofs = append( |
|||
circuit.friProof.QueryRoundProofs, |
|||
FriQueryRound{ |
|||
InitialTreesProof: FriInitialTreeProof{evalsProof}, |
|||
Steps: steps, |
|||
}, |
|||
) |
|||
|
|||
fmt.Println("circuit friproof QueryRoundProofs allocated for round", i) |
|||
} |
|||
|
|||
// Final poly allocation
|
|||
finalPolyLenBit := commonCircuitData.DegreeBits |
|||
for _, arityBit := range commonCircuitData.FriParams.ReductionArityBits { |
|||
finalPolyLenBit -= arityBit |
|||
} |
|||
|
|||
circuit.friProof.FinalPoly.Coeffs = make([]QuadraticExtension, 0) |
|||
for i := 0; i < (1 << finalPolyLenBit); i++ { |
|||
circuit.friProof.FinalPoly.Coeffs = append(circuit.friProof.FinalPoly.Coeffs, NewEmptyQuadraticExtension()) |
|||
} |
|||
|
|||
fmt.Println("circuit friproof FinalPoly allocated") |
|||
|
|||
// PowWitness allocation
|
|||
circuit.friProof.PowWitness = NewEmptyFieldElement() |
|||
fmt.Println("Partial witness allocation done") |
|||
*/ |
|||
|
|||
proofWithPis := DeserializeProofWithPublicInputs("./plonky2_verifier/data/dummy_2^14_gates/proof_with_public_inputs.json") |
|||
verifierOnlyCircuitData := DeserializeVerifierOnlyCircuitData("./plonky2_verifier/data/dummy_2^14_gates/verifier_only_circuit_data.json") |
|||
|
|||
zeta := QuadraticExtension{ |
|||
NewFieldElementFromString("17377750363769967882"), |
|||
NewFieldElementFromString("11921191651424768462"), |
|||
} |
|||
friChallenges := FriChallenges{ |
|||
FriAlpha: QuadraticExtension{ |
|||
NewFieldElementFromString("16721004555774385479"), |
|||
NewFieldElementFromString("10688151135543754663"), |
|||
}, |
|||
FriBetas: []QuadraticExtension{ |
|||
{ |
|||
NewFieldElementFromString("3312441922957827805"), |
|||
NewFieldElementFromString("15128092514958289671"), |
|||
}, |
|||
{ |
|||
NewFieldElementFromString("13630530769060141802"), |
|||
NewFieldElementFromString("14559883974933163008"), |
|||
}, |
|||
{ |
|||
NewFieldElementFromString("16146508250083930687"), |
|||
NewFieldElementFromString("5176346568444408396"), |
|||
}, |
|||
}, |
|||
FriPowResponse: NewFieldElement(4389), |
|||
FriQueryIndicies: []F{ |
|||
NewFieldElementFromString("16334967868590615051"), |
|||
NewFieldElementFromString("2911473540496037915"), |
|||
NewFieldElementFromString("14887216056886344225"), |
|||
NewFieldElementFromString("7808811227805914295"), |
|||
NewFieldElementFromString("2018594961417375749"), |
|||
NewFieldElementFromString("3733368398777208435"), |
|||
NewFieldElementFromString("2623035669037055104"), |
|||
NewFieldElementFromString("299243030573481514"), |
|||
NewFieldElementFromString("7189789717962704433"), |
|||
NewFieldElementFromString("14566344026886816268"), |
|||
NewFieldElementFromString("12555390069003437453"), |
|||
NewFieldElementFromString("17225508403199418233"), |
|||
NewFieldElementFromString("5088797913879903292"), |
|||
NewFieldElementFromString("9715691392773433023"), |
|||
NewFieldElementFromString("7565836764713256165"), |
|||
NewFieldElementFromString("1500143546029322929"), |
|||
NewFieldElementFromString("1245802417104422080"), |
|||
NewFieldElementFromString("6831959786661245110"), |
|||
NewFieldElementFromString("17271054758535453780"), |
|||
NewFieldElementFromString("6225460404576395409"), |
|||
NewFieldElementFromString("15932661092896277351"), |
|||
NewFieldElementFromString("12452534049198240575"), |
|||
NewFieldElementFromString("4225199666055520177"), |
|||
NewFieldElementFromString("13235091290587791090"), |
|||
NewFieldElementFromString("2562357622728700774"), |
|||
NewFieldElementFromString("17676678042980201498"), |
|||
NewFieldElementFromString("5837067135702409874"), |
|||
NewFieldElementFromString("11238419549114325157"), |
|||
}, |
|||
} |
|||
|
|||
initialMerkleCaps := []MerkleCap{ |
|||
verifierOnlyCircuitData.ConstantSigmasCap, |
|||
proofWithPis.Proof.WiresCap, |
|||
proofWithPis.Proof.PlonkZsPartialProductsCap, |
|||
proofWithPis.Proof.QuotientPolysCap, |
|||
} |
|||
|
|||
circuit.zeta = zeta |
|||
circuit.openings = proofWithPis.Proof.Openings.ToFriOpenings() |
|||
circuit.friChallenges = friChallenges |
|||
circuit.initialMerkleCaps = initialMerkleCaps |
|||
circuit.friProof = proofWithPis.Proof.OpeningProof |
|||
|
|||
r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) |
|||
if err != nil { |
|||
fmt.Println("error in building circuit", err) |
|||
os.Exit(1) |
|||
} |
|||
|
|||
return r1cs |
|||
} |
|||
|
|||
func createProof(r1cs frontend.CompiledConstraintSystem) groth16.Proof { |
|||
proofWithPis := DeserializeProofWithPublicInputs("./plonky2_verifier/data/dummy_2^14_gates/proof_with_public_inputs.json") |
|||
verifierOnlyCircuitData := DeserializeVerifierOnlyCircuitData("./plonky2_verifier/data/dummy_2^14_gates/verifier_only_circuit_data.json") |
|||
|
|||
zeta := QuadraticExtension{ |
|||
NewFieldElementFromString("17377750363769967882"), |
|||
NewFieldElementFromString("11921191651424768462"), |
|||
} |
|||
friChallenges := FriChallenges{ |
|||
FriAlpha: QuadraticExtension{ |
|||
NewFieldElementFromString("16721004555774385479"), |
|||
NewFieldElementFromString("10688151135543754663"), |
|||
}, |
|||
FriBetas: []QuadraticExtension{ |
|||
{ |
|||
NewFieldElementFromString("3312441922957827805"), |
|||
NewFieldElementFromString("15128092514958289671"), |
|||
}, |
|||
{ |
|||
NewFieldElementFromString("13630530769060141802"), |
|||
NewFieldElementFromString("14559883974933163008"), |
|||
}, |
|||
{ |
|||
NewFieldElementFromString("16146508250083930687"), |
|||
NewFieldElementFromString("5176346568444408396"), |
|||
}, |
|||
}, |
|||
FriPowResponse: NewFieldElement(4389), |
|||
FriQueryIndicies: []F{ |
|||
NewFieldElementFromString("16334967868590615051"), |
|||
NewFieldElementFromString("2911473540496037915"), |
|||
NewFieldElementFromString("14887216056886344225"), |
|||
NewFieldElementFromString("7808811227805914295"), |
|||
NewFieldElementFromString("2018594961417375749"), |
|||
NewFieldElementFromString("3733368398777208435"), |
|||
NewFieldElementFromString("2623035669037055104"), |
|||
NewFieldElementFromString("299243030573481514"), |
|||
NewFieldElementFromString("7189789717962704433"), |
|||
NewFieldElementFromString("14566344026886816268"), |
|||
NewFieldElementFromString("12555390069003437453"), |
|||
NewFieldElementFromString("17225508403199418233"), |
|||
NewFieldElementFromString("5088797913879903292"), |
|||
NewFieldElementFromString("9715691392773433023"), |
|||
NewFieldElementFromString("7565836764713256165"), |
|||
NewFieldElementFromString("1500143546029322929"), |
|||
NewFieldElementFromString("1245802417104422080"), |
|||
NewFieldElementFromString("6831959786661245110"), |
|||
NewFieldElementFromString("17271054758535453780"), |
|||
NewFieldElementFromString("6225460404576395409"), |
|||
NewFieldElementFromString("15932661092896277351"), |
|||
NewFieldElementFromString("12452534049198240575"), |
|||
NewFieldElementFromString("4225199666055520177"), |
|||
NewFieldElementFromString("13235091290587791090"), |
|||
NewFieldElementFromString("2562357622728700774"), |
|||
NewFieldElementFromString("17676678042980201498"), |
|||
NewFieldElementFromString("5837067135702409874"), |
|||
NewFieldElementFromString("11238419549114325157"), |
|||
}, |
|||
} |
|||
|
|||
initialMerkleCaps := []MerkleCap{ |
|||
verifierOnlyCircuitData.ConstantSigmasCap, |
|||
proofWithPis.Proof.WiresCap, |
|||
proofWithPis.Proof.PlonkZsPartialProductsCap, |
|||
proofWithPis.Proof.QuotientPolysCap, |
|||
} |
|||
|
|||
// Witness
|
|||
assignment := &BenchmarkLargeDummyFriCircuit{ |
|||
zeta: zeta, |
|||
openings: proofWithPis.Proof.Openings.ToFriOpenings(), |
|||
friChallenges: friChallenges, |
|||
initialMerkleCaps: initialMerkleCaps, |
|||
friProof: proofWithPis.Proof.OpeningProof, |
|||
} |
|||
|
|||
fmt.Println("Generating witness", time.Now()) |
|||
witness, _ := frontend.NewWitness(assignment, ecc.BN254.ScalarField()) |
|||
publicWitness, _ := witness.Public() |
|||
pk, vk, err := groth16.Setup(r1cs) |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
os.Exit(1) |
|||
} |
|||
|
|||
fmt.Println("Creating proof", time.Now()) |
|||
proof, err := groth16.Prove(r1cs, pk, witness) |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
os.Exit(1) |
|||
} |
|||
fmt.Println("Verifying proof", time.Now()) |
|||
err = groth16.Verify(proof, vk, publicWitness) |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
os.Exit(1) |
|||
} |
|||
|
|||
return proof |
|||
} |
|||
|
|||
func main() { |
|||
r1cs := compileCircuit() |
|||
fi, _ := os.Open("dummy_fri.r1cs") |
|||
r1cs.WriteTo(fi) |
|||
proof := createProof(r1cs) |
|||
fmt.Println(proof.CurveID(), time.Now()) |
|||
} |
|||
@ -1,132 +0,0 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
. "gnark-ed25519/field" |
|||
. "gnark-ed25519/plonky2_verifier" |
|||
"os" |
|||
"time" |
|||
|
|||
"github.com/consensys/gnark-crypto/ecc" |
|||
"github.com/consensys/gnark/backend/groth16" |
|||
"github.com/consensys/gnark/frontend" |
|||
"github.com/consensys/gnark/frontend/cs/r1cs" |
|||
) |
|||
|
|||
type BenchmarkPlonkCircuit struct { |
|||
proofChallenges ProofChallenges |
|||
openings OpeningSet |
|||
} |
|||
|
|||
func (circuit *BenchmarkPlonkCircuit) Define(api frontend.API) error { |
|||
commonCircuitData := DeserializeCommonCircuitData("./plonky2_verifier/data/dummy_2^14_gates/common_circuit_data.json") |
|||
|
|||
field := NewFieldAPI(api) |
|||
qeAPI := NewQuadraticExtensionAPI(field, commonCircuitData.DegreeBits) |
|||
|
|||
plonkChip := NewPlonkChip(api, qeAPI, commonCircuitData) |
|||
|
|||
plonkChip.Verify(circuit.proofChallenges, circuit.openings) |
|||
|
|||
return nil |
|||
} |
|||
|
|||
func compileCircuit() frontend.CompiledConstraintSystem { |
|||
fmt.Println("compiling circuit", time.Now()) |
|||
circuit := BenchmarkPlonkCircuit{} |
|||
|
|||
proofWithPis := DeserializeProofWithPublicInputs("./plonky2_verifier/data/dummy_2^14_gates/proof_with_public_inputs.json") |
|||
|
|||
// Challenge associated with the data from "/.data/dummy_2^14_gates/*"
|
|||
proofChallenges := ProofChallenges{ |
|||
PlonkBetas: []F{ |
|||
NewFieldElementFromString("4678728155650926271"), |
|||
NewFieldElementFromString("13611962404289024887"), |
|||
}, |
|||
PlonkGammas: []F{ |
|||
NewFieldElementFromString("13237663823305715949"), |
|||
NewFieldElementFromString("15389314098328235145"), |
|||
}, |
|||
PlonkAlphas: []F{ |
|||
NewFieldElementFromString("14505919539124304197"), |
|||
NewFieldElementFromString("1695455639263736117"), |
|||
}, |
|||
PlonkZeta: QuadraticExtension{ |
|||
NewFieldElementFromString("14887793628029982930"), |
|||
NewFieldElementFromString("1136137158284059037"), |
|||
}, |
|||
} |
|||
|
|||
circuit.proofChallenges = proofChallenges |
|||
circuit.openings = proofWithPis.Proof.Openings |
|||
|
|||
r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) |
|||
if err != nil { |
|||
fmt.Println("error in building circuit", err) |
|||
os.Exit(1) |
|||
} |
|||
|
|||
return r1cs |
|||
} |
|||
|
|||
func createProof(r1cs frontend.CompiledConstraintSystem) groth16.Proof { |
|||
proofWithPis := DeserializeProofWithPublicInputs("./plonky2_verifier/data/dummy_2^14_gates/proof_with_public_inputs.json") |
|||
|
|||
// Challenge associated with the data from "/.data/dummy_2^14_gates/*"
|
|||
proofChallenges := ProofChallenges{ |
|||
PlonkBetas: []F{ |
|||
NewFieldElementFromString("4678728155650926271"), |
|||
NewFieldElementFromString("13611962404289024887"), |
|||
}, |
|||
PlonkGammas: []F{ |
|||
NewFieldElementFromString("13237663823305715949"), |
|||
NewFieldElementFromString("15389314098328235145"), |
|||
}, |
|||
PlonkAlphas: []F{ |
|||
NewFieldElementFromString("14505919539124304197"), |
|||
NewFieldElementFromString("1695455639263736117"), |
|||
}, |
|||
PlonkZeta: QuadraticExtension{ |
|||
NewFieldElementFromString("14887793628029982930"), |
|||
NewFieldElementFromString("1136137158284059037"), |
|||
}, |
|||
} |
|||
|
|||
// Witness
|
|||
assignment := &BenchmarkPlonkCircuit{ |
|||
proofChallenges: proofChallenges, |
|||
openings: proofWithPis.Proof.Openings, |
|||
} |
|||
|
|||
fmt.Println("Generating witness", time.Now()) |
|||
witness, _ := frontend.NewWitness(assignment, ecc.BN254.ScalarField()) |
|||
publicWitness, _ := witness.Public() |
|||
pk, vk, err := groth16.Setup(r1cs) |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
os.Exit(1) |
|||
} |
|||
|
|||
fmt.Println("Creating proof", time.Now()) |
|||
proof, err := groth16.Prove(r1cs, pk, witness) |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
os.Exit(1) |
|||
} |
|||
fmt.Println("Verifying proof", time.Now()) |
|||
err = groth16.Verify(proof, vk, publicWitness) |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
os.Exit(1) |
|||
} |
|||
|
|||
return proof |
|||
} |
|||
|
|||
func main() { |
|||
r1cs := compileCircuit() |
|||
fi, _ := os.Open("dummy_fri.r1cs") |
|||
r1cs.WriteTo(fi) |
|||
proof := createProof(r1cs) |
|||
fmt.Println(proof.CurveID(), time.Now()) |
|||
} |
|||
@ -1,94 +0,0 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
. "gnark-ed25519/field" |
|||
. "gnark-ed25519/plonky2_verifier" |
|||
"gnark-ed25519/poseidon" |
|||
"os" |
|||
"time" |
|||
|
|||
"github.com/consensys/gnark-crypto/ecc" |
|||
"github.com/consensys/gnark/backend/groth16" |
|||
"github.com/consensys/gnark/frontend" |
|||
"github.com/consensys/gnark/frontend/cs/r1cs" |
|||
) |
|||
|
|||
type BenchmarkPlonky2VerifierCircuit struct { |
|||
proofWithPis ProofWithPublicInputs |
|||
|
|||
verifierChip *VerifierChip |
|||
} |
|||
|
|||
func (circuit *BenchmarkPlonky2VerifierCircuit) Define(api frontend.API) error { |
|||
proofWithPis := DeserializeProofWithPublicInputs("./plonky2_verifier/data/dummy_2^14_gates/proof_with_public_inputs.json") |
|||
commonCircuitData := DeserializeCommonCircuitData("./plonky2_verifier/data/dummy_2^14_gates/common_circuit_data.json") |
|||
verifierOnlyCircuitData := DeserializeVerifierOnlyCircuitData("./plonky2_verifier/data/dummy_2^14_gates/verifier_only_circuit_data.json") |
|||
|
|||
fieldAPI := NewFieldAPI(api) |
|||
qeAPI := NewQuadraticExtensionAPI(fieldAPI, commonCircuitData.DegreeBits) |
|||
hashAPI := NewHashAPI(fieldAPI) |
|||
poseidonChip := poseidon.NewPoseidonChip(api, fieldAPI) |
|||
friChip := NewFriChip(api, fieldAPI, qeAPI, hashAPI, poseidonChip, &commonCircuitData.FriParams) |
|||
plonkChip := NewPlonkChip(api, qeAPI, commonCircuitData) |
|||
circuit.verifierChip = NewVerifierChip(api, fieldAPI, qeAPI, poseidonChip, plonkChip, friChip) |
|||
|
|||
circuit.verifierChip.Verify(proofWithPis, verifierOnlyCircuitData, commonCircuitData) |
|||
|
|||
return nil |
|||
} |
|||
|
|||
func compileCircuit() frontend.CompiledConstraintSystem { |
|||
circuit := BenchmarkPlonky2VerifierCircuit{} |
|||
proofWithPis := DeserializeProofWithPublicInputs("./plonky2_verifier/data/dummy_2^14_gates/proof_with_public_inputs.json") |
|||
circuit.proofWithPis = proofWithPis |
|||
|
|||
r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) |
|||
if err != nil { |
|||
fmt.Println("error in building circuit", err) |
|||
os.Exit(1) |
|||
} |
|||
|
|||
return r1cs |
|||
} |
|||
|
|||
func createProof(r1cs frontend.CompiledConstraintSystem) groth16.Proof { |
|||
proofWithPis := DeserializeProofWithPublicInputs("./plonky2_verifier/data/dummy_2^14_gates/proof_with_public_inputs.json") |
|||
|
|||
// Witness
|
|||
assignment := &BenchmarkPlonky2VerifierCircuit{ |
|||
proofWithPis: proofWithPis, |
|||
} |
|||
|
|||
fmt.Println("Generating witness", time.Now()) |
|||
witness, _ := frontend.NewWitness(assignment, ecc.BN254.ScalarField()) |
|||
publicWitness, _ := witness.Public() |
|||
|
|||
fmt.Println("Running circuit setup", time.Now()) |
|||
pk, vk, err := groth16.Setup(r1cs) |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
os.Exit(1) |
|||
} |
|||
|
|||
fmt.Println("Creating proof", time.Now()) |
|||
proof, err := groth16.Prove(r1cs, pk, witness) |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
os.Exit(1) |
|||
} |
|||
fmt.Println("Verifying proof", time.Now()) |
|||
err = groth16.Verify(proof, vk, publicWitness) |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
os.Exit(1) |
|||
} |
|||
|
|||
return proof |
|||
} |
|||
|
|||
func main() { |
|||
r1cs := compileCircuit() |
|||
proof := createProof(r1cs) |
|||
fmt.Println(proof.CurveID(), time.Now()) |
|||
} |
|||
@ -1,293 +0,0 @@ |
|||
package sha512 |
|||
|
|||
/* Based on https://gist.github.com/illia-v/7883be942da5d416521375004cecb68f */ |
|||
|
|||
import ( |
|||
"github.com/consensys/gnark/frontend" |
|||
) |
|||
|
|||
func Sha512(api frontend.API, in []frontend.Variable) [512]frontend.Variable { |
|||
_not := func(x [64]frontend.Variable) [64]frontend.Variable { |
|||
return not(api, x) |
|||
} |
|||
_and := func(xs ...[64]frontend.Variable) [64]frontend.Variable { |
|||
return and(api, xs...) |
|||
} |
|||
_add := func(xs ...[64]frontend.Variable) [64]frontend.Variable { |
|||
return add(api, xs...) |
|||
} |
|||
_xor := func(xs ...[64]frontend.Variable) [64]frontend.Variable { |
|||
return xor(api, xs...) |
|||
} |
|||
zip_add := func(a, b Array8_64) Array8_64 { |
|||
a0, a1, a2, a3, a4, a5, a6, a7 := unpack8(a) |
|||
b0, b1, b2, b3, b4, b5, b6, b7 := unpack8(b) |
|||
return Array8_64{ |
|||
_add(a0, b0), |
|||
_add(a1, b1), |
|||
_add(a2, b2), |
|||
_add(a3, b3), |
|||
_add(a4, b4), |
|||
_add(a5, b5), |
|||
_add(a6, b6), |
|||
_add(a7, b7), |
|||
} |
|||
} |
|||
initial_hash := []uint64{ |
|||
0x6a09e667f3bcc908, |
|||
0xbb67ae8584caa73b, |
|||
0x3c6ef372fe94f82b, |
|||
0xa54ff53a5f1d36f1, |
|||
0x510e527fade682d1, |
|||
0x9b05688c2b3e6c1f, |
|||
0x1f83d9abfb41bd6b, |
|||
0x5be0cd19137e2179, |
|||
} |
|||
round_constants := []uint64{ |
|||
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, |
|||
0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, |
|||
0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, |
|||
0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, |
|||
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, |
|||
0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, |
|||
0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, |
|||
0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, |
|||
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, |
|||
0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, |
|||
0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, |
|||
0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, |
|||
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, |
|||
0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, |
|||
0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, |
|||
0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, |
|||
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, |
|||
0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, |
|||
0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, |
|||
0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, |
|||
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, |
|||
0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, |
|||
0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, |
|||
0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, |
|||
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, |
|||
0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, |
|||
0x5fcb6fab3ad6faec, 0x6c44198c4a475817, |
|||
} |
|||
for _, v := range in { |
|||
api.AssertIsBoolean(v) |
|||
} |
|||
mdi := divChecked(len(in), 8) % 128 |
|||
var padding_len int |
|||
if mdi < 112 { |
|||
padding_len = 119 - mdi |
|||
} else { |
|||
padding_len = 247 - mdi |
|||
} |
|||
message_length_bits := uint64ToBits(uint64(len(in))) |
|||
in = append(in, 1) |
|||
for i := 0; i < 7; i++ { |
|||
in = append(in, 0) |
|||
} |
|||
for i := 0; i < padding_len*8; i++ { |
|||
in = append(in, 0) |
|||
} |
|||
for i := 0; i < 64; i++ { |
|||
in = append(in, message_length_bits[i]) |
|||
} |
|||
|
|||
sha512_hash := Array8_64{ |
|||
uint64ToBits(initial_hash[0]), |
|||
uint64ToBits(initial_hash[1]), |
|||
uint64ToBits(initial_hash[2]), |
|||
uint64ToBits(initial_hash[3]), |
|||
uint64ToBits(initial_hash[4]), |
|||
uint64ToBits(initial_hash[5]), |
|||
uint64ToBits(initial_hash[6]), |
|||
uint64ToBits(initial_hash[7]), |
|||
} |
|||
for chunk_start := 0; chunk_start < divChecked(len(in), 8); chunk_start += 128 { |
|||
chunk := in[chunk_start*8 : (chunk_start+128)*8] |
|||
if len(chunk) != 1024 { |
|||
panic("bad length") |
|||
} |
|||
u := make([]frontend.Variable, 80*64) |
|||
for i, _ := range u { |
|||
u[i] = 0 |
|||
} |
|||
copy(u, chunk) |
|||
|
|||
w := reshape(u) |
|||
|
|||
for i := 16; i < 80; i++ { |
|||
s0 := _xor( |
|||
_right_rotate(w[i-15], 1), |
|||
_right_rotate(w[i-15], 8), |
|||
_shr(w[i-15], 7), |
|||
) |
|||
s1 := _xor( |
|||
_right_rotate(w[i-2], 19), |
|||
_right_rotate(w[i-2], 61), |
|||
_shr(w[i-2], 6), |
|||
) |
|||
w[i] = _add(w[i-16], s0, w[i-7], s1) |
|||
} |
|||
a, b, c, d, e, f, g, h := unpack8(sha512_hash) |
|||
for i := 0; i < 80; i++ { |
|||
sum1 := _xor( |
|||
_right_rotate(e, 14), |
|||
_right_rotate(e, 18), |
|||
_right_rotate(e, 41), |
|||
) |
|||
ch := _xor(_and(e, f), _and(_not(e), g)) |
|||
temp1 := _add(h, sum1, ch, uint64ToBits(round_constants[i]), w[i]) |
|||
sum0 := _xor( |
|||
_right_rotate(a, 28), |
|||
_right_rotate(a, 34), |
|||
_right_rotate(a, 39), |
|||
) |
|||
maj := _xor(_and(a, b), _and(a, c), _and(b, c)) |
|||
temp2 := _add(sum0, maj) |
|||
|
|||
h = g |
|||
g = f |
|||
f = e |
|||
e = _add(d, temp1) |
|||
d = c |
|||
c = b |
|||
b = a |
|||
a = _add(temp1, temp2) |
|||
} |
|||
sha512_hash = zip_add(sha512_hash, Array8_64{a, b, c, d, e, f, g, h}) |
|||
} |
|||
return flatten8(sha512_hash) |
|||
} |
|||
|
|||
func _right_rotate(n [64]frontend.Variable, bits int) [64]frontend.Variable { |
|||
var result [64]frontend.Variable |
|||
for i := 0; i < len(n); i++ { |
|||
result[(i+bits)%len(n)] = n[i] |
|||
} |
|||
return result |
|||
} |
|||
|
|||
func reshape(u []frontend.Variable) [][64]frontend.Variable { |
|||
l := divChecked(len(u), 64) |
|||
result := make([][64]frontend.Variable, l) |
|||
for i := 0; i < l; i++ { |
|||
var arr [64]frontend.Variable |
|||
for k := 0; k < 64; k++ { |
|||
arr[k] = u[i*64+k] |
|||
} |
|||
result[i] = arr |
|||
} |
|||
return result |
|||
} |
|||
|
|||
type Array8_64 [8][64]frontend.Variable |
|||
|
|||
func unpack8(x Array8_64) ([64]frontend.Variable, [64]frontend.Variable, [64]frontend.Variable, [64]frontend.Variable, [64]frontend.Variable, [64]frontend.Variable, [64]frontend.Variable, [64]frontend.Variable) { |
|||
return x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7] |
|||
} |
|||
|
|||
func flatten8(x Array8_64) [512]frontend.Variable { |
|||
var result [512]frontend.Variable |
|||
k := 0 |
|||
for i := 0; i < 8; i++ { |
|||
for j := 0; j < 64; j++ { |
|||
result[k] = x[i][j] |
|||
k++ |
|||
} |
|||
} |
|||
return result |
|||
} |
|||
|
|||
func uint64ToBits(value uint64) [64]frontend.Variable { |
|||
var result [64]frontend.Variable |
|||
for k := 0; k < 64; k++ { |
|||
if (value & (1 << (63 - k))) != 0 { |
|||
result[k] = 1 |
|||
} else { |
|||
result[k] = 0 |
|||
} |
|||
} |
|||
return result |
|||
} |
|||
|
|||
func xor(api frontend.API, args ...[64]frontend.Variable) [64]frontend.Variable { |
|||
if len(args) == 1 { |
|||
return args[0] |
|||
} else { |
|||
return xor2(api, args[0], xor(api, args[1:]...)) |
|||
} |
|||
} |
|||
func add(api frontend.API, args ...[64]frontend.Variable) [64]frontend.Variable { |
|||
if len(args) == 1 { |
|||
return args[0] |
|||
} else { |
|||
return add2(api, args[0], add(api, args[1:]...)) |
|||
} |
|||
} |
|||
func and(api frontend.API, args ...[64]frontend.Variable) [64]frontend.Variable { |
|||
if len(args) == 1 { |
|||
return args[0] |
|||
} else { |
|||
return and2(api, args[0], and(api, args[1:]...)) |
|||
} |
|||
} |
|||
|
|||
func xor2(api frontend.API, a, b [64]frontend.Variable) [64]frontend.Variable { |
|||
var result [64]frontend.Variable |
|||
for i := 0; i < 64; i++ { |
|||
result[i] = api.Xor(a[i], b[i]) |
|||
} |
|||
return result |
|||
} |
|||
|
|||
func and2(api frontend.API, a, b [64]frontend.Variable) [64]frontend.Variable { |
|||
var result [64]frontend.Variable |
|||
for i := 0; i < 64; i++ { |
|||
result[i] = api.And(a[i], b[i]) |
|||
} |
|||
return result |
|||
} |
|||
|
|||
func add2(api frontend.API, a, b [64]frontend.Variable) [64]frontend.Variable { |
|||
var result [64]frontend.Variable |
|||
var carry frontend.Variable = 0 |
|||
for i := 63; i >= 0; i-- { |
|||
sum := api.Add(a[i], b[i], carry) |
|||
sumBin := api.ToBinary(sum, 2) |
|||
if len(sumBin) != 2 { |
|||
panic("bad length") |
|||
} |
|||
result[i] = sumBin[0] |
|||
carry = sumBin[1] |
|||
} |
|||
return result |
|||
} |
|||
|
|||
func _shr(n [64]frontend.Variable, bits int) [64]frontend.Variable { |
|||
var result [64]frontend.Variable |
|||
for i := 0; i < 64; i++ { |
|||
if i < bits { |
|||
result[i] = 0 |
|||
} else { |
|||
result[i] = n[i-bits] |
|||
} |
|||
} |
|||
return result |
|||
} |
|||
|
|||
func not(api frontend.API, n [64]frontend.Variable) [64]frontend.Variable { |
|||
var result [64]frontend.Variable |
|||
for i := 0; i < 64; i++ { |
|||
result[i] = api.Sub(1, n[i]) |
|||
} |
|||
return result |
|||
} |
|||
|
|||
func divChecked(a, b int) int { |
|||
if a%b != 0 { |
|||
panic("divChecked: does not divide evenly") |
|||
} |
|||
return a / b |
|||
} |
|||
@ -1,79 +0,0 @@ |
|||
package sha512 |
|||
|
|||
import ( |
|||
"encoding/hex" |
|||
"testing" |
|||
|
|||
"github.com/consensys/gnark-crypto/ecc" |
|||
"github.com/consensys/gnark/frontend" |
|||
"github.com/consensys/gnark/test" |
|||
) |
|||
|
|||
type TestSha512Circuit struct { |
|||
in []frontend.Variable `gnark:"in"` |
|||
out []frontend.Variable `gnark:"out"` |
|||
} |
|||
|
|||
func (circuit *TestSha512Circuit) Define(api frontend.API) error { |
|||
res := Sha512(api, circuit.in) |
|||
if len(res) != 512 { |
|||
panic("bad length") |
|||
} |
|||
for i := 0; i < 512; i++ { |
|||
api.AssertIsEqual(res[i], circuit.out[i]) |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
var testCurve = ecc.BN254 |
|||
|
|||
func TestSha512Witness(t *testing.T) { |
|||
assert := test.NewAssert(t) |
|||
|
|||
testCase := func(in []byte, output string) { |
|||
out, err := hex.DecodeString(output) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
if len(out) != 512/8 { |
|||
panic("bad output length") |
|||
} |
|||
|
|||
circuit := TestSha512Circuit{ |
|||
in: toBits(in), |
|||
out: toBits(out), |
|||
} |
|||
witness := TestSha512Circuit{ |
|||
in: toBits(in), |
|||
out: toBits(out), |
|||
} |
|||
err = test.IsSolved(&circuit, &witness, testCurve.ScalarField()) |
|||
assert.NoError(err) |
|||
} |
|||
|
|||
testCase([]byte(""), "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e") |
|||
testCase([]byte("Succinct Labs"), "503ace098aa03f6feec1b5df0a38aee923f744a775508bc81f2b94ad139be297c2e8cd8c44af527b5d3f017a7fc929892c896604047e52e3f518924f52bff0dc") |
|||
testCase(decode("35c323757c20640a294345c89c0bfcebe3d554fdb0c7b7a0bdb72222c531b1ecf7ec1c43f4de9d49556de87b86b26a98942cb078486fdb44de38b80864c3973153756363696e6374204c616273"), "4388243c4452274402673de881b2f942ff5730fd2c7d8ddb94c3e3d789fb3754380cba8faa40554d9506a0730a681e88ab348a04bc5c41d18926f140b59aed39") |
|||
} |
|||
|
|||
func toBits(arr []byte) []frontend.Variable { |
|||
result := make([]frontend.Variable, len(arr)*8) |
|||
for i, v := range arr { |
|||
for j := 0; j < 8; j++ { |
|||
if (v & (1 << (7 - j))) != 0 { |
|||
result[i*8+j] = 1 |
|||
} else { |
|||
result[i*8+j] = 0 |
|||
} |
|||
} |
|||
} |
|||
return result |
|||
} |
|||
|
|||
func decode(s string) []byte { |
|||
result, err := hex.DecodeString(s) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
return result |
|||
} |
|||