diff --git a/circuits.go b/circuits.go index 0894ac6..58a2197 100644 --- a/circuits.go +++ b/circuits.go @@ -22,7 +22,7 @@ const ( // AtomicQueryMTPV2CircuitID is a type for credentialAtomicQueryMTPV2.circom AtomicQueryMTPV2CircuitID CircuitID = "credentialAtomicQueryMTPV2" // AtomicQueryV3CircuitID is a type for credentialAtomicQueryV3.circom - AtomicQueryV3CircuitID CircuitID = "credentialAtomicQueryV3-beta.0" + AtomicQueryV3CircuitID CircuitID = "credentialAtomicQueryV3-beta.1" // AtomicQueryMTPV2OnChainCircuitID is a type for credentialAtomicQueryMTPV2OnChain.circom AtomicQueryMTPV2OnChainCircuitID CircuitID = "credentialAtomicQueryMTPV2OnChain" // AtomicQuerySigCircuitID is a type for credentialAttrQuerySig.circom @@ -32,7 +32,7 @@ const ( // AtomicQuerySigV2OnChainCircuitID is a type for credentialAttrQuerySigV2OnChain.circom AtomicQuerySigV2OnChainCircuitID CircuitID = "credentialAtomicQuerySigV2OnChain" // AtomicQueryV3OnChainCircuitID is a type for credentialAtomicQueryV3OnChain.circom - AtomicQueryV3OnChainCircuitID CircuitID = "credentialAtomicQueryV3OnChain-beta.0" + AtomicQueryV3OnChainCircuitID CircuitID = "credentialAtomicQueryV3OnChain-beta.1" // JsonLDAtomicQueryMTPCircuitID is a type for credentialJsonLDAtomicQueryMTP.circom JsonLDAtomicQueryMTPCircuitID CircuitID = "credentialJsonLDAtomicQueryMTP" // SybilMTPCircuitID is a type for sybilMTP.circom @@ -40,7 +40,7 @@ const ( // SybilSigCircuitID is a type for sybilSig.circom SybilSigCircuitID CircuitID = "sybilCredentialAtomicSig" // LinkedMultiQuery10CircuitID is a type for linkedMultiQuery10.circom - LinkedMultiQuery10CircuitID CircuitID = "linkedMultiQuery10-beta.0" + LinkedMultiQuery10CircuitID CircuitID = "linkedMultiQuery10-beta.1" ) // ErrorCircuitIDNotFound returns if CircuitID is not registered diff --git a/credentialAtomicQueryV3.go b/credentialAtomicQueryV3.go index c68c9bd..f51b16d 100644 --- a/credentialAtomicQueryV3.go +++ b/credentialAtomicQueryV3.go @@ -84,18 +84,18 @@ type atomicQueryV3CircuitInputs struct { IsRevocationChecked int `json:"isRevocationChecked"` // Query // JSON path - ClaimPathNotExists int `json:"claimPathNotExists"` // 0 for inclusion, 1 for non-inclusion - ClaimPathMtp []string `json:"claimPathMtp"` - ClaimPathMtpNoAux string `json:"claimPathMtpNoAux"` // 1 if aux node is empty, 0 if non-empty or for inclusion proofs - ClaimPathMtpAuxHi *merkletree.Hash `json:"claimPathMtpAuxHi"` // 0 for inclusion proof - ClaimPathMtpAuxHv *merkletree.Hash `json:"claimPathMtpAuxHv"` // 0 for inclusion proof - ClaimPathKey string `json:"claimPathKey"` // hash of path in merklized json-ld document - ClaimPathValue string `json:"claimPathValue"` // value in this path in merklized json-ld document - - Operator int `json:"operator"` - SlotIndex int `json:"slotIndex"` - Timestamp int64 `json:"timestamp"` - Value []string `json:"value"` + ClaimPathMtp []string `json:"claimPathMtp"` + ClaimPathMtpNoAux string `json:"claimPathMtpNoAux"` // 1 if aux node is empty, 0 if non-empty or for inclusion proofs + ClaimPathMtpAuxHi *merkletree.Hash `json:"claimPathMtpAuxHi"` // 0 for inclusion proof + ClaimPathMtpAuxHv *merkletree.Hash `json:"claimPathMtpAuxHv"` // 0 for inclusion proof + ClaimPathKey string `json:"claimPathKey"` // hash of path in merklized json-ld document + ClaimPathValue string `json:"claimPathValue"` // value in this path in merklized json-ld document + + Operator int `json:"operator"` + SlotIndex int `json:"slotIndex"` + Timestamp int64 `json:"timestamp"` + Value []string `json:"value"` + ActualValueArraySize int `json:"valueArraySize"` IssuerClaimMtp []*merkletree.Hash `json:"issuerClaimMtp"` IssuerClaimClaimsTreeRoot *merkletree.Hash `json:"issuerClaimClaimsTreeRoot"` @@ -127,6 +127,10 @@ func (a AtomicQueryV3Inputs) Validate() error { return errors.New(ErrorEmptyQueryValue) } + if err := a.Query.ValidateValueArraySize(a.GetValueArrSize()); err != nil { + return err + } + switch a.ProofType { case BJJSignatureProofType: if a.Claim.SignatureProof == nil { @@ -265,7 +269,6 @@ func (a AtomicQueryV3Inputs) InputsMarshal() ([]byte, error) { s.IssuerClaimNonRevMtpAuxHv = nodeAuxNonRev.value s.IssuerClaimNonRevMtpNoAux = nodeAuxNonRev.noAux - s.ClaimPathNotExists = existenceToInt(valueProof.MTP.Existence) nodAuxJSONLD := GetNodeAuxValue(valueProof.MTP) s.ClaimPathMtpNoAux = nodAuxJSONLD.noAux s.ClaimPathMtpAuxHi = nodAuxJSONLD.key @@ -278,6 +281,7 @@ func (a AtomicQueryV3Inputs) InputsMarshal() ([]byte, error) { return nil, err } s.Value = bigIntArrayToStringArray(values) + s.ActualValueArraySize = len(a.Query.Values) s.LinkNonce = "0" if a.LinkNonce != nil { @@ -337,7 +341,6 @@ type AtomicQueryV3PubSignals struct { Timestamp int64 `json:"timestamp"` Merklized int `json:"merklized"` ClaimPathKey *big.Int `json:"claimPathKey"` - ClaimPathNotExists int `json:"claimPathNotExists"` // 0 for inclusion, 1 for non-inclusion IsRevocationChecked int `json:"isRevocationChecked"` // 0 revocation not check, // 1 for check revocation ProofType int `json:"proofType"` LinkID *big.Int `json:"linkID"` @@ -345,6 +348,7 @@ type AtomicQueryV3PubSignals struct { OperatorOutput *big.Int `json:"operatorOutput"` VerifierID *core.ID `json:"verifierID"` NullifierSessionID *big.Int `json:"nullifierSessionID"` + ActualValueArraySize int `json:"valueArraySize"` } // PubSignalsUnmarshal unmarshal credentialAtomicQueryV3.circom public signals @@ -363,11 +367,11 @@ func (ao *AtomicQueryV3PubSignals) PubSignalsUnmarshal(data []byte) error { // issuerClaimNonRevState // timestamp // claimSchema - // claimPathNotExists // claimPathKey // slotIndex // operator // value + // valueArraySize // verifierID // nullifierSessionID @@ -469,12 +473,6 @@ func (ao *AtomicQueryV3PubSignals) PubSignalsUnmarshal(data []byte) error { ao.ClaimSchema = core.NewSchemaHashFromInt(schemaInt) fieldIdx++ - // - ClaimPathNotExists - if ao.ClaimPathNotExists, err = strconv.Atoi(sVals[fieldIdx]); err != nil { - return err - } - fieldIdx++ - // - ClaimPathKey if ao.ClaimPathKey, ok = big.NewInt(0).SetString(sVals[fieldIdx], 10); !ok { return fmt.Errorf("invalid claimPathKey: %s", sVals[fieldIdx]) @@ -504,6 +502,12 @@ func (ao *AtomicQueryV3PubSignals) PubSignalsUnmarshal(data []byte) error { fieldIdx++ } + // - valueArraySize + if ao.ActualValueArraySize, err = strconv.Atoi(sVals[fieldIdx]); err != nil { + return err + } + fieldIdx++ + // - VerifierID if sVals[fieldIdx] != "0" { if ao.VerifierID, err = idFromIntStr(sVals[fieldIdx]); err != nil { diff --git a/credentialAtomicQueryV3OnChain.go b/credentialAtomicQueryV3OnChain.go index 4750506..c5bf9df 100644 --- a/credentialAtomicQueryV3OnChain.go +++ b/credentialAtomicQueryV3OnChain.go @@ -49,7 +49,7 @@ type AtomicQueryV3OnChainInputs struct { NullifierSessionID *big.Int - AuthEnabled int + IsBJJAuthEnabled int } // atomicQueryV3OnChainCircuitInputs type represents credentialAtomicQueryV3OnChain.circom private inputs required by prover @@ -90,18 +90,18 @@ type atomicQueryV3OnChainCircuitInputs struct { IsRevocationChecked int `json:"isRevocationChecked"` // Query // JSON path - ClaimPathNotExists int `json:"claimPathNotExists"` // 0 for inclusion, 1 for non-inclusion - ClaimPathMtp []string `json:"claimPathMtp"` - ClaimPathMtpNoAux string `json:"claimPathMtpNoAux"` // 1 if aux node is empty, 0 if non-empty or for inclusion proofs - ClaimPathMtpAuxHi *merkletree.Hash `json:"claimPathMtpAuxHi"` // 0 for inclusion proof - ClaimPathMtpAuxHv *merkletree.Hash `json:"claimPathMtpAuxHv"` // 0 for inclusion proof - ClaimPathKey string `json:"claimPathKey"` // hash of path in merklized json-ld document - ClaimPathValue string `json:"claimPathValue"` // value in this path in merklized json-ld document - - Operator int `json:"operator"` - SlotIndex int `json:"slotIndex"` - Timestamp int64 `json:"timestamp"` - Value []string `json:"value"` + ClaimPathMtp []string `json:"claimPathMtp"` + ClaimPathMtpNoAux string `json:"claimPathMtpNoAux"` // 1 if aux node is empty, 0 if non-empty or for inclusion proofs + ClaimPathMtpAuxHi *merkletree.Hash `json:"claimPathMtpAuxHi"` // 0 for inclusion proof + ClaimPathMtpAuxHv *merkletree.Hash `json:"claimPathMtpAuxHv"` // 0 for inclusion proof + ClaimPathKey string `json:"claimPathKey"` // hash of path in merklized json-ld document + ClaimPathValue string `json:"claimPathValue"` // value in this path in merklized json-ld document + + Operator int `json:"operator"` + SlotIndex int `json:"slotIndex"` + Timestamp int64 `json:"timestamp"` + Value []string `json:"value"` + ValueArraySize int `json:"valueArraySize"` IssuerClaimMtp []*merkletree.Hash `json:"issuerClaimMtp"` IssuerClaimClaimsTreeRoot *merkletree.Hash `json:"issuerClaimClaimsTreeRoot"` @@ -146,7 +146,7 @@ type atomicQueryV3OnChainCircuitInputs struct { NullifierSessionID string `json:"nullifierSessionID"` - AuthEnabled string `json:"authEnabled"` + IsBJJAuthEnabled string `json:"isBJJAuthEnabled"` } func (a AtomicQueryV3OnChainInputs) Validate() error { @@ -163,11 +163,15 @@ func (a AtomicQueryV3OnChainInputs) Validate() error { return errors.New(ErrorEmptyQueryValue) } + if err := a.Query.ValidateValueArraySize(a.GetValueArrSize()); err != nil { + return err + } + if a.Challenge == nil { return errors.New(ErrorEmptyChallenge) } - if a.AuthEnabled == 1 { + if a.IsBJJAuthEnabled == 1 { if a.AuthClaimIncMtp == nil { return errors.New(ErrorEmptyAuthClaimProof) } @@ -272,7 +276,7 @@ func (a AtomicQueryV3OnChainInputs) InputsMarshal() ([]byte, error) { s.Challenge = a.Challenge.String() - if a.AuthEnabled == 1 { + if a.IsBJJAuthEnabled == 1 { s.AuthClaim = a.AuthClaim s.ClaimsTreeRoot = a.TreeState.ClaimsRoot @@ -358,7 +362,6 @@ func (a AtomicQueryV3OnChainInputs) InputsMarshal() ([]byte, error) { s.IssuerClaimNonRevMtpAuxHv = nodeAuxNonRev.value s.IssuerClaimNonRevMtpNoAux = nodeAuxNonRev.noAux - s.ClaimPathNotExists = existenceToInt(valueProof.MTP.Existence) nodAuxJSONLD := GetNodeAuxValue(valueProof.MTP) s.ClaimPathMtpNoAux = nodAuxJSONLD.noAux s.ClaimPathMtpAuxHi = nodAuxJSONLD.key @@ -371,6 +374,7 @@ func (a AtomicQueryV3OnChainInputs) InputsMarshal() ([]byte, error) { return nil, err } s.Value = bigIntArrayToStringArray(values) + s.ValueArraySize = len(a.Query.Values) s.LinkNonce = "0" if a.LinkNonce != nil { @@ -387,7 +391,7 @@ func (a AtomicQueryV3OnChainInputs) InputsMarshal() ([]byte, error) { s.NullifierSessionID = a.NullifierSessionID.String() } - s.AuthEnabled = strconv.Itoa(a.AuthEnabled) + s.IsBJJAuthEnabled = strconv.Itoa(a.IsBJJAuthEnabled) return json.Marshal(s) } @@ -454,8 +458,6 @@ type AtomicQueryV3OnChainPubSignals struct { IssuerState *merkletree.Hash `json:"issuerState"` IssuerClaimNonRevState *merkletree.Hash `json:"issuerClaimNonRevState"` Timestamp int64 `json:"timestamp"` - Merklized int `json:"merklized"` - IsRevocationChecked int `json:"isRevocationChecked"` // 0 revocation not check, // 1 for check revocation QueryHash *big.Int `json:"circuitQueryHash"` Challenge *big.Int `json:"challenge"` GlobalRoot *merkletree.Hash `json:"gistRoot"` @@ -463,15 +465,12 @@ type AtomicQueryV3OnChainPubSignals struct { LinkID *big.Int `json:"linkID"` Nullifier *big.Int `json:"nullifier"` OperatorOutput *big.Int `json:"operatorOutput"` - VerifierID *core.ID `json:"verifierID"` - NullifierSessionID *big.Int `json:"nullifierSessionID"` - AuthEnabled int `json:"authEnabled"` + IsBJJAuthEnabled int `json:"isBJJAuthEnabled"` } // PubSignalsUnmarshal unmarshal credentialAtomicQueryV3OnChain.circom public signals func (ao *AtomicQueryV3OnChainPubSignals) PubSignalsUnmarshal(data []byte) error { // expected order: - // merklized // userID // circuitQueryHash // issuerState @@ -483,12 +482,9 @@ func (ao *AtomicQueryV3OnChainPubSignals) PubSignalsUnmarshal(data []byte) error // challenge // gistRoot // issuerID - // isRevocationChecked // issuerClaimNonRevState // timestamp - // verifierID - // nullifierSessionID - // authEnabled + // isBJJAuthEnabled var sVals []string err := json.Unmarshal(data, &sVals) @@ -498,12 +494,6 @@ func (ao *AtomicQueryV3OnChainPubSignals) PubSignalsUnmarshal(data []byte) error fieldIdx := 0 - // -- merklized - if ao.Merklized, err = strconv.Atoi(sVals[fieldIdx]); err != nil { - return err - } - fieldIdx++ - // - userID if ao.UserID, err = idFromIntStr(sVals[fieldIdx]); err != nil { return err @@ -571,12 +561,6 @@ func (ao *AtomicQueryV3OnChainPubSignals) PubSignalsUnmarshal(data []byte) error } fieldIdx++ - // - isRevocationChecked - if ao.IsRevocationChecked, err = strconv.Atoi(sVals[fieldIdx]); err != nil { - return err - } - fieldIdx++ - // - issuerClaimNonRevState if ao.IssuerClaimNonRevState, err = merkletree.NewHashFromString(sVals[fieldIdx]); err != nil { return err @@ -590,22 +574,8 @@ func (ao *AtomicQueryV3OnChainPubSignals) PubSignalsUnmarshal(data []byte) error } fieldIdx++ - // - VerifierID - if sVals[fieldIdx] != "0" { - if ao.VerifierID, err = idFromIntStr(sVals[fieldIdx]); err != nil { - return err - } - } - fieldIdx++ - - // - NullifierSessionID - if ao.NullifierSessionID, ok = big.NewInt(0).SetString(sVals[fieldIdx], 10); !ok { - return fmt.Errorf("invalid verifier session ID: %s", sVals[fieldIdx]) - } - fieldIdx++ - - // - AuthEnabled - if ao.AuthEnabled, err = strconv.Atoi(sVals[fieldIdx]); err != nil { + // - IsBJJAuthEnabled + if ao.IsBJJAuthEnabled, err = strconv.Atoi(sVals[fieldIdx]); err != nil { return err } diff --git a/credentialAtomicQueryV3OnChain_test.go b/credentialAtomicQueryV3OnChain_test.go index 6ecb217..14cfb24 100644 --- a/credentialAtomicQueryV3OnChain_test.go +++ b/credentialAtomicQueryV3OnChain_test.go @@ -88,7 +88,7 @@ func TestAttrQueryV3OnChain_SigPart_PrepareInputs(t *testing.T) { Query: Query{ ValueProof: nil, Operator: EQ, - Values: it.PrepareIntArray([]*big.Int{big.NewInt(10)}, 64), + Values: []*big.Int{big.NewInt(10)}, SlotIndex: 2, }, CurrentTimeStamp: timestamp, @@ -107,7 +107,7 @@ func TestAttrQueryV3OnChain_SigPart_PrepareInputs(t *testing.T) { VerifierID: it.IDFromStr( t, "21929109382993718606847853573861987353620810345503358891473103689157378049"), NullifierSessionID: big.NewInt(32), - AuthEnabled: 1, + IsBJJAuthEnabled: 1, } bytesInputs, err := in.InputsMarshal() @@ -179,7 +179,7 @@ func TestAttrQueryV3OnChain_MTPPart_PrepareInputs(t *testing.T) { Query: Query{ ValueProof: nil, Operator: EQ, - Values: it.PrepareIntArray([]*big.Int{big.NewInt(10)}, 64), + Values: []*big.Int{big.NewInt(10)}, SlotIndex: 2, }, CurrentTimeStamp: timestamp, @@ -198,7 +198,7 @@ func TestAttrQueryV3OnChain_MTPPart_PrepareInputs(t *testing.T) { VerifierID: it.IDFromStr( t, "21929109382993718606847853573861987353620810345503358891473103689157378049"), NullifierSessionID: big.NewInt(32), - AuthEnabled: 1, + IsBJJAuthEnabled: 1, } bytesInputs, err := in.InputsMarshal() @@ -213,25 +213,21 @@ func TestAtomicQueryV3OnChainOutputs_Sig_CircuitUnmarshal(t *testing.T) { out := new(AtomicQueryV3OnChainPubSignals) err := out.PubSignalsUnmarshal([]byte( `[ - "0", - "26109404700696283154998654512117952420503675471097392618762221546565140481", - "7002038488948284767652984010448061038733120594540539539730565455904340350321", - "2943483356559152311923412925436024635269538717812859789851139200242297094", - "0", - "0", - "0", - "0", - "23", - "10", - "20177832565449474772630743317224985532862797657496372535616634430055981993180", - "27918766665310231445021466320959318414450284884582375163563581940319453185", - "1", - "20177832565449474772630743317224985532862797657496372535616634430055981993180", - "1642074362", - "21929109382993718606847853573861987353620810345503358891473103689157378049", - "32", - "1" -]`)) + "26109404700696283154998654512117952420503675471097392618762221546565140481", + "1985992055626993205360700288228074716165415322842329919733176531545165024097", + "2943483356559152311923412925436024635269538717812859789851139200242297094", + "0", + "0", + "0", + "0", + "23", + "10", + "20177832565449474772630743317224985532862797657496372535616634430055981993180", + "27918766665310231445021466320959318414450284884582375163563581940319453185", + "20177832565449474772630743317224985532862797657496372535616634430055981993180", + "1642074362", + "1" + ]`)) require.NoError(t, err) expValue, err := PrepareCircuitArrayValues([]*big.Int{big.NewInt(10)}, 64) @@ -241,7 +237,7 @@ func TestAtomicQueryV3OnChainOutputs_Sig_CircuitUnmarshal(t *testing.T) { schema := it.CoreSchemaFromStr(t, "180410020913331409885634153623124536270") slotIndex := 2 operator := 1 - queryHash, err := poseidon.Hash([]*big.Int{ + firstPartQueryHash, err := poseidon.Hash([]*big.Int{ schema.BigInt(), big.NewInt(int64(slotIndex)), big.NewInt(int64(operator)), @@ -250,6 +246,15 @@ func TestAtomicQueryV3OnChainOutputs_Sig_CircuitUnmarshal(t *testing.T) { valueHash, }) require.NoError(t, err) + queryHash, err := poseidon.Hash([]*big.Int{ + firstPartQueryHash, + big.NewInt(int64(1)), + big.NewInt(int64(1)), + big.NewInt(0), + big.NewInt(0), + new(big.Int), + }) + require.NoError(t, err) exp := AtomicQueryV3OnChainPubSignals{ RequestID: big.NewInt(23), @@ -260,18 +265,13 @@ func TestAtomicQueryV3OnChainOutputs_Sig_CircuitUnmarshal(t *testing.T) { IssuerClaimNonRevState: it.MTHashFromStr(t, "20177832565449474772630743317224985532862797657496372535616634430055981993180"), QueryHash: queryHash, Timestamp: int64(1642074362), - Merklized: 0, - IsRevocationChecked: 1, Challenge: big.NewInt(10), GlobalRoot: it.MTHashFromStr(t, "20177832565449474772630743317224985532862797657496372535616634430055981993180"), ProofType: 0, OperatorOutput: big.NewInt(0), LinkID: big.NewInt(0), Nullifier: big.NewInt(0), - VerifierID: it.IDFromStr( - t, "21929109382993718606847853573861987353620810345503358891473103689157378049"), - NullifierSessionID: big.NewInt(32), - AuthEnabled: 1, + IsBJJAuthEnabled: 1, } jsonOut, err := json.Marshal(out) @@ -286,25 +286,21 @@ func TestAtomicQueryV3OnChainOutputs_MTP_CircuitUnmarshal(t *testing.T) { out := new(AtomicQueryV3OnChainPubSignals) err := out.PubSignalsUnmarshal([]byte( `[ - "0", - "26109404700696283154998654512117952420503675471097392618762221546565140481", - "7002038488948284767652984010448061038733120594540539539730565455904340350321", - "2943483356559152311923412925436024635269538717812859789851139200242297094", - "0", - "0", - "0", - "1", - "23", - "10", - "20177832565449474772630743317224985532862797657496372535616634430055981993180", - "27918766665310231445021466320959318414450284884582375163563581940319453185", - "1", - "20177832565449474772630743317224985532862797657496372535616634430055981993180", - "1642074362", - "21929109382993718606847853573861987353620810345503358891473103689157378049", - "32", - "1" -]`)) + "26109404700696283154998654512117952420503675471097392618762221546565140481", + "1985992055626993205360700288228074716165415322842329919733176531545165024097", + "2943483356559152311923412925436024635269538717812859789851139200242297094", + "0", + "0", + "0", + "1", + "23", + "10", + "20177832565449474772630743317224985532862797657496372535616634430055981993180", + "27918766665310231445021466320959318414450284884582375163563581940319453185", + "20177832565449474772630743317224985532862797657496372535616634430055981993180", + "1642074362", + "1" + ]`)) require.NoError(t, err) expValue, err := PrepareCircuitArrayValues([]*big.Int{big.NewInt(10)}, 64) @@ -314,7 +310,8 @@ func TestAtomicQueryV3OnChainOutputs_MTP_CircuitUnmarshal(t *testing.T) { schema := it.CoreSchemaFromStr(t, "180410020913331409885634153623124536270") slotIndex := 2 operator := 1 - queryHash, err := poseidon.Hash([]*big.Int{ + + firstPartQueryHash, err := poseidon.Hash([]*big.Int{ schema.BigInt(), big.NewInt(int64(slotIndex)), big.NewInt(int64(operator)), @@ -322,6 +319,16 @@ func TestAtomicQueryV3OnChainOutputs_MTP_CircuitUnmarshal(t *testing.T) { big.NewInt(1), valueHash, }) + require.NoError(t, err) + queryHash, err := poseidon.Hash([]*big.Int{ + firstPartQueryHash, + big.NewInt(int64(1)), + big.NewInt(int64(1)), + big.NewInt(0), + big.NewInt(0), + new(big.Int), + }) + require.NoError(t, err) exp := AtomicQueryV3OnChainPubSignals{ @@ -332,8 +339,6 @@ func TestAtomicQueryV3OnChainOutputs_MTP_CircuitUnmarshal(t *testing.T) { IssuerClaimNonRevState: it.MTHashFromStr(t, "20177832565449474772630743317224985532862797657496372535616634430055981993180"), QueryHash: queryHash, Timestamp: int64(1642074362), - Merklized: 0, - IsRevocationChecked: 1, Challenge: big.NewInt(10), GlobalRoot: it.MTHashFromStr(t, "20177832565449474772630743317224985532862797657496372535616634430055981993180"), ProofType: 1, @@ -341,10 +346,7 @@ func TestAtomicQueryV3OnChainOutputs_MTP_CircuitUnmarshal(t *testing.T) { OperatorOutput: big.NewInt(0), LinkID: big.NewInt(0), Nullifier: big.NewInt(0), - VerifierID: it.IDFromStr( - t, "21929109382993718606847853573861987353620810345503358891473103689157378049"), - NullifierSessionID: big.NewInt(32), - AuthEnabled: 1, + IsBJJAuthEnabled: 1, } jsonOut, err := json.Marshal(out) diff --git a/credentialAtomicQueryV3_test.go b/credentialAtomicQueryV3_test.go index 682f71c..17c59e7 100644 --- a/credentialAtomicQueryV3_test.go +++ b/credentialAtomicQueryV3_test.go @@ -74,7 +74,7 @@ func TestAttrQueryV3_SigPart_PrepareInputs(t *testing.T) { Query: Query{ ValueProof: nil, Operator: EQ, - Values: it.PrepareIntArray([]*big.Int{big.NewInt(10)}, 64), + Values: []*big.Int{big.NewInt(10)}, SlotIndex: 2, }, CurrentTimeStamp: timestamp, @@ -142,7 +142,7 @@ func TestAttrQueryV3_MTPPart_PrepareInputs(t *testing.T) { Query: Query{ ValueProof: nil, Operator: EQ, - Values: it.PrepareIntArray([]*big.Int{big.NewInt(10)}, 64), + Values: []*big.Int{big.NewInt(10)}, SlotIndex: 2, }, CurrentTimeStamp: timestamp, @@ -180,7 +180,6 @@ func TestAtomicQueryV3Outputs_Sig_CircuitUnmarshal(t *testing.T) { "1642074362", "180410020913331409885634153623124536270", "0", - "0", "2", "1", "10", @@ -247,6 +246,7 @@ func TestAtomicQueryV3Outputs_Sig_CircuitUnmarshal(t *testing.T) { "0", "0", "0", + "1", "21929109382993718606847853573861987353620810345503358891473103689157378049", "32" ]`)) @@ -267,18 +267,18 @@ func TestAtomicQueryV3Outputs_Sig_CircuitUnmarshal(t *testing.T) { "2943483356559152311923412925436024635269538717812859789851139200242297094"), ClaimSchema: it.CoreSchemaFromStr(t, "180410020913331409885634153623124536270"), - SlotIndex: 2, - Operator: 1, - Value: expValue, - Timestamp: int64(1642074362), - Merklized: 0, - ClaimPathKey: big.NewInt(0), - ClaimPathNotExists: 0, - IsRevocationChecked: 1, - ProofType: 0, - LinkID: big.NewInt(0), - Nullifier: big.NewInt(0), - OperatorOutput: big.NewInt(0), + SlotIndex: 2, + Operator: 1, + Value: expValue, + ActualValueArraySize: 1, + Timestamp: int64(1642074362), + Merklized: 0, + ClaimPathKey: big.NewInt(0), + IsRevocationChecked: 1, + ProofType: 0, + LinkID: big.NewInt(0), + Nullifier: big.NewInt(0), + OperatorOutput: big.NewInt(0), VerifierID: it.IDFromStr( t, "21929109382993718606847853573861987353620810345503358891473103689157378049"), NullifierSessionID: big.NewInt(32), @@ -310,7 +310,6 @@ func TestAtomicQueryV3Outputs_MTP_CircuitUnmarshal(t *testing.T) { "1642074362", "180410020913331409885634153623124536270", "0", - "0", "2", "1", "10", @@ -377,6 +376,7 @@ func TestAtomicQueryV3Outputs_MTP_CircuitUnmarshal(t *testing.T) { "0", "0", "0", + "1", "21929109382993718606847853573861987353620810345503358891473103689157378049", "32" ]`)) @@ -397,18 +397,18 @@ func TestAtomicQueryV3Outputs_MTP_CircuitUnmarshal(t *testing.T) { "5687720250943511874245715094520098014548846873346473635855112185560372332782"), ClaimSchema: it.CoreSchemaFromStr(t, "180410020913331409885634153623124536270"), - SlotIndex: 2, - Operator: 1, - Value: expValue, - Timestamp: int64(1642074362), - Merklized: 0, - ClaimPathKey: big.NewInt(0), - ClaimPathNotExists: 0, - IsRevocationChecked: 1, - ProofType: 1, - LinkID: big.NewInt(0), - Nullifier: big.NewInt(0), - OperatorOutput: big.NewInt(0), + SlotIndex: 2, + Operator: 1, + Value: expValue, + ActualValueArraySize: 1, + Timestamp: int64(1642074362), + Merklized: 0, + ClaimPathKey: big.NewInt(0), + IsRevocationChecked: 1, + ProofType: 1, + LinkID: big.NewInt(0), + Nullifier: big.NewInt(0), + OperatorOutput: big.NewInt(0), VerifierID: it.IDFromStr( t, "21929109382993718606847853573861987353620810345503358891473103689157378049"), NullifierSessionID: big.NewInt(32), diff --git a/errors.go b/errors.go index 233a0a6..cae9021 100644 --- a/errors.go +++ b/errors.go @@ -24,4 +24,5 @@ const ( ErrorInvalidProofType = "invalid proof type" ErrorEmptySignatureProof = "empty signature proof" ErrorEmptyMTPProof = "empty MTP proof" + ErrorInvalidValuesArrSize = "invalid query Values array size" ) diff --git a/linkedMultiQuery.go b/linkedMultiQuery.go index 518d376..11063b0 100644 --- a/linkedMultiQuery.go +++ b/linkedMultiQuery.go @@ -22,20 +22,19 @@ type LinkedMultiQueryInputs struct { // linkedMultiQueryCircuitInputs type reflect linkedMultiQuery10.circom private inputs required by prover type linkedMultiQueryCircuitInputs struct { - LinkNonce string `json:"linkNonce"` - IssuerClaim *core.Claim `json:"issuerClaim"` - Enabled []int `json:"enabled"` - ClaimSchema string `json:"claimSchema"` - ClaimPathNotExists []int `json:"claimPathNotExists"` // 0 for inclusion, 1 for non-inclusion - ClaimPathMtp [][]string `json:"claimPathMtp"` - ClaimPathMtpNoAux []string `json:"claimPathMtpNoAux"` // 1 if aux node is empty, 0 if non-empty or for inclusion proofs - ClaimPathMtpAuxHi []*merkletree.Hash `json:"claimPathMtpAuxHi"` // 0 for inclusion proof - ClaimPathMtpAuxHv []*merkletree.Hash `json:"claimPathMtpAuxHv"` // 0 for inclusion proof - ClaimPathKey []string `json:"claimPathKey"` // hash of path in merklized json-ld document - ClaimPathValue []string `json:"claimPathValue"` // value in this path in merklized json-ld document - SlotIndex []int `json:"slotIndex"` - Operator []int `json:"operator"` - Value [][]string `json:"value"` + LinkNonce string `json:"linkNonce"` + IssuerClaim *core.Claim `json:"issuerClaim"` + ClaimSchema string `json:"claimSchema"` + ClaimPathMtp [][]string `json:"claimPathMtp"` + ClaimPathMtpNoAux []string `json:"claimPathMtpNoAux"` // 1 if aux node is empty, 0 if non-empty or for inclusion proofs + ClaimPathMtpAuxHi []*merkletree.Hash `json:"claimPathMtpAuxHi"` // 0 for inclusion proof + ClaimPathMtpAuxHv []*merkletree.Hash `json:"claimPathMtpAuxHv"` // 0 for inclusion proof + ClaimPathKey []string `json:"claimPathKey"` // hash of path in merklized json-ld document + ClaimPathValue []string `json:"claimPathValue"` // value in this path in merklized json-ld document + SlotIndex []int `json:"slotIndex"` + Operator []int `json:"operator"` + Value [][]string `json:"value"` + ActualValueArraySize []int `json:"valueArraySize"` } // InputsMarshal returns Circom private inputs for linkedMultiQuery10.circom @@ -45,8 +44,6 @@ func (l LinkedMultiQueryInputs) InputsMarshal() ([]byte, error) { s.IssuerClaim = l.Claim s.ClaimSchema = l.Claim.GetSchemaHash().BigInt().String() - s.Enabled = make([]int, LinkedMultiQueryLength) - s.ClaimPathNotExists = make([]int, LinkedMultiQueryLength) s.ClaimPathMtp = make([][]string, LinkedMultiQueryLength) s.ClaimPathMtpNoAux = make([]string, LinkedMultiQueryLength) s.ClaimPathMtpAuxHi = make([]*merkletree.Hash, LinkedMultiQueryLength) @@ -56,11 +53,10 @@ func (l LinkedMultiQueryInputs) InputsMarshal() ([]byte, error) { s.SlotIndex = make([]int, LinkedMultiQueryLength) s.Operator = make([]int, LinkedMultiQueryLength) s.Value = make([][]string, LinkedMultiQueryLength) + s.ActualValueArraySize = make([]int, LinkedMultiQueryLength) for i := 0; i < LinkedMultiQueryLength; i++ { if l.Query[i] == nil { - s.Enabled[i] = 0 - s.ClaimPathNotExists[i] = 0 s.ClaimPathMtp[i] = PrepareSiblingsStr([]*merkletree.Hash{}, l.GetMTLevelsClaim()) s.ClaimPathMtpNoAux[i] = "0" @@ -78,10 +74,10 @@ func (l LinkedMultiQueryInputs) InputsMarshal() ([]byte, error) { return nil, err } s.Value[i] = bigIntArrayToStringArray(values) + s.ActualValueArraySize[i] = 0 continue } - s.Enabled[i] = 1 valueProof := l.Query[i].ValueProof if valueProof == nil { valueProof = &ValueProof{} @@ -90,7 +86,6 @@ func (l LinkedMultiQueryInputs) InputsMarshal() ([]byte, error) { valueProof.MTP = &merkletree.Proof{} } - s.ClaimPathNotExists[i] = existenceToInt(valueProof.MTP.Existence) s.ClaimPathMtp[i] = PrepareSiblingsStr(valueProof.MTP.AllSiblings(), l.GetMTLevelsClaim()) @@ -104,6 +99,7 @@ func (l LinkedMultiQueryInputs) InputsMarshal() ([]byte, error) { s.SlotIndex[i] = l.Query[i].SlotIndex s.Operator[i] = l.Query[i].Operator + s.ActualValueArraySize[i] = len(l.Query[i].Values) values, err := PrepareCircuitArrayValues(l.Query[i].Values, l.GetValueArrSize()) if err != nil { return nil, err @@ -120,7 +116,6 @@ type LinkedMultiQueryPubSignals struct { Merklized int `json:"merklized"` OperatorOutput []*big.Int `json:"operatorOutput"` CircuitQueryHash []*big.Int `json:"circuitQueryHash"` - Enabled []bool `json:"enabled"` } // PubSignalsUnmarshal unmarshal linkedMultiQuery10.circom public inputs to LinkedMultiQueryPubSignals @@ -130,9 +125,8 @@ func (lo *LinkedMultiQueryPubSignals) PubSignalsUnmarshal(data []byte) error { // merklized // operatorOutput // circuitQueryHash - // enabled - outputsLength := LinkedMultiQueryLength*3 + 2 + outputsLength := LinkedMultiQueryLength*2 + 2 var sVals []string err := json.Unmarshal(data, &sVals) if err != nil { @@ -175,17 +169,6 @@ func (lo *LinkedMultiQueryPubSignals) PubSignalsUnmarshal(data []byte) error { fieldIdx++ } - // -- enabled - lo.Enabled = make([]bool, LinkedMultiQueryLength) - for i := 0; i < LinkedMultiQueryLength; i++ { - enabledInt, err := strconv.Atoi(sVals[fieldIdx]) - if err != nil { - return err - } - lo.Enabled[i] = enabledInt == 1 - fieldIdx++ - } - return nil } diff --git a/linkedMultiQuery_test.go b/linkedMultiQuery_test.go index 97e6320..c0157db 100644 --- a/linkedMultiQuery_test.go +++ b/linkedMultiQuery_test.go @@ -19,21 +19,21 @@ func TestLinkedMultiQueryInputs_PrepareInputs(t *testing.T) { queries[0] = &Query{ ValueProof: nil, Operator: EQ, - Values: it.PrepareIntArray([]*big.Int{big.NewInt(10)}, 64), + Values: []*big.Int{big.NewInt(10)}, SlotIndex: 2, } queries[1] = &Query{ ValueProof: nil, Operator: LT, - Values: it.PrepareIntArray([]*big.Int{big.NewInt(133)}, 64), + Values: []*big.Int{big.NewInt(133)}, SlotIndex: 2, } queries[2] = &Query{ ValueProof: nil, Operator: LTE, - Values: it.PrepareIntArray([]*big.Int{big.NewInt(555)}, 64), + Values: []*big.Int{big.NewInt(555)}, SlotIndex: 2, } @@ -77,32 +77,22 @@ func TestLinkedMultiQueryPubSignals_CircuitUnmarshal(t *testing.T) { "0", "0", "0", - "0", - "1", - "1", - "1", - "1", - "1", - "0", - "0", - "0", - "0", "0" ]`)) require.NoError(t, err) operatorOutput := make([]*big.Int, 10) circuitQueryHash := make([]*big.Int, 10) - enabled := make([]bool, 10) + valueArrSize := make([]int, 10) for i := 1; i <= 10; i++ { indx := i - 1 operatorOutput[indx] = big.NewInt((int64(i))) circuitQueryHash[indx] = big.NewInt(int64(i * 100)) - enabled[indx] = true + valueArrSize[indx] = 1 if i > 5 { operatorOutput[indx] = big.NewInt(0) circuitQueryHash[indx] = big.NewInt(0) - enabled[indx] = false + valueArrSize[indx] = 0 } } @@ -111,7 +101,6 @@ func TestLinkedMultiQueryPubSignals_CircuitUnmarshal(t *testing.T) { Merklized: 1, OperatorOutput: operatorOutput, CircuitQueryHash: circuitQueryHash, - Enabled: enabled, } jsonOut, err := json.Marshal(out) diff --git a/query.go b/query.go index 372f84e..36b4d7a 100644 --- a/query.go +++ b/query.go @@ -19,24 +19,28 @@ const ( LTE GTE BETWEEN + NONBETWEEN + EXISTS SD = 16 NULLIFY = 17 ) // QueryOperators represents operators for atomic circuits var QueryOperators = map[string]int{ - "$noop": NOOP, - "$eq": EQ, - "$lt": LT, - "$gt": GT, - "$in": IN, - "$nin": NIN, - "$ne": NE, - "$lte": LTE, - "$gte": GTE, - "$between": BETWEEN, - "$sd": SD, - "$nullify": NULLIFY, + "$noop": NOOP, + "$eq": EQ, + "$lt": LT, + "$gt": GT, + "$in": IN, + "$nin": NIN, + "$ne": NE, + "$lte": LTE, + "$gte": GTE, + "$between": BETWEEN, + "$nonbetween": NONBETWEEN, + "$exists": EXISTS, + "$sd": SD, + "$nullify": NULLIFY, } // Comparer value. @@ -118,6 +122,14 @@ func (v *Vector) Compare(t int) (bool, error) { return true, nil } return false, nil + case NONBETWEEN: + if len(v.y) < 2 { + return false, nil + } + if !(v.x.Cmp(v.y[0]) >= 0 && v.x.Cmp(v.y[1]) <= 0) { + return true, nil + } + return false, nil } return false, errors.New("unknown compare type for vector") } @@ -147,6 +159,41 @@ type Query struct { ValueProof *ValueProof } +// Validate value size for operator +func (q Query) ValidateValueArraySize(maxArrSize int) error { + oneArrLengthOps := []int{EQ, LT, GT, NE, LTE, GTE, EXISTS} + twoArrLengthOps := []int{BETWEEN, NONBETWEEN} + maxArrLengthOps := []int{IN, NIN} + + arrSize := len(q.Values) + if contains(oneArrLengthOps, q.Operator) { + if arrSize != 1 { + return errors.New(ErrorInvalidValuesArrSize) + } else { + return nil + } + } + if contains(twoArrLengthOps, q.Operator) { + if arrSize != 2 { + return errors.New(ErrorInvalidValuesArrSize) + } else { + return nil + } + } + if contains(maxArrLengthOps, q.Operator) { + if arrSize == 0 || arrSize > maxArrSize { + return errors.New(ErrorInvalidValuesArrSize) + } else { + return nil + } + } + + if arrSize != 0 { + return errors.New(ErrorInvalidValuesArrSize) + } + return nil +} + func (q Query) validate() error { for i := range q.Values { if q.Values[i] == nil { diff --git a/query_test.go b/query_test.go index 5884c88..81b137b 100644 --- a/query_test.go +++ b/query_test.go @@ -199,7 +199,7 @@ func TestVectorCompare(t *testing.T) { name: "testing unknown operator", x: big.NewInt(0), y: []*big.Int{big.NewInt(1), big.NewInt(10), big.NewInt(100)}, - operator: 10, // unknown operator. + operator: 12, // unknown operator. expected: false, withErr: true, }, diff --git a/testdata/V3_mtp_inputs.json b/testdata/V3_mtp_inputs.json index 8c7f5f5..ba22201 100644 --- a/testdata/V3_mtp_inputs.json +++ b/testdata/V3_mtp_inputs.json @@ -160,7 +160,6 @@ "issuerAuthRootsTreeRoot": "0", "issuerAuthState": "0", "isRevocationChecked": 1, - "claimPathNotExists": 1, "claimPathMtp": [ "0", "0", @@ -269,6 +268,7 @@ "0", "0" ], + "valueArraySize": 1, "issuerClaimMtp": [ "0", "10304430946970870697981400054531724100803206948489006715521525892274350097449", diff --git a/testdata/V3_sig_inputs.json b/testdata/V3_sig_inputs.json index 3facff0..5a155bd 100644 --- a/testdata/V3_sig_inputs.json +++ b/testdata/V3_sig_inputs.json @@ -169,7 +169,6 @@ "issuerAuthRootsTreeRoot": "0", "issuerAuthState": "20177832565449474772630743317224985532862797657496372535616634430055981993180", "isRevocationChecked": 1, - "claimPathNotExists": 1, "claimPathMtp": [ "0", "0", @@ -320,6 +319,7 @@ "0", "0" ], + "valueArraySize": 1, "issuerClaimClaimsTreeRoot": "0", "issuerClaimRevTreeRoot": "0", "issuerClaimRootsTreeRoot": "0", diff --git a/testdata/linkedMultiQuery_inputs.json b/testdata/linkedMultiQuery_inputs.json index f0e4e9a..2c2e14d 100644 --- a/testdata/linkedMultiQuery_inputs.json +++ b/testdata/linkedMultiQuery_inputs.json @@ -10,7 +10,7 @@ "0", "0" ], - "enabled": [ + "valueArraySize": [ 1, 1, 1, @@ -23,18 +23,6 @@ 0 ], "claimSchema": "180410020913331409885634153623124536270", - "claimPathNotExists": [ - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], "claimPathMtp": [ [ "0", diff --git a/testdata/onchain_V3_mtp_inputs.json b/testdata/onchain_V3_mtp_inputs.json index af306b9..d9cdcff 100644 --- a/testdata/onchain_V3_mtp_inputs.json +++ b/testdata/onchain_V3_mtp_inputs.json @@ -111,7 +111,6 @@ "issuerClaimNonRevMtpNoAux": "1", "isRevocationChecked": 1, "claimSchema": "180410020913331409885634153623124536270", - "claimPathNotExists": 1, "claimPathMtp": [ "0", "0", @@ -491,8 +490,9 @@ "0", "0" ], + "valueArraySize": 1, "linkNonce": "0", "verifierID": "21929109382993718606847853573861987353620810345503358891473103689157378049", "nullifierSessionID": "32", - "authEnabled": "1" + "isBJJAuthEnabled": "1" } diff --git a/testdata/onchain_V3_sig_inputs.json b/testdata/onchain_V3_sig_inputs.json index c245055..c77e521 100755 --- a/testdata/onchain_V3_sig_inputs.json +++ b/testdata/onchain_V3_sig_inputs.json @@ -169,7 +169,6 @@ "issuerAuthRootsTreeRoot": "0", "issuerAuthState": "20177832565449474772630743317224985532862797657496372535616634430055981993180", "isRevocationChecked": 1, - "claimPathNotExists": 1, "claimPathMtp": [ "0", "0", @@ -496,6 +495,7 @@ "0", "0" ], + "valueArraySize": 1, "issuerClaimClaimsTreeRoot": "0", "issuerClaimRevTreeRoot": "0", "issuerClaimRootsTreeRoot": "0", @@ -503,5 +503,5 @@ "linkNonce": "0", "verifierID": "21929109382993718606847853573861987353620810345503358891473103689157378049", "nullifierSessionID": "32", - "authEnabled": "1" + "isBJJAuthEnabled": "1" } diff --git a/utils.go b/utils.go index 4870f91..f65ec7a 100644 --- a/utils.go +++ b/utils.go @@ -212,3 +212,12 @@ func PoseidonHashValue(values []*big.Int) (*big.Int, error) { } return fullHash, nil } + +func contains(s []int, e int) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +}