-
Notifications
You must be signed in to change notification settings - Fork 0
support td1 #37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ilya-korotya
wants to merge
12
commits into
main
Choose a base branch
from
feature/circuit-for-id-card
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
support td1 #37
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
35115e0
support td1
ilya-korotya 10b741c
update pipeline actions; use yarn
ilya-korotya dc78d35
use pnpm instead of yarn
ilya-korotya 7474de0
remove unused deps
ilya-korotya f5fba12
try to use yarn instead of pnpm
ilya-korotya a8ee2b0
revert pnpm
ilya-korotya 6db6947
clean install
ilya-korotya bf22769
build idcard circuits
ilya-korotya 3c03540
fix type in credential integration tests
ilya-korotya 9fe6d98
use gitmodules instead of node_modules from self
ilya-korotya 4558c78
add new artifacts
ilya-korotya 30e05de
remove packageManager from package.json
ilya-korotya File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| pragma circom 2.1.9; | ||
|
|
||
| // dg1TagSize size of tag before dg1 content | ||
| function dg1TagSize() { | ||
| return 5; | ||
| } | ||
|
|
||
| // Document code: Line 1, Position 1, Size 2 (0-indexed: 0) | ||
| function documentCodePosition() { | ||
| return 0 + dg1TagSize(); | ||
| } | ||
| function documentCodeSize() { | ||
| return 2; | ||
| } | ||
|
|
||
| // Issuing State or organization: Line 1, Position 3, Size 3 (0-indexed: 2) | ||
| function issuingStatePosition() { | ||
| return 2 + dg1TagSize(); | ||
| } | ||
| function issuingStateSize() { | ||
| return 3; | ||
| } | ||
|
|
||
| // Document number: Line 1, Position 6, Size 9 (0-indexed: 5) | ||
| function documentNumberPosition() { | ||
| return 5 + dg1TagSize(); | ||
| } | ||
| function documentNumberSize() { | ||
| return 9; | ||
| } | ||
|
|
||
| // DOB: Line 2, Position 1, Size 6 (0-indexed: 30 in concatenated) | ||
| function dobPosition() { | ||
| return 30 + dg1TagSize(); | ||
| } | ||
| function dobSize() { | ||
| return 6; | ||
| } | ||
|
|
||
| // Sex: Line 2, Position 8, Size 1 (0-indexed: 37 in concatenated) | ||
| function sexPosition() { | ||
| return 37 + dg1TagSize(); | ||
| } | ||
| function sexSize() { | ||
| return 1; | ||
| } | ||
|
|
||
| // Date of expiry: Line 2, Position 9, Size 6 (0-indexed: 38 in concatenated) | ||
| function dateOfExpiryPosition() { | ||
| return 38 + dg1TagSize(); | ||
| } | ||
| function dateOfExpirySize() { | ||
| return 6; | ||
| } | ||
|
|
||
| // Nationality: Line 2, Position 16, Size 3 (0-indexed: 45 in concatenated) | ||
| function nationalityPosition() { | ||
| return 45 + dg1TagSize(); | ||
| } | ||
| function nationalitySize() { | ||
| return 3; | ||
| } | ||
|
|
||
| // Name of holder: Line 3, Size 30 (0-indexed: 60 in concatenated) | ||
| function nameOfHolderPosition() { | ||
| return 60 + dg1TagSize(); | ||
| } | ||
| function nameOfHolderSize() { | ||
| return 30; // Holder size for TD1 | ||
| } | ||
|
|
||
| function getMaxDSCLength(){ | ||
| return 1792; | ||
| } | ||
|
|
||
| // Symbol '<' in ASCII encoding | ||
| function dg1DelimiterSymbol() { | ||
| return 60; // < | ||
| } | ||
|
|
||
| // Symbol ' ' (space) in ASCII encoding | ||
| function spaceSymbol() { | ||
| return 32; | ||
| } | ||
|
|
||
| // Size of DG1 (with tag) - TD1 has 90 characters + 5 tag bytes | ||
| function DG1_TD1_SIZE() { | ||
| return 95; | ||
| } | ||
|
|
||
| // Max chunks bytes for Poseidon chunk | ||
| function chunkSize() { | ||
| return 31; | ||
| } | ||
|
|
||
| // Max Poseidon chunks | ||
| function chunkCount() { | ||
| return 16; | ||
| } | ||
|
|
||
| // Max Poseidon message size | ||
| function messageMaxSize() { | ||
| return chunkSize() * chunkCount(); | ||
| } | ||
|
|
||
| // Part of hashIndex. V0 | ||
| function v0() { | ||
| return 14586288774771787882356214884390414373502; | ||
| } | ||
|
|
||
| function DG1_TD1_SIZE_BITS() { | ||
| return DG1_TD1_SIZE() * 8; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,216 @@ | ||
| pragma circom 2.1.9; | ||
|
|
||
| include "./constants.circom"; | ||
|
|
||
| include "../utils/iden3/claimbuilder.circom"; | ||
| include "../utils/iden3/linkId.circom"; | ||
| include "../utils/iden3/poseidon.circom"; | ||
| include "../utils/iden3/constants.circom"; | ||
| include "../utils/iden3/numbers.circom"; | ||
| include "../utils/iden3/strings.circom"; | ||
| include "../utils/passport/parser/extractors.circom"; | ||
| include "../utils/passport/date/dateDiffGreaterThanYear.circom"; | ||
|
|
||
| include "circuits/circuits/utils/crypto/bitify/bytes.circom"; // from self | ||
| include "circuits/circuits/utils/crypto/hasher/hash.circom"; // from self | ||
| include "@openpassport/zk-email-circuits/utils/array.circom"; | ||
| include "circomlib/circuits/poseidon.circom"; | ||
|
|
||
| template Integrity(hashAlgo) { | ||
| signal input dg1[DG1_TD1_SIZE()]; | ||
| signal output poseidonDg1Hash; | ||
|
|
||
| var hashAlgBytesSize = hashAlgo / 8; | ||
| signal dg1Bits[DG1_TD1_SIZE_BITS()] <== BytesToBitsArray(DG1_TD1_SIZE())(dg1); | ||
| signal dg1ShaBits[hashAlgo] <== ShaHashBits(DG1_TD1_SIZE_BITS(), hashAlgo)(dg1Bits); | ||
|
|
||
| signal dg1ShaBytes[hashAlgBytesSize]; | ||
| dg1ShaBytes <== BitsToBytesArray(hashAlgo)(dg1ShaBits); | ||
| poseidonDg1Hash <== PaddingAndPoseidon(hashAlgBytesSize)(dg1ShaBytes); | ||
| } | ||
|
|
||
| template ValidateHolderNameSizeInput() { | ||
| signal input dg1[DG1_TD1_SIZE()]; | ||
| signal input holderNameSize; | ||
|
|
||
| component rawNameOfHolder = SelectSubArray(DG1_TD1_SIZE(), nameOfHolderSize()); | ||
| rawNameOfHolder.in <== dg1; | ||
| rawNameOfHolder.startIndex <== nameOfHolderPosition(); | ||
| rawNameOfHolder.length <== nameOfHolderSize(); | ||
|
|
||
| component originalDelimiterSize = CountTrailing(nameOfHolderSize()); | ||
| originalDelimiterSize.string <== rawNameOfHolder.out; | ||
| originalDelimiterSize.symbol <== dg1DelimiterSymbol(); | ||
| originalDelimiterSize.count + holderNameSize === nameOfHolderSize(); | ||
| } | ||
|
|
||
| /* | ||
| The template DG1FieldParser cuts fields as from DG1 (TD1 format): | ||
| 1. Document code: Line 1, Position 1, Size 2 | ||
| 2. Issuing State or organization: Line 1, Position 3, Size 3 | ||
| 3. Document number: Line 1, Position 6, Size 9 | ||
| 4. DOB: Line 2, Position 1, Size 6 | ||
| 5. Sex: Line 2, Position 8, Size 1 | ||
| 6. Date of expiry: Line 2, Position 9, Size 6 | ||
| 7. Nationality: Line 2, Position 16, Size 3 | ||
| 8. Name of holder: Line 3, Size 30 | ||
| */ | ||
| template DG1FieldParser(hashAlgo, nLevels, smtChanges) { | ||
| signal input dg1[DG1_TD1_SIZE()]; | ||
| signal input holderNameSize; | ||
|
|
||
| signal input credentialStatusID; | ||
| signal input credentialSubjectID; | ||
| signal input userID; | ||
|
|
||
| signal input linkNonce; | ||
| signal input siblings[smtChanges][nLevels]; | ||
|
|
||
| signal output hashIndex; | ||
| signal output hashValue; | ||
| signal output linkId; | ||
|
|
||
| // public inputs | ||
| signal input currentDate; // Format: YYMMDD | ||
| signal input issuanceDate; | ||
| signal input templateRoot; | ||
| signal input issuer; | ||
| signal input revocationNonce; | ||
|
|
||
| // check if currentDate exists between 0 and 1,048,575; | ||
| // to prevent pass any value between p/2 and p-1 (negative) | ||
| component currentDateFitsTo20Bits = CheckMaxBits(20); | ||
| currentDateFitsTo20Bits.inputInteger <== currentDate; | ||
|
|
||
| component documentCodeExtractor = Extractor(DG1_TD1_SIZE(), documentCodePosition(), documentCodeSize()); | ||
| documentCodeExtractor.dg1 <== dg1; | ||
| signal documentCodeHash <== documentCodeExtractor.hash; | ||
|
|
||
| component documentIssuerExtractor = Extractor(DG1_TD1_SIZE(), issuingStatePosition(), issuingStateSize()); | ||
| documentIssuerExtractor.dg1 <== dg1; | ||
| signal documentIssuerHash <== documentIssuerExtractor.hash; | ||
|
|
||
| ValidateHolderNameSizeInput()(dg1, holderNameSize); | ||
|
|
||
| component holderNameExtractor = ExtractorHolder(DG1_TD1_SIZE(), nameOfHolderSize()); | ||
| holderNameExtractor.dg1 <== dg1; | ||
| holderNameExtractor.start <== nameOfHolderPosition(); | ||
| holderNameExtractor.end <== holderNameSize; | ||
| signal holderNameHash <== holderNameExtractor.hash; | ||
|
|
||
| component documentNumberExtractor = Extractor(DG1_TD1_SIZE(), documentNumberPosition(), documentNumberSize()); | ||
| documentNumberExtractor.dg1 <== dg1; | ||
| signal documentNumberHash <== documentNumberExtractor.hash; | ||
|
|
||
| component documentNationalityExtractor = Extractor(DG1_TD1_SIZE(), nationalityPosition(), nationalitySize()); | ||
| documentNationalityExtractor.dg1 <== dg1; | ||
| signal documentNationalityHash <== documentNationalityExtractor.hash; | ||
|
|
||
| component documentDOBExtractor = ExtractorDOB(DG1_TD1_SIZE(), dobPosition(), dobSize()); | ||
| documentDOBExtractor.dg1 <== dg1; | ||
| documentDOBExtractor.currentDate <== currentDate; | ||
| signal documentDOB <== documentDOBExtractor.out; | ||
|
|
||
| component documentSexExtractor = Extractor(DG1_TD1_SIZE(), sexPosition(), sexSize()); | ||
| documentSexExtractor.dg1 <== dg1; | ||
| signal documentSexHash <== documentSexExtractor.hash; | ||
|
|
||
| component documentDOEExtractor = ExtractorDOE(DG1_TD1_SIZE(), dateOfExpiryPosition(), dateOfExpirySize()); | ||
| documentDOEExtractor.dg1 <== dg1; | ||
| documentDOEExtractor.currentDate <== currentDate; | ||
| signal documentDOE <== documentDOEExtractor.out; | ||
| signal documentDOETimestamp <== documentDOEExtractor.timestamp; | ||
|
|
||
| var keysToUpdate[smtChanges] = [ | ||
| GetDateOfBirth(), // credentialSubject.dateOfBirth | ||
| GetDocumentExpirationDate(), // credentialSubject.documentExpirationDate | ||
| GetFullName(), // credentialSubject.fullName | ||
| GetGovernmentIdentifier(), // credentialSubject.governmentIdentifier | ||
| GetGovernmentIdentifierType(), // credentialSubject.governmentIdentifierType | ||
| GetSex(), // credentialSubject.sex | ||
| GetRevocationNonce(), // credentialStatus.revocationNonce | ||
| GetCredentialStatusID(), // credentialStatus.id | ||
| GetCredentialSubjectID(), // credentialSubject.id | ||
| GetExpirationDate(), // expirationDate.id | ||
| GetIssuanceDate(), // issuanceDate.id | ||
| GetIssuer(), // issuer.id | ||
| GetDocumentNationality(), // credentialSubject.nationalities | ||
| GetDocumentIssuer() // credentialSubject.nationalities | ||
| ]; | ||
|
|
||
| // check if issuanceDate exists between 0 and int64; | ||
| // to prevent pass any value between p/2 and p-1 (negative) | ||
| component issuanceDateFitsTo64Bits = CheckMaxBits(64); | ||
| issuanceDateFitsTo64Bits.inputInteger <== issuanceDate; | ||
|
|
||
| // issuanceDate and documentDOETimestamp are in UnixTimestamp format | ||
| signal credentialExpiration <== DateDiffGreaterThanYear()(issuanceDate, documentDOETimestamp); | ||
|
|
||
|
|
||
| // For debuging mt update | ||
| /* | ||
| log(documentDOB); | ||
| log(documentDOE); // expiration date in format YYYYMMDD == passport mrz | ||
| log(holderNameHash); | ||
| log(documentNumberHash); | ||
| log(documentCodeHash); | ||
| log(documentSexHash); | ||
| log(revocationNonce); | ||
| log(credentialStatusID); | ||
| log(credentialSubjectID); | ||
| log(credentialExpiration * 1000000000); | ||
| log(issuanceDate * 1000000000); | ||
| log(issuer); | ||
| log(documentNationalityHash);*/ | ||
|
|
||
|
|
||
| var valuesToUpdate[smtChanges] = [ | ||
| documentDOB, // credentialSubject.dateOfBirth | ||
| documentDOE, // credentialSubject.documentExpirationDate | ||
| holderNameHash, // credentialSubject.fullName | ||
| documentNumberHash, // credentialSubject.govermentIdentifier | ||
| documentCodeHash, // credentialSubject.governmentIdentifierType | ||
| documentSexHash, // credentialSubject.sex | ||
| revocationNonce, // credentialStatus.revocationNonce | ||
| credentialStatusID, // credentialStatus.id | ||
| credentialSubjectID, // credentialSubject.id | ||
| credentialExpiration * 1000000000, // expirationDate.id | ||
| issuanceDate * 1000000000, // issuanceDate.id | ||
| issuer, // issuer.id | ||
| documentNationalityHash, // credentialSubject.nationalities | ||
| documentIssuerHash // credentialSubject.nationalities | ||
| ]; | ||
|
|
||
| component c = ClaimRootBuilder(nLevels, smtChanges); | ||
| c.templateRoot <== templateRoot; | ||
| c.siblings <== siblings; | ||
| c.keys <== keysToUpdate; | ||
| c.values <== valuesToUpdate; | ||
|
|
||
| // For debuging mt root | ||
| // log(c.newRoot); | ||
|
|
||
| // The value was calculated using the go-iden3-core library | ||
| var i0 = v0(); | ||
| component hI = Poseidon(4); | ||
| hI.inputs[0] <== i0; | ||
| hI.inputs[1] <== userID; | ||
| hI.inputs[2] <== c.newRoot; | ||
| hI.inputs[3] <== 0; | ||
|
|
||
| component V0Calc = V0Calculator(); | ||
| V0Calc.revocation <== revocationNonce; | ||
| V0Calc.expiration <== credentialExpiration; | ||
|
|
||
| component hV = Poseidon(4); | ||
| hV.inputs[0] <== V0Calc.out; | ||
| hV.inputs[1] <== 0; | ||
| hV.inputs[2] <== 0; | ||
| hV.inputs[3] <== 0; | ||
|
|
||
| hashIndex <== hI.out; | ||
| hashValue <== hV.out; | ||
|
|
||
| signal poseidonDg1Hash <== Integrity(hashAlgo)(dg1); | ||
| linkId <== LinkID()(poseidonDg1Hash, linkNonce); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| pragma circom 2.1.9; | ||
|
|
||
| include "../idcard.circom"; | ||
|
|
||
| component main { public [currentDate, issuanceDate, templateRoot, issuer, revocationNonce] } = DG1FieldParser(160, 8, 14); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| pragma circom 2.1.9; | ||
|
|
||
| include "../idcard.circom"; | ||
|
|
||
| component main { public [currentDate, issuanceDate, templateRoot, issuer, revocationNonce] } = DG1FieldParser(224, 8, 14); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| pragma circom 2.1.9; | ||
|
|
||
| include "../idcard.circom"; | ||
|
|
||
| component main { public [currentDate, issuanceDate, templateRoot, issuer, revocationNonce] } = DG1FieldParser(256, 8, 14); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.