Skip to content

Commit

Permalink
Fix auth claim revocation status check
Browse files Browse the repository at this point in the history
  • Loading branch information
olomix committed Jan 24, 2024
1 parent c5028a2 commit 52e3f8d
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 40 deletions.
97 changes: 59 additions & 38 deletions verifiable/credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,7 @@ func (vc *W3CCredential) VerifyProof(ctx context.Context, proofType ProofType,
o(&verifyConfig)
}

var (
credProof CredentialProof
coreClaim *core.Claim
)
var credProof CredentialProof
for _, p := range vc.Proof {
if p.ProofType() == proofType {
credProof = p
Expand All @@ -63,23 +60,18 @@ func (vc *W3CCredential) VerifyProof(ctx context.Context, proofType ProofType,
return errors.New("can't get core claim")
}

var credProofBytes []byte
credProofBytes, err = json.Marshal(credProof)
if err != nil {
return err
}
switch proofType {
case BJJSignatureProofType:
var proof BJJSignatureProof2021
err = json.Unmarshal(credProofBytes, &proof)
err = remarshalObj(&proof, credProof)
if err != nil {
return err
}
return verifyBJJSignatureProof(ctx, proof, coreClaim, didResolver,
verifyConfig)
case Iden3SparseMerkleTreeProofType:
var proof Iden3SparseMerkleTreeProof
err = json.Unmarshal(credProofBytes, &proof)
err = remarshalObj(&proof, credProof)
if err != nil {
return err
}
Expand All @@ -94,40 +86,23 @@ func verifyBJJSignatureProof(ctx context.Context, proof BJJSignatureProof2021,
coreClaim *core.Claim, didResolver DIDResolver,
verifyConfig w3CProofVerificationConfig) error {

// issuer claim
authClaim := &core.Claim{}
err := authClaim.FromHex(proof.IssuerData.AuthCoreClaim)
// issuer's claim with public key
authClaim, err := proof.IssuerData.authClaim()
if err != nil {
return err
}

rawSlotInts := authClaim.RawSlotsAsInts()
var publicKey babyjub.PublicKey
publicKey.X = rawSlotInts[2] // Ax should be in indexSlotA
publicKey.Y = rawSlotInts[3] // Ay should be in indexSlotB

// core claim's signature
sig, err := bjjSignatureFromHexString(proof.Signature)
if err != nil || sig == nil {
return err
}

// core claim hash
hi, hv, err := coreClaim.HiHv()
if err != nil {
return err
}

claimHash, err := poseidon.Hash([]*big.Int{hi, hv})
err = verifyClaimSignature(coreClaim, sig, authClaim)
if err != nil {
return err
}

valid := publicKey.VerifyPoseidon(claimHash, sig)

if !valid {
return err
}

issuerDID, err := w3c.ParseDID(proof.IssuerData.ID)
if err != nil {
return err
Expand Down Expand Up @@ -169,19 +144,65 @@ func verifyBJJSignatureProof(ctx context.Context, proof BJJSignatureProof2021,
}
}

credStatus, err := coerceCredentialStatus(proof.IssuerData.CredentialStatus)
err = validateAuthClaimRevocation(ctx, proof.IssuerData,
verifyConfig.credStatusValidationOpts...)
if err != nil {
return err
}

if credStatus.RevocationNonce != coreClaim.GetRevocationNonce() {
return errors.New("revocation nonce mismatch: credential revocation " +
"nonce != proof claim revocation nonce")
return err
}

func verifyClaimSignature(claim *core.Claim, sig *babyjub.Signature,
authClaim *core.Claim) error {

publicKey := publicKeyFromClaim(authClaim)

// core claim hash
hi, hv, err := claim.HiHv()
if err != nil {
return err
}

_, err = ValidateCredentialStatus(ctx, *credStatus,
verifyConfig.credStatusValidationOpts...)
claimHash, err := poseidon.Hash([]*big.Int{hi, hv})
if err != nil {
return err
}

valid := publicKey.VerifyPoseidon(claimHash, sig)
if !valid {
return errors.New("claim signature validation failed")
}
return nil
}

func publicKeyFromClaim(claim *core.Claim) *babyjub.PublicKey {
rawSlotInts := claim.RawSlotsAsInts()
var publicKey babyjub.PublicKey
publicKey.X = rawSlotInts[2] // Ax should be in indexSlotA
publicKey.Y = rawSlotInts[3] // Ay should be in indexSlotB
return &publicKey
}

func validateAuthClaimRevocation(ctx context.Context, issuerData IssuerData,
opts ...CredentialStatusValidationOption) error {
credStatus, err := coerceCredentialStatus(issuerData.CredentialStatus)
if err != nil {
return err
}

authClaim, err := issuerData.authClaim()
if err != nil {
return err
}

if credStatus.RevocationNonce != authClaim.GetRevocationNonce() {
return fmt.Errorf("revocation nonce mismatch: credential revocation "+
"nonce (%v) != auth claim revocation nonce (%v)",
credStatus.RevocationNonce, authClaim.GetRevocationNonce())
}

_, err = ValidateCredentialStatus(ctx, *credStatus, opts...)
return err
}

Expand Down
4 changes: 2 additions & 2 deletions verifiable/credential_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -470,8 +470,8 @@ func TestW3CCredential_ValidateBJJSignatureProofIssuerStatus(t *testing.T) {

defer tst.MockHTTPClient(t,
map[string]string{
"http://my-universal-resolver/1.0/identifiers/did%3Apolygonid%3Apolygon%3Amumbai%3A2qNuE5Jxmvrx6EithQ5bMs4DcWN91SjxepUzdQtddn?state=95e4f8437be5d50a569bb532713110e4f5d2ac97765fae54041dddae9638a119": `./testdata/verifycred//my-universal-resolver-5.json`,
"http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qNuE5Jxmvrx6EithQ5bMs4DcWN91SjxepUzdQtddn/claims/revocation/status/0": `./testdata/verifycred//issuer-state-response.json`,
"http://my-universal-resolver/1.0/identifiers/did%3Apolygonid%3Apolygon%3Amumbai%3A2qNuE5Jxmvrx6EithQ5bMs4DcWN91SjxepUzdQtddn?state=95e4f8437be5d50a569bb532713110e4f5d2ac97765fae54041dddae9638a119": `./testdata/verifycred/my-universal-resolver-5.json`,
"http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qNuE5Jxmvrx6EithQ5bMs4DcWN91SjxepUzdQtddn/claims/revocation/status/0": `./testdata/verifycred/issuer-state-response.json`,
})()

resolverRegisty := CredentialStatusResolverRegistry{}
Expand Down
5 changes: 5 additions & 0 deletions verifiable/proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ type IssuerData struct {
CredentialStatus interface{} `json:"credentialStatus,omitempty"`
}

func (id *IssuerData) authClaim() (*core.Claim, error) {
var claim core.Claim
return &claim, claim.FromHex(id.AuthCoreClaim)
}

// State represents the state of the issuer
type State struct {
TxID *string `json:"txId,omitempty"`
Expand Down

0 comments on commit 52e3f8d

Please sign in to comment.