Created
November 17, 2011 12:25
-
-
Save BastienClement/1373027 to your computer and use it in GitHub Desktop.
iban.coffee
This file contains 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
` | |
// BigInt.js - Arbitrary size integer math package for JavaScript | |
// Copyright (C) 2000 Masanao Izumo <[email protected]> | |
// Version: 1.0.1 | |
// Licence: GPL | |
// | |
// This program is free software; you can redistribute it and/or modify | |
// it under the terms of the GNU General Public License as published by | |
// the Free Software Foundation; either version 2 of the License, or | |
// (at your option) any later version. | |
// | |
// This program is distributed in the hope that it will be useful, | |
// but WITHOUT ANY WARRANTY; without even the implied warranty of | |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
// GNU General Public License for more details. | |
// | |
// | |
// Interfaces: | |
// x = new BigInt("1234567890123456789012345678901234567890"); | |
// y = new BigInt("0x123456789abcdef0123456789abcdef0"); | |
// z = x.clone(); | |
// z = bigint_uminus(x); | |
// z = bigint_plus(x, y); | |
// z = bigint_minus(x, y); | |
// z = bigint_mul(x, y); | |
// z = bigint_div(x, y); | |
// z = bigint_mod(x, y); | |
// cmp = bigint_cmp(x, y); /* return -1, 0, or 1 */ | |
// num = bigint_number(x); /* convert normal number (may be floating) */ | |
// | |
function _BigInt_toString() | |
{ | |
return this.toStringBase(10); | |
} | |
function _BigInt_toStringBase(base) | |
{ | |
var i, j, hbase; | |
var t; | |
var ds; | |
var c; | |
i = this.len; | |
if(i == 0) | |
return "0"; | |
if(i == 1 && !this.digits[0]) | |
return "0"; | |
switch(base) { | |
default: | |
case 10: | |
j = Math.floor((2*8*i*241)/800)+2; | |
hbase = 10000; | |
break; | |
case 16: | |
j = Math.floor((2*8*i)/4)+2; | |
hbase = 0x10000; | |
break; | |
case 8: | |
j = (2*8*i)+2; | |
hbase = 010000; | |
break; | |
case 2: | |
j = (2*8*i)+2; | |
hbase = 020; | |
break; | |
} | |
t = this.clone(); | |
ds = t.digits; | |
s = ""; | |
while (i && j) { | |
var k = i; | |
var num = 0; | |
while (k--) { | |
num = (num<<16) + ds[k]; | |
if(num < 0) num += 4294967296; | |
ds[k] = Math.floor(num / hbase); | |
num %= hbase; | |
} | |
if (ds[i-1] == 0) | |
i--; | |
k = 4; | |
while (k--) { | |
c = (num % base); | |
s = "0123456789abcdef".charAt(c) + s; | |
--j; | |
num = Math.floor(num / base); | |
if (i == 0 && num == 0) { | |
break; | |
} | |
} | |
} | |
i = 0; | |
while(i < s.length && s.charAt(i) == "0") | |
i++; | |
if(i) | |
s = s.substring(i, s.length); | |
if(!this.sign) | |
s = "-" + s; | |
return s; | |
} | |
function _BigInt_clone() | |
{ | |
var x, i; | |
x = new BigInt(this.len, this.sign); | |
for(i = 0; i < this.len; i++) | |
x.digits[i] = this.digits[i]; | |
return x; | |
} | |
function BigInt(len, sign) | |
{ | |
var i, x, need_init; | |
// Setup member functions. | |
// Note: There is G.C. bug of function() in Netscape! | |
// Don't use anonymous function. | |
this.toString = _BigInt_toString; | |
this.toStringBase = _BigInt_toStringBase; | |
this.clone = _BigInt_clone; | |
if(BigInt.arguments.length == 0) { | |
this.sign = true; | |
this.len = len = 1; | |
this.digits = new Array(1); | |
need_init = true; | |
} else if(BigInt.arguments.length == 1) { | |
x = bigint_from_any(BigInt.arguments[0]); | |
if(x == BigInt.arguments[0]) | |
x = x.clone(); | |
this.sign = x.sign; | |
this.len = x.len; | |
this.digits = x.digits; | |
need_init = false; | |
} else { | |
this.sign = (sign ? true : false); | |
this.len = len; | |
this.digits = new Array(len); | |
need_init = true; | |
} | |
if(need_init) { | |
for(i = 0; i < len; i++) | |
this.digits[i] = 0; | |
} | |
} | |
function bigint_norm(x) | |
{ | |
var len = x.len; | |
var ds = x.digits; | |
while(len-- && !ds[len]) | |
; | |
x.len = ++len; | |
return x; | |
} | |
function bigint_from_int(n) | |
{ | |
var sign, big, i; | |
if(n < 0) { | |
n = -n; | |
sign = false; | |
} else | |
sign = true; | |
n &= 0x7fffffff; | |
if(n <= 0xffff) { | |
big = new BigInt(1, 1); | |
big.digits[0] = n; | |
} else { | |
big = new BigInt(2, 1); | |
big.digits[0] = (n & 0xffff); | |
big.digits[1] = ((n>>16) & 0xffff); | |
} | |
return big; | |
} | |
function bigint_from_string(str, base) | |
{ | |
var str_i; | |
var sign = true; | |
var c; | |
var len; | |
var z; | |
var zds; | |
var num; | |
var i; | |
var blen = 1; | |
str += "@"; // Terminator; | |
str_i = 0; | |
// TODO: skip white spaces | |
if(str.charAt(str_i) == "+") { | |
str_i++; | |
} | |
else if (str.charAt(str_i) == "-") { | |
str_i++; | |
sign = false; | |
} | |
if (str.charAt(str_i) == "@") | |
return null; | |
if (!base) { | |
if (str.charAt(str_i) == "0") { | |
c = str.charAt(str_i + 1); | |
if (c == "x" || c == "X") { | |
base = 16; | |
} | |
else if (c == "b" || c == "B") { | |
base = 2; | |
} | |
else { | |
base = 8; | |
} | |
} | |
else { | |
base = 10; | |
} | |
} | |
if (base == 8) { | |
while (str.charAt(str_i) == "0") | |
str_i++; | |
len = 3 * (str.length - str_i); | |
} | |
else { // base == 10, 2 or 16 | |
if (base == 16 && str.charAt(str_i) == '0' && (str.charAt(str_i+1) == "x" || str.charAt(str_i+1) == "X")) { | |
str_i += 2; | |
} | |
if (base == 2 && str.charAt(str_i) == '0' && (str.charAt(str_i+1) == "b"||str.charAt(str_i+1) == "B")) { | |
str_i += 2; | |
} | |
while (str.charAt(str_i) == "0") | |
str_i++; | |
if (str.charAt(str_i) == "@") str_i--; | |
len = 4 * (str.length - str_i); | |
} | |
len = (len>>4)+1; | |
z = new BigInt(len, sign); | |
zds = z.digits; | |
while(true) { | |
c = str.charAt(str_i++); | |
if(c == "@") | |
break; | |
switch (c) { | |
case '0': c = 0; break; | |
case '1': c = 1; break; | |
case '2': c = 2; break; | |
case '3': c = 3; break; | |
case '4': c = 4; break; | |
case '5': c = 5; break; | |
case '6': c = 6; break; | |
case '7': c = 7; break; | |
case '8': c = 8; break; | |
case '9': c = 9; break; | |
case 'a': case 'A': c = 10; break; | |
case 'b': case 'B': c = 11; break; | |
case 'c': case 'C': c = 12; break; | |
case 'd': case 'D': c = 13; break; | |
case 'e': case 'E': c = 14; break; | |
case 'f': case 'F': c = 15; break; | |
default: | |
c = base; | |
break; | |
} | |
if (c >= base) | |
break; | |
i = 0; | |
num = c; | |
while(true) { | |
while (i<blen) { | |
num += zds[i]*base; | |
zds[i++] = (num & 0xffff); | |
num >>>= 16; | |
} | |
if (num) { | |
blen++; | |
continue; | |
} | |
break; | |
} | |
} | |
return bigint_norm(z); | |
} | |
function bigint_from_any(x) | |
{ | |
if(typeof(x) == "object") { | |
if(x.constructor == BigInt) | |
return x; | |
return BigInt(1, 1); | |
} | |
if(typeof(x) == "string") { | |
return bigint_from_string(x); | |
} | |
if(typeof(x) == "number") { | |
var i, x1, x2, fpt, np; | |
if(-2147483647 <= x && x <= 2147483647) { | |
return bigint_from_int(x); | |
} | |
x = x + ""; | |
i = x.indexOf("e", 0); | |
if(i == -1) | |
return bigint_from_string(x); | |
x1 = x.substr(0, i); | |
x2 = x.substr(i+2, x.length - (i+2)); | |
fpt = x1.indexOf(".", 0); | |
if(fpt != -1) { | |
np = x1.length - (fpt+1); | |
x1 = x1.substr(0, fpt) + x1.substr(fpt+1, np); | |
x2 = parseInt(x2) - np; | |
} else { | |
x2 = parseInt(x2); | |
} | |
while(x2-- > 0) { | |
x1 += "0"; | |
} | |
return bigint_from_string(x1); | |
} | |
return BigInt(1, 1); | |
} | |
function bigint_uminus(x) | |
{ | |
var z = x.clone(); | |
z.sign = !z.sign; | |
return bigint_norm(z); | |
} | |
function bigint_add_internal(x, y, sign) | |
{ | |
var z; | |
var num; | |
var i, len; | |
sign = (sign == y.sign); | |
if (x.sign != sign) { | |
if (sign) | |
return bigint_sub_internal(y, x); | |
return bigint_sub_internal(x, y); | |
} | |
if (x.len > y.len) { | |
len = x.len + 1; | |
z = x; x = y; y = z; | |
} else { | |
len = y.len + 1; | |
} | |
z = new BigInt(len, sign); | |
len = x.len; | |
for (i = 0, num = 0; i < len; i++) { | |
num += x.digits[i] + y.digits[i]; | |
z.digits[i] = (num & 0xffff); | |
num >>>= 16; | |
} | |
len = y.len; | |
while (num && i < len) { | |
num += y.digits[i]; | |
z.digits[i++] = (num & 0xffff); | |
num >>>= 16; | |
} | |
while (i < len) { | |
z.digits[i] = y.digits[i]; | |
i++; | |
} | |
z.digits[i] = (num & 0xffff); | |
return bigint_norm(z); | |
// return z; | |
} | |
function bigint_sub_internal(x, y) | |
{ | |
var z = 0; | |
var zds; | |
var num; | |
var i; | |
i = x.len; | |
// if x is larger than y, swap | |
if (x.len < y.len) { | |
z = x; x = y; y = z; // swap x y | |
} | |
else if (x.len == y.len) { | |
while (i > 0) { | |
i--; | |
if (x.digits[i] > y.digits[i]) { | |
break; | |
} | |
if (x.digits[i] < y.digits[i]) { | |
z = x; x = y; y = z; // swap x y | |
break; | |
} | |
} | |
} | |
z = new BigInt(x.len, (z == 0) ? 1 : 0); | |
zds = z.digits; | |
for (i = 0, num = 0; i < y.len; i++) { | |
num += x.digits[i] - y.digits[i]; | |
zds[i] = (num & 0xffff); | |
num >>>= 16; | |
} | |
while (num && i < x.len) { | |
num += x.digits[i]; | |
zds[i++] = (num & 0xffff); | |
num >>>= 16; | |
} | |
while (i < x.len) { | |
zds[i] = x.digits[i]; | |
i++; | |
} | |
return bigint_norm(z); | |
} | |
function bigint_plus(x, y) | |
{ | |
x = bigint_from_any(x); | |
y = bigint_from_any(y); | |
return bigint_add_internal(x, y, 1); | |
} | |
function bigint_minus(x, y) | |
{ | |
x = bigint_from_any(x); | |
y = bigint_from_any(y); | |
return bigint_add_internal(x, y, 0); | |
} | |
function bigint_mul(x, y) | |
{ | |
var i, j; | |
var n = 0; | |
var z; | |
var zds, xds, yds; | |
var dd, ee; | |
var ylen; | |
x = bigint_from_any(x); | |
y = bigint_from_any(y); | |
j = x.len + y.len + 1; | |
z = new BigInt(j, x.sign == y.sign); | |
xds = x.digits; | |
yds = y.digits; | |
zds = z.digits; | |
ylen = y.len; | |
while (j--) | |
zds[j] = 0; | |
for (i = 0; i < x.len; i++) { | |
dd = xds[i]; | |
if (dd == 0) | |
continue; | |
n = 0; | |
for (j = 0; j < ylen; j++) { | |
ee = n + dd * yds[j]; | |
n = zds[i + j] + ee; | |
if (ee) | |
zds[i + j] = (n & 0xffff); | |
n >>>= 16; | |
} | |
if (n) { | |
zds[i + j] = n; | |
} | |
} | |
return bigint_norm(z); | |
} | |
function bigint_divmod(x, y, modulo) | |
{ | |
var nx = x.len; | |
var ny = y.len; | |
var i, j; | |
var yy, z; | |
var xds, yds, zds, tds; | |
var t2; | |
var num; | |
var dd, q; | |
var ee; | |
var mod, div; | |
yds = y.digits; | |
if (ny == 0 && yds[0] == 0) | |
return null; // Division by zero | |
if (nx < ny || nx == ny && x.digits[nx - 1] < y.digits[ny - 1]) { | |
if (modulo) | |
return bigint_norm(x); | |
return BigInt(1, 1); | |
} | |
xds = x.digits; | |
if (ny == 1) { | |
dd = yds[0]; | |
z = x.clone(); | |
zds = z.digits; | |
t2 = 0; | |
i = nx; | |
while (i--) { | |
t2 = t2 * 65536 + zds[i]; | |
zds[i] = (t2 / dd) & 0xffff; | |
t2 %= dd; | |
} | |
z.sign = (x.sign == y.sign); | |
if (modulo) { | |
if (!x.sign) | |
t2 = -t2; | |
if (x.sign != y.sign) { | |
t2 = t2 + yds[0] * (y.sign ? 1 : -1); | |
} | |
return bigint_from_int(t2); | |
} | |
return bigint_norm(z); | |
} | |
z = new BigInt(nx == ny ? nx + 2 : nx + 1, | |
x.sign == y.sign); | |
zds = z.digits; | |
if (nx == ny) | |
zds[nx + 1] = 0; | |
while (!yds[ny - 1]) | |
ny--; | |
if ((dd = ((65536/(yds[ny-1]+1)) & 0xffff)) != 1) { | |
yy = y.clone(); | |
tds = yy.digits; | |
j = 0; | |
num = 0; | |
while (j<ny) { | |
num += yds[j]*dd; | |
tds[j++] = num & 0xffff; | |
num >>= 16; | |
} | |
yds = tds; | |
j = 0; | |
num = 0; | |
while (j<nx) { | |
num += xds[j] * dd; | |
zds[j++] = num & 0xffff; | |
num >>= 16; | |
} | |
zds[j] = num & 0xffff; | |
} | |
else { | |
zds[nx] = 0; | |
j = nx; | |
while (j--) zds[j] = xds[j]; | |
} | |
j = nx==ny?nx+1:nx; | |
do { | |
if (zds[j] == yds[ny-1]) q = 65535; | |
else q = ((zds[j]*65536 + zds[j-1])/yds[ny-1]) & 0xffff; | |
if (q) { | |
i = 0; num = 0; t2 = 0; | |
do { // multiply and subtract | |
t2 += yds[i] * q; | |
ee = num - (t2 & 0xffff); | |
num = zds[j - ny + i] + ee; | |
if (ee) zds[j - ny + i] = num & 0xffff; | |
num >>= 16; | |
t2 >>>= 16; | |
} while (++i < ny); | |
num += zds[j - ny + i] - t2; // borrow from high digit; don't update | |
while (num) { // "add back" required | |
i = 0; num = 0; q--; | |
do { | |
ee = num + yds[i]; | |
num = zds[j - ny + i] + ee; | |
if (ee) zds[j - ny + i] = num & 0xffff; | |
num >>= 16; | |
} while (++i < ny); | |
num--; | |
} | |
} | |
zds[j] = q; | |
} while (--j >= ny); | |
if (modulo) { // just normalize remainder | |
mod = z.clone(); | |
if (dd) { | |
zds = mod.digits; | |
t2 = 0; i = ny; | |
while (i--) { | |
t2 = (t2*65536) + zds[i]; | |
zds[i] = (t2 / dd) & 0xffff; | |
t2 %= dd; | |
} | |
} | |
mod.len = ny; | |
mod.sign = x.sign; | |
if (x.sign != y.sign) { | |
return bigint_add_internal(mod, y, 1); | |
} | |
return bigint_norm(mod); | |
} | |
div = z.clone(); | |
zds = div.digits; | |
j = (nx==ny ? nx+2 : nx+1) - ny; | |
for (i = 0;i < j;i++) zds[i] = zds[i+ny]; | |
div.len = i; | |
return bigint_norm(div); | |
} | |
function bigint_div(x, y) | |
{ | |
x = bigint_from_any(x); | |
y = bigint_from_any(y); | |
return bigint_divmod(x, y, 0); | |
} | |
function bigint_mod(x, y) | |
{ | |
x = bigint_from_any(x); | |
y = bigint_from_any(y); | |
return bigint_divmod(x, y, 1); | |
} | |
function bigint_cmp(x, y) | |
{ | |
var xlen; | |
if(x == y) | |
return 0; // Same object | |
x = bigint_from_any(x); | |
y = bigint_from_any(y); | |
xlen = x.len; | |
if(x.sign != y.sign) { | |
if(x.sign) | |
return 1; | |
return -1; | |
} | |
if (xlen < y.len) | |
return (x.sign) ? -1 : 1; | |
if (xlen > y.len) | |
return (x.sign) ? 1 : -1; | |
while(xlen-- && (x.digits[xlen] == y.digits[xlen])) | |
; | |
if (-1 == xlen) | |
return 0; | |
return (x.digits[xlen] > y.digits[xlen]) ? | |
(x.sign ? 1 : -1) : | |
(x.sign ? -1 : 1); | |
} | |
function bigint_number(x) | |
{ | |
var d = 0.0; | |
var i = x.len; | |
var ds = x.digits; | |
while (i--) { | |
d = ds[i] + 65536.0 * d; | |
} | |
if (!x.sign) d = -d; | |
return d; | |
} | |
` | |
alphabet = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] | |
randomAlphas = -> | |
a = b = Math.round(Math.random()*25) | |
b = Math.round(Math.random()*25) while b is a | |
[alphabet[a], alphabet[b]] | |
alphasSwitch = (alphas) -> | |
[a, b] = alphas | |
[b, a] | |
mod97_10 = (iban) -> | |
countryCode = iban.slice 0, 4 | |
bankAccountCode = iban.slice 4 | |
iban = bankAccountCode+countryCode | |
numericIbanString = ""; | |
for i in [0..(iban.length-1)] | |
currentChar = iban.charAt(i); | |
currentCharCode = iban.charCodeAt(i); | |
if currentChar is "0" and numericIbanString is "" | |
continue | |
if 47 < currentCharCode < 58 | |
numericIbanString += currentChar; | |
else | |
value = currentCharCode-65+10; | |
numericIbanString += value | |
x = new BigInt numericIbanString | |
m = 98-bigint_number bigint_mod x, "97" | |
m = if m < 10 then "0"+m else ""+m | |
return m | |
generateIbans1 = -> | |
iban = "CH0000" | |
s1 = Math.round(Math.random()*12) | |
account_pre = "" | |
account_pre += Math.round(Math.random()*9) for [1..s1] | |
account_post = "" | |
account_post += Math.round(Math.random()*9) for [1..(13-s1)] | |
c1 = randomAlphas()[0] | |
c2 = Math.round(Math.random()*9) | |
i1 = "CH0000"+account_pre+c1+c2+account_post | |
i2 = "CH0000"+account_pre+c2+c1+account_post | |
m1 = mod97_10 i1 | |
m2 = mod97_10 i2 | |
return [i1, m1, i2, m2] | |
generateIbans2 = -> | |
iban = "CH0000" | |
s1 = Math.round(Math.random()*13) | |
account_pre = "" | |
account_pre += Math.round(Math.random()*9) for [1..s1] | |
account_post = "" | |
account_post += Math.round(Math.random()*9) for [1..(14-s1)] | |
i1 = "CH0000"+account_pre+"0"+account_post | |
i2 = "CH0000"+account_pre+"O"+account_post | |
m1 = mod97_10 i1 | |
m2 = mod97_10 i2 | |
return [i1, m1, i2, m2] | |
generateIbans3 = -> | |
iban = "CH0000" | |
c1 = randomAlphas() | |
c2 = randomAlphas() | |
c1_ = alphasSwitch c1 | |
c2_ = alphasSwitch c2 | |
s1 = Math.round(Math.random()*10) | |
s2 = Math.round(Math.random()*(11-s1)) | |
account = "" | |
account += Math.round(Math.random()*9) for [1..11] | |
a1 = account.slice 0, s1 | |
a2 = account.slice s1, s1+s2 | |
a3 = account.slice s1+s2 | |
t1 = c1.join "" | |
t2 = c2.join "" | |
t1_ = c1_.join "" | |
t2_ = c2_.join "" | |
i1 = "CH0000"+a1+t1+a2+t2+a3 | |
i2 = "CH0000"+a1+t1_+a2+t2_+a3 | |
m1 = mod97_10 i1 | |
m2 = mod97_10 i2 | |
return [i1, m1, i2, m2] | |
# - - - - - | |
loop | |
[i1, m1, i2, m2] = generateIbans1() | |
if m1 is m2 | |
console.log "FOUND 1:" | |
console.log [i1, m1, i2, m2].join ", " | |
break | |
loop | |
[i1, m1, i2, m2] = generateIbans2() | |
if m1 is m2 | |
console.log "FOUND 2:" | |
console.log [i1, m1, i2, m2].join ", " | |
break | |
loop | |
[i1, m1, i2, m2] = generateIbans3() | |
if m1 is m2 | |
console.log "FOUND 3:" | |
console.log [i1, m1, i2, m2].join ", " | |
break |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment