Phép chia hai số lớn không âm [2], [4], [5], [9]

Một phần của tài liệu Số học số lớn cho mật mã luận án thạc sĩ (Trang 52 - 72)

6. Ý nghĩa khoa học và thực tiễn cửa đề tài

2.2.5 Phép chia hai số lớn không âm [2], [4], [5], [9]

Xét phép chia x/y = t + d, trong đó t là thƣơng của phép chia còn d là số dƣ của phép chia.Thí dụ với x = 79, y = 8 ta có: x/y = 79/8 = 8 9 + 7 t = 9, d

= 7. Việc chia x cho y ta liên tƣởng đến việc có tấm vải có độ dài là x và thƣớc có độ dài là y kết quả của phép chia chính là số lần dùng thƣớc đo đƣợc tấm vải (t = 9) và còn dƣ ra một phần của tấm vải (d = 7). Bây giờ thay vì dùng thƣớc có độ dài là y ta liên tục tăng thƣớc lên 2 lần cho đến khi thƣớc lớn hơn hoặc bằng

x. Sau đó ta lại tiếp tục chia thƣớc cho 2 đến khi bằng thƣớc cũ, số lần chia nhân với 2 cộng thêm 1 là thƣơng của phép chia, còn số dƣ chính bằng d = x

Vải x Thƣớc y t d 79 8 16 32 64 128 64 1 32 2 16 4 8 8 8 + 1 =9 79 – 9 8 = 7

Nhƣ vậy việc chia x/y bây giờ chỉ đƣợc tính toán bởi các phép tự chia 2, tự nhân 2, phép tính cộng, và phép tính trừ đơn thuần.

Ta có giải thuật sau:

Input: Hai đối tƣợng số lớn không âm x, y có độ dài len1len2

Output: Đối tƣợng t, d thoả: y t + d = x Algorithm: 1 a= x, y = b,w = b; 2 while (w <= a){ w.nhan2(); } 3 if (|w > a|) { t = 0; d = a;} 4 While(w > b){ w.chia2(); t*=2; if (w<=d){ ++t; d = d – w;} } 5 Return t, d.

Độ phức tạp của thuật toán: y 2k (k: số lần)

Phép chia lấy phần dƣ của hai số lớn xy không âm(x % y): Đƣợc xây dựng dựa trên giải thuật phép chia hai số lớn không âm đã trình bày ở trên ở đây giá trị trả về là phần dƣ (d):

Input: Hai đối tƣợng số lớn không âm x, y có độ dài len1len2

Output: Đối tƣợng t Algorithm: % (x % y) 1 a= x, y = b,w = b; 2 while (w <= a){ w.nhan2(); } 3 if (|w > a|) { d = a;} 4 While(w > b){ chia2(w); if (w<=d){ d = d – w;} } 5 Return d. 2.2.6 Lũy thừa [2], [4], [5], [11]

Ta có luỹ thừa mũ n của x đƣợc ký hiệu xn: xn = xx (n lần)

Thí dụ: n = 35 quá trình tính xn qua 35 bƣớc: 1 xx2 = x x x3 = x2 x … x35 = x34 x

Ta nhận thấy rằng có thể giảm bớt số phép nhân chẳng hặn với dãy phép tính 1 xx2 = x x,x4 = (x2)2 , x8 = (x4)2 , x16 = (x8)2 , x17 = (x8)2 x,

x34 = (x17)2 x35 = (x34)2 x

Quá trình tính toán trên chính là quá trình tính nhờ công thức đệ quy 1. Với n = 0 thì xn =1

Nhƣ vậy phép tính xn đƣợc quy về một số phép bình phƣơng và phép nhân do vậy mà có tên gọi “thuật toán bình phương và nhân”.

Từ nhận xét trên ta có thuật toán tính xn nhƣ sau:

Input: Hai đối tƣợng số lớn x, và số lớn không âm n

Output:

Đối tƣợng số lớn: z = xn

Algorithm:

1 z=1; n.myAbs(); // lấy giá trị tuyệt đối n 2 if (n==0) { return z;} 3 While(n > 0){ if(n chẵn); z*=x; x=x*x; n.chia2(); } 4 Return z.

Độ phức tạp của thuật toán là

Thí dụ: với x = 12, n = 3 thuật toán đƣợc mô tả nhƣ sau: B1: z =1; n = |n| =|3| = 3;

