@ -309,6 +309,13 @@ func stringToBigInt(s string) (*big.Int, error) {
return n , nil
return n , nil
}
}
func addPadding32 ( b [ ] byte ) [ ] byte {
if len ( b ) != 32 {
b = addZPadding ( b )
}
return b
}
func addZPadding ( b [ ] byte ) [ ] byte {
func addZPadding ( b [ ] byte ) [ ] byte {
var z [ 32 ] byte
var z [ 32 ] byte
var r [ ] byte
var r [ ] byte
@ -831,6 +838,7 @@ func ParsePkBin(f *os.File) (*types.Pk, error) {
if o != pPointsHExps {
if o != pPointsHExps {
return nil , fmt . Errorf ( "Unexpected offset, expected: %v, actual: %v" , pPointsHExps , o )
return nil , fmt . Errorf ( "Unexpected offset, expected: %v, actual: %v" , pPointsHExps , o )
}
}
// HExps
for i := 0 ; i < pk . DomainSize ; i ++ {
for i := 0 ; i < pk . DomainSize ; i ++ {
b , err = readNBytes ( r , 64 )
b , err = readNBytes ( r , 64 )
if err != nil {
if err != nil {
@ -965,3 +973,349 @@ func coordFromMont(u, q *big.Int) *big.Int {
q ,
q ,
)
)
}
}
// PkToGoBin converts the ProvingKey (*types.Pk) into binary format defined by
// go-circom-prover-verifier. PkGoBin is a own go-circom-prover-verifier
// binary format that allows to go faster when parsing.
func PkToGoBin ( pk * types . Pk ) ( [ ] byte , error ) {
var r [ ] byte
o := 0
var b [ 4 ] byte
binary . LittleEndian . PutUint32 ( b [ : ] , uint32 ( pk . NVars ) )
r = append ( r , b [ : ] ... )
binary . LittleEndian . PutUint32 ( b [ : ] , uint32 ( pk . NPublic ) )
r = append ( r , b [ : ] ... )
binary . LittleEndian . PutUint32 ( b [ : ] , uint32 ( pk . DomainSize ) )
r = append ( r , b [ : ] ... )
o += 12
// reserve space for pols (A, B) pos
b = [ 4 ] byte { }
r = append ( r , b [ : ] ... ) // 12:16
r = append ( r , b [ : ] ... ) // 16:20
o += 8
// reserve space for points (A, B1, B2, C, HExps) pos
r = append ( r , b [ : ] ... ) // 20:24
r = append ( r , b [ : ] ... ) // 24
r = append ( r , b [ : ] ... ) // 28
r = append ( r , b [ : ] ... ) // 32
r = append ( r , b [ : ] ... ) // 36:40
o += 20
pb1 := pk . VkAlpha1 . Marshal ( )
r = append ( r , pb1 [ : ] ... )
pb1 = pk . VkBeta1 . Marshal ( )
r = append ( r , pb1 [ : ] ... )
pb1 = pk . VkDelta1 . Marshal ( )
r = append ( r , pb1 [ : ] ... )
pb2 := pk . VkBeta2 . Marshal ( )
r = append ( r , pb2 [ : ] ... )
pb2 = pk . VkDelta2 . Marshal ( )
r = append ( r , pb2 [ : ] ... )
o += 448
// polsA
binary . LittleEndian . PutUint32 ( r [ 12 : 16 ] , uint32 ( o ) )
for i := 0 ; i < pk . NVars ; i ++ {
binary . LittleEndian . PutUint32 ( b [ : ] , uint32 ( len ( pk . PolsA [ i ] ) ) )
r = append ( r , b [ : ] ... )
o += 4
for j , v := range pk . PolsA [ i ] {
binary . LittleEndian . PutUint32 ( b [ : ] , uint32 ( j ) )
r = append ( r , b [ : ] ... )
r = append ( r , addPadding32 ( v . Bytes ( ) ) ... )
o += 32 + 4
}
}
// polsB
binary . LittleEndian . PutUint32 ( r [ 16 : 20 ] , uint32 ( o ) )
for i := 0 ; i < pk . NVars ; i ++ {
binary . LittleEndian . PutUint32 ( b [ : ] , uint32 ( len ( pk . PolsB [ i ] ) ) )
r = append ( r , b [ : ] ... )
o += 4
for j , v := range pk . PolsB [ i ] {
binary . LittleEndian . PutUint32 ( b [ : ] , uint32 ( j ) )
r = append ( r , b [ : ] ... )
r = append ( r , addPadding32 ( v . Bytes ( ) ) ... )
o += 32 + 4
}
}
// A
binary . LittleEndian . PutUint32 ( r [ 20 : 24 ] , uint32 ( o ) )
for i := 0 ; i < pk . NVars ; i ++ {
pb1 = pk . A [ i ] . Marshal ( )
r = append ( r , pb1 [ : ] ... )
o += 64
}
// B1
binary . LittleEndian . PutUint32 ( r [ 24 : 28 ] , uint32 ( o ) )
for i := 0 ; i < pk . NVars ; i ++ {
pb1 = pk . B1 [ i ] . Marshal ( )
r = append ( r , pb1 [ : ] ... )
o += 64
}
// B2
binary . LittleEndian . PutUint32 ( r [ 28 : 32 ] , uint32 ( o ) )
for i := 0 ; i < pk . NVars ; i ++ {
pb2 = pk . B2 [ i ] . Marshal ( )
r = append ( r , pb2 [ : ] ... )
o += 128
}
// C
binary . LittleEndian . PutUint32 ( r [ 32 : 36 ] , uint32 ( o ) )
for i := pk . NPublic + 1 ; i < pk . NVars ; i ++ {
pb1 = pk . C [ i ] . Marshal ( )
r = append ( r , pb1 [ : ] ... )
o += 64
}
// HExps
binary . LittleEndian . PutUint32 ( r [ 36 : 40 ] , uint32 ( o ) )
for i := 0 ; i < pk . DomainSize + 1 ; i ++ {
pb1 = pk . HExps [ i ] . Marshal ( )
r = append ( r , pb1 [ : ] ... )
o += 64
}
return r [ : ] , nil
}
// ParsePkGoBin parses go-circom-prover-verifier binary file representation of
// the ProvingKey into ProvingKey struct (*types.Pk). PkGoBin is a own
// go-circom-prover-verifier binary format that allows to go faster when
// parsing.
func ParsePkGoBin ( f * os . File ) ( * types . Pk , error ) {
o := 0
var pk types . Pk
r := bufio . NewReader ( f )
b , err := readNBytes ( r , 12 )
if err != nil {
return nil , err
}
pk . NVars = int ( binary . LittleEndian . Uint32 ( b [ : 4 ] ) )
pk . NPublic = int ( binary . LittleEndian . Uint32 ( b [ 4 : 8 ] ) )
pk . DomainSize = int ( binary . LittleEndian . Uint32 ( b [ 8 : 12 ] ) )
o += 12
b , err = readNBytes ( r , 8 )
if err != nil {
return nil , err
}
pPolsA := int ( binary . LittleEndian . Uint32 ( b [ : 4 ] ) )
pPolsB := int ( binary . LittleEndian . Uint32 ( b [ 4 : 8 ] ) )
o += 8
b , err = readNBytes ( r , 20 )
if err != nil {
return nil , err
}
pPointsA := int ( binary . LittleEndian . Uint32 ( b [ : 4 ] ) )
pPointsB1 := int ( binary . LittleEndian . Uint32 ( b [ 4 : 8 ] ) )
pPointsB2 := int ( binary . LittleEndian . Uint32 ( b [ 8 : 12 ] ) )
pPointsC := int ( binary . LittleEndian . Uint32 ( b [ 12 : 16 ] ) )
pPointsHExps := int ( binary . LittleEndian . Uint32 ( b [ 16 : 20 ] ) )
o += 20
b , err = readNBytes ( r , 64 )
if err != nil {
return nil , err
}
pk . VkAlpha1 = new ( bn256 . G1 )
_ , err = pk . VkAlpha1 . Unmarshal ( b )
if err != nil {
return & pk , err
}
b , err = readNBytes ( r , 64 )
if err != nil {
return nil , err
}
pk . VkBeta1 = new ( bn256 . G1 )
_ , err = pk . VkBeta1 . Unmarshal ( b )
if err != nil {
return & pk , err
}
b , err = readNBytes ( r , 64 )
if err != nil {
return nil , err
}
pk . VkDelta1 = new ( bn256 . G1 )
_ , err = pk . VkDelta1 . Unmarshal ( b )
if err != nil {
return & pk , err
}
b , err = readNBytes ( r , 128 )
if err != nil {
return nil , err
}
pk . VkBeta2 = new ( bn256 . G2 )
_ , err = pk . VkBeta2 . Unmarshal ( b )
if err != nil {
return & pk , err
}
b , err = readNBytes ( r , 128 )
if err != nil {
return nil , err
}
pk . VkDelta2 = new ( bn256 . G2 )
_ , err = pk . VkDelta2 . Unmarshal ( b )
if err != nil {
return & pk , err
}
o += 448
if o != pPolsA {
return nil , fmt . Errorf ( "Unexpected offset, expected: %v, actual: %v" , pPolsA , o )
}
// PolsA
for i := 0 ; i < pk . NVars ; i ++ {
b , err = readNBytes ( r , 4 )
if err != nil {
return nil , err
}
keysLength := int ( binary . LittleEndian . Uint32 ( b [ : 4 ] ) )
o += 4
polsMap := make ( map [ int ] * big . Int )
for j := 0 ; j < keysLength ; j ++ {
bK , err := readNBytes ( r , 4 )
if err != nil {
return nil , err
}
key := int ( binary . LittleEndian . Uint32 ( bK [ : 4 ] ) )
o += 4
b , err := readNBytes ( r , 32 )
if err != nil {
return nil , err
}
polsMap [ key ] = new ( big . Int ) . SetBytes ( b [ : 32 ] )
o += 32
}
pk . PolsA = append ( pk . PolsA , polsMap )
}
if o != pPolsB {
return nil , fmt . Errorf ( "Unexpected offset, expected: %v, actual: %v" , pPolsB , o )
}
// PolsB
for i := 0 ; i < pk . NVars ; i ++ {
b , err = readNBytes ( r , 4 )
if err != nil {
return nil , err
}
keysLength := int ( binary . LittleEndian . Uint32 ( b [ : 4 ] ) )
o += 4
polsMap := make ( map [ int ] * big . Int )
for j := 0 ; j < keysLength ; j ++ {
bK , err := readNBytes ( r , 4 )
if err != nil {
return nil , err
}
key := int ( binary . LittleEndian . Uint32 ( bK [ : 4 ] ) )
o += 4
b , err := readNBytes ( r , 32 )
if err != nil {
return nil , err
}
polsMap [ key ] = new ( big . Int ) . SetBytes ( b [ : 32 ] )
o += 32
}
pk . PolsB = append ( pk . PolsB , polsMap )
}
if o != pPointsA {
return nil , fmt . Errorf ( "Unexpected offset, expected: %v, actual: %v" , pPointsA , o )
}
// A
for i := 0 ; i < pk . NVars ; i ++ {
b , err = readNBytes ( r , 64 )
if err != nil {
return nil , err
}
p1 := new ( bn256 . G1 )
_ , err = p1 . Unmarshal ( b )
if err != nil {
return nil , err
}
pk . A = append ( pk . A , p1 )
o += 64
}
if o != pPointsB1 {
return nil , fmt . Errorf ( "Unexpected offset, expected: %v, actual: %v" , pPointsB1 , o )
}
// B1
for i := 0 ; i < pk . NVars ; i ++ {
b , err = readNBytes ( r , 64 )
if err != nil {
return nil , err
}
p1 := new ( bn256 . G1 )
_ , err = p1 . Unmarshal ( b )
if err != nil {
return nil , err
}
pk . B1 = append ( pk . B1 , p1 )
o += 64
}
if o != pPointsB2 {
return nil , fmt . Errorf ( "Unexpected offset, expected: %v, actual: %v" , pPointsB2 , o )
}
// B2
for i := 0 ; i < pk . NVars ; i ++ {
b , err = readNBytes ( r , 128 )
if err != nil {
return nil , err
}
p2 := new ( bn256 . G2 )
_ , err = p2 . Unmarshal ( b )
if err != nil {
return nil , err
}
pk . B2 = append ( pk . B2 , p2 )
o += 128
}
if o != pPointsC {
return nil , fmt . Errorf ( "Unexpected offset, expected: %v, actual: %v" , pPointsC , o )
}
// C
zb := make ( [ ] byte , 64 )
z := new ( bn256 . G1 )
_ , err = z . Unmarshal ( zb )
if err != nil {
return nil , err
}
pk . C = append ( pk . C , z )
pk . C = append ( pk . C , z )
pk . C = append ( pk . C , z )
for i := pk . NPublic + 1 ; i < pk . NVars ; i ++ {
b , err = readNBytes ( r , 64 )
if err != nil {
return nil , err
}
p1 := new ( bn256 . G1 )
_ , err = p1 . Unmarshal ( b )
if err != nil {
return nil , err
}
pk . C = append ( pk . C , p1 )
o += 64
}
if o != pPointsHExps {
return nil , fmt . Errorf ( "Unexpected offset, expected: %v, actual: %v" , pPointsHExps , o )
}
// HExps
for i := 0 ; i < pk . DomainSize + 1 ; i ++ {
b , err = readNBytes ( r , 64 )
if err != nil {
return nil , err
}
p1 := new ( bn256 . G1 )
_ , err = p1 . Unmarshal ( b )
if err != nil {
return nil , err
}
pk . HExps = append ( pk . HExps , p1 )
}
return & pk , nil
}