Skip to content

refactor: update RS256 circuit to enhance certificate verification#10

Open
vivianjeng wants to merge 6 commits intomainfrom
issuer-signature-smt
Open

refactor: update RS256 circuit to enhance certificate verification#10
vivianjeng wants to merge 6 commits intomainfrom
issuer-signature-smt

Conversation

@vivianjeng
Copy link
Member

@vivianjeng vivianjeng commented Mar 22, 2026

  • Changed the template name from CertRSA256VerifyWithRevocation to FullCertRSA256VerifyWithRevocation to reflect the expanded functionality.
  • Updated parameters to include a 2048-bit RSA key size and modified public input names for clarity.
  • Added utility functions for SHA256 padding verification and index selection.
  • Integrated issuer signature verification logic into the RS256 circuit implementation.
  • Introduced a new utility file for shared functions used across circuits.
  • Updated main circuit file to utilize the new template and adjusted public inputs accordingly.

Description

Certificate Chain Structure

┌─────────────────────────────────────────────────────┐
│                   Issuer CA cert                     │
│  ┌─────────────────────────────────────────────┐    │
│  │           issuer TBS (925 bytes)             │    │
│  │  - issuer info, validity, subject            │    │
│  │  - issuer public key (issuer_rsa_modulus)    │    │
│  └─────────────────────────────────────────────┘    │
│  signatureAlgorithm                                  │
│  issuer_rsa_signature  ← signed by Root CA          │
└─────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────┐
│                   User cert (full DER)               │
│  ┌─────────────────────────────────────────────┐    │
│  │           user TBS (929 bytes)               │    │
│  │  - issuer info, validity, subject            │    │
│  │  - user public key  ← extract this           │    │
│  │  - serialNumber     ← check revocation       │    │
│  └─────────────────────────────────────────────┘    │
│  signatureAlgorithm                                  │
│  issuer_rsa_signature  ← signed by Issuer CA        │
└─────────────────────────────────────────────────────┘

1. VerifyTBSinCert — Bind full cert to issuer TBS

user_cert_zero_padded:  [48,130,4,181, 48,130,3,157, m2, m3 ...]
                         ^^ 4B header ^ ^^ issuer TBS embedded here ^^

issuer_tbs:                            [48,130,3,157, m2, m3 ...]

proves: user_cert_zero_padded[4 .. 4+actual_issuer_tbs_length]
             ==
        issuer_tbs[0 .. actual_issuer_tbs_length]

Why: Proves the issuer_tbs signal is genuinely the TBS portion of the full user cert — not some attacker-supplied fake.

2. ExtractModulus — Pull user's public key from full cert

user_cert_zero_padded (full DER):
[... TBSCertificate > SubjectPublicKeyInfo > BIT STRING > SEQUENCE > INTEGER > modulus_bytes ...]
                                                                                ^^^^^^^^^^^^^
                                                                     at user_modulus_offset

proves: bytes at user_modulus_offset with 0x02 tag at user_modulus_tag_offset
      = user_rsa_extracted_modulus

Why: Extracts the user's RSA public key from the raw cert bytes. Offset hints are supplied by prover (Rust parse_cert_offsets) and verified in-circuit by checking the ASN.1 tag byte.


3. First CertRSA256Verify — Verify user cert's own signature

Input:  tbs[]                    (user TBS, sha256-padded)
        tbs_length               (960, padded length)
        user_rsa_extracted_modulus (user pubkey, just extracted above)
        user_rsa_signature        (from user_circuit_input)

proves: RSA_verify(
            user_rsa_extracted_modulus,
            SHA256(tbs[0..tbs_length]),
            user_rsa_signature
        ) == true

Why: Confirms the extracted modulus is correct — if ExtractModulus returned wrong bytes, this RSA verify would fail. Also confirms the user TBS is well-formed.


4. Second CertRSA256Verify — Verify issuer signed user cert

Input:  issuer_tbs[]             (issuer TBS, sha256-padded)
        issuer_tbs_length        (960, padded length)
        issuer_rsa_modulus       (issuer pubkey, trusted public input)
        issuer_rsa_signature     (signature from full user cert)