B2: kiểm tra n == 0 ? thực hiện bƣớc 3 B3: Lặp

B3.1: Kiểm tra n = 3 lẻ thực hiện z=xz = 1 12 =12;

Tiếp x = x x = 12 12 = 24; sau đó chia n với 2 lấy phần nguyên (3>>=1) n =1; B3.2: Kiểm tra n = 1 lẻ thực hiện z=xz = 12 24 =1728;

Tiếp x = x x = 24 24 = 48; sau đó chia n với 2 lấy phần nguyên (1>>=1) n =0; Với n = 0 kết thúc vòng lặp

Trong giải thuật trên phép tính nhân số lớn áp dụng thuật toán nhân số lớn ở trên.

2.2.7 Ước chung lớn nhất [1], [2], [6], [7]

Sử dụng thuật toán Euclid tìm ƣớc chung lớn nhất của 2 số nguyên lớn

Input: Hai đối tƣợng số nguyên lớn bn1bn2 có độ dài len1len2

Output: Đối tƣợng z = gcd(bn1,bn2); Algorithm: 1 while (!bn1.Zero()) { if (bn1 > bn2) { bn1 = bn1 - bn2; } else { bn2 = bn2 - bn1; } if (bn1.Zero() || bn2.Zero()) return Z = bn1; } Return Z = bn1; 2.2.8 Phép cộng theo modulo p [1], [2], [6], [7]

Cho p là số nguyên dƣơng. Nhƣ trƣớc, các phần tử trong Zp đƣợc thể hiện bởi các số nguyên {0, 1, 2,…, p - 1}. Nhận xét rằng: nếu a, b Zp thì:

