 # File: dot.vs.gfmul128.php Download
 ```hbin = \$this->h2bin = array(); for (\$k=0;\$k<16;\$k++) { \$this->hbin[\$k]=sprintf("%04b",\$k); \$this->h2bin[\$this->hbin[\$k]]=dechex(\$k); } } function convert(\$x) { \$poly = 0; for (\$b=0;\$b<16;\$b++) { \$byte_val = 0; for (\$i=7; \$i>-1; \$i--) { \$index = 127 - (8 * \$b) - \$i; \$t_byte_val = bcmul(gmp_and(bcdiv(\$x,bcpow('2',\$index)) , 1),bcpow('2',\$i)); \$byte_val = bcadd(\$t_byte_val,\$byte_val) ; } \$poly = bcadd(bcmul(\$poly,256) , \$byte_val) ; } return \$poly; } function gf128_dot(\$x, \$y, \$R) { /*''' Multiplication in GF(2^128). The caller specifies the irreducible polynomial. '''*/ \$z = 0; for (\$i=127;\$i>-1;\$i--) { \$z = \$z ^ (\$x * gmp_and(bcdiv(\$y,bcpow('2',\$i)),1)); # if MSB is 0, XOR with 0, else XOR with x \$x = bcdiv(\$x,2) ^ (gmp_and(\$x , 1) * \$R); # shift and also reduce by R if overflow detected } return \$z; } function u128_dec(\$hex) { \$dec = 0; \$len = strlen(\$hex); for (\$i = 1; \$i <= \$len; \$i++) \$dec = bcadd(\$dec, bcmul(strval(hexdec(\$hex[\$i - 1])), bcpow('16', strval(\$len - \$i)))); return \$dec; } function dot_big_math(\$a,\$b) { /* Working with long long elements mod R=0x010000000000000000000000000000C2 convert elements 1- ab=mul a,b 2- r=mul ab,Ri=0x01000000000000000000000000000492 */ \$Ri = \$this->convert(\$this->u128_dec("01000000000000000000000000000492")); \$R = \$this->convert(\$this->u128_dec("010000000000000000000000000000C2")); \$b = \$this->convert(\$this->u128_dec(\$b)); \$X = str_split(\$a,32); \$i = 0;\$r = str_repeat("\0",16); while(\$iconvert(\$this->u128_dec(bin2hex(pack("H*",\$X[\$i])^\$r))); \$ab = \$this->gf128_dot(\$a , \$b, \$R); \$r = gmp_Export(\$this->convert(\$this->gf128_dot(\$ab, \$Ri, \$R))); ++\$i; } return bin2hex(\$r); } function dot2(\$a,\$b) { /* simplified dot no need to convert mod R=0xe1000000000000000000000000000000 1- a=strrev a 2- b=mul b,H 3- r=mul a,b */ \$H = \$this->u128_dec("40000000000000000000000000000000"); \$R = \$this->u128_dec("e1000000000000000000000000000000"); \$b = \$this->gf128_dot(\$this->u128_dec(\$this->reverse(\$b)) , \$H, \$R); \$X = str_split(\$a,32); \$i = 0;\$r = str_repeat("\0",16); while(\$iu128_dec(bin2hex(strrev(pack("H*",\$X[\$i]))^\$r)); \$r = gmp_Export(\$this->gf128_dot(\$a, \$b, \$R)); ++\$i; } return bin2hex(strrev(\$r)); } /*********************************************************************************************************/ function reverse(\$hex) { return implode(array_reverse(str_split(\$hex,2))); } function bstr(\$hex) { // from hex to binary string return str_replace(\$this->h2bin,\$this->hbin,\$hex); } function to128(\$bin) { \$result="";foreach (str_split(bin2hex(\$bin),2) as \$z) \$result.=\$z; return \$result; } function bstrtohex(\$bin) { \$hex="";foreach (str_split(\$this->to128(\$bin),4) as \$bin) \$hex.=dechex(bindec(\$bin)); return \$hex; } function mul(\$binX) { \$mask0 = str_repeat(sprintf("%08b",1),16); \$mask1 = str_repeat("01111111",16); // polynomial reduction \$R = \$this->bstr("000000000000000000000000000000e1"); \$xLSB = \$binX; \$binX = "0".substr(\$binX,0,-1)&\$mask1|substr(\$binX&\$mask0,15); if (\$xLSB) \$binX = \$this->to128(\$binX^\$R); return \$binX; } function PCLMULQDQ(\$X,\$Y) { // as defined in https://www.intel.cn/content/dam/www/public/us/en/documents/white-papers/carry-less-multiplication-instruction-in-gcm-mode-paper.pdf /* a = 7b5b54657374566563746f725d53475d b = 48692853686179295b477565726f6e5d PCLMULQDQ (a, b) = 040229a09a5ed12e7e4e10da323506d2 little endian rbits = Reflecting Bits PCLMULQDQ (a, b) = rbits(GFMUL (rbits(a),rbits(b))) with reduction */ \$p = str_repeat("0",128); \$binY = strrev(\$this->bstr(\$Y)); \$binX = strrev(\$this->bstr(\$this->reverse(\$X))); for(\$i = 0; \$i < 128; \$i++) { if (\$binY[\$i]) \$p^=\$binX; \$binX = \$this->mul(\$binX); } return \$this->reverse(\$this->bstrtohex(strrev(\$p))); } function GFMUL(\$X,\$Y) { // as defined in https://www.intel.cn/content/dam/www/public/us/en/documents/white-papers/carry-less-multiplication-instruction-in-gcm-mode-paper.pdf /* Counter mode Data: 952b2a56a5604ac0b32b6656a05b40b6 Hash Key: dfa6bf4ded81db03ffcaff95f830f061 Multiplication Result: da53eb0ad2c55bb64fc4802cc3feda60 */ \$p = str_repeat("0",128); \$binY = \$this->bstr(\$this->reverse(\$Y)); \$binY = implode(array_reverse(str_split(\$binY,8))); \$binX = \$this->bstr(\$this->reverse(\$X)); for(\$i = 0; \$i < 128; \$i++) { if (\$binY[\$i]) \$p^=\$binX; \$binX = \$this->mul(\$binX); } return \$this->reverse(\$this->bstrtohex(\$p)); } function mulX_POLYVAL(\$X) { /* multiplies X by bigendian(010000000000000000000000000000c2) and reduce modulo 000000000000000000000000000000e1 let H = 25629347589242761d31f826ba4b757b If we wished to calculate this given only an implementation of POLYVAL then we would first calculate the key for POLYVAL, mulX_POLYVAL(ByteReverse(H)) = f6ea96744df0633aec8424b18e26c54a */ \$Ri = \$this->reverse("010000000000000000000000000000c2"); return \$this->reverse(\$this->gfmul(\$X,\$Ri)); } function mulX_GHASH(\$X) { /* multiplies X by bigendian(40000000000000000000000000000000) and reduce modulo 000000000000000000000000000000e1 let H = 25629347589242761d31f826ba4b757b If we wished to calculate this given only an implementation of GHASH then the key for GHASH would be mulX_GHASH(ByteReverse(H)) = dcbaa5dd137c188ebb21492c23c9b112 */ \$binX = \$this->mul(\$this->bstr(\$X)); return \$this->reverse(\$this->bstrtohex(\$binX)); } function dot_siv_ghash(\$X,\$Y) { // as defined in https://www.ietf.org/id/draft-irtf-cfrg-gcmsiv-09.txt /* GHASH(H, X_1, ..., X_n) = ByteReverse(POLYVAL(mulX_POLYVAL(ByteReverse(H)), ByteReverse(X_1), ..., ByteReverse(X_n))) let H = 25629347589242761d31f826ba4b757b X_1 = 4f4f95668c83dfb6401762bb2d01a262 X_2 = d1a24ddd2721d006bbe45f20d3c9f362 GHASH(H, X_1, X_2)= bd9b3997046731fb96251b91f9c99d7a */ \$X =str_split(\$X,32); \$H =\$Y; \$GHASH =str_repeat("\0",16); \$i =0; while(\$igfmul(bin2hex(\$GHASH^pack("H*",\$X[\$i])),\$H)); ++\$i; } return bin2hex(\$GHASH); } function dot_siv_polyval(\$X,\$Y) { // as defined in https://www.ietf.org/id/draft-irtf-cfrg-gcmsiv-09.txt /* POLYVAL(H, X_1, ..., X_n) = ByteReverse(GHASH(mulX_GHASH(ByteReverse(H)), ByteReverse(X_1), ..., ByteReverse(X_n))) let H = 25629347589242761d31f826ba4b757b X_1 = 4f4f95668c83dfb6401762bb2d01a262 X_2 = d1a24ddd2721d006bbe45f20d3c9f362 POLYVAL(H, X_1, X_2)= f7a3b47b846119fae5b7866cf5e5b77e */ \$X = str_split(\$X,32); \$H = \$this->mulX_GHASH(\$Y); \$GHASH = str_repeat("\0",16); \$i = 0; while(\$igfmul(bin2hex(\$GHASH^pack("H*",\$this->reverse(\$X[\$i]))),\$H)); ++\$i; } return \$this->reverse(bin2hex(\$GHASH)); } } \$gf128=new Galois128; echo " PCLMULQDQ ".\$gf128->PCLMULQDQ("7b5b54657374566563746f725d53475d","48692853686179295b477565726f6e5d")."\n"; echo " GFMUL ".\$gf128->GFMUL("952b2a56a5604ac0b32b6656a05b40b6","dfa6bf4ded81db03ffcaff95f830f061")."\n"; echo " mulX_POLYVAL ".\$gf128->mulX_POLYVAL(("25629347589242761d31f826ba4b757b"))."\n"; echo " mulX_GHASH ".\$gf128->mulX_GHASH(("25629347589242761d31f826ba4b757b"))."\n"; echo " GHASH ".\$gf128->dot_siv_ghash("4f4f95668c83dfb6401762bb2d01a262d1a24ddd2721d006bbe45f20d3c9f362","25629347589242761d31f826ba4b757b")."\n"; /* from https://www.ietf.org/id/draft-irtf-cfrg-gcmsiv-09.txt page 10 The latter halves of the ciphertext blocks are discarded and the remaining bytes are concatenated to form the per-message keys. Thus the message-authentication key is 310728d9911f1f3837b24316c3fab9a0 and the message-encryption key is a4c5ae6249963279c100be4d7e2c6edd. The length block contains the encoding of the bit-lengths of the additional data and plaintext, respectively. The string "example" is seven characters, thus 56 bits (or 0x38 in hex). The string "Hello world" is 11 characters, or 88 = 0x58 bits. Thus the length block is 38000000000000005800000000000000. The input to POLYVAL is the padded additional data, padded plaintext and then the length block. This is 6578616d706c6500000000000000000048656c6c6f20776f726c64000000000038000000000000005800000000000000 based on the ASCII encoding of "example" (6578616d706c65) and of "Hello world" (48656c6c6f20776f726c64). Calling POLYVAL with the message-authentication key and the input above results in S_s = ad7fcf0b5169851662672f3c5f95138f. */ echo "\nComputing POLYVAL\n\n"; \$input ="6578616d706c6500000000000000000048656c6c6f20776f726c64000000000038000000000000005800000000000000"; \$authkey="310728d9911f1f3837b24316c3fab9a0"; echo " Valid result ad7fcf0b5169851662672f3c5f95138f\n"; \$t=hrtime(true); echo " POLYVAL ".\$gf128->dot_siv_polyval(\$input,\$authkey)." "; echo ((hrtime(true)-\$t)/1000000)." ms (in binary mode)\n"; \$t=hrtime(true); echo " dot_big_math ".\$gf128->dot_big_math(\$input,\$authkey)." "; echo ((hrtime(true)-\$t)/1000000)." ms (long long mode 1)\n"; \$t=hrtime(true); echo " dot_big_math2 ".\$gf128->dot2(\$input,\$authkey)." "; echo ((hrtime(true)-\$t)/1000000)." ms (long long mode 2)\n"; ``` About us Advertise on this site Site map Newsletter Statistics Site tips Privacy policy Contact
For more information send a message to `info at phpclasses dot org`.