Skip to content

Commit

Permalink
Feature/value arr size input (#69)
Browse files Browse the repository at this point in the history
* split v2 and v3 verification, beta.1 circuit

* go-circuits 2.1.0

---------

Co-authored-by: vbasiuk <[email protected]>
  • Loading branch information
vmidyllic and volodymyr-basiuk authored Mar 4, 2024
1 parent 20d50f1 commit e0a1d82
Show file tree
Hide file tree
Showing 16 changed files with 1,276 additions and 1,148 deletions.
111 changes: 58 additions & 53 deletions auth_test.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/golang/mock v1.6.0
github.com/google/uuid v1.3.0
github.com/iden3/contracts-abi/state/go/abi v1.0.0-beta.3
github.com/iden3/go-circuits/v2 v2.0.2-0.20240131165639-deb061a1b3e6
github.com/iden3/go-circuits/v2 v2.1.0
github.com/iden3/go-iden3-core/v2 v2.0.3
github.com/iden3/go-iden3-crypto v0.0.15
github.com/iden3/go-jwz/v2 v2.0.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY=
github.com/iden3/contracts-abi/state/go/abi v1.0.0-beta.3 h1:ZHFnK2dU3NJglY+igY48JLHWtNGN/Vhf5/L/qrFk/tM=
github.com/iden3/contracts-abi/state/go/abi v1.0.0-beta.3/go.mod h1:TxgIrXCvxms3sbOdsy8kTvffUCIpEEifNy0fSXdkU4w=
github.com/iden3/go-circuits/v2 v2.0.2-0.20240131165639-deb061a1b3e6 h1:DoyzPqOZWkUBGAQc2UQbddWAD3HYF5QX1zP9b+KmSH8=
github.com/iden3/go-circuits/v2 v2.0.2-0.20240131165639-deb061a1b3e6/go.mod h1:VIFIp51+IH0hOzjnKhb84bCeyq7hq76zX/C14ua6zh4=
github.com/iden3/go-circuits/v2 v2.1.0 h1:Dk+noXGXOJYFjj2iWu3KLPd/KLoIhZ3eT6qYEfKyocc=
github.com/iden3/go-circuits/v2 v2.1.0/go.mod h1:VIFIp51+IH0hOzjnKhb84bCeyq7hq76zX/C14ua6zh4=
github.com/iden3/go-iden3-core/v2 v2.0.3 h1:ce9Jbw10zDsinWXFc05SiK2Hof/wu4zV4/ai5gQy29k=
github.com/iden3/go-iden3-core/v2 v2.0.3/go.mod h1:L9PxhWPvoS9qTb3inEkZBm1RpjHBt+VTwvxssdzbAdw=
github.com/iden3/go-iden3-crypto v0.0.15 h1:4MJYlrot1l31Fzlo2sF56u7EVFeHHJkxGXXZCtESgK4=
Expand Down
2 changes: 1 addition & 1 deletion pubsignals/atomicMtpV2.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (c *AtomicQueryMTPV2) VerifyQuery(
IsRevocationChecked: c.IsRevocationChecked,
}

err := query.Check(ctx, schemaLoader, &pubSig, verifiablePresentation, false, opts...)
err := query.Check(ctx, schemaLoader, &pubSig, verifiablePresentation, circuits.AtomicQueryMTPV2CircuitID, opts...)
return CircuitVerificationResult{}, err
}

Expand Down
3 changes: 1 addition & 2 deletions pubsignals/atomicSigV2.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,9 @@ func (c *AtomicQuerySigV2) VerifyQuery(
Merklized: c.Merklized,
ClaimPathKey: c.ClaimPathKey,
ClaimPathNotExists: c.ClaimPathNotExists,
ValueArraySize: c.ValueArraySize,
IsRevocationChecked: c.IsRevocationChecked,
}
err := query.Check(ctx, schemaLoader, &pubSig, verifiablePresentation, false, opts...)
err := query.Check(ctx, schemaLoader, &pubSig, verifiablePresentation, circuits.AtomicQuerySigV2CircuitID, opts...)
return CircuitVerificationResult{}, err
}