p b a if n b a p b a if b a = p mod b) + (a

Vì vậy, phép cộng modulo (và phép trừ modulo) có thể đƣợc thực hiện mà không cần thực hiện các phép chia dài.

Giải thuật:

Input: Đối tƣợng số nguyên lớn a, bp

Output: z = a + b mod p Algorithm: AddMod 1 z = 0; 2 if(a > p) a = a%p; 3 if(b>p) b = b%p; 4 z = a + b; 5 if(z < p) return z; 6 if(z >= p) return (z - n); Thí dụ: a = 5, b = 6, p = 8 B1: z = a + b = 5 + 6 =11 B2: z = 11 > p =8 z = zn = 11 – 8 = 3;

2.2.9 Phép nhân theo modulo p [1], [2], [6], [7]

Việc thực hiện phép nhân trong modulo p làm theo phƣơng pháp „bình phương và nhân‟ đã đề cập ở trên các kết quả trung gian không vƣợt quá p:

Input: Đối tƣợng số nguyên lớn a, bp

Output: Đối tƣợng z = a b mod p; Algorithm: MultMod 1 z = 0; 2 if (a == p || b == p) return 0; 3 if(a > p) a = a%p; 4 if(b>p) b = b%p; 5 while (a != 0) {

if (a lẻ ) z = AddMod(z,b,p); //cộngtrong modul p a >>= 1; // a tự chia 2 b = AddMod(b,b,p); } 6 return z; 2.2.10 Phép cộng có dấu [1], [2], [4], [6]

Phép cộng hai số có dấu đƣợc thực hiện dựa trên phép so sánh, phép cộng hai số không âm và phép trừ đã trình bày. Dấu của số lớn đƣợc lƣu ở phần tử cuối của danh sách.

Thuật toán cộng hai số lớn có dấu đƣợc thực hiện nhƣ sau:

Input: Hai đối tƣợng số lớn x, y

Output: z = x + y; Algorithm: 1. If (x, y cùng dấu) 1.1. z = x + y; 1.2. đặt z cùng dấu với x; 1.3. Return z; 2. if (x dương) // y âm 2.1. If(s = ComparePositive(x,y)!=0) Retum z = x |y|; 2.2. If(s==0) z = 0;

Đặt z cùng dấu với y; return z; 3. if (x âm) // y dương

3.1. if((s = ComparePositive(x,y))==0) Retum z = y |x|;

3.2 if(s==0) z = 0; Retum z

2.2.11 Phép trừ có dấu [1], [2], [4], [6]

Phép trừ hai số có dấu đƣợc thực hiện dựa trên phép cộng hai số, cụ thể:

Input: Hai đối tƣợng số lớn x, y

Output: z = x y

Algorithm:

1. Đổi dấu của y;

2. Cộng có dấu z = x + y; 3. retum z;

2.3.12 Phép nhân có dấu [1], [2], [4], [6]

Phép nhân hai số có dấu đƣợc thực hiện dựa trên phép nhân hai số không âm đã đƣợc trình bày ở trên. Thuật toán nhân hai số có dấu nhƣ sau:

Input: Hai đối tƣợng số lớn x, y

Output: đối tƣợng z = x y; Algorithm: 1. If (x, y cùng dấu) return z = x y; 2. If(x, y khác dấu) z = x y; Đổi dấu z; 3. Return z; 2.3.13 Phép chia có dấu [1], [2], [4], [6]

Phép chia hai số có dấu đƣợc thực hiện dựa trên phép chia hai số không âm đã đƣợc trình bày ở trên. Thuật toán nhân hai số có dấu nhƣ sau:

Input: Hai đối tƣợng số lớn x, y

Output: đối tƣợng z = x / y;

Algorithm:

1. If (x, y cùng dấu) return z = x/y; 2. If(x, y khác dấu)

z = x/y; Đổi dấu z; 3. Return z;

Chƣơng 3

ỨNG DỤNG THƢ VIỆN SỐ LỚN CHO HỆ MẬT MÃ RSA 3.1 Phân tích các phép xử lý toán học trong hệ mật mã RSA

Các thuật toán cơ bản đƣợc sử dụng trong hệ mật mã RSA:  Kiểm tra tính nguyên tố

 Phép cộng, trừ, nhân, chia số nguyên lớn  Sinh các số nguyên tố trong khoảng 1..n

 Sinh số nguyên tố sát sau  Căn nguyên bậc n của a

 Tính ax mod n

 Tính phần tử nghịch đảo trong mod n

3.2 Xây dựng hệ mật mã RSA thử nghiệm [1], [2], [4], [6], [7], [8]

Việc xây dựng hệ mã RSA muốn thành công thì phải giải quyết các bài toán ở trên, các bài toán ở trên đƣợc cài đặt nhƣ sau:

Hàm kiểm tra tính nguyên tố Cú pháp

bool Prime(BigNum p); Input: số p

Output: true nếu p là số nguyên tố; false ngoài ra. Thí dụ Prime( 1) = false; Prime(0) = false; Prime(1) = false; Prime(2) = true; Prime(5) = true; Prime(120) = false; Thuật toán

Nếu p là số lẻ thì chỉ cần kiểm tra xem p có ƣớc lẻ hay không (1). Số nguyên tố chẵn duy nhất là số 2.

Số p là nguyên tố khi và chỉ khi p không có ƣớc nguyên tố nào trong khoảng 2..

Nếu đã biết dãy k số nguyên tố q1 = 2, q2, …, qk thì chỉ cần xét xem p có ƣớc qi nào trong khoảng 2.. .

Thuật toán AKS của ba nhà toán học India Manindra Agrawal, Neeraj Kayal, và Nitin Saxena Đại học Indian Institute of Technology Kanpur (đề xuất tháng 8 năm 2002) có thể kiểm tra tính nguyên tố trong thời gian đa thức.

Input: integer p > 1.

Output: true nếu p là số nguyên tố; false, ngoài ra. If n = ab a, b nguyên > 1 then return false.

Tìm số nguyên dương nhỏ nhất r thỏa or(n) > (log n)2. If tồn tại a ≤ r thỏa 1 < ucln(a,n) < n then return false;

If n ≤ r then return true. For a = 1 to do

if (X+a)n ≠ Xn+a (mod xr−1,n) then return false; return true.

log tính theo cơ số 2. (r) là hàm Euler = số lƣợng các số nguyên dƣơng < r và nguyên tố cùng nhau với r. or(n) là bậc nhân tử của n theo modulo r.

Cài đặt theo định nghĩa (1).

bool Prime(BigNum p){ if (p < 2) return 0; if (p < 4) return 1;

if (EVEN(p)) return 0; // so chan BigNum can = BigNum(sqrt(p)); BigNum d = 3;

while(d<=can) { if (p % d == 0) return 0; d+=2; } return 1; }

Hàm sinh các số nguyên tố trong khoảng 1.. n

Cú pháp

Long Sieve(const char * fn, int n);

Input: - fn: tên file fn ghi các số nguyên tố sẽ sinh ra. - n giới hạn tìm kiếm.

Output: file fn chứa các số nguyên tố trong khoảng 1.. n.

Thí dụ: Long Sieve(“prime.dat”, 100);

Sinh và ghi các số nguyên tố trong khoảng 1..100 vào file prime.dat, mỗi số một dòng. 2 3 5 … 97

Thuật toán: Sàng Eratosthenes Viết dãy số 1.. n;

Xóa số 1. for i = 2..

if (số i chƣa bị xóa) then

Xóa các bội của i kể từ i2 .. n; endif

Ghi các số chƣa bị xóa vào file fn.

Cài đặt: Dùng mảng a đánh dấu, a[i] = 0 i là số nguyên tố (không bị xóa);

a[i] = 1 i là hợp số (xóa);

int LSieve(const char * fn, int n) { const char XOA = 1;

const char NGTO = 0; char * a = new char[n];

memset(a,NGTO,n*sizeof(char)); int i, j , can = int(sqrt(n)); for (i = 2; i <= can; ++i)

if (a[i] == NGTO) { // i ng to for (j = i*i; j <= n; j += i) a[j] = XOA; } ofstream f(fn); j = 0; for (i = 2; i <= n; ++i)

if (a[i] == NGTO) { f << i << endl; ++j; } f.close();

delete [] a; return j; }

Hàm sinh số nguyên tố sát sau số x. Cú pháp

BigNum NextPrime(BigNum x); Input: số x.

Output: số nguyên tố sát sau x.

Thí dụ:

p = NextPrime(p); // p = 101 Thuật toán

Nếu x < 2 return 2;

Duyệt các số lẻ sau x gặp số nguyên tố đầu tiên thì return. Cài đặt

BigNum NextPrime(BigNum x){ if (x < 2) return 2;

BingNum p = (Even(x)) ? x: x-1;

do{p += 2;}while(!Prime(p));//Kiểm tra số nguyên tố return p;

}

Hàm tính căn nguyên bậc n của a

Nhận xét: Nếu số n đƣợc biểu diễn trong hệ d thì số chữ số của n là Int(logdn) (Int cho phần nguyên dƣ).

Thí dụ, để biểu diễn a = 1026 Trong hệ 10 ta cần int(log101026) = 4 chữ số ; n = 102610. Trong hệ 2 ta cần int(log21026) = 11 chữ số ; n = 100000000102. Trong hệ 4 ta cần int(log41026) = 6 chữ số ; n = 1000024... Cú pháp int LBitCount(Long n) Input: Số nguyên dƣơng p

Output: Số bit biểu diễn p. Thí dụ int v = LBitCount(7); // v = 3 v = LBitCount(1026); // v = 11 Thuật toán Nếu tìm đƣợc k thỏa 2k > n thì k là đáp số. Cài đặt

// So bit bieu dien n int LBitCounter(Long n){ Long b = 2; int sb = 1; while (b <= n) { ++sb; b <<= 1; } return sb; }

Nhận xét 2: Để tính số chữ số s cần cho biểu diễn a trong hệ d ta đếm số lần nhân liên tiếp d cho đến khi vƣợt quá a:

s = 1; v = d;

while (va) { ++s; v = v d; }

Định lí Newton: Cho hàm liên tục f(x) và (ta giả thiết thêm là f(x) = 0 tức là đồ thị của f cắt trục hoành). Biết f(x1) > 0. Khi đó với x2 = x1 – f(x1)/f‟(x1) ta có

f(x2) < f(x1).

Để tính căn bậc n của a ta làm nhƣ sau:

Xét hàm f(x) = xn – a. Nếu tìm đƣợc trị x để f(x) = 0 ta có ngay kết quả. Ta có f‟(x) = nxn-1 . Khi đó

y = xf(x) / f‟(x) = x – (xn – a) / nxn 1 = (nxn – xn + a) / nxn 1 = x(n 1) / n + a / nxn 1 = (x(n 1) + a / nxn 1) / n.

Mọi kết quả trung gian đều là nguyên. Chọn điểm xuất phát x;

Lặp

y = xf(x)f‟(x) ;

Nếu y x thì cho kết quả x ;nếu không đặt lại x = y ;

Ta chọn giá trị xuất phát cho x đủ nhỏ thì tốt. Ta chọn x là giá trị nhỏ nhất thỏa

Từ đây suy ra phải chọn x thỏa xn a.

Lấy log cơ số 2 ta có: nlog x log a, hay log x log a/n. Đặt b = log a /

n, ta có:

log x b. Từ đây suy ra x 2b.

log a = số chữ số của a trong hệ 2 = số bít cần thiết để biểu diễn a.  Nhận xét 3: x.2k = x << k ; x / 2k = x >> k; x mod 2k = x and (2k – 1). Cài đặt

// Newton Method

Long LRoot(Long a, Long n){ if (a == 0) return 0; if (a < 0 || n <= 0) {

cout << "\n Error: Inputs must be positive numbers !"; cin.get(); exit(1); } Long x, y; x = 1 << ((LBitCount(a)+n-1)/n); // cout << "\n a = " << a << " x = " << x; while (1){ y = (x*(n-1)+a/LExp(x,n-1))/n; if (y >= x) return x; x = y; } }

Hàm kiểm tra dạng lũy thừa (proper power) của số p.

Số nguyên p > 1 gọi là số dạng thừa tồn tại hai số nguyên i, b > 1 thỏa: ab = p. Từ hệ thức trên suy ra ( )b = p với mọi b.

Có cần với mọi b hay không? Không. Ta chỉ cần chọn b sao cho > 1 . Max b = (số chữ số của p)/2.

Cú pháp

Long ProperPower(Long p); Input: số nguyên p > 1.

Output: b > 1 nếu ( )b = p; noài ra: 0. Thí dụ Long b = ProperPower(12*12*12); // b = 3 Thuật toán Cài đặt Long ProperPower(Long p){ Long sb = (LBitCount(p)+1)/2, b; for (b = 2; b < sb; ++b){ if (LExp(LRoot(p,b),b) == p) return b;} return 0; }  Tính ax mod n

Thuật toán bình phƣơng và nhân là thuật toán tính nhanh lũy thừa tự nhiên của một số (thực hoặc nguyên), trong trƣờng hợp cơ số là số nguyên có thể đƣợc rút gọn theo một modulo nào đó.

Tạo bảng:

x a d =1 (Khởi tạo)

Điền giá trị x Điền giá trị a

… … …

Thí dụ: 1535 mod 79 x a d Khởi tạo d = 1 35 15 15 x lẻ  tính lại d, x, a trong if d = d (a mod n) = 1 (15 mod 79) = 15 x >>=1 = 35 div 2 = 17 a = (a a) mod n = (15 15) mod 79 = 67 17 67 57 x lẻ  tính lại d, x, a tƣơng tự nhƣ trên

8 65 x chẵn  không tính lại d

vẫn tính lại x, a nhƣ trên 4 38 x chẵn  tƣơng tự nhƣ trên 2 22 x chẵn  tƣơng tự nhƣ trên 1 10 17 x chẵn  tƣơng tự nhƣ trên

0 x = 0  dừng tính, lấy d cuối cùng (d = 17) là kết quả Cài đặt: Input: a, x, n Output: ax mod n Algorithm: PowMod(a,x, n) d =1; While(x <> 0){

if(x mod 2 <> 0) d: = d * (a mod n); x >>=1;

a = (a*a) mod n; }

return d;

 Tìm phần từ nghịch đảo theo modulo p.

Số y là số nghịch đảo của x theo modulo p nếu x y mod p = 1 và 1 y < p.

Nếu y là số nghịch đảo của x theo modulo n thì ngƣợc lại, x là số nghịch đảo của y theo modulo n.

Cú pháp: Inv(Bignum a, BigNum p)

Input: Hai đối tƣợng số nguyên lớn a, p thoả (a, p) = 1

Output: x là số nghịch đảo của a theo modulo p, a x mod p = 1 Thí dụ: x = Inv(3,10) // x = 7 vì 3 7 mod 10 = 21 mod 10 = 1

x = Inv(4, 7); // x = 2 vì 4 2 mod 7 = 8 mod 7 = 1 Thuật toán:

Theo thuật toán Euclid với hai số ap tùy ý ta luôn tìm đƣợc hai số x

y thỏa:

ax + py = (a,p)

Vì (a,p) = 1 nên ax + ny = 1. Từ đây suy ra ax = 1 py và do đó ax mod p = 1

Một phần của tài liệu Số học số lớn cho mật mã luận án thạc sĩ (Trang 52 - 72)

Tải bản đầy đủ (PDF)

(72 trang)