proves: RSA_verify(
            issuer_rsa_modulus,
            SHA256(issuer_tbs[0..issuer_tbs_length]),
            issuer_rsa_signature
        ) == true

Why: The core chain verification — proves the Issuer CA actually signed this user certificate.


5. SMTNonMembershipVerifier — Check not revoked

proves: serialNumber ∉ SMT revocation tree
      = certificate is still valid, not revoked

Full Proof Statement

This proof shows:
  1. user_cert_zero_padded contains issuer_tbs at offset 4        (VerifyTBSinCert)
  2. user_rsa_extracted_modulus is the pubkey inside user_cert     (ExtractModulus)
  3. user_rsa_extracted_modulus correctly verifies user TBS        (CertRSA256Verify #1)
  4. issuer_rsa_modulus correctly verifies issuer_tbs              (CertRSA256Verify #2)
  5. serialNumber is not in the revocation tree                    (SMTNonMembershipVerifier)

Therefore: the user certificate was legitimately issued by the
trusted Issuer CA and has not been revoked.

Related Issue(s)

Other information

Checklist

  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Important

We do not accept pull requests for minor grammatical fixes (e.g., correcting typos, rewording sentences) or for fixing broken links, unless they significantly improve clarity or functionality. These contributions, while appreciated, are not a priority for merging. If you notice any of these issues, please create a GitHub Issue to report them so they can be properly tracked and addressed.

- Changed the template name from `CertRSA256VerifyWithRevocation` to `FullCertRSA256VerifyWithRevocation` to reflect the expanded functionality.
- Updated parameters to include a 2048-bit RSA key size and modified public input names for clarity.
- Added utility functions for SHA256 padding verification and index selection.
- Integrated issuer signature verification logic into the RS256 circuit implementation.
- Introduced a new utility file for shared functions used across circuits.
- Updated main circuit file to utilize the new template and adjusted public inputs accordingly.
- Removed zero-padded TBS input and actual TBS length parameters.
- Added zero-padded user certificate input and actual user certificate length parameters for enhanced clarity and functionality.
- Adjusted SHA256 padding verification to utilize the new user certificate inputs.
…TBS verification

- Introduced new signals for issuer TBS length and user modulus offsets in the RS256 circuit.
- Replaced SHA256 padding verification with a new TBS verification method to ensure accurate certificate validation.
- Added a utility function to extract the RSA modulus from DER-encoded certificates, improving clarity and functionality.
- Updated the circuit input structure to accommodate the new parameters for better handling of user certificates.
- Eliminated the user RSA modulus input from the FullCertRSA256VerifyWithRevocation template and the Rs256Circuit implementation for improved clarity.
- Adjusted related input structures to streamline user certificate handling and maintain consistency across the circuit.
- Expanded the input JSON for RS256 to include detailed issuer RSA modulus, signature, and certificate parameters for enhanced clarity and functionality.
- Commented out unused certificate parsing logic in the RS256 circuit implementation to streamline the code and improve maintainability.
- Adjusted the structure to better accommodate the new input parameters, ensuring consistency across the circuit.
…handling

- Renamed and adjusted input signals in the RS256 circuit to replace user certificate references with issuer TBS parameters for improved clarity.
- Updated the input JSON structure to include the actual issuer TBS length and issuer TBS data, enhancing the overall functionality and consistency of the circuit.
- Streamlined the circuit implementation to ensure accurate verification processes with the new issuer-related inputs.
@vivianjeng
Copy link
Member Author

vivianjeng commented Mar 23, 2026

Planned

  • Extract serialNumber from user_cert_zero_padded in-circuit (currently supplied as public input)
  • Expose user TBS hash as a public output
  • Extract Subject DN bytes from user_cert_zero_padded in-circuit using offset hints (same pattern as -ExtractModulus)
  • Compute hash(Subject DN) as a nullifier public output — links identity across proofs without revealing the DN itself

@vivianjeng vivianjeng marked this pull request as ready for review March 23, 2026 03:09
This was referenced Mar 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant