Brazilian "SSN" (CPF) and "EIN" (CNPJ) generator in Ruby
In this post I used two official documents of Brazil's government called CPF which is the equivalent of the Social Security Number in the USA (SSN) and another one called CNPJ that would be the Employer Identification Number in the USA (EIN).
I always had a certain curiosity about how numbers of official documents (social security number, credit cards, etc) are generated. Certainly they're not just randomly chosen numbers and must follow a determined logic during its generation, otherwise they wouldn't be valid numbers. It happens that for every number that is used there is a calculation behind it which the result will determine the document validity. There are several websites that offers this kind of service in a easy way, not just for one document.
Here I'll show you the algorithm of CPF/CNPJ generation and its implementations which are very similar. Both were wrote in Ruby.
Well, I coded two very simple scripts following just what came in my mind at the moment. Therefore, I have no idea if the algorithm it's implemented in the most efficient way (most certainly it isn't). Once said that the implementation are similar so will be the scripts.
CPF
This is the algorithm for the generation of a CPF valid number:
To exemplify the process let's generate a valid CPF calculating the verification digits of a hypothetical number, 111.444.777-XX.
Calculation the First Verification Digit
The CPF first verification digit is calculated utilizing the following algorithm.
1) Distribute the 9 first digits on a frame puting the values 10, 9, 8, 7, 6, 5, 4, 3, 2 beneath the hypothetical number from the left to the right, according to the representation below:
1 1 1 4 4 4 7 7 7 10 9 8 7 6 5 4 3 2 2) Multiply the values of all the columns:
1 1 1 4 4 4 7 7 7 10 9 8 7 6 5 4 3 2 10 9 8 28 24 20 28 21 14 3) Calculate the sum of the results (10+9+...+21+14) = 162
4) The result obtained (162) will be divided by 11. Consider as quotient just the integer value, the rest of the division will be responsible by the calculation of the first verification digit.
Let's keep up with this: 162 divided by 11 we obtained 14 as quotient and 8 as the rest of the division. If the rest of the division is less than 2, our first verification digit will be 0 (zero), otherwise we subtract the quotient from 11 which is our case. Thus, our first verification digit is 11-8 that is 3. So we got a part of our CPF: 111.444.777-3X.
Calculating the Second Verification Digit
1) For the calculation of the second verification digit it will be used the first verification digit that we already calculated. We'll construct a table similar ot the previous one but this time we'll use on the second line the values 11, 10, 9, 8, 7, 6, 5, 4, 3, 2 once we're incorporating one more digit for this calculation.
1 1 1 4 4 4 7 7 7 3 11 10 9 8 7 6 5 4 3 2 2) On the next step we'll do the same thing we did for the first digit which is multiply the values of all the columns of the table and perform the sum of the results: (11+10+...+21+6) = 204.
1 1 1 4 4 4 7 7 7 3 11 10 9 8 7 6 5 4 3 2 11 10 9 32 28 24 35 28 21 6 3) We again calculate the module of 11, divide the sum by 11 and consider the rest of the division.
Let's keep up with this: 204 divided by 11 we obtained 18 as quotient and 6 as the rest of the division.
4) If the value of the rest of the division is less than 2, this value becomes automatically 0 (zero), otherwise it is necessary to subtract the obtained value by 11 for obtain the verification digit. Therefore, 11-6 = 5, which is our verification digit.
In this case we were able to reach the end of the calculation and we discovered that the two verification digits of our hypothetical CPF are 3 and 5. Thus our CPF would like this: 111.444.777.35.
The Ruby script for the generation would be like this:
1 def cpf 2 basenum = [] 3 9.times { basenum << rand(10) } 4 5 pesos = Array(2..10).reverse 7 8 n = (0...basenum.length).inject(0) { |a, b| a + basenum[b] * pesos[b] } 9 10 dv1 = if n%11 < 2; 0; 11 else; 11-(n%11); end 12 13 basenum << dv1 14 15 pesos.unshift(11) 16 n2 = (0...basenum.length).inject(0) { |r, i| r + basenum[i] * pesos[i] } 17 dv2 = if n2%11 < 2; 0; 18 else; 11-(n2%11); end 19 cpf = basenum << dv2 20 21 return cpf.inspect 22 end 23 24 cpf
CNPJ
And this is the algorithm for generation of a CNPJ valid number:
The CNPJ is composed by fourteen digits divided in three blocks:
- the first one that represents the subscription number itself;
- the second one located after the slash which represents an unique code for the matrix or a subsidiary;
- the third represented by the two last digits are called the verification digits
The verification digits are created from the twelve first digits. The calculation is performed in two steps using the module of 11.
To exemplify the process and become easier the explanation we'll calculate the verifications digits of a hypothetical CNPJ. For example, 11.444.777/0001-XX.
Calculating the First Verification Digit
The first digit is calculated using the following algorithm.
1) Distribute the 12 first digits on a frame puting the values 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 beneath from the left to the right as it's shown below:
1 1 4 4 4 7 7 7 0 0 0 1 5 4 3 2 9 8 7 6 5 4 3 2 2) Multiply the values of each one of the columns:
1 1 4 4 4 7 7 7 0 0 0 1 5 4 3 2 9 8 7 6 5 4 3 2 5 4 12 8 36 56 49 42 0 0 0 2 3) Calculate the sum of the results (5+4+...+0+2) = 214
4) The result obtained (214) will be divided by 11. Consider as quotient just the integer value and the rest of the division will be responsible for the calculation of the first verification digit.
Let's keep up with this: 214 divided by 11 we obtained 19 as quotient and 5 as the rest of the division. If the rest of the division is less than 2, our first verification digit is gonna be 0 (zero), otherwise it is necessary to subtract the value from 11 which is our case. Thus, our verification digit is 11-5 = 6. So we got the first verification digit and our CNPJ is currently like this: 11.444.777/0001-6X.
Calculating the Second Verification Digit
1) For the calculation of the second verification digit we'll use the first verification digit already obtained. We are gonna construct a table similar to the previous one but we'll use on the second line these values: 6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 once we are incorporating one more digit for this calculation.
1 1 4 4 4 7 7 7 0 0 0 1 6 6 5 4 3 2 9 8 7 6 5 4 3 2 2) On the next step we will do the same process as in the first verification digit calculation and multiply the values of each one of the columns and sum the obtained results: (6+5+...+3+12) = 221.
1 1 4 4 4 7 7 7 0 0 0 1 6 6 5 4 3 2 9 8 7 6 5 4 3 2 6 5 16 12 8 63 56 49 0 0 0 3 12 3) We again calculate the module of 11, divide the sum of the results by 11 and we consider the rest of the division.
Let's keep this up: 230 divided by 11 we obtained 20 as the quotient and 10 as the rest of the division.
4) If the value of the rest of the division is less than 2 it automatically becomes 0 (zero), otherwise (which is our case) it is necessary to subtract the obtained value from 11 in order to obtain the verification digit as we did on the first digit calculation. Therefore 11-10 = 1 which is our second verification digit.
We reached at the final of our calculation and we discovered both the verification digits of our hypothetical CNPJ number which are 6 and 1, therefore the CNPJ number would be like this: 11.444.777/0001-61.
The Ruby script for the generation would be like this:
1 def cnpj 2 basenum = [] 3 12.times { basenum << rand(10) } 4 pesos = [5,4,3,2,9,8,7,6,5,4,3,2] 5 6 n = (0...basenum.length).inject(0) { |a, b| a + basenum[b] * pesos[b] } 7 dv1 = if n%11 < 2; 0; 8 else; 11-(n%11); end 9 basenum << dv1 10 11 pesos.unshift(6) 12 13 n2 = (0...basenum.length).inject(0) { |a, b| a + basenum[b] * pesos[b] } 14 dv2 = if n2%11 < 2; 0; 15 else; 11-(n2%11); end 16 cnpj = basenum << dv2 17 18 return cnpj.inspect 19 end 20 21 puts cnpj
Notice that I used the inspect ruby method to return the numbers of the documents so the output won't be so beautiful but the numbers are correct. You can assure the validity of the generated numbers on the following platforms:
CPF - https://www.4devs.com.br/validador_cpf
CNPJ - https://www.4devs.com.br/validador_cnpj
In the future I'll try to code generators for others documents such as CNH (driver's license in the USA) and credit card numbers from different banks. All will be written in Ruby.
Hope y'all enjoyed.
Github: https://github.com/mxm0z/generators
Comments
Post a Comment