Expand Down
5 changes: 2 additions & 3 deletions pubsignals/atomicV3.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ func (c *AtomicQueryV3) VerifyQuery(
Timestamp: c.Timestamp,
Merklized: c.Merklized,
ClaimPathKey: c.ClaimPathKey,
ClaimPathNotExists: c.ClaimPathNotExists,
ValueArraySize: c.ValueArraySize,
ValueArraySize: c.ActualValueArraySize,
IsRevocationChecked: c.IsRevocationChecked,
// V3 NEW
LinkID: c.LinkID,
Expand All @@ -52,7 +51,7 @@ func (c *AtomicQueryV3) VerifyQuery(
Nullifier: c.Nullifier,
ProofType: c.ProofType,
}
err := query.Check(ctx, schemaLoader, &pubSig, verifiablePresentation, true, opts...)
err := query.Check(ctx, schemaLoader, &pubSig, verifiablePresentation, circuits.AtomicQueryV3CircuitID, opts...)
if err != nil {
return output, err
}
Expand Down
129 changes: 114 additions & 15 deletions pubsignals/common.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package pubsignals

import (
"bytes"
"context"
"encoding/json"
"fmt"
"math/big"
"strconv"

"github.com/iden3/go-circuits/v2"
"github.com/iden3/go-iden3-crypto/poseidon"
Expand Down Expand Up @@ -52,6 +54,14 @@ func ParseCredentialSubject(_ context.Context, credentialSubject any) (out []Pro
if !ok {
return nil, errors.New("Failed to convert credential subject to JSONObject")
}
if len(jsonObject) == 0 {
return []PropertyQuery{
{
Operator: circuits.NOOP,
FieldName: "",
},
}, nil
}

for fieldName, fieldReq := range jsonObject {
fieldReqEntries, ok := fieldReq.(map[string]interface{})
Expand Down Expand Up @@ -79,21 +89,24 @@ func ParseCredentialSubject(_ context.Context, credentialSubject any) (out []Pro

// ParseQueryMetadata parse property query and return query metadata
func ParseQueryMetadata(ctx context.Context, propertyQuery PropertyQuery, ldContextJSON, credentialType string, options merklize.Options) (query *QueryMetadata, err error) {
datatype, err := options.TypeFromContext([]byte(ldContextJSON), fmt.Sprintf("%s.%s", credentialType, propertyQuery.FieldName))
if err != nil {
return nil, err
}

query = &QueryMetadata{
PropertyQuery: propertyQuery,
SlotIndex: 0,
MerklizedSchema: false,
Datatype: datatype,
Datatype: "",
ClaimPathKey: big.NewInt(0),
Values: []*big.Int{},
Path: &merklize.Path{},
}

if query.FieldName != "" {
query.Datatype, err = options.TypeFromContext([]byte(ldContextJSON), fmt.Sprintf("%s.%s", credentialType, propertyQuery.FieldName))
if err != nil {
return nil, err
}
}

var ctxObj map[string]interface{}
err = json.Unmarshal([]byte(ldContextJSON), &ctxObj)
if err != nil {
Expand Down Expand Up @@ -139,14 +152,17 @@ func ParseQueryMetadata(ctx context.Context, propertyQuery PropertyQuery, ldCont
query.Path = &path
}

if propertyQuery.OperatorValue != nil {
if !IsValidOperation(datatype, propertyQuery.Operator) {
if propertyQuery.OperatorValue != nil && query.Datatype != "" {
if !IsValidOperation(query.Datatype, propertyQuery.Operator) {
operatorName, _ := getKeyByValue(circuits.QueryOperators, propertyQuery.Operator)
return nil, fmt.Errorf("invalid operation '%s' for field type '%s'", operatorName, datatype)
return nil, fmt.Errorf("invalid operation '%s' for field type '%s'", operatorName, query.Datatype)
}
}

query.Values, err = transformQueryValueToBigInts(ctx, propertyQuery.OperatorValue, datatype)
if propertyQuery.Operator == circuits.EXISTS {
query.Values, err = transformQueryValueToBigInts(ctx, propertyQuery.OperatorValue, ld.XSDBoolean) // TODO: refactor
} else {
query.Values, err = transformQueryValueToBigInts(ctx, propertyQuery.OperatorValue, query.Datatype)
}
if err != nil {
return nil, err
}
Expand All @@ -155,7 +171,7 @@ func ParseQueryMetadata(ctx context.Context, propertyQuery PropertyQuery, ldCont
}

// ParseQueriesMetadata parse credential subject and return array of query metadata
func ParseQueriesMetadata(ctx context.Context, credentialType, ldContextJSON string, credentialSubject any, options merklize.Options) (out []QueryMetadata, err error) {
func ParseQueriesMetadata(ctx context.Context, credentialType, ldContextJSON string, credentialSubject map[string]interface{}, options merklize.Options) (out []QueryMetadata, err error) {
queriesMetadata, err := ParseCredentialSubject(ctx, credentialSubject)
if err != nil {
return nil, err
Expand All @@ -172,8 +188,12 @@ func ParseQueriesMetadata(ctx context.Context, credentialType, ldContextJSON str
}

func transformQueryValueToBigInts(_ context.Context, value any, ldType string) (out []*big.Int, err error) {
if ldType == "" {
return []*big.Int{}, nil
}

if value == nil {
return out, nil
return make([]*big.Int, 0), nil
}

listOfValues, ok := value.([]interface{})
Expand Down Expand Up @@ -201,6 +221,33 @@ func transformQueryValueToBigInts(_ context.Context, value any, ldType string) (
return []*big.Int{hashValue}, err
}

func isPositiveInteger(v interface{}) bool {
number, err := strconv.ParseFloat(fmt.Sprintf("%v", v), 64)
if err != nil {
// value is not a number
return true
}
return number >= 0
}

// IsValidOperation checks if operation and type are supported.
func IsValidOperation(typ string, op int) bool {
if op == circuits.NOOP {
return true
}

ops, ok := availableTypesOperations[typ]
if !ok {
// by default all unknown types will be considered as string
ops = availableTypesOperations[ld.XSDString]
_, ok = ops[op]
return ok
}

_, ok = ops[op]
return ok
}

func getKeyByValue(m map[string]int, targetValue int) (string, bool) {
for key, value := range m {
if value == targetValue {
Expand All @@ -217,7 +264,14 @@ func CalculateQueryHash(
slotIndex int,
operator int,
claimPathKey *big.Int,
claimPathNotExists *big.Int) (*big.Int, error) {
isMerklized bool,
) (*big.Int, error) {
merklized := big.NewInt(0)
if isMerklized {
merklized.SetInt64(1)
}

valArrSize := big.NewInt(int64(len(values)))
circuitValues, err := circuits.PrepareCircuitArrayValues(values, 64)
if err != nil {
return nil, err
Expand All @@ -227,13 +281,58 @@ func CalculateQueryHash(
if err != nil {
return nil, err
}
return poseidon.Hash([]*big.Int{
firstPart, err := poseidon.Hash([]*big.Int{
schemaHash,
big.NewInt(int64(slotIndex)),
big.NewInt(int64(operator)),
claimPathKey,
claimPathNotExists,
merklized,
valueHash,
})
if err != nil {
return nil, err
}
return poseidon.Hash([]*big.Int{
firstPart,
valArrSize,
big.NewInt(0),
big.NewInt(0),
big.NewInt(0),
big.NewInt(0),
})

}

func fieldValueFromVerifiablePresentation(ctx context.Context, verifiablePresentation json.RawMessage, schemaLoader ld.DocumentLoader, key string) (*big.Int, error) {
if verifiablePresentation == nil {
return nil, errors.New("selective disclosure value is missed")
}

mz, err := merklize.MerklizeJSONLD(ctx,
bytes.NewBuffer(verifiablePresentation),
merklize.WithDocumentLoader(schemaLoader))
if err != nil {
return nil, errors.Errorf("failed to merklize doc: %v", err)
}

merklizedPath, err := merklize.Options{DocumentLoader: schemaLoader}.
NewPathFromDocument(verifiablePresentation,
fmt.Sprintf("verifiableCredential.credentialSubject.%s", key))
if err != nil {
return nil, errors.Errorf("failed build path to '%s' key: %v", key, err)
}

proof, valueByPath, err := mz.Proof(ctx, merklizedPath)
if err != nil {
return nil, errors.Errorf("failed get raw value: %v", err)
}
if !proof.Existence {
return nil, errors.Errorf("path '%v' doesn't exist in document", merklizedPath.Parts())
}

mvBig, err := valueByPath.MtEntry()
if err != nil {
return nil, errors.Errorf("failed to hash value: %v", err)
}
return mvBig, nil
}
Loading

0 comments on commit e0a1d82

Please sign in to comment.