├── Makefile ├── xboxlib.h ├── sha1.h ├── README.md ├── main.c ├── xbevalidate.c ├── xbestructure.h ├── giants.h ├── sha1.c ├── xboxlib.c ├── xbedump.c ├── xboxkrnl.h └── giants.c /Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | OPT = -O2 3 | FLAGS = $(OPT) -ansi -Wall -Wextra -pedantic 4 | 5 | 6 | TOPDIR := $(shell /bin/pwd) 7 | 8 | THINGS = giants.o sha1.o xboxlib.o xbedump.o xbevalidate.o main.o 9 | 10 | all: clean xbe 11 | 12 | %.o : %.c 13 | ${CXX} ${FLAGS} -o $@ -c $< 14 | 15 | xbe: ${THINGS} ${CRYPTOLIB} 16 | ${CXX} -o $@ -lm ${THINGS} 17 | clean: 18 | -rm -f *.o xbe core 19 | -------------------------------------------------------------------------------- /xboxlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | typedef struct _RSA_PUBLIC_KEY 3 | { 4 | // 000 Magic - always "RSA1" 5 | char Magic[4]; 6 | // 004 Size of the key in bytes, starting at Unknown??? (0x108) 7 | SIZE_T KeySize; 8 | // 008 Size of the RSA modulus in bits (always 0x800) 9 | ULONG ModulusSize; 10 | // 00C Unknown (always 0xFF) 11 | ULONG Unknown; 12 | // 010 RSA public exponent (65537) 13 | ULONG PublicExponent; 14 | // 014 RSA modulus in Intel order 15 | UCHAR Modulus[1]; 16 | } RSA_PUBLIC_KEY, *PRSA_PUBLIC_KEY; 17 | */ 18 | 19 | void shax(unsigned char *result, unsigned char *data, unsigned int len); 20 | int VerifySignaturex(void *xbe,int debugout); 21 | int GenarateSignaturex(void *xbe); 22 | int dump_rsaxbe(char *filename); 23 | int read_rsafromflash(char *filename,unsigned int dumpflag); 24 | int VerifyCertificatex(void *xbe); 25 | int load_rsa(unsigned int dumpflag); 26 | 27 | int load_xbefile(void* &xbe,unsigned int &filesize,char *filename); 28 | unsigned int xorentry(int modus); 29 | unsigned int xorthunk(int modus); 30 | -------------------------------------------------------------------------------- /sha1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sha1.h 3 | * 4 | * Description: 5 | * This is the header file for code which implements the Secure 6 | * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published 7 | * April 17, 1995. 8 | * 9 | * Many of the variable names in this code, especially the 10 | * single character names, were used because those were the names 11 | * used in the publication. 12 | * 13 | * Please read the file sha1.c for more information. 14 | * 15 | */ 16 | 17 | #ifndef _SHA1_H_ 18 | #define _SHA1_H_ 19 | 20 | #include 21 | /* 22 | * If you do not have the ISO standard stdint.h header file, then you 23 | * must typdef the following: 24 | * name meaning 25 | * uint32_t unsigned 32 bit integer 26 | * uint8_t unsigned 8 bit integer (i.e., unsigned char) 27 | * int_least16_t integer of >= 16 bits 28 | * 29 | */ 30 | 31 | #ifndef _SHA_enum_ 32 | #define _SHA_enum_ 33 | enum 34 | { 35 | shaSuccess = 0, 36 | shaNull, /* Null pointer parameter */ 37 | shaInputTooLong, /* input data too long */ 38 | shaStateError /* called Input after Result */ 39 | }; 40 | #endif 41 | #define SHA1HashSize 20 42 | 43 | /* 44 | * This structure will hold context information for the SHA-1 45 | * hashing operation 46 | */ 47 | typedef struct SHA1Context 48 | { 49 | uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ 50 | 51 | uint32_t Length_Low; /* Message length in bits */ 52 | uint32_t Length_High; /* Message length in bits */ 53 | 54 | /* Index into message block array */ 55 | int_least16_t Message_Block_Index; 56 | uint8_t Message_Block[64]; /* 512-bit message blocks */ 57 | 58 | int Computed; /* Is the digest computed? */ 59 | int Corrupted; /* Is the message digest corrupted? */ 60 | } SHA1Context; 61 | 62 | /* 63 | * Function Prototypes 64 | */ 65 | 66 | int SHA1Reset( SHA1Context *); 67 | int SHA1Input( SHA1Context *, 68 | const uint8_t *, 69 | unsigned int); 70 | int SHA1Result( SHA1Context *, 71 | uint8_t Message_Digest[SHA1HashSize]); 72 | 73 | 74 | #endif /* _SHA1_H_ */ 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xbedump 2 | Modifications and bugfixes of xbedump for the XQEMU project. 3 | 4 | Upstream: http://xbox.cvs.sourceforge.net/viewvc/xbox-linux/xbedump/ 5 | 6 | #Original Readme: 7 | 8 | ``` 9 | XBE Dumper 0.4 10 | --------------- 11 | 12 | by franz@caos.at, based on the original XBE 13 | Dumper by Michael Steil (mist@c64.org) 14 | 15 | 16 | The XBE dumper is now in the process of being enhanced to perform 17 | the same crypto operations on the XBE file as the Xbox kernel itself, 18 | using the same algorithms. 19 | 20 | The XBE signing process is in two stages. In Stage one, a SHA-1 hash of 21 | the contents of each XBE section is made and the hash stored in a table 22 | in the XBE header section. In stage 2, a single SHA-1 hash is made of 23 | the header region (including the section hashes and a signer certificate), 24 | the resulting single hash is then itself encrypted with strong 2048-bit 25 | RSA public/private key encryption and the resulting encrypted single hash 26 | ''signature'' stored near the start of the final, signed XBE file. 27 | 28 | In this release, the action of the first& second stage is implemented, so that 29 | the software is able to compute and store in the header SHA-1 hashes 30 | for each section in the unsigned XBE. It is also able to confirm that 31 | the hashes stored in the header are correct for the corresponding section 32 | contents. Work has started to implement Stage two, although this will be 33 | quite hard to fully complete without having the private key :-) 34 | 35 | However, the intention is to at least be able to have a functional model 36 | of the xbox validation actions, so that the correctness of any attempt to 37 | create a signed XBE can be reliably and rapidly assessed without using 38 | any Microsoft code. In the other direction, it is intended to have proven 39 | all of the code needed to sign XBEs given a valid signer certificate and 40 | the correct private key (which we of course lack at the moment). 41 | 42 | Additionally, this Software gives us the oportunity to make "cleaner" xbe's 43 | as the patching of Kernel (done by mod_chips) is reduced, and only the real 44 | Verify signature has to be "adapted". 45 | 46 | There are 2 additional key's in the source, these are key's build with my computer. 47 | The keys are test keys and do not work on "real" xboxes. 48 | We have agreed not to publish the MS$ public key in the CVS, as this would be a copyright 49 | problem. You have to copy a decryped and decompressed flash to the same directory, 50 | the programm is working in. 51 | 52 | Please refeer to the Help in the programm itself for operations. 53 | 54 | 55 | Installation 56 | ------------ 57 | 58 | The app relies on the OpenSSL libraries from 59 | http://www.openssl.org/source 60 | 61 | Here are the steps for installation: 62 | 63 | 1) download and unpack the openssl sources somewhere 64 | 2) enter the openssl-0.9.6g (<-- or whatever) directory 65 | 3) ./config 66 | 4) make 67 | 5) make test (should end with some version info, no explicit OK) 68 | 6) su (<-- make yourself root) 69 | 7) make install (<--- installs SSL stuff into /usr/local/ssl) 70 | 8) exit (<-- make yourself normal user again) 71 | 9) cd to where xbe dumper sources are 72 | 10) make (<--- should be no errors or warnings) 73 | 74 | One note, it was found that there are bogus link errors with the 75 | GCC 3.2 version shipped with Redhat 8.0 beta, if you experience 76 | these bogus "undefined reference to `__gxx_personality_v0'" 77 | errors uncomment the definition of this symbol in xbe.c and 78 | remake. 79 | 80 | 81 | 82 | Changelog 83 | --------- 84 | 85 | 0.2b Franz has added code to verify the signature 86 | 0.2a Franz started on adding crypto structure code 87 | 0.3a Mismatch of Andy and Franz checking, now learned to work with CVS 88 | 0.3b Checking the RSA signature + update sections hashes 89 | 0.3c Generation of a "custom signature" implemented 90 | 91 | (this document by andy@warmcat.com & franz@caos.at) 92 | ``` 93 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* Note: this code will work on little-endian 32-bit machines only! */ 2 | /*************************************************************************** 3 | * * 4 | * This program is free software; you can redistribute it and/or modify * 5 | * it under the terms of the GNU General Public License as published by * 6 | * the Free Software Foundation; either version 2 of the License, or * 7 | * (at your option) any later version. * 8 | * * 9 | ***************************************************************************/ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "xbestructure.h" 23 | #include "xboxlib.h" 24 | 25 | 26 | void usage(){ 27 | 28 | printf( 29 | "Usage: xbe [xbefile] [options]\n\n" 30 | 31 | " -da Dumps the complete XBE Header Structure\n" 32 | " -dh Dumps the Header info\n" 33 | " -dc Dumps the Certificate\n" 34 | " -ds Dumps the Sections\n" 35 | " -dl Dumps the Library Sections\n\n" 36 | 37 | " -vh Verifies the .xbe Header \n" 38 | " -wb Writes back the update to file out.xbe \n\n" 39 | 40 | " -sm Uses Microsoft Signature (default mode)\n" 41 | " (Note: Signing not possible, as we do not have the private key)\n" 42 | " -shabibi Uses the Habibi Signature Keys\n" 43 | " -st Uses the Test Keys i have created .. leaves the XOR unchanged\n\n" 44 | 45 | " -d1 Debug output for option -vh\n\n" 46 | 47 | " ---- Special Options -----\n\n" 48 | 49 | " -habibi Special Option, Signs the xbe with Habibi Key and Sets all media flags\n" 50 | " -sign Special Option, Signs the xbe with the key who is stored in the xboxlib.c\n" 51 | " patches the XOR Keys\n" 52 | " -xbgs Dumps xbgs output\n" 53 | " ? Display Help\n\n" 54 | 55 | "Note: This code will work on little-endian 32-bit machines only! \n\n" 56 | 57 | "(C)2002,2003 by XBL Team (hamtitampti) \n"); 58 | 59 | 60 | } 61 | 62 | int main (int argc, const char * argv[]) 63 | { 64 | int counter=0; 65 | unsigned int dumpflag=0; 66 | char filename[512]; 67 | int verifyagain=0; 68 | void* xbefile; 69 | unsigned int filesize; 70 | 71 | // dumpxbe("secret/xboxdash.xbe"); 72 | //validatexbe("secret/xboxdash.xbe"); 73 | if (argc == 2) { 74 | if (strcmp(argv[1],"--test")==0) { 75 | return 0; 76 | } 77 | } 78 | 79 | if (argc > 2) { 80 | 81 | strcpy(&filename[0],argv[1]); 82 | 83 | for (counter=2;counter 3 | #include 4 | 5 | /*************************************************************************** 6 | * * 7 | * This program is free software; you can redistribute it and/or modify * 8 | * it under the terms of the GNU General Public License as published by * 9 | * the Free Software Foundation; either version 2 of the License, or * 10 | * (at your option) any later version. * 11 | * * 12 | ***************************************************************************/ 13 | 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | #include "xbestructure.h" 25 | #include "xboxlib.h" 26 | 27 | 28 | int validatexbe(void *xbe,unsigned int filesize,unsigned int option_flag){ 29 | FILE *f; 30 | 31 | // int warn; 32 | int i; 33 | 34 | int fail=0; 35 | unsigned int xorkey; 36 | 37 | XBE_HEADER *header; 38 | XBE_CERTIFICATE *cert; 39 | XBE_SECTION *sechdr; 40 | // XBE_TLS *tls; 41 | // XBE_LIBRARY *lib; 42 | // unsigned char sha1hashout[20]; 43 | // unsigned char md5hashout[16]; 44 | 45 | // unsigned int EntryPoint; 46 | // unsigned int KernelThunkTable; 47 | unsigned char sha_Message_Digest[20]; 48 | int eax; 49 | 50 | 51 | 52 | 53 | header = (XBE_HEADER*) xbe; 54 | 55 | // If the magic value XBEH is not present, error 56 | printf("Magic XBEH value: "); 57 | if (memcmp(header->Magic, "XBEH", 4)==0) { printf("pass\n"); } else { fail=1; printf("fail\n"); } 58 | 59 | #if 0 60 | // If the header has the correct size, error ??? 61 | printf("Header Size: "); 62 | if (header->XbeHeaderSize == 0x178) { printf("pass\n"); } else { fail=1; printf("fail (0x%X)\n",header->XbeHeaderSize); } 63 | #endif 64 | 65 | // If the image base is not 00010000, 66 | printf("Image Base Address: "); 67 | if (((int)header->BaseAddress)== 0x10000) { printf("pass\n"); } else { fail=1; printf("fail\n"); } 68 | 69 | //eax = header->HeaderSize; 70 | eax = header->XbeHeaderSize; 71 | eax += 0x10000; 72 | 73 | // Validates the Certificate Entry Address 74 | printf("Certificate Address: "); 75 | if (eax == (int)header->Certificate) { printf("pass\n"); } else { fail=1; printf("fail\n"); } 76 | 77 | // Only continue if xbe is valid 78 | //if (fail == 1) { fprintf(stderr,"Invalid xbe\n"); exit(1); } 79 | 80 | printf("Certificate Size : "); 81 | cert = (XBE_CERTIFICATE *)(((char *)xbe) + (int)header->Certificate - (int)header->BaseAddress); 82 | if (cert->Size>=0x1d0) { printf("pass\n"); } else { fail=1; printf("fail\n"); } 83 | 84 | // Correct it, if Correct Bit Set 85 | if (option_flag & 0x00020000) { 86 | if (option_flag & 0x20000000) { // Habibi Option 87 | printf("Correcting Mediatypes and Regions \n"); 88 | cert->MediaTypes = 0x800000FF; 89 | cert->GameRegion = 0x80000007; 90 | } 91 | } 92 | // Validates the Section Header Address 93 | printf("Section Address: "); 94 | //eax +=0x1D0; 95 | eax += cert->Size; 96 | if (eax == (int)header->Sections) { printf("pass\n"); } else { fail=1; printf("fail\n"); } 97 | 98 | 99 | // Check, that Debug Address is not set 100 | printf("Debug Address: "); 101 | if ((int)header->DebugImportTable== 0) { printf("pass\n"); } else { fail=1; printf("fail\n"); } 102 | 103 | // XOR Entry Address 104 | //header->EntryPoint = (void *)((int) header->EntryPoint ^0xA8FC57AB); 105 | // XOR Kernel Image thunk Address 106 | //header->KernelThunkTable = (unsigned int *)((int) header->KernelThunkTable ^ 0x5B6D40B6); 107 | 108 | if (option_flag & 0x00100000) { 109 | // Patch XOR keys 110 | printf("Patch XOR Keys\n"); 111 | header->EntryPoint ^= xorentry(1); 112 | header->KernelThunkTable ^= xorthunk(1); 113 | 114 | } 115 | xorkey=xorentry(0); 116 | printf("Kernel Entry: %08X (KEY: %08X)\n",(int)header->EntryPoint^xorkey,xorkey); 117 | xorkey=xorthunk(0); 118 | printf("Kernel Thunk Table: %08X (KEY: %08X)\n",(int)header->KernelThunkTable^xorkey,xorkey); 119 | // Check the Hash of the Sections 120 | 121 | //printf("THUNK-ENTRY XOR: %08X\n",xorthunk()) ; 122 | //printf("DEGUG-ENTRY XOR: %08X\n",xorentry()) ; 123 | 124 | sechdr = (XBE_SECTION *)(((char *)xbe) + (int)header->Sections - (int)header->BaseAddress); 125 | 126 | for (i = 0; i < header->NumSections; i++, sechdr++) { 127 | shax(&sha_Message_Digest[0], ((unsigned char *)xbe)+(int)sechdr->FileAddress ,sechdr->FileSize); 128 | 129 | printf("Section: %2d Hash: ",i); 130 | 131 | 132 | if (memcmp(&sha_Message_Digest[0],&sechdr->ShaHash[0],20)==0) { 133 | printf("pass"); 134 | } else { 135 | fail=1; 136 | printf("fail"); 137 | } 138 | 139 | // Debug Message D1 140 | if (option_flag & 0x01000000) { 141 | printf("\n in File -> "); 142 | for (int a=0;a<20;a++) printf("%02x",sechdr->ShaHash[a]); 143 | printf("\n should be -> "); 144 | for (int a=0;a<20;a++) printf("%02x",sha_Message_Digest[a]); 145 | 146 | } 147 | 148 | // Correct it, if Correct Bit Set 149 | if (option_flag & 0x00020000) { 150 | memcpy(&sechdr->ShaHash[0],&sha_Message_Digest[0],20); 151 | printf(" -> corrected"); 152 | } 153 | 154 | printf("\n"); 155 | } 156 | 157 | if (option_flag & 0x00080000) { 158 | printf("Correcting Signature:\n"); 159 | GenarateSignaturex(xbe); 160 | } 161 | 162 | printf("2048 RSA Signature: "); 163 | if (VerifySignaturex(xbe,0)== 1) { 164 | printf("pass"); 165 | // Debug Message D1 166 | if (option_flag & 0x01000000) { 167 | VerifySignaturex(xbe,1); 168 | } 169 | } else { 170 | fail=1; 171 | printf("fail"); 172 | if (option_flag & 0x01000000) { 173 | VerifySignaturex(xbe,1); 174 | } 175 | } 176 | 177 | 178 | printf("\n"); 179 | if (!(option_flag & 0x00020000)){ 180 | if (fail==0) { 181 | printf("\nXBE file integrity: OK\n"); 182 | } 183 | else { 184 | printf("\nXBE file integrity: FALSE !!!!!!! FALSE !!!!!\n"); 185 | } 186 | } 187 | 188 | if (option_flag & 0x00020000){ 189 | f = fopen("out.xbe", "wb"); 190 | if (f==NULL) { 191 | fprintf(stderr,"\nError writing out.xbe - %s\n",strerror(errno)); 192 | exit(1); 193 | } 194 | else { 195 | fwrite(xbe, 1, filesize, f); 196 | fclose(f); 197 | } 198 | } 199 | 200 | 201 | 202 | 203 | return 0; 204 | } 205 | 206 | 207 | -------------------------------------------------------------------------------- /xbestructure.h: -------------------------------------------------------------------------------- 1 | // XBE stuff 2 | // Not used in any exported kernel calls, but still useful. 3 | 4 | /*************************************************************************** 5 | * * 6 | * This program is free software; you can redistribute it and/or modify * 7 | * it under the terms of the GNU General Public License as published by * 8 | * the Free Software Foundation; either version 2 of the License, or * 9 | * (at your option) any later version. * 10 | * * 11 | ***************************************************************************/ 12 | 13 | 14 | #include 15 | 16 | // XBE header information 17 | typedef struct _XBE_HEADER { 18 | // 000 "XBEH" 19 | uint8_t Magic[4]; 20 | // 004 RSA digital signature of the entire header area 21 | uint8_t HeaderSignature[256]; 22 | //uint32_t HeaderSignature[64]; 23 | // 104 Base address of XBE image (must be 0x00010000?) 24 | uint32_t BaseAddress; 25 | // 108 Size of all headers combined - other headers must be within this 26 | uint32_t HeaderSize; 27 | // 10C Size of entire image 28 | uint32_t ImageSize; 29 | // 110 Size of this header (always 0x178?) 30 | uint32_t XbeHeaderSize; 31 | // 114 Image timestamp - unknown format 32 | uint32_t Timestamp; 33 | // 118 Pointer to certificate data (must be within HeaderSize) 34 | /*struct _XBE_CERTIFICATE */ uint32_t Certificate; 35 | // 11C Number of sections 36 | int32_t NumSections; 37 | // 120 Pointer to section headers (must be within HeaderSize) 38 | /*struct _XBE_SECTION */ uint32_t Sections; 39 | // 124 Initialization flags 40 | uint32_t InitFlags; 41 | // 128 Entry point32_t (XOR'd; see xboxhacker.net) 42 | uint32_t EntryPoint; 43 | // 12C Pointer to TLS directory 44 | /*struct _XBE_TLS_DIRECTORY */ uint32_t TlsDirectory; 45 | // 130 Stack commit size 46 | uint32_t StackCommit; 47 | // 134 Heap reserve size 48 | uint32_t HeapReserve; 49 | // 138 Heap commit size 50 | uint32_t HeapCommit; 51 | // 13C PE base address (?) 52 | uint32_t PeBaseAddress; 53 | // 140 PE image size (?) 54 | uint32_t PeImageSize; 55 | // 144 PE checksum (?) 56 | uint32_t PeChecksum; 57 | // 148 PE timestamp (?) 58 | uint32_t PeTimestamp; 59 | // 14C PC path and filename to EXE file from which XBE is derived 60 | /*uint8_t*/ uint32_t PcExePath; 61 | // 150 PC filename (last part of PcExePath) from which XBE is derived 62 | /*uint8_t*/ uint32_t PcExeFilename; 63 | // 154 PC filename (Unicode version of PcExeFilename) 64 | uint32_t PcExeFilenameUnicode; 65 | // 158 Pointer to kernel thunk table (XOR'd; EFB1F152 debug) 66 | uint32_t KernelThunkTable; 67 | // 15C Non-kernel import table (debug only) 68 | uint32_t DebugImportTable; 69 | // 160 Number of library headers 70 | int32_t NumLibraries; 71 | // 164 Pointer to library headers 72 | /*struct _XBE_LIBRARY */ uint32_t Libraries; 73 | // 168 Pointer to kernel library header 74 | /*struct _XBE_LIBRARY */ uint32_t KernelLibrary; 75 | // 16C Pointer to XAPI library 76 | /*struct _XBE_LIBRARY */ uint32_t XapiLibrary; 77 | // 170 Pointer to logo bitmap (NULL = use default of Microsoft) 78 | uint32_t LogoBitmap; 79 | // 174 Size of logo bitmap 80 | uint32_t LogoBitmapSize; 81 | // 178 82 | } XBE_HEADER, *PXBE_HEADER; 83 | 84 | // Certificate structure 85 | typedef struct _XBE_CERTIFICATE { 86 | // 000 Size of certificate 87 | uint32_t Size; 88 | // 004 Certificate timestamp (unknown format) 89 | uint32_t Timestamp; 90 | // 008 Title ID 91 | uint32_t TitleId; 92 | // 00C Name of the game (Unicode) 93 | int16_t TitleName[40]; 94 | // 05C Alternate title ID's (0-terminated) 95 | uint32_t AlternateTitleIds[16]; 96 | // 09C Allowed media types - 1 bit match between XBE and media = boots 97 | uint32_t MediaTypes; 98 | // 0A0 Allowed game regions - 1 bit match between this and XBOX = boots 99 | uint32_t GameRegion; 100 | // 0A4 Allowed game ratings - 1 bit match between this and XBOX = boots 101 | uint32_t GameRating; 102 | // 0A8 Disk number (?) 103 | uint32_t DiskNumber; 104 | // 0AC Version (?) 105 | uint32_t Version; 106 | // 0B0 LAN key for this game 107 | uint8_t LanKey[16]; 108 | // 0C0 Signature key for this game 109 | uint8_t SignatureKey[16]; 110 | // 0D0 Signature keys for the alternate title ID's 111 | uint8_t AlternateSignatureKeys[16][16]; 112 | // 1D0 113 | } XBE_CERTIFICATE, *PXBE_CERTIFICATE; 114 | 115 | // Section headers 116 | typedef struct _XBE_SECTION { 117 | // 000 Flags 118 | uint32_t Flags; 119 | // 004 Virtual address (where this section loads in RAM) 120 | //uint32_t VirtualAddress; 121 | uint32_t VirtualAddress; 122 | // 008 Virtual size (size of section in RAM; after FileSize it's 00'd) 123 | uint32_t VirtualSize; 124 | // 00C File address (where in the file from which this section comes) 125 | uint32_t FileAddress; 126 | // 010 File size (size of the section in the XBE file) 127 | uint32_t FileSize; 128 | // 014 Pointer to section name 129 | /*uint8_t*/ uint32_t SectionName; 130 | // 018 Section reference count - when >= 1, section is loaded 131 | int32_t SectionReferenceCount; 132 | // 01C Pointer to head shared page reference count 133 | /*int16_t */ uint32_t HeadReferenceCount; 134 | // 020 Pointer to tail shared page reference count 135 | /*int16_t */ uint32_t TailReferenceCount; 136 | // 024 SHA1 hash. Hash int32_t containing FileSize, then hash section. 137 | uint8_t ShaHash[20]; 138 | // 038 139 | } XBE_SECTION, *PXBE_SECTION; 140 | 141 | // TLS directory information 142 | typedef struct _XBE_TLS { 143 | // 000 raw data start address 144 | int32_t RawStart; 145 | // 004 raw data end address 146 | int32_t RawEnd; 147 | // 008 TLS index address 148 | int32_t TlsIndex; 149 | // 00C TLS callbacks address 150 | int32_t TlsCallbacks; 151 | // 010 size of zero fill 152 | int32_t SizeZeroFill; 153 | // 014 uint8_tacteristics 154 | uint8_t uint8_tacteristics[8]; 155 | // 01C 156 | } XBE_TLS, *PXBE_TLS; 157 | 158 | // Library version data 159 | typedef struct _XBE_LIBRARY { 160 | // 000 Library Name 161 | uint8_t Name[8]; 162 | // 008 Major Version 163 | int16_t MajorVersion; 164 | // 00A Middle Version 165 | int16_t MiddleVersion; 166 | // 00C Minor Version 167 | int16_t MinorVersion; 168 | // 00E Flags 169 | int16_t Flags; 170 | // 010 171 | } XBE_LIBRARY, *PXBELIBRARY; 172 | 173 | // Initialization flags 174 | #define XBE_INIT_MOUNT_UTILITY 0x00000001 175 | #define XBE_INIT_FORMAT_UTILITY 0x00000002 176 | #define XBE_INIT_64M_RAM_ONLY 0x00000004 177 | #define XBE_INIT_DONT_SETUP_HDD 0x00000008 178 | 179 | // Region codes 180 | #define XBE_REGION_US_CANADA 0x00000001 181 | #define XBE_REGION_JAPAN 0x00000002 182 | #define XBE_REGION_ELSEWHERE 0x00000004 183 | #define XBE_REGION_DEBUG 0x80000000 184 | 185 | // Media types 186 | #define XBE_MEDIA_HDD 0x00000001 187 | #define XBE_MEDIA_XBOX_DVD 0x00000002 188 | #define XBE_MEDIA_ANY_CD_OR_DVD 0x00000004 189 | #define XBE_MEDIA_CD 0x00000008 190 | #define XBE_MEDIA_1LAYER_DVDROM 0x00000010 191 | #define XBE_MEDIA_2LAYER_DVDROM 0x00000020 192 | #define XBE_MEDIA_1LAYER_DVDR 0x00000040 193 | #define XBE_MEDIA_2LAYER_DVDR 0x00000080 194 | #define XBE_MEDIA_USB 0x00000100 195 | #define XBE_MEDIA_ALLOW_UNLOCKED_HDD 0x40000000 196 | 197 | // Section flags 198 | #define XBE_SEC_WRITABLE 0x00000001 199 | #define XBE_SEC_PRELOAD 0x00000002 200 | #define XBE_SEC_EXECUTABLE 0x00000004 201 | #define XBE_SEC_INSERTED_FILE 0x00000008 202 | #define XBE_SEC_RO_HEAD_PAGE 0x00000010 203 | #define XBE_SEC_RO_TAIL_PAGE 0x00000020 204 | 205 | void shax(uint8_t *result, uint8_t *data, uint32_t len); 206 | int32_t validatexbe(void *xbe,uint32_t filesize,uint32_t option_flag); 207 | int32_t dumpxbe (void *xbe,uint32_t option_flag); 208 | 209 | -------------------------------------------------------------------------------- /giants.h: -------------------------------------------------------------------------------- 1 | /************************************************************** 2 | * 3 | * giants.h 4 | * 5 | * Header file for large-integer arithmetic library giants.c. 6 | * 7 | * Updates: 8 | * 18 Jul 99 REC Added fer_mod(). 9 | * 30 Apr 98 JF USE_ASSEMBLER_MUL removed 10 | * 29 Apr 98 JF Function prototypes cleaned up 11 | * 20 Apr 97 RDW 12 | * 13 | * c. 1997 Perfectly Scientific, Inc. 14 | * All Rights Reserved. 15 | * 16 | **************************************************************/ 17 | 18 | 19 | /************************************************************** 20 | * 21 | * Error Codes 22 | * 23 | **************************************************************/ 24 | 25 | #define DIVIDEBYZERO 1 26 | #define OVFLOW 2 27 | #define SIGN 3 28 | #define OVERRANGE 4 29 | #define AUTO_MUL 0 30 | #define GRAMMAR_MUL 1 31 | #define FFT_MUL 2 32 | #define KARAT_MUL 3 33 | 34 | /************************************************************** 35 | * 36 | * Preprocessor definitions 37 | * 38 | **************************************************************/ 39 | 40 | /* 2^(16*MAX_SHORTS)-1 will fit into a giant, but take care: 41 | * one usually has squares, etc. of giants involved, and 42 | * every intermediate giant in a calculation must fit into 43 | * this many shorts. Thus, if you want systematically to effect 44 | * arithmetic on B-bit operands, you need MAX_SHORTS > B/8, 45 | * perferably a tad larger than this; e.g. MAX_SHORTS > B/7. 46 | */ 47 | #define MAX_SHORTS (1<<19) 48 | 49 | #define GIANT_INFINITY (-1) 50 | #define FA 0 51 | #define TR 1 52 | #define COLUMNWIDTH 64 53 | 54 | #define TWOPI (double)(2*3.1415926535897932384626433) 55 | #define SQRT2 (double)(1.414213562373095048801688724209) 56 | #define SQRTHALF (double)(0.707106781186547524400844362104) 57 | #define TWO16 (double)(65536.0) 58 | #define TWOM16 (double)(0.0000152587890625) 59 | 60 | /* Decimal digit ceiling in digit-input routines. */ 61 | #define MAX_DIGITS 10000 62 | 63 | /* Next, mumber of shorts per operand 64 | at which Karatsuba breaks over. */ 65 | #define KARAT_BREAK 40 66 | 67 | /* Next, mumber of shorts per operand 68 | at which FFT breaks over. */ 69 | #define FFT_BREAK 200 70 | 71 | #define newmin(a,b) ((a)<(b)? (a) : (b)) 72 | #define newmax(a,b) ((a)>(b)? (a) : (b)) 73 | 74 | /* Maximum number of recursive steps needed to calculate 75 | * gcds of integers. */ 76 | #define STEPS 32 77 | 78 | /* The limit below which hgcd is too ponderous */ 79 | #define GCDLIMIT 5000 80 | 81 | /* The limit below which ordinary ints will be used */ 82 | #define INTLIMIT 31 83 | 84 | /* Size by which to increment the stack used in pushg() and popg(). */ 85 | #define STACK_GROW 16 86 | 87 | #define gin(x) gread(x,stdin) 88 | #define gout(x) gwriteln(x,stdout) 89 | 90 | 91 | /************************************************************** 92 | * 93 | * Structure definitions 94 | * 95 | **************************************************************/ 96 | 97 | typedef struct 98 | { 99 | int sign; 100 | unsigned short n[1]; /* number of shorts = abs(sign) */ 101 | } giantstruct; 102 | 103 | typedef giantstruct *giant; 104 | 105 | typedef struct _matrix 106 | { 107 | giant ul; /* upper left */ 108 | giant ur; /* upper right */ 109 | giant ll; /* lower left */ 110 | giant lr; /* lower right */ 111 | } *gmatrix; 112 | 113 | typedef struct 114 | { 115 | double re; 116 | double im; 117 | } complex; 118 | 119 | 120 | /************************************************************** 121 | * 122 | * Function Prototypes 123 | * 124 | **************************************************************/ 125 | 126 | /************************************************************** 127 | * 128 | * Initialization and utility functions 129 | * 130 | **************************************************************/ 131 | 132 | /* trig lookups. */ 133 | void init_sinCos(int); 134 | double s_sin(int); 135 | double s_cos(int); 136 | 137 | 138 | /* Creates a new giant, numshorts = GIANT_INFINITY invokes the 139 | * maximum MAX_SHORTS. */ 140 | giant newgiant(int numshorts); 141 | 142 | /* Creates a new giant matrix, but does not malloc 143 | * the component giants. */ 144 | gmatrix newgmatrix(void); 145 | 146 | /* Returns the bit-length n; e.g. n=7 returns 3. */ 147 | int bitlen(giant n); 148 | 149 | /* Returns the value of the pos bit of n. */ 150 | int bitval(giant n, int pos); 151 | 152 | /* Returns whether g is one. */ 153 | int isone(giant g); 154 | 155 | /* Returns whether g is zero. */ 156 | int isZero(giant g); 157 | 158 | /* Copies one giant to another. */ 159 | void gtog(giant src, giant dest); 160 | 161 | /* Integer <-> giant. */ 162 | void itog(int n, giant g); 163 | signed int gtoi (giant); 164 | 165 | /* Returns the sign of g: -1, 0, 1. */ 166 | int gsign(giant g); 167 | 168 | /* Returns 1, 0, -1 as a>b, a=b, a (included via "sha1.h" to define 32 and 8 19 | * bit unsigned integer types. If your C compiler does not 20 | * support 32 bit unsigned integers, this code is not 21 | * appropriate. 22 | * 23 | * Caveats: 24 | * SHA-1 is designed to work with messages less than 2^64 bits 25 | * long. Although SHA-1 allows a message digest to be generated 26 | * for messages of any number of bits less than 2^64, this 27 | * implementation only works with messages with a length that is 28 | * a multiple of the size of an 8-bit character. 29 | * 30 | */ 31 | 32 | 33 | #include "sha1.h" 34 | 35 | 36 | 37 | /* 38 | * Define the SHA1 circular left shift macro 39 | */ 40 | #define SHA1CircularShift(bits,word) \ 41 | (((word) << (bits)) | ((word) >> (32-(bits)))) 42 | /* Local Function Prototyptes */ 43 | void SHA1PadMessage(SHA1Context *); 44 | void SHA1ProcessMessageBlock(SHA1Context *); 45 | 46 | /* 47 | * SHA1Reset 48 | * 49 | * Description: 50 | * This function will initialize the SHA1Context in preparation 51 | * for computing a new SHA1 message digest. 52 | * 53 | * Parameters: 54 | * context: [in/out] 55 | * The context to reset. 56 | * 57 | * Returns: 58 | * sha Error Code. 59 | * 60 | */ 61 | int SHA1Reset(SHA1Context *context) 62 | { 63 | if (!context) 64 | { 65 | return shaNull; 66 | } 67 | 68 | context->Length_Low = 0; 69 | context->Length_High = 0; 70 | context->Message_Block_Index = 0; 71 | 72 | context->Intermediate_Hash[0] = 0x67452301; 73 | context->Intermediate_Hash[1] = 0xEFCDAB89; 74 | context->Intermediate_Hash[2] = 0x98BADCFE; 75 | context->Intermediate_Hash[3] = 0x10325476; 76 | context->Intermediate_Hash[4] = 0xC3D2E1F0; 77 | 78 | context->Computed = 0; 79 | context->Corrupted = 0; 80 | 81 | return shaSuccess; 82 | } 83 | 84 | /* 85 | * SHA1Result 86 | * 87 | * Description: 88 | * This function will return the 160-bit message digest into the 89 | * Message_Digest array provided by the caller. 90 | * NOTE: The first octet of hash is stored in the 0th element, 91 | * the last octet of hash in the 19th element. 92 | * 93 | * Parameters: 94 | * context: [in/out] 95 | * The context to use to calculate the SHA-1 hash. 96 | * Message_Digest: [out] 97 | * Where the digest is returned. 98 | * 99 | * Returns: 100 | * sha Error Code. 101 | * 102 | */ 103 | int SHA1Result( SHA1Context *context, 104 | uint8_t Message_Digest[SHA1HashSize]) 105 | { 106 | int i; 107 | 108 | if (!context || !Message_Digest) 109 | { 110 | return shaNull; 111 | } 112 | 113 | if (context->Corrupted) 114 | { 115 | return context->Corrupted; 116 | } 117 | 118 | if (!context->Computed) 119 | { 120 | SHA1PadMessage(context); 121 | for(i=0; i<64; ++i) 122 | { 123 | /* message may be sensitive, clear it out */ 124 | context->Message_Block[i] = 0; 125 | } 126 | context->Length_Low = 0; /* and clear length */ 127 | context->Length_High = 0; 128 | context->Computed = 1; 129 | 130 | } 131 | 132 | for(i = 0; i < SHA1HashSize; ++i) 133 | { 134 | Message_Digest[i] = context->Intermediate_Hash[i>>2] 135 | >> 8 * ( 3 - ( i & 0x03 ) ); 136 | 137 | // printf("\n%08x",context->Intermediate_Hash[i]); 138 | } 139 | 140 | return shaSuccess; 141 | } 142 | 143 | /* 144 | * SHA1Input 145 | * 146 | * Description: 147 | * This function accepts an array of octets as the next portion 148 | * of the message. 149 | * 150 | * Parameters: 151 | * context: [in/out] 152 | * The SHA context to update 153 | * message_array: [in] 154 | * An array of characters representing the next portion of 155 | * the message. 156 | * length: [in] 157 | * The length of the message in message_array 158 | * 159 | * Returns: 160 | * sha Error Code. 161 | * 162 | */ 163 | int SHA1Input( SHA1Context *context, 164 | const uint8_t *message_array, 165 | unsigned length) 166 | { 167 | if (!length) return shaSuccess; 168 | 169 | 170 | if (!context || !message_array) return shaNull; 171 | 172 | if (context->Computed) { 173 | context->Corrupted = shaStateError; 174 | return shaStateError; 175 | } 176 | 177 | if (context->Corrupted) return context->Corrupted; 178 | 179 | 180 | while(length-- && !context->Corrupted){ 181 | context->Message_Block[context->Message_Block_Index++] = (*message_array & 0xFF); 182 | context->Length_Low += 8; 183 | 184 | if (context->Length_Low == 0){ 185 | context->Length_High++; 186 | 187 | if (context->Length_High == 0) { 188 | /* Message is too long */ 189 | context->Corrupted = 1; 190 | } 191 | } 192 | 193 | if (context->Message_Block_Index == 64) { 194 | SHA1ProcessMessageBlock(context); 195 | } 196 | 197 | message_array++; 198 | } 199 | 200 | return shaSuccess; 201 | } 202 | 203 | /* 204 | * SHA1ProcessMessageBlock 205 | * 206 | * Description: 207 | * This function will process the next 512 bits of the message 208 | * stored in the Message_Block array. 209 | * 210 | * Parameters: 211 | * None. 212 | * 213 | * Returns: 214 | * Nothing. 215 | * 216 | * Comments: 217 | 218 | * Many of the variable names in this code, especially the 219 | * single character names, were used because those were the 220 | * names used in the publication. 221 | * 222 | * 223 | */ 224 | void SHA1ProcessMessageBlock(SHA1Context *context) 225 | { 226 | const uint32_t K[] = { /* Constants defined in SHA-1 */ 227 | 0x5A827999, 228 | 0x6ED9EBA1, 229 | 0x8F1BBCDC, 230 | 0xCA62C1D6 231 | }; 232 | int t; /* Loop counter */ 233 | uint32_t temp; /* Temporary word value */ 234 | uint32_t W[80]; /* Word sequence */ 235 | uint32_t A, B, C, D, E; /* Word buffers */ 236 | 237 | for(t = 0; t < 16; t++) 238 | { 239 | W[t] = context->Message_Block[t * 4] << 24; 240 | W[t] |= context->Message_Block[t * 4 + 1] << 16; 241 | W[t] |= context->Message_Block[t * 4 + 2] << 8; 242 | W[t] |= context->Message_Block[t * 4 + 3]; 243 | } 244 | 245 | 246 | 247 | for(t = 16; t < 80; t++) 248 | { 249 | W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); 250 | } 251 | 252 | 253 | 254 | 255 | A = context->Intermediate_Hash[0]; 256 | B = context->Intermediate_Hash[1]; 257 | C = context->Intermediate_Hash[2]; 258 | D = context->Intermediate_Hash[3]; 259 | E = context->Intermediate_Hash[4]; 260 | 261 | for(t = 0; t < 20; t++) 262 | { 263 | temp = SHA1CircularShift(5,A) + 264 | ((B & C) | ((~B) & D)) + E + W[t] + K[0]; 265 | E = D; 266 | D = C; 267 | C = SHA1CircularShift(30,B); 268 | 269 | B = A; 270 | A = temp; 271 | } 272 | 273 | 274 | 275 | for(t = 20; t < 40; t++) 276 | { 277 | temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; 278 | E = D; 279 | D = C; 280 | C = SHA1CircularShift(30,B); 281 | B = A; 282 | A = temp; 283 | } 284 | 285 | for(t = 40; t < 60; t++) 286 | { 287 | temp = SHA1CircularShift(5,A) + 288 | ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; 289 | E = D; 290 | D = C; 291 | C = SHA1CircularShift(30,B); 292 | B = A; 293 | A = temp; 294 | } 295 | 296 | for(t = 60; t < 80; t++) 297 | { 298 | temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; 299 | E = D; 300 | D = C; 301 | C = SHA1CircularShift(30,B); 302 | B = A; 303 | A = temp; 304 | } 305 | 306 | context->Intermediate_Hash[0] += A; 307 | context->Intermediate_Hash[1] += B; 308 | context->Intermediate_Hash[2] += C; 309 | context->Intermediate_Hash[3] += D; 310 | context->Intermediate_Hash[4] += E; 311 | 312 | context->Message_Block_Index = 0; 313 | } 314 | 315 | /* 316 | * SHA1PadMessage 317 | * 318 | 319 | * Description: 320 | * According to the standard, the message must be padded to an even 321 | * 512 bits. The first padding bit must be a '1'. The last 64 322 | * bits represent the length of the original message. All bits in 323 | * between should be 0. This function will pad the message 324 | * according to those rules by filling the Message_Block array 325 | * accordingly. It will also call the ProcessMessageBlock function 326 | * provided appropriately. When it returns, it can be assumed that 327 | * the message digest has been computed. 328 | * 329 | * Parameters: 330 | * context: [in/out] 331 | * The context to pad 332 | * ProcessMessageBlock: [in] 333 | * The appropriate SHA*ProcessMessageBlock function 334 | * Returns: 335 | * Nothing. 336 | * 337 | */ 338 | 339 | void SHA1PadMessage(SHA1Context *context) 340 | { 341 | 342 | /* 343 | * Check to see if the current message block is too small to hold 344 | * the initial padding bits and length. If so, we will pad the 345 | * block, process it, and then continue padding into a second 346 | * block. 347 | */ 348 | 349 | if (context->Message_Block_Index > 55) 350 | { 351 | context->Message_Block[context->Message_Block_Index++] = 0x80; 352 | while(context->Message_Block_Index < 64) 353 | { 354 | context->Message_Block[context->Message_Block_Index++] = 0; 355 | } 356 | 357 | SHA1ProcessMessageBlock(context); 358 | 359 | while(context->Message_Block_Index < 56) 360 | { 361 | context->Message_Block[context->Message_Block_Index++] = 0; 362 | } 363 | } 364 | else 365 | { 366 | context->Message_Block[context->Message_Block_Index++] = 0x80; 367 | while(context->Message_Block_Index < 56) 368 | { 369 | 370 | context->Message_Block[context->Message_Block_Index++] = 0; 371 | } 372 | } 373 | 374 | /* 375 | * Store the message length as the last 8 octets 376 | */ 377 | context->Message_Block[56] = context->Length_High >> 24; 378 | context->Message_Block[57] = context->Length_High >> 16; 379 | context->Message_Block[58] = context->Length_High >> 8; 380 | context->Message_Block[59] = context->Length_High; 381 | context->Message_Block[60] = context->Length_Low >> 24; 382 | context->Message_Block[61] = context->Length_Low >> 16; 383 | context->Message_Block[62] = context->Length_Low >> 8; 384 | context->Message_Block[63] = context->Length_Low; 385 | 386 | SHA1ProcessMessageBlock(context); 387 | 388 | 389 | 390 | } 391 | 392 | 393 | -------------------------------------------------------------------------------- /xboxlib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /*************************************************************************** 5 | * * 6 | * This program is free software; you can redistribute it and/or modify * 7 | * it under the terms of the GNU General Public License as published by * 8 | * the Free Software Foundation; either version 2 of the License, or * 9 | * (at your option) any later version. * 10 | * * 11 | ***************************************************************************/ 12 | 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "xboxlib.h" 24 | #include "xbestructure.h" 25 | 26 | 27 | #include "giants.h" 28 | #include "sha1.h" 29 | 30 | 31 | // prototype 32 | 33 | 34 | // Test keys with Exponent = 1 35 | unsigned char Testkey[] = { 36 | 0x52,0x53,0x41,0x31, 0x08,0x01,0x00,0x00, 0x00,0x08,0x00,0x00, 0xff,0x00,0x00,0x00, 37 | 0x01,0x00,0x00,0x00, 38 | // Public Modulus "m" 39 | 0xd3,0xd7,0x4e,0xe5, 0x66,0x3d,0xd7,0xe6, 0xc2,0xd4,0xa3,0xa1, 0xf2,0x17,0x36,0xd4, 40 | 0x2e,0x52,0xf6,0xd2, 0x02,0x10,0xf5,0x64, 0x9c,0x34,0x7b,0xff, 0xef,0x7f,0xc2,0xee, 41 | 0xbd,0x05,0x8b,0xde, 0x79,0xb4,0x77,0x8e, 0x5b,0x8c,0x14,0x99, 0xe3,0xae,0xc6,0x73, 42 | 0x72,0x73,0xb5,0xfb, 0x01,0x5b,0x58,0x46, 0x6d,0xfc,0x8a,0xd6, 0x95,0xda,0xed,0x1b, 43 | 0x2e,0x2f,0xa2,0x29, 0xe1,0x3f,0xf1,0xb9, 0x5b,0x64,0x51,0x2e, 0xa2,0xc0,0xf7,0xba, 44 | 0xb3,0x3e,0x8a,0x75, 0xff,0x06,0x92,0x5c, 0x07,0x26,0x75,0x79, 0x10,0x5d,0x47,0xbe, 45 | 0xd1,0x6a,0x52,0x90, 0x0b,0xae,0x6a,0x0b, 0x33,0x44,0x93,0x5e, 0xf9,0x9d,0xfb,0x15, 46 | 0xd9,0xa4,0x1c,0xcf, 0x6f,0xe4,0x71,0x94, 0xbe,0x13,0x00,0xa8, 0x52,0xca,0x07,0xbd, 47 | 0x27,0x98,0x01,0xa1, 0x9e,0x4f,0xa3,0xed, 0x9f,0xa0,0xaa,0x73, 0xc4,0x71,0xf3,0xe9, 48 | 0x4e,0x72,0x42,0x9c, 0xf0,0x39,0xce,0xbe, 0x03,0x76,0xfa,0x2b, 0x89,0x14,0x9a,0x81, 49 | 0x16,0xc1,0x80,0x8c, 0x3e,0x6b,0xaa,0x05, 0xec,0x67,0x5a,0xcf, 0xa5,0x70,0xbd,0x60, 50 | 0x0c,0xe8,0x37,0x9d, 0xeb,0xf4,0x52,0xea, 0x4e,0x60,0x9f,0xe4, 0x69,0xcf,0x52,0xdb, 51 | 0x68,0xf5,0x11,0xcb, 0x57,0x8f,0x9d,0xa1, 0x38,0x0a,0x0c,0x47, 0x1b,0xb4,0x6c,0x5a, 52 | 0x53,0x6e,0x26,0x98, 0xf1,0x88,0xae,0x7c, 0x96,0xbc,0xf6,0xbf, 0xb0,0x47,0x9a,0x8d, 53 | 0xe4,0xb3,0xe2,0x98, 0x85,0x61,0xb1,0xca, 0x5f,0xf7,0x98,0x51, 0x2d,0x83,0x81,0x76, 54 | 0x0c,0x88,0xba,0xd4, 0xc2,0xd5,0x3c,0x14, 0xc7,0x72,0xda,0x7e, 0xbd,0x1b,0x4b,0xa4, 55 | // Private Key "d" 56 | 57 | 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 58 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 59 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 60 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 61 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 62 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 63 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 64 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 65 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 66 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 67 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 68 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 69 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 70 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 71 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 72 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 73 | 74 | }; 75 | 76 | 77 | unsigned char xboxPublicKeyData[] = { 78 | 0x52,0x53,0x41,0x31, 0x08,0x01,0x00,0x00, 0x00,0x08,0x00,0x00, 0xff,0x00,0x00,0x00, 79 | 0x01,0x00,0x01,0x00, 80 | // Public Modulus "m" 81 | 0xd3,0xd7,0x4e,0xe5, 0x66,0x3d,0xd7,0xe6, 0xc2,0xd4,0xa3,0xa1, 0xf2,0x17,0x36,0xd4, 82 | 0x2e,0x52,0xf6,0xd2, 0x02,0x10,0xf5,0x64, 0x9c,0x34,0x7b,0xff, 0xef,0x7f,0xc2,0xee, 83 | 0xbd,0x05,0x8b,0xde, 0x79,0xb4,0x77,0x8e, 0x5b,0x8c,0x14,0x99, 0xe3,0xae,0xc6,0x73, 84 | 0x72,0x73,0xb5,0xfb, 0x01,0x5b,0x58,0x46, 0x6d,0xfc,0x8a,0xd6, 0x95,0xda,0xed,0x1b, 85 | 0x2e,0x2f,0xa2,0x29, 0xe1,0x3f,0xf1,0xb9, 0x5b,0x64,0x51,0x2e, 0xa2,0xc0,0xf7,0xba, 86 | 0xb3,0x3e,0x8a,0x75, 0xff,0x06,0x92,0x5c, 0x07,0x26,0x75,0x79, 0x10,0x5d,0x47,0xbe, 87 | 0xd1,0x6a,0x52,0x90, 0x0b,0xae,0x6a,0x0b, 0x33,0x44,0x93,0x5e, 0xf9,0x9d,0xfb,0x15, 88 | 0xd9,0xa4,0x1c,0xcf, 0x6f,0xe4,0x71,0x94, 0xbe,0x13,0x00,0xa8, 0x52,0xca,0x07,0xbd, 89 | 0x27,0x98,0x01,0xa1, 0x9e,0x4f,0xa3,0xed, 0x9f,0xa0,0xaa,0x73, 0xc4,0x71,0xf3,0xe9, 90 | 0x4e,0x72,0x42,0x9c, 0xf0,0x39,0xce,0xbe, 0x03,0x76,0xfa,0x2b, 0x89,0x14,0x9a,0x81, 91 | 0x16,0xc1,0x80,0x8c, 0x3e,0x6b,0xaa,0x05, 0xec,0x67,0x5a,0xcf, 0xa5,0x70,0xbd,0x60, 92 | 0x0c,0xe8,0x37,0x9d, 0xeb,0xf4,0x52,0xea, 0x4e,0x60,0x9f,0xe4, 0x69,0xcf,0x52,0xdb, 93 | 0x68,0xf5,0x11,0xcb, 0x57,0x8f,0x9d,0xa1, 0x38,0x0a,0x0c,0x47, 0x1b,0xb4,0x6c,0x5a, 94 | 0x53,0x6e,0x26,0x98, 0xf1,0x88,0xae,0x7c, 0x96,0xbc,0xf6,0xbf, 0xb0,0x47,0x9a,0x8d, 95 | 0xe4,0xb3,0xe2,0x98, 0x85,0x61,0xb1,0xca, 0x5f,0xf7,0x98,0x51, 0x2d,0x83,0x81,0x76, 96 | 0x0c,0x88,0xba,0xd4, 0xc2,0xd5,0x3c,0x14, 0xc7,0x72,0xda,0x7e, 0xbd,0x1b,0x4b,0xa4 97 | // Private Key "d" 98 | // Could somebody insert it ? 99 | }; 100 | 101 | struct RSA_PUBLIC_KEY 102 | { 103 | char Magic[4]; // "RSA1" 104 | unsigned int Bloblen; // 264 (Modulus + Exponent + Modulussize) 105 | unsigned char Bitlen[4]; // 2048 106 | unsigned int ModulusSize; // 255 (bytes in the Modulus) 107 | unsigned char Exponent[4]; 108 | unsigned char Modulus[256]; // Bit endian style 109 | unsigned char Privatekey[256]; // Private Key .. we do not have it -- Big endian style 110 | }; 111 | struct RSA_PUBLIC_KEY xePublicKeyData; 112 | 113 | // Asterix .bin File format structure 114 | struct XboxKey 115 | { 116 | // Magic string ("RSA1") 117 | uint8_t magic[4]; 118 | // Size of key? Always 0x108 119 | uint32_t byte_size; 120 | // Bit size of key? Always 2048 121 | uint32_t bit_size; 122 | // Unknown; always 0xFF 123 | uint32_t unknown_FF; 124 | // Public exponent, always 65537 125 | uint32_t public_exponent; 126 | // modulus, which is factor1 * factor2 127 | uint8_t modulus[256]; 128 | 129 | // Private portions (these are kept secret to the Xbox Linux team) 130 | 131 | // First factor of the modulus 132 | uint8_t factor1[128]; 133 | // Second factor of the modulus 134 | uint8_t factor2[128]; 135 | // Random number used to make factor1 (factor1 = nextprime(random1)) 136 | uint8_t random1[128]; 137 | // Random number used to make factor2 (factor2 = nextprime(random2)) 138 | uint8_t random2[128]; 139 | // "Phi", which is (factor1 - 1) * (factor2 - 1) 140 | uint8_t phi[256]; 141 | // Private exponent, which is 65537^-1 mod phi 142 | uint8_t private_exponent[256]; 143 | }; 144 | 145 | const unsigned char RSApkcs1paddingtable[3][16] = { 146 | {0x0F, 0x14,0x04,0x00,0x05,0x1A,0x02,0x03,0x0E,0x2B,0x05,0x06,0x09,0x30,0x21,0x30}, 147 | {0x0D, 0x14,0x04,0x1A,0x02,0x03,0x0E,0x2B,0x05,0x06,0x07,0x30,0x1F,0x30,0x00,0x00}, 148 | {0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} 149 | }; 150 | 151 | 152 | int read_rsafrombin_asterix() 153 | { 154 | FILE *f; 155 | unsigned char *flash=0; 156 | int filesize=0; 157 | 158 | struct XboxKey tempkey; 159 | 160 | printf("Using Linux Test Keys from linuxkey.bin\n"); 161 | //memcpy(&xePublicKeyData,&Testkey[0],20+256+256); 162 | 163 | f = fopen("linuxkey.bin", "rb"); 164 | if (f!=NULL) 165 | { 166 | fseek(f, 0, SEEK_END); 167 | filesize = ftell(f); 168 | fseek(f, 0, SEEK_SET); 169 | 170 | flash = (unsigned char*) malloc(filesize); 171 | 172 | fread(flash, 1, filesize, f); 173 | fclose(f); 174 | printf("Key File loaded (format asterix): %d bytes",filesize); 175 | } else printf("linuxkey.bin not found"); 176 | 177 | memcpy(&tempkey,&flash[0],filesize); 178 | 179 | 180 | memcpy(&xePublicKeyData.Modulus[0],tempkey.modulus,256); 181 | memcpy(&xePublicKeyData.Privatekey[0],tempkey.private_exponent,256); 182 | 183 | //memcpy(&xePublicKeyData,&Testkey[0],20+256+256); 184 | return 0; 185 | } 186 | 187 | void gigimport(giant g, const unsigned char *buff, int len) { 188 | 189 | // copy buffered 'number' into giant's number buffer 190 | memcpy(g->n, buff, len); 191 | 192 | assert((len % 2) == 0); 193 | 194 | // Get number of shorts 195 | g->sign = len / 2; 196 | 197 | // Only count used shorts 198 | while((g->sign >= 1) && (g->n[g->sign - 1] == 0)) { 199 | g->sign -= 1; 200 | } 201 | 202 | } 203 | 204 | // DE - Crypting 205 | int decrypt_signature(unsigned char *c_number,unsigned char *cryptbuffer) { 206 | 207 | giant n = newgiant(GIANT_INFINITY); 208 | giant e = newgiant(GIANT_INFINITY); 209 | giant sig = newgiant(GIANT_INFINITY); 210 | 211 | gigimport(sig,c_number,256); 212 | 213 | gigimport(n,xePublicKeyData.Modulus,256); 214 | 215 | gigimport(e,xePublicKeyData.Exponent,4); 216 | 217 | 218 | /* x := x^n (mod z). */ 219 | powermodg(sig,e, n); 220 | 221 | //gout(n); 222 | //gout(e); 223 | //gout(sig); 224 | 225 | memset(cryptbuffer,0x00,256); 226 | memcpy(cryptbuffer,sig->n,256); 227 | //for (count=0; count < 256;count++) printf("%02X",cryptbuffer[count]); 228 | 229 | return 1; 230 | } 231 | 232 | // END DE-Crypting 233 | 234 | 235 | int Verifyhash(unsigned char *hash,unsigned char *decryptBuffer,int debugout){ 236 | 237 | unsigned char cmphash[20]; 238 | int a; 239 | int zero_position = 20; 240 | 241 | // Convert Hash to "Big-Endian Format" 242 | for (a=0;a<20;a++) cmphash[a] = hash[19-a]; 243 | 244 | if (debugout!=0) { 245 | 246 | printf("\n in File -> "); 247 | for (a=0;a<20;a++) printf("%02X",decryptBuffer[a]); 248 | printf("\n should be -> "); 249 | for (a=0;a<20;a++) printf("%02X",cmphash[a]); 250 | 251 | printf("\n"); 252 | if (decryptBuffer[zero_position]!= 0x00) 253 | printf("Padding Step 1: fail\n"); else printf("Padding Step 1: pass\n"); 254 | 255 | if (decryptBuffer[xePublicKeyData.ModulusSize]!= 0x00) 256 | printf("Padding Step 2: fail\n"); else printf("Padding Step 2: pass\n"); 257 | 258 | if (decryptBuffer[xePublicKeyData.ModulusSize-1]!= 0x01) 259 | printf("Padding Step 3: fail\n"); else printf("Padding Step 3: pass\n"); 260 | 261 | for (unsigned int i = zero_position+1; i < (xePublicKeyData.ModulusSize-1); i++) { 262 | if (decryptBuffer[i] != 0xff) { 263 | printf("Padding Step 4: fail\n"); 264 | break; 265 | } 266 | if (i==xePublicKeyData.ModulusSize-2) printf("Padding Step 4: pass\n"); 267 | 268 | } 269 | 270 | } 271 | 272 | // Compare if the Hash Results (first 20 Bytes) are the same 273 | if (memcmp(decryptBuffer, cmphash, 20)!=0) return 0; 274 | 275 | unsigned char *pkcspad; 276 | for (int tableIndex = 0; RSApkcs1paddingtable[tableIndex][0] !=0; tableIndex++) { 277 | 278 | pkcspad=(unsigned char*)RSApkcs1paddingtable[tableIndex]; 279 | int difference = memcmp(pkcspad+1,&decryptBuffer[20],*pkcspad); 280 | 281 | if (!difference) 282 | { 283 | zero_position = *pkcspad + 20; 284 | break; 285 | } 286 | 287 | } 288 | 289 | // Padding checking , xbox does exactly the same 290 | 291 | if (decryptBuffer[zero_position]!= 0x00) return 0; 292 | 293 | if (decryptBuffer[xePublicKeyData.ModulusSize]!= 0x00) return 0; 294 | 295 | if (decryptBuffer[xePublicKeyData.ModulusSize-1]!= 0x01) return 0; 296 | 297 | for (unsigned int i = zero_position+1; i < (xePublicKeyData.ModulusSize-1); i++) { 298 | if (decryptBuffer[i] != 0xff) return 0; 299 | //printf("%02X",decryptBuffer[i]) ; 300 | } 301 | 302 | 303 | return 1; 304 | 305 | } 306 | 307 | 308 | int crypt_signature(unsigned char *c_number,unsigned char *cryptbuffer){ 309 | 310 | int count; 311 | unsigned char c_signature[256]; 312 | unsigned char c_hash[20]; 313 | unsigned int a; 314 | 315 | giant n = newgiant(GIANT_INFINITY); 316 | giant e = newgiant(GIANT_INFINITY); 317 | giant sig = newgiant(GIANT_INFINITY); 318 | 319 | gigimport(n,xePublicKeyData.Modulus,256); 320 | 321 | 322 | gigimport(e,xePublicKeyData.Privatekey,256); 323 | 324 | 325 | for (count=0;count<20;count++) c_hash[count]=c_number[19-count]; 326 | 327 | int zero_position=20; 328 | // Message Padding 329 | c_signature[xePublicKeyData.ModulusSize]=0x00; 330 | c_signature[xePublicKeyData.ModulusSize-1]=0x01; 331 | memcpy(&c_signature[0],&c_hash[0],20); 332 | 333 | int padmethod=2; 334 | memcpy(&c_signature[20],&RSApkcs1paddingtable[padmethod][1],RSApkcs1paddingtable[padmethod][0]); 335 | zero_position += RSApkcs1paddingtable[padmethod][0]; 336 | 337 | c_signature[zero_position]=0x00; 338 | for (a=zero_position+1;a<(xePublicKeyData.ModulusSize-1);a++) c_signature[a]=0xFF; 339 | 340 | // for (count=0;count<256/2;count++) printf("%04x",n->n[count]); 341 | 342 | 343 | gigimport(sig,c_signature,256); 344 | 345 | // gout(n); 346 | // gout(e); 347 | // gout(sig); 348 | 349 | 350 | /* x := x^n (mod z). */ 351 | powermodg(sig,e, n); 352 | 353 | memset(cryptbuffer,0x00,256); 354 | memcpy(cryptbuffer,sig->n,256); 355 | 356 | return 1; 357 | } 358 | 359 | 360 | int GenarateSignaturex(void *xbe) { 361 | 362 | unsigned char sha_Message_Digest[20]; 363 | XBE_HEADER *header; 364 | // unsigned char crypt_buffer[256]; 365 | header = (XBE_HEADER*) xbe; 366 | shax(&sha_Message_Digest[0], ((unsigned char *)xbe)+0x104 ,header->HeaderSize - 0x104); 367 | crypt_signature(&sha_Message_Digest[0],header->HeaderSignature); 368 | return 0; 369 | 370 | } 371 | 372 | int VerifySignaturex(void *xbe,int debugout) { 373 | 374 | unsigned char sha_Message_Digest[20]; 375 | XBE_HEADER *header; 376 | unsigned char crypt_buffer[256]; 377 | 378 | //printf("Verify Signature Entry\n"); 379 | 380 | header = (XBE_HEADER*) xbe; 381 | 382 | shax(&sha_Message_Digest[0], ((unsigned char *)xbe)+0x104 ,header->HeaderSize - 0x104); 383 | 384 | //printf("\nCall Encrypt RSA Signature\n"); 385 | 386 | decrypt_signature(header->HeaderSignature,crypt_buffer); 387 | // for (int a=0;a<256;a++) printf("%02x",crypt_buffer[a]); 388 | return Verifyhash(&sha_Message_Digest[0],crypt_buffer,debugout); 389 | 390 | } 391 | 392 | 393 | 394 | 395 | 396 | void shax(unsigned char *result, unsigned char *data, unsigned int len) 397 | { 398 | struct SHA1Context context; 399 | 400 | SHA1Reset(&context); 401 | SHA1Input(&context, (unsigned char *)&len, 4); 402 | SHA1Input(&context,data,len); 403 | SHA1Result(&context,result); 404 | } 405 | 406 | 407 | 408 | int generate_habibi(void){ 409 | 410 | unsigned int temp; 411 | 412 | giant p = newgiant(GIANT_INFINITY); 413 | giant phi = newgiant(GIANT_INFINITY); 414 | 415 | memset(&Testkey[0],0x00,20+256+256); 416 | memcpy(&Testkey[0],&xboxPublicKeyData[0],20+256); 417 | temp = 0x899c906b; 418 | memcpy(&Testkey[272],&temp,4); 419 | 420 | gigimport(phi,&Testkey[20],256); 421 | 422 | idivg(3,phi); // phi = phi/3 423 | itog(1, p); // p=1 424 | subg(p,phi); // phi = phi - p 425 | 426 | itog(2, p); // p = 2 427 | mulg(p, phi); // phi = phi * p 428 | 429 | gigimport(p,&Testkey[16],4); 430 | 431 | invg(phi,p); 432 | memcpy(&Testkey[20+256],p->n,256); 433 | //gout(phi); 434 | return 0; 435 | } 436 | 437 | 438 | int load_rsa(unsigned int dumpflag) 439 | { 440 | int counter; 441 | // Reset the Keys 442 | for (counter=0;counter<256;counter++) xePublicKeyData.Privatekey[counter]=0x00; 443 | 444 | if (dumpflag & 0x10000000) { 445 | printf("Using Linux Test Keys \n"); 446 | memcpy(&xePublicKeyData,&Testkey[0],20+256+256); 447 | return 0; 448 | }; 449 | 450 | if (dumpflag & 0x20000000) { 451 | generate_habibi(); 452 | printf("Using Habibi Keys \n"); 453 | memcpy(&xePublicKeyData,&Testkey[0],20+256+256); 454 | return 0; 455 | }; 456 | 457 | 458 | memcpy(&xePublicKeyData,&xboxPublicKeyData[0],20+256); 459 | 460 | //int read_rsafrombin_asterix(); 461 | //read_rsafrombin_asterix(); 462 | 463 | return 0; 464 | } 465 | 466 | unsigned int xorthunk(int modus) { 467 | 468 | unsigned int xortemp[5+64]; 469 | unsigned int resulting=0; 470 | 471 | if (modus==0){ 472 | memcpy(&xortemp[0],&xePublicKeyData,20+256); 473 | resulting = xortemp[0x21]^xortemp[0x22]; 474 | } 475 | if (modus==1){ 476 | // Patch mode 477 | memcpy(&xortemp[0],&xboxPublicKeyData[0],20+256); 478 | resulting = xortemp[0x21]^xortemp[0x22]; 479 | memcpy(&xortemp[0],&Testkey[0],20+256); 480 | resulting ^= xortemp[0x21]^xortemp[0x22]; 481 | } 482 | return resulting; 483 | } 484 | 485 | unsigned int xorentry(int modus) { 486 | 487 | unsigned int xortemp[5+64]; 488 | unsigned int resulting=0; 489 | 490 | if (modus==0){ 491 | memcpy(&xortemp[0],&xePublicKeyData,20+256); 492 | resulting = xortemp[0x20]^xortemp[0x24]; 493 | } 494 | if (modus==1){ 495 | // Patch mode 496 | memcpy(&xortemp[0],&xboxPublicKeyData[0],20+256); 497 | resulting = xortemp[0x20]^xortemp[0x24]; 498 | memcpy(&xortemp[0],&Testkey[0],20+256); 499 | resulting ^= xortemp[0x20]^xortemp[0x24]; 500 | } 501 | 502 | return resulting; 503 | } 504 | 505 | 506 | 507 | int read_rsafromflash(char *filename,unsigned int dumpflag) 508 | { 509 | FILE *f; 510 | unsigned char *flash=0; 511 | int filesize; 512 | int counter; 513 | int found=0; 514 | 515 | // Load the Test Key 516 | for (counter=0;counter<256;counter++) xePublicKeyData.Privatekey[counter]=0x00; 517 | 518 | if (dumpflag & 0x10000000) { 519 | printf("Using Linux Test Keys \n "); 520 | memcpy(&xePublicKeyData,&Testkey[0],20+256+256); 521 | return 0; 522 | }; 523 | 524 | 525 | // Load the "real Key from flash.bin" 526 | f = fopen(filename, "rb"); 527 | if (f!=NULL) 528 | { 529 | fseek(f, 0, SEEK_END); filesize = ftell(f); fseek(f, 0, SEEK_SET); 530 | 531 | flash = (unsigned char*) malloc(filesize); 532 | 533 | fread(flash, 1, filesize, f); 534 | fclose(f); 535 | 536 | for (counter=0; countern, c_number); 610 | for (int y=0;y<16;y++) { 611 | for (int x=0;x<16;x++) { 612 | fprintf(f,"0x%02X,",c_number[255 -(x+16*y)]); 613 | } 614 | fprintf(f,"\n"); 615 | } 616 | fclose(f); 617 | 618 | f = fopen("linuxpri.cert", "w"); 619 | BN_bn2bin(rsa->d, c_number); 620 | for (int y=0;y<16;y++) { 621 | for (int x=0;x<16;x++) { 622 | fprintf(f,"0x%02X,",c_number[255-(x+16*y)]); 623 | } 624 | fprintf(f,"\n"); 625 | } 626 | fclose(f); 627 | return 0; 628 | } 629 | */ 630 | -------------------------------------------------------------------------------- /xbedump.c: -------------------------------------------------------------------------------- 1 | /* Note: this code will work on little-endian 32-bit machines only! */ 2 | 3 | /*************************************************************************** 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | ***************************************************************************/ 11 | 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | 26 | #include "xbestructure.h" 27 | #include "xboxlib.h" 28 | #include "xboxkrnl.h" 29 | 30 | 31 | void printdate(uint32_t t_time) { 32 | 33 | time_t rawtime=t_time; 34 | printf("%s",ctime(&rawtime)); 35 | } 36 | 37 | void printhex_strip(uint8_t d) { 38 | if (d<16) printf("0"); 39 | printf("%x", d); 40 | } 41 | 42 | void printhexm_strip(uint8_t *d, int size) { 43 | int i; 44 | for (i = 0; i < size; i++, d++) { 45 | if (!(i & 15) && i != 0) printf("\n"); 46 | printhex_strip(*d); 47 | } 48 | printf("\n"); 49 | } 50 | 51 | void printhex_cert(uint8_t *d, int size) { 52 | int i; 53 | int line = 0; 54 | for (i = 0; i < size; i++, d++) { 55 | if (!(i & 15)) { 56 | line ++; 57 | printf("\n KEY_ALT%d=",line); 58 | } 59 | printhex_strip(*d); 60 | } 61 | printf("\n"); 62 | } 63 | 64 | void printhex(uint8_t d) { 65 | if (d<16) printf("0"); 66 | printf("%x ", d); 67 | } 68 | 69 | void printhexm(uint8_t *d, int size) { 70 | int i; 71 | for (i = 0; i < size; i++, d++) { 72 | if (!(i & 15)) printf("\n "); 73 | printhex(*d); 74 | } 75 | printf("\n"); 76 | } 77 | 78 | void printhex32(uint32_t d) { 79 | printf("0x%x ", d); 80 | } 81 | 82 | void printhex32mz(uint32_t *d, int size) { 83 | int i; 84 | if (!*d) { 85 | printf("\n\tnone\n"); 86 | return; 87 | } 88 | for (i = 0; i < size; i++, d++) { 89 | if (!*d) return; 90 | if (!(i & 7)) printf("\n\t"); 91 | printhex32(*d); 92 | } 93 | printf("\n"); 94 | } 95 | 96 | void printhex32m(uint32_t *d, int size) { 97 | int i; 98 | for (i = 0; i < size; i++, d++) { 99 | if (!(i & 7)) printf("\n\t"); 100 | printhex32(*d); 101 | } 102 | printf("\n"); 103 | } 104 | 105 | void printunicode(short *s) { 106 | while (*s) { 107 | printf("%c", *s); 108 | s++; 109 | } 110 | } 111 | 112 | void printn(char *s, int len) { 113 | int i; 114 | for (i = 0; (i < len) && *s; i++, s++) { 115 | printf("%c", *s); 116 | } 117 | } 118 | 119 | void printw(char *s) { 120 | printf("** warning: %s\n", s); 121 | } 122 | 123 | void printInitFlags(int f) { 124 | if (!f) { 125 | printf("\n : "); 126 | printf("none"); 127 | } else { 128 | printf("0x%08X",f); 129 | if (f & XBE_INIT_MOUNT_UTILITY) { 130 | printf("\n : "); 131 | printf("XBE_INIT_MOUNT_UTILITY "); 132 | } 133 | if (f & XBE_INIT_FORMAT_UTILITY) { 134 | printf("\n : "); 135 | printf("XBE_INIT_FORMAT_UTILITY "); 136 | } 137 | if (f & XBE_INIT_64M_RAM_ONLY) { 138 | printf("\n : "); 139 | printf("XBE_INIT_64M_RAM_ONLY "); 140 | } 141 | if (f & XBE_INIT_DONT_SETUP_HDD) { 142 | printf("\n : "); 143 | printf("XBE_INIT_DONT_SETUP_HDD "); 144 | } 145 | } 146 | } 147 | 148 | void printMediaTypes(int f) { 149 | if (!f) { 150 | printf("\n : "); 151 | printf("none"); 152 | } else { 153 | printf("0x%08X",f); 154 | if (f & XBE_MEDIA_HDD) { 155 | printf("\n : "); 156 | printf("XBE_MEDIA_HDD "); 157 | } 158 | if (f & XBE_MEDIA_XBOX_DVD) { 159 | printf("\n : "); 160 | printf("XBE_MEDIA_XBOX_DVD "); 161 | } 162 | if (f & XBE_MEDIA_ANY_CD_OR_DVD) { 163 | printf("\n : "); 164 | printf("XBE_MEDIA_ANY_CD_OR_DVD "); 165 | } 166 | if (f & XBE_MEDIA_CD) { 167 | printf("\n : "); 168 | printf("XBE_MEDIA_CD "); 169 | } 170 | if (f & XBE_MEDIA_1LAYER_DVDROM) { 171 | printf("\n : "); 172 | printf("XBE_MEDIA_1LAYER_DVDROM "); 173 | } 174 | if (f & XBE_MEDIA_2LAYER_DVDROM) { 175 | printf("\n : "); 176 | printf("XBE_MEDIA_2LAYER_DVDROM "); 177 | } 178 | if (f & XBE_MEDIA_1LAYER_DVDR) { 179 | printf("\n : "); 180 | printf("XBE_MEDIA_1LAYER_DVDR "); 181 | } 182 | if (f & XBE_MEDIA_2LAYER_DVDR) { 183 | printf("\n : "); 184 | printf("XBE_MEDIA_2LAYER_DVDR "); 185 | } 186 | if (f & XBE_MEDIA_USB) { 187 | printf("\n : "); 188 | printf("XBE_MEDIA_USB "); 189 | } 190 | if (f & XBE_MEDIA_ALLOW_UNLOCKED_HDD) { 191 | printf("\n : "); 192 | printf("XBE_MEDIA_ALLOW_UNLOCKED_HDD "); 193 | } 194 | } 195 | } 196 | 197 | void printGameRegion(int f) { 198 | if (!f) { 199 | printf("\n : "); 200 | printf("none"); 201 | } else { 202 | printf("0x%08X",f); 203 | if (f & XBE_REGION_US_CANADA) { 204 | printf("\n : "); 205 | printf("XBE_REGION_US_CANADA "); 206 | } 207 | if (f & XBE_REGION_JAPAN) { 208 | printf("\n : "); 209 | printf("XBE_REGION_JAPAN "); 210 | } 211 | if (f & XBE_REGION_ELSEWHERE) { 212 | printf("\n : "); 213 | printf("XBE_REGION_ELSEWHERE "); 214 | } 215 | if (f & XBE_REGION_DEBUG) { 216 | printf("\n : "); 217 | printf("XBE_REGION_DEBUG "); 218 | } 219 | } 220 | } 221 | 222 | void printFlags(int f) { 223 | if (!f) { 224 | printf("\n : "); 225 | printf("none"); 226 | } else { 227 | printf("0x%08X",f); 228 | if (f & XBE_SEC_WRITABLE) { 229 | printf("\n : "); 230 | printf("XBE_SEC_WRITABLE "); 231 | } 232 | if (f & XBE_SEC_PRELOAD) { 233 | printf("\n : "); 234 | printf("XBE_SEC_PRELOAD "); 235 | } 236 | if (f & XBE_SEC_EXECUTABLE) { 237 | printf("\n : "); 238 | printf("XBE_SEC_EXECUTABLE "); 239 | } 240 | if (f & XBE_SEC_INSERTED_FILE) { 241 | printf("\n : "); 242 | printf("XBE_SEC_INSERTED_FILE "); 243 | } 244 | if (f & XBE_SEC_RO_HEAD_PAGE) { 245 | printf("\n : "); 246 | printf("XBE_SEC_RO_HEAD_PAGE "); 247 | } 248 | if (f & XBE_SEC_RO_TAIL_PAGE) { 249 | printf("\n : "); 250 | printf("XBE_SEC_RO_TAIL_PAGE "); 251 | } 252 | } 253 | } 254 | 255 | XBE_SECTION *findSection(void *xbe, uint32_t addr) { 256 | int i; 257 | XBE_HEADER *header = (XBE_HEADER*) xbe; 258 | XBE_SECTION *sechdr = (XBE_SECTION *)(((char *)xbe) + (int)header->Sections - (int)header->BaseAddress); 259 | for (i = 0; i < header->NumSections; i++, sechdr++) { 260 | if (addr < sechdr->VirtualAddress) { continue; } 261 | if (addr >= sechdr->VirtualAddress + sechdr->VirtualSize) { continue; } 262 | return sechdr; 263 | } 264 | printf("Couldn't find 0x%X\n",addr); 265 | return NULL; 266 | } 267 | 268 | int dumpxbe (void *xbe,uint32_t option_flag){ 269 | int i; 270 | unsigned int j; 271 | int a; 272 | 273 | XBE_HEADER *header; 274 | XBE_CERTIFICATE *cert; 275 | XBE_SECTION *sechdr; 276 | //XBE_TLS *tls; 277 | XBE_LIBRARY *lib; 278 | 279 | uint32_t KernelThunkTable; 280 | uint8_t sha_Message_Digest[20]; 281 | uint32_t xorkey; 282 | 283 | 284 | 285 | 286 | /* header */ 287 | header = (XBE_HEADER*) xbe; 288 | 289 | if (option_flag == 0x0000000A) { 290 | cert = (XBE_CERTIFICATE *)(((char *)xbe) + (int)header->Certificate - (int)header->BaseAddress); 291 | printf("#\n# "); printunicode(cert->TitleName); printf("\n#\n"); 292 | printf("[Game-%08X]\n\n",cert->TitleId); 293 | printf(" NAME=");printunicode(cert->TitleName); printf("\n\n"); 294 | printf(" ID=%08X\n",cert->TitleId); printf("\n"); 295 | printf(" HASH_METHOD=HM_UNKNOWN\n\n"); 296 | printf(" WHICH_KEY=KEY_SIG\n\n"); 297 | printf(" KEY_SIG="); printhexm_strip(cert->SignatureKey, sizeof(cert->SignatureKey)); 298 | printf(" KEY_LAN="); printhexm_strip(cert->LanKey, sizeof(cert->LanKey)); 299 | printhex_cert((uint8_t *)cert->AlternateSignatureKeys, sizeof(cert->AlternateSignatureKeys)); 300 | printf("\n"); 301 | return 0; 302 | } 303 | 304 | if (option_flag & 0x00000001) { 305 | 306 | printf("\nXBE header\n~~~~~~~~~~\n"); 307 | printf("Magic : %c%c%c%c\n", header->Magic[0], header->Magic[1], header->Magic[2], header->Magic[3]); 308 | // if (warn) if (strncmp("XBEH", header->Magic, 4)) printw("must be \"XBEH\""); 309 | printf("RSA digital signature : "); 310 | if (VerifySignaturex(xbe,0)== 1) printf("(Valid)"); else printf("(Fail)"); 311 | printhexm(header->HeaderSignature, sizeof(header->HeaderSignature)); 312 | //for (i=0;iHeaderSignature);i++) printf( "%02X",header->HeaderSignature[i]); 313 | 314 | printf("Base address : 0x%08X\n", ((uint32_t )header->BaseAddress)); 315 | 316 | printf("Size of all headers: : 0x%08X\n", header->HeaderSize); 317 | /* TODO */ 318 | printf("Size of entire image : 0x%08X\n", header->ImageSize); 319 | 320 | printf("Size of this header : 0x%08X\n",header->XbeHeaderSize); 321 | printf("Image timestamp : 0x%08X ",(uint32_t )header->Timestamp); 322 | printdate(header->Timestamp); 323 | printf("Pointer to certificate data : 0x%08X\n", (uint32_t )header->Certificate); 324 | printf("Number of sections : 0x%08X\n", (uint32_t )header->NumSections); 325 | printf("Pointer to section headers : 0x%08X\n", (uint32_t )header->Sections); 326 | printf("Initialization flags : "); 327 | 328 | printInitFlags(header->InitFlags); printf("\n"); 329 | 330 | } 331 | // EntryPoint = (uint32_t )header->EntryPoint ^ 0xa8fc57ab; /* debug: 0x0x94859d4b */ 332 | if (option_flag & 0x00000001) { 333 | xorkey=xorentry(0); 334 | printf("Entrypoint : 0x%08X \n" 335 | " : 0x%08X (Actual)\n" 336 | " : 0x%08X (Retail)\n" 337 | " : 0x%08X (Debug)\n", 338 | (uint32_t )header->EntryPoint, 339 | (uint32_t )header->EntryPoint^xorkey, 340 | (uint32_t )header->EntryPoint^0xa8fc57ab, 341 | (uint32_t )header->EntryPoint^0x94859d4b); 342 | 343 | printf("Pointer to TLS directory : 0x%08X\n", (uint32_t )header->TlsDirectory); 344 | printf("Stack commit size : 0x%08X\n", (uint32_t )header->StackCommit); 345 | printf("Heap reserve size : 0x%08X\n", (uint32_t )header->HeapReserve); 346 | printf("Heap commit size : 0x%08X\n", (uint32_t )header->HeapCommit); 347 | printf("PE base address : 0x%08X\n", (uint32_t )header->PeBaseAddress); 348 | printf("PE image size : 0x%08X\n", (uint32_t )header->PeImageSize); 349 | printf("PE checksum : 0x%08X\n", (uint32_t )header->PeChecksum); 350 | printf("PE timestamp : 0x%08X ",(uint32_t )header->PeTimestamp); 351 | printdate(header->PeTimestamp); 352 | printf("PC path and filename to EXE : 0x%08X (\"%s\")\n",(uint32_t)header->PcExePath, ((char *)xbe)+(uintptr_t)header->PcExePath-(uintptr_t)header->BaseAddress); 353 | printf("PC filename to EXE : 0x%08X (\"%s\")\n", (uint32_t)header->PcExeFilename,((char *)xbe)+(uintptr_t)header->PcExeFilename-(uintptr_t)header->BaseAddress); 354 | printf("PC filename to EXE (Unicode) : 0x%08X (\"",(uint32_t)header->PcExeFilenameUnicode); 355 | printunicode( (short int*) (((char *)xbe)+(uintptr_t)header->PcExeFilenameUnicode-(uintptr_t)header->BaseAddress)); 356 | printf("\")\n"); 357 | } 358 | //KernelThunkTable = (uint32_t )header->KernelThunkTable ^ 0x5b6d40b6; /* debug: 0xEFB1F152 */ 359 | 360 | xorkey=xorthunk(0); 361 | KernelThunkTable = (uint32_t )header->KernelThunkTable ^ xorkey; 362 | 363 | if (option_flag & 0x00000001) { 364 | 365 | printf("Pointer to kernel thunk table : 0x%08X \n" 366 | " : 0x%08X (Actual)\n" 367 | " : 0x%08X (Retail)\n" 368 | " : 0x%08X (Debug)\n", 369 | (uint32_t )header->KernelThunkTable, 370 | (uint32_t )header->KernelThunkTable^xorkey, 371 | (uint32_t )header->KernelThunkTable^0x5b6d40b6, 372 | (uint32_t )header->KernelThunkTable^0xEFB1F152); 373 | 374 | /* FIXME: Move elsewhere */ 375 | /* FIXME: Allow use of other keys from cli! */ 376 | uint32_t kt = KernelThunkTable; 377 | while(1) { 378 | XBE_SECTION *kt_section = findSection(xbe, kt); 379 | if (kt_section == NULL) { 380 | printf("Kernel thunk table broken!\n"); 381 | break; 382 | } 383 | uint32_t* kt_entry = (uint32_t *)((uint8_t *)xbe + kt_section->FileAddress + kt - kt_section->VirtualAddress); 384 | if (*kt_entry == 0) { 385 | break; 386 | } 387 | const char *name; 388 | unsigned int index = *kt_entry & 0x7FFFFFFF; 389 | if (index < sizeof(xboxkrnlExports) / sizeof(const char*)) { 390 | name = xboxkrnlExports[index]; 391 | } else { 392 | name = NULL; 393 | } 394 | printf("Kernel import : 0x%08X (@%d%s%s)\n", 395 | *kt_entry, 396 | index, 397 | name ? ", " : "", 398 | name ? name : ""); 399 | kt += 4; 400 | } 401 | 402 | 403 | printf("Non-kernel import table (debug only): 0x%08X\n", (uint32_t )header->DebugImportTable); 404 | printf("Number of library headers : 0x%08X\n", header->NumLibraries); 405 | printf("Pointer to library headers : 0x%08X\n", (uint32_t )header->Libraries); 406 | printf("Pointer to kernel library header : 0x%08X\n", (uint32_t )(header->KernelLibrary)); 407 | printf("Pointer to XAPI library header : 0x%08X\n", (uint32_t )(header->XapiLibrary)); 408 | printf("Pointer to logo bitmap : 0x%08X\n", (uint32_t )(header->LogoBitmap)); 409 | printf("Size of logo bitmap : 0x%08X\n", header->LogoBitmapSize); 410 | } 411 | cert = (XBE_CERTIFICATE *)(((char *)xbe) + (int)header->Certificate - (int)header->BaseAddress); 412 | 413 | if (option_flag & 0x00000002) { 414 | printf("\nCertificate\n~~~~~~~~~~~\n"); 415 | printf("Size of certificate : 0x%08X\n", cert->Size); 416 | printf("Certificate timestamp : 0x%08X ",cert->Timestamp); printdate(cert->Timestamp); 417 | printf("Title ID : 0x%08X\n", cert->TitleId); 418 | printf("Title name : \""); printunicode(cert->TitleName); printf("\"\n"); 419 | printf("Alternate title ID's : "); printhex32mz(cert->AlternateTitleIds, 16); 420 | printf("Allowed media types : "); printMediaTypes(cert->MediaTypes); printf("\n"); 421 | printf("Allowed game regions : "); printGameRegion(cert->GameRegion); printf("\n"); 422 | printf("Allowed game rating : 0x%08X\n", cert->GameRating); 423 | printf("Disk number : 0x%08X\n", cert->DiskNumber); 424 | printf("Version : 0x%08X\n", cert->Version); 425 | printf("LAN key : "); 426 | for (j = 0; j< sizeof(cert->LanKey);j++) printf("%02X ",cert->LanKey[j]); 427 | printf("\n"); 428 | printf("Signature key : "); 429 | for (j = 0; j< sizeof(cert->SignatureKey);j++) printf("%02X ",cert->SignatureKey[j]); 430 | printf("\n"); 431 | printf("Alternate signature keys : "); 432 | printhexm((uint8_t *)cert->AlternateSignatureKeys, sizeof(cert->AlternateSignatureKeys)); 433 | 434 | } 435 | 436 | 437 | sechdr = (XBE_SECTION *)(((char *)xbe) + (int)header->Sections - (int)header->BaseAddress); 438 | for (i = 0; i < header->NumSections; i++, sechdr++) { 439 | if (option_flag & 0x00000004) { 440 | printf("\nSection Header %i\n~~~~~~~~~~~~~~~~~\n", i); 441 | 442 | printf("Flags : "); printFlags(sechdr->Flags); printf("\n"); 443 | printf("Flags : 0x%08X \n",sechdr->Flags); 444 | printf("Virtual address : 0x%08X\n", sechdr->VirtualAddress); 445 | printf("Virtual size : 0x%08X\n", sechdr->VirtualSize); 446 | printf("File address : 0x%08X\n", sechdr->FileAddress); 447 | printf("File size : 0x%08X\n", sechdr->FileSize); 448 | printf("Section name Address : 0x%08X (\"%s\")\n",(int)sechdr->SectionName, ((uint8_t *)xbe)+(int)sechdr->SectionName-(int)header->BaseAddress); 449 | printf("Section reference count : 0x%08X\n", sechdr->SectionReferenceCount); 450 | printf("Head shared page reference count : 0x%08X\n", (uint32_t )sechdr->HeadReferenceCount); 451 | printf("Tail shared page reference count : 0x%08X\n", (uint32_t )sechdr->TailReferenceCount); 452 | 453 | printf("SHA1 hash : "); 454 | 455 | shax(&sha_Message_Digest[0], ((uint8_t *)xbe)+(int)sechdr->FileAddress ,sechdr->FileSize); 456 | 457 | for (a=0;a<20;a++) printf("%02X",sechdr->ShaHash[a]); 458 | 459 | if (memcmp(&sha_Message_Digest[0],&sechdr->ShaHash[0],20)==0) { 460 | printf(" (Valid)"); 461 | } else { 462 | //fail=1; 463 | printf(" (False)"); 464 | printf("\nSHA1 hash (Needed) : "); 465 | for (a=0;a<20;a++) printf("%02X",sha_Message_Digest[a]); 466 | } 467 | 468 | printf("\n"); 469 | } 470 | 471 | } 472 | 473 | lib = (XBE_LIBRARY *)(((char *)xbe) + (uint32_t)header->Libraries - (uint32_t)header->BaseAddress); 474 | 475 | for (i = 0; i < header->NumLibraries; i++, lib++) { 476 | 477 | if (option_flag & 0x00000008) { 478 | printf("\nLibrary %i\n~~~~~~~~~~\n", i); 479 | printf("Library name : \""); printn((char*)lib->Name, sizeof(lib->Name)); printf("\"\n"); 480 | printf("Major Version : 0x%08X\n", lib->MajorVersion); 481 | printf("Middle Version : 0x%08X\n", lib->MiddleVersion); 482 | printf("Minor Version : 0x%08X\n", lib->MinorVersion); 483 | printf("Flags : 0x%08X\n", lib->Flags); 484 | } 485 | 486 | } 487 | 488 | 489 | // tls = (XBE_TLS *)(((char *)xbe) + (int)header->TlsDirectory - (int)header->BaseAddress); 490 | //tls = (XBE_TLS *)(((char *)xbe) + (int)header->TlsDirectory - KernelThunkTable );// 491 | //(int)header->BaseAddress); 492 | 493 | if (option_flag & 0x00000001) { 494 | /* 495 | printf("\nThread Local Storage Directory - Still Buggy\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); 496 | printf("Raw data start address : 0x%08X\n", tls->RawStart); 497 | printf("Raw data end address : 0x%08X\n", tls->RawEnd); 498 | printf("TLS index address : 0x%08X\n", tls->TlsIndex); 499 | printf("TLS callbacks address : 0x%08X\n", tls->TlsCallbacks); 500 | printf("Size of zero fill : 0x%08x\n", tls->SizeZeroFill); 501 | //printf("Characteristics : 0x%08X\n", (uint8_t *)xbe+(uint32_t )tls->Characteristics-(uint32_t )header->BaseAddress); 502 | printf("Characteristics : %s\n", tls->Characteristics); 503 | */ 504 | } 505 | 506 | // free(xbe); 507 | 508 | 509 | return 0; 510 | } 511 | 512 | -------------------------------------------------------------------------------- /xboxkrnl.h: -------------------------------------------------------------------------------- 1 | const char* xboxkrnlExports[] = { 2 | NULL, 3 | "AvGetSavedDataAddress", // @1 4 | "AvSendTVEncoderOption", // @2 5 | "AvSetDisplayMode", // @3 6 | "AvSetSavedDataAddress", // @4 7 | "DbgBreakPoint", // @5 8 | "DbgBreakPointWithStatus", // @6 9 | "DbgLoadImageSymbols", // @7 10 | "DbgPrint", // @8 11 | "HalReadSMCTrayState", // @9 12 | "DbgPrompt", // @10 13 | "DbgUnLoadImageSymbols", // @11 14 | "ExAcquireReadWriteLockExclusive", // @12 15 | "ExAcquireReadWriteLockShared", // @13 16 | "ExAllocatePool", // @14 17 | "ExAllocatePoolWithTag", // @15 18 | "ExEventObjectType", // @16 (Object) 19 | "ExFreePool", // @17 20 | "ExInitializeReadWriteLock", // @18 21 | "ExInterlockedAddLargeInteger", // @19 22 | "ExInterlockedAddLargeStatistic", // @20 23 | "ExInterlockedCompareExchange64", // @21 24 | "ExMutantObjectType", // @22 (Object) 25 | "ExQueryPoolBlockSize", // @23 26 | "ExQueryNonVolatileSetting", // @24 27 | "ExReadWriteRefurbInfo", // @25 28 | "ExRaiseException", // @26 29 | "ExRaiseStatus", // @27 30 | "ExReleaseReadWriteLock", // @28 31 | "ExSaveNonVolatileSetting", // @29 32 | "ExSemaphoreObjectType", // @30 (Object) 33 | "ExTimerObjectType", // @31 (Object) 34 | "ExfInterlockedInsertHeadList", // @32 35 | "ExfInterlockedInsertTailList", // @33 36 | "ExfInterlockedRemoveHeadList", // @34 37 | "FscGetCacheSize", // @35 38 | "FscInvalidateIdleBlocks", // @36 39 | "FscSetCacheSize", // @37 40 | "HalClearSoftwareInterrupt", // @38 41 | "HalDisableSystemInterrupt", // @39 42 | "HalDiskCachePartitionCount", // @40 (Object) 43 | "HalDiskModelNumber", // @41 (Object) 44 | "HalDiskSerialNumber", // @42 (Object) 45 | "HalEnableSystemInterrupt", // @43 46 | "HalGetInterruptVector", // @44 47 | "HalReadSMBusValue", // @45 48 | "HalReadWritePCISpace", // @46 49 | "HalRegisterShutdownNotification", // @47 50 | "HalRequestSoftwareInterrupt", // @48 51 | "HalReturnToFirmware", // @49 52 | "HalWriteSMBusValue", // @50 53 | "InterlockedCompareExchange", // @51 54 | "InterlockedDecrement", // @52 55 | "InterlockedIncrement", // @53 56 | "InterlockedExchange", // @54 57 | "InterlockedExchangeAdd", // @55 58 | "InterlockedFlushSList", // @56 59 | "InterlockedPopEntrySList", // @57 60 | "InterlockedPushEntrySList", // @58 61 | "IoAllocateIrp", // @59 62 | "IoBuildAsynchronousFsdRequest", // @60 63 | "IoBuildDeviceIoControlRequest", // @61 64 | "IoBuildSynchronousFsdRequest", // @62 65 | "IoCheckShareAccess", // @63 66 | "IoCompletionObjectType", // @64 (Object) 67 | "IoCreateDevice", // @65 68 | "IoCreateFile", // @66 69 | "IoCreateSymbolicLink", // @67 70 | "IoDeleteDevice", // @68 71 | "IoDeleteSymbolicLink", // @69 72 | "IoDeviceObjectType", // @70 (Object) 73 | "IoFileObjectType", // @71 (Object) 74 | "IoFreeIrp", // @72 75 | "IoInitializeIrp", // @73 76 | "IoInvalidDeviceRequest", // @74 77 | "IoQueryFileInformation", // @75 78 | "IoQueryVolumeInformation", // @76 79 | "IoQueueThreadIrp", // @77 80 | "IoRemoveShareAccess", // @78 81 | "IoSetIoCompletion", // @79 82 | "IoSetShareAccess", // @80 83 | "IoStartNextPacket", // @81 84 | "IoStartNextPacketByKey", // @82 85 | "IoStartPacket", // @83 86 | "IoSynchronousDeviceIoControlRequest", // @84 87 | "IoSynchronousFsdRequest", // @85 88 | "IofCallDriver", // @86 89 | "IofCompleteRequest", // @87 90 | "KdDebuggerEnabled", // @88 (Object) 91 | "KdDebuggerNotPresent", // @89 (Object) 92 | "IoDismountVolume", // @90 93 | "IoDismountVolumeByName", // @91 94 | "KeAlertResumeThread", // @92 95 | "KeAlertThread", // @93 96 | "KeBoostPriorityThread", // @94 97 | "KeBugCheck", // @95 98 | "KeBugCheckEx", // @96 99 | "KeCancelTimer", // @97 100 | "KeConnectInterrupt", // @98 101 | "KeDelayExecutionThread", // @99 102 | "KeDisconnectInterrupt", // @100 103 | "KeEnterCriticalRegion", // @101 104 | "MmGlobalData", // @102 (Object) 105 | "KeGetCurrentIrql", // @103 106 | "KeGetCurrentThread", // @104 107 | "KeInitializeApc", // @105 108 | "KeInitializeDeviceQueue", // @106 109 | "KeInitializeDpc", // @107 110 | "KeInitializeEvent", // @108 111 | "KeInitializeInterrupt", // @109 112 | "KeInitializeMutant", // @110 113 | "KeInitializeQueue", // @111 114 | "KeInitializeSemaphore", // @112 115 | "KeInitializeTimerEx", // @113 116 | "KeInsertByKeyDeviceQueue", // @114 117 | "KeInsertDeviceQueue", // @115 118 | "KeInsertHeadQueue", // @116 119 | "KeInsertQueue", // @117 120 | "KeInsertQueueApc", // @118 121 | "KeInsertQueueDpc", // @119 122 | "KeInterruptTime", // @120 (Object) 123 | "KeIsExecutingDpc", // @121 124 | "KeLeaveCriticalRegion", // @122 125 | "KePulseEvent", // @123 126 | "KeQueryBasePriorityThread", // @124 127 | "KeQueryInterruptTime", // @125 128 | "KeQueryPerformanceCounter", // @126 129 | "KeQueryPerformanceFrequency", // @127 130 | "KeQuerySystemTime", // @128 131 | "KeRaiseIrqlToDpcLevel", // @129 132 | "KeRaiseIrqlToSynchLevel", // @130 133 | "KeReleaseMutant", // @131 134 | "KeReleaseSemaphore", // @132 135 | "KeRemoveByKeyDeviceQueue", // @133 136 | "KeRemoveDeviceQueue", // @134 137 | "KeRemoveEntryDeviceQueue", // @135 138 | "KeRemoveQueue", // @136 139 | "KeRemoveQueueDpc", // @137 140 | "KeResetEvent", // @138 141 | "KeRestoreFloatingPointState", // @139 142 | "KeResumeThread", // @140 143 | "KeRundownQueue", // @141 144 | "KeSaveFloatingPointState", // @142 145 | "KeSetBasePriorityThread", // @143 146 | "KeSetDisableBoostThread", // @144 147 | "KeSetEvent", // @145 148 | "KeSetEventBoostPriority", // @146 149 | "KeSetPriorityProcess", // @147 150 | "KeSetPriorityThread", // @148 151 | "KeSetTimer", // @149 152 | "KeSetTimerEx", // @150 153 | "KeStallExecutionProcessor", // @151 154 | "KeSuspendThread", // @152 155 | "KeSynchronizeExecution", // @153 156 | "KeSystemTime", // @154 (Object) 157 | "KeTestAlertThread", // @155 158 | "KeTickCount", // @156 (Object) 159 | "KeTimeIncrement", // @157 (Object) 160 | "KeWaitForMultipleObjects", // @158 161 | "KeWaitForSingleObject", // @159 162 | "KfRaiseIrql", // @160 163 | "KfLowerIrql", // @161 164 | "KiBugCheckData", // @162 (Object) 165 | "KiUnlockDispatcherDatabase", // @163 166 | "LaunchDataPage", // @164 (Object) 167 | "MmAllocateContiguousMemory", // @165 168 | "MmAllocateContiguousMemoryEx", // @166 169 | "MmAllocateSystemMemory", // @167 170 | "MmClaimGpuInstanceMemory", // @168 171 | "MmCreateKernelStack", // @169 172 | "MmDeleteKernelStack", // @170 173 | "MmFreeContiguousMemory", // @171 174 | "MmFreeSystemMemory", // @172 175 | "MmGetPhysicalAddress", // @173 176 | "MmIsAddressValid", // @174 177 | "MmLockUnlockBufferPages", // @175 178 | "MmLockUnlockPhysicalPage", // @176 179 | "MmMapIoSpace", // @177 180 | "MmPersistContiguousMemory", // @178 181 | "MmQueryAddressProtect", // @179 182 | "MmQueryAllocationSize", // @180 183 | "MmQueryStatistics", // @181 184 | "MmSetAddressProtect", // @182 185 | "MmUnmapIoSpace", // @183 186 | "NtAllocateVirtualMemory", // @184 187 | "NtCancelTimer", // @185 188 | "NtClearEvent", // @186 189 | "NtClose", // @187 190 | "NtCreateDirectoryObject", // @188 191 | "NtCreateEvent", // @189 192 | "NtCreateFile", // @190 193 | "NtCreateIoCompletion", // @191 194 | "NtCreateMutant", // @192 195 | "NtCreateSemaphore", // @193 196 | "NtCreateTimer", // @194 197 | "NtDeleteFile", // @195 198 | "NtDeviceIoControlFile", // @196 199 | "NtDuplicateObject", // @197 200 | "NtFlushBuffersFile", // @198 201 | "NtFreeVirtualMemory", // @199 202 | "NtFsControlFile", // @200 203 | "NtOpenDirectoryObject", // @201 204 | "NtOpenFile", // @202 205 | "NtOpenSymbolicLinkObject", // @203 206 | "NtProtectVirtualMemory", // @204 207 | "NtPulseEvent", // @205 208 | "NtQueueApcThread", // @206 209 | "NtQueryDirectoryFile", // @207 210 | "NtQueryDirectoryObject", // @208 211 | "NtQueryEvent", // @209 212 | "NtQueryFullAttributesFile", // @210 213 | "NtQueryInformationFile", // @211 214 | "NtQueryIoCompletion", // @212 215 | "NtQueryMutant", // @213 216 | "NtQuerySemaphore", // @214 217 | "NtQuerySymbolicLinkObject", // @215 218 | "NtQueryTimer", // @216 219 | "NtQueryVirtualMemory", // @217 220 | "NtQueryVolumeInformationFile", // @218 221 | "NtReadFile", // @219 222 | "NtReadFileScatter", // @220 223 | "NtReleaseMutant", // @221 224 | "NtReleaseSemaphore", // @222 225 | "NtRemoveIoCompletion", // @223 226 | "NtResumeThread", // @224 227 | "NtSetEvent", // @225 228 | "NtSetInformationFile", // @226 229 | "NtSetIoCompletion", // @227 230 | "NtSetSystemTime", // @228 231 | "NtSetTimerEx", // @229 232 | "NtSignalAndWaitForSingleObjectEx", // @230 233 | "NtSuspendThread", // @231 234 | "NtUserIoApcDispatcher", // @232 235 | "NtWaitForSingleObject", // @233 236 | "NtWaitForSingleObjectEx", // @234 237 | "NtWaitForMultipleObjectsEx", // @235 238 | "NtWriteFile", // @236 239 | "NtWriteFileGather", // @237 240 | "NtYieldExecution", // @238 241 | "ObCreateObject", // @239 242 | "ObDirectoryObjectType", // @240 (Object) 243 | "ObInsertObject", // @241 244 | "ObMakeTemporaryObject", // @242 245 | "ObOpenObjectByName", // @243 246 | "ObOpenObjectByPointer", // @244 247 | "ObpObjectHandleTable", // @245 (Object) 248 | "ObReferenceObjectByHandle", // @246 249 | "ObReferenceObjectByName", // @247 250 | "ObReferenceObjectByPointer", // @248 251 | "ObSymbolicLinkObjectType", // @249 (Object) 252 | "ObfDereferenceObject", // @250 253 | "ObfReferenceObject", // @251 254 | "PhyGetLinkState", // @252 255 | "PhyInitialize", // @253 256 | "PsCreateSystemThread", // @254 257 | "PsCreateSystemThreadEx", // @255 258 | "PsQueryStatistics", // @256 259 | "PsSetCreateThreadNotifyRoutine", // @257 260 | "PsTerminateSystemThread", // @258 261 | "PsThreadObjectType", // @259 (Object) 262 | "RtlAnsiStringToUnicodeString", // @260 263 | "RtlAppendStringToString", // @261 264 | "RtlAppendUnicodeStringToString", // @262 265 | "RtlAppendUnicodeToString", // @263 266 | "RtlAssert", // @264 267 | "RtlCaptureContext", // @265 268 | "RtlCaptureStackBackTrace", // @266 269 | "RtlCharToInteger", // @267 270 | "RtlCompareMemory", // @268 271 | "RtlCompareMemoryUlong", // @269 272 | "RtlCompareString", // @270 273 | "RtlCompareUnicodeString", // @271 274 | "RtlCopyString", // @272 275 | "RtlCopyUnicodeString", // @273 276 | "RtlCreateUnicodeString", // @274 277 | "RtlDowncaseUnicodeChar", // @275 278 | "RtlDowncaseUnicodeString", // @276 279 | "RtlEnterCriticalSection", // @277 280 | "RtlEnterCriticalSectionAndRegion", // @278 281 | "RtlEqualString", // @279 282 | "RtlEqualUnicodeString", // @280 283 | "RtlExtendedIntegerMultiply", // @281 284 | "RtlExtendedLargeIntegerDivide", // @282 285 | "RtlExtendedMagicDivide", // @283 286 | "RtlFillMemory", // @284 287 | "RtlFillMemoryUlong", // @285 288 | "RtlFreeAnsiString", // @286 289 | "RtlFreeUnicodeString", // @287 290 | "RtlGetCallersAddress", // @288 291 | "RtlInitAnsiString", // @289 292 | "RtlInitUnicodeString", // @290 293 | "RtlInitializeCriticalSection", // @291 294 | "RtlIntegerToChar", // @292 295 | "RtlIntegerToUnicodeString", // @293 296 | "RtlLeaveCriticalSection", // @294 297 | "RtlLeaveCriticalSectionAndRegion", // @295 298 | "RtlLowerChar", // @296 299 | "RtlMapGenericMask", // @297 300 | "RtlMoveMemory", // @298 301 | "RtlMultiByteToUnicodeN", // @299 302 | "RtlMultiByteToUnicodeSize", // @300 303 | "RtlNtStatusToDosError", // @301 304 | "RtlRaiseException", // @302 305 | "RtlRaiseStatus", // @303 306 | "RtlTimeFieldsToTime", // @304 307 | "RtlTimeToTimeFields", // @305 308 | "RtlTryEnterCriticalSection", // @306 309 | "RtlUlongByteSwap", // @307 310 | "RtlUnicodeStringToAnsiString", // @308 311 | "RtlUnicodeStringToInteger", // @309 312 | "RtlUnicodeToMultiByteN", // @310 313 | "RtlUnicodeToMultiByteSize", // @311 314 | "RtlUnwind", // @312 315 | "RtlUpcaseUnicodeChar", // @313 316 | "RtlUpcaseUnicodeString", // @314 317 | "RtlUpcaseUnicodeToMultiByteN", // @315 318 | "RtlUpperChar", // @316 319 | "RtlUpperString", // @317 320 | "RtlUshortByteSwap", // @318 321 | "RtlWalkFrameChain", // @319 322 | "RtlZeroMemory", // @320 323 | "XboxEEPROMKey", // @321 (Object) 324 | "XboxHardwareInfo", // @322 (Object) 325 | "XboxHDKey", // @323 (Object) 326 | "XboxKrnlVersion", // @324 (Object) 327 | "XboxSignatureKey", // @325 (Object) 328 | "XeImageFileName", // @326 (Object) 329 | "XeLoadSection", // @327 330 | "XeUnloadSection", // @328 331 | "READ_PORT_BUFFER_UCHAR", // @329 332 | "READ_PORT_BUFFER_USHORT", // @330 333 | "READ_PORT_BUFFER_ULONG", // @331 334 | "WRITE_PORT_BUFFER_UCHAR", // @332 335 | "WRITE_PORT_BUFFER_USHORT", // @333 336 | "WRITE_PORT_BUFFER_ULONG", // @334 337 | "XcSHAInit", // @335 338 | "XcSHAUpdate", // @336 339 | "XcSHAFinal", // @337 340 | "XcRC4Key", // @338 341 | "XcRC4Crypt", // @339 342 | "XcHMAC", // @340 343 | "XcPKEncPublic", // @341 344 | "XcPKDecPrivate", // @342 345 | "XcPKGetKeyLen", // @343 346 | "XcVerifyPKCS1Signature", // @344 347 | "XcModExp", // @345 348 | "XcDESKeyParity", // @346 349 | "XcKeyTable", // @347 350 | "XcBlockCrypt", // @348 351 | "XcBlockCryptCBC", // @349 352 | "XcCryptService", // @350 353 | "XcUpdateCrypto", // @351 354 | "RtlRip", // @352 355 | "XboxLANKey", // @353 (Object) 356 | "XboxAlternateSignatureKeys", // @354 (Object) 357 | "XePublicKeyData", // @355 (Object) 358 | "HalBootSMCVideoMode", // @356 (Object) 359 | "IdexChannelObject", // @357 (Object) 360 | "HalIsResetOrShutdownPending", // @358 361 | "IoMarkIrpMustComplete", // @359 362 | "HalInitiateShutdown", // @360 363 | "RtlSnprintf", // @361 364 | "RtlSprintf", // @362 365 | "RtlVsnprintf", // @363 366 | "RtlVsprintf", // @364 367 | "HalEnableSecureTrayEject", // @365 368 | "HalWriteSMCScratchRegister", // @366 369 | NULL, 370 | NULL, 371 | NULL, 372 | NULL, 373 | NULL, 374 | NULL, 375 | NULL, 376 | "MmDbgAllocateMemory", // @374 377 | "MmDbgFreeMemory", // @375 378 | "MmDbgQueryAvailablePages", // @376 379 | "MmDbgReleaseAddress", // @377 380 | "MmDbgWriteCheck", // @378 381 | }; 382 | -------------------------------------------------------------------------------- /giants.c: -------------------------------------------------------------------------------- 1 | /************************************************************** 2 | * 3 | * giants.c 4 | * 5 | * Library for large-integer arithmetic. 6 | * 7 | * The large-gcd implementation is due to J. P. Buhler. 8 | * Special mod routines use ideas of R. McIntosh. 9 | * Contributions from G. Woltman, A. Powell acknowledged. 10 | * 11 | * Updates: 12 | * 11 Feb 03 REC R. McIntosh fixes to fermatpowermodg, mersennepowermodg 13 | * 20 Oct 01 REC R. McIntosh fixes to: mersennemod, fermatmod, fer_mod 14 | * 18 Jul 99 REC Added routine fer_mod(), for use when Fermat 15 | giant itself is available. 16 | * 17 Jul 99 REC Fixed sign bug in fermatmod() 17 | * 17 Apr 99 REC Fixed various comment/line wraps 18 | * 25 Mar 99 REC G. Woltman/A. Powell fixes Karat. routines 19 | * 05 Mar 99 REC Moved invaux, binvaux giants to stack 20 | * 05 Mar 99 REC Moved gread/gwrite giants to stack 21 | * 05 Mar 99 REC No static on cur_den, cur_recip (A. Powell) 22 | * 28 Feb 99 REC Error detection added atop newgiant(). 23 | * 27 Feb 99 REC Reduced wasted work in addsignal(). 24 | * 27 Feb 99 REC Reduced wasted work in FFTmulg(). 25 | * 19 Feb 99 REC Generalized iaddg() per R. Mcintosh. 26 | * 2 Feb 99 REC Fixed comments. 27 | * 6 Dec 98 REC Fixed yet another Karatsuba glitch. 28 | * 1 Dec 98 REC Fixed errant case of addg(). 29 | * 28 Nov 98 REC Installed A. Powell's (correct) variant of 30 | Karatsuba multiply. 31 | * 15 May 98 REC Modified gwrite() to handle huge integers. 32 | * 13 May 98 REC Changed to static stack declarations 33 | * 11 May 98 REC Installed Karatsuba multiply, to handle 34 | * medregion 'twixt grammar- and FFT-multiply. 35 | * 1 May 98 JF gshifts now handle bits < 0 correctly. 36 | * 30 Apr 98 JF 68k assembler code removed, 37 | * stack giant size now invariant and based 38 | * on first call of newgiant(), 39 | * stack memory leaks fixed. 40 | * 29 Apr 98 JF function prototyes cleaned up, 41 | * GCD no longer uses personal stack, 42 | * optimized shifts for bits%16 == 0. 43 | * 27 Apr 98 JF scratch giants now replaced with stack 44 | * 20 Apr 98 JF grammarsquareg fixed for asize == 0. 45 | * scratch giants now static. 46 | * 29 Jan 98 JF Corrected out-of-range errors in 47 | * mersennemod and fermatmod. 48 | * 23 Dec 97 REC Sped up divide routines via split-shift. 49 | * 18 Nov 97 JF Improved mersennemod, fermatmod. 50 | * 9 Nov 97 JF Sped up grammarsquareg. 51 | * 20 May 97 RDW Fixed Win32 compiler warnings. 52 | * 18 May 97 REC Installed new, fast divide. 53 | * 17 May 97 REC Reduced memory for FFT multiply. 54 | * 26 Apr 97 REC Creation. 55 | * 56 | * c. 1997,1998 Perfectly Scientific, Inc. 57 | * All Rights Reserved. 58 | * 59 | **************************************************************/ 60 | 61 | 62 | /* Include Files. */ 63 | 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include "giants.h" 69 | 70 | 71 | /* Compiler options. */ 72 | 73 | #ifdef _WIN32 74 | #pragma warning( disable : 4127 4706 ) /* disable conditional is constant warning */ 75 | #endif 76 | 77 | 78 | /* Global variables. */ 79 | 80 | int error = 0; 81 | int mulmode = AUTO_MUL; 82 | int cur_prec = 0; 83 | int cur_shift = 0; 84 | static int cur_stack_size = 0; 85 | static int cur_stack_elem = 0; 86 | static int stack_glen = 0; 87 | static giant *stack; 88 | giant cur_den = NULL, 89 | cur_recip = NULL; 90 | int current_max_size = 0, 91 | cur_run = 0; 92 | double * sinCos=NULL; 93 | int checkFFTerror = 0; 94 | double maxFFTerror; 95 | static double *z = NULL, 96 | *z2 = NULL; 97 | 98 | /* stack handling functions. */ 99 | static giant popg(void); 100 | static void pushg(int); 101 | 102 | 103 | /* Private function prototypes. */ 104 | 105 | int gerr(void); 106 | double gfloor(double); 107 | int radixdiv(int, int, giant); 108 | void columnwrite(FILE *, short *, const char *, short, int); 109 | 110 | void normal_addg(giant, giant); 111 | void normal_subg(giant, giant); 112 | void reverse_subg(giant, giant); 113 | int binvaux(giant, giant); 114 | int invaux(giant, giant); 115 | int allzeros(int, int, giant); 116 | void auxmulg(giant a, giant b); 117 | void karatmulg(giant a, giant b); 118 | void karatsquareg(giant b); 119 | void grammarmulg(giant a, giant b); 120 | void grammarsquareg(giant b); 121 | 122 | int lpt(int, int *); 123 | void addsignal(giant, double *, int); 124 | void FFTsquareg(giant x); 125 | void FFTmulg(giant y, giant x); 126 | void scramble_real(); 127 | void fft_real_to_hermitian(double *z, int n); 128 | void fftinv_hermitian_to_real(double *z, int n); 129 | void mul_hermitian(double *a, double *b, int n); 130 | void square_hermitian(double *b, int n); 131 | void giant_to_double(giant x, int sizex, double *z, int L); 132 | void gswap(giant *, giant *); 133 | void onestep(giant, giant, gmatrix); 134 | void mulvM(gmatrix, giant, giant); 135 | void mulmM(gmatrix, gmatrix); 136 | void writeM(gmatrix); 137 | static void punch(giant, gmatrix); 138 | static void dotproduct(giant, giant, giant, giant); 139 | void fix(giant *, giant *); 140 | void hgcd(int, giant, giant, gmatrix); 141 | void shgcd(int, int, gmatrix); 142 | 143 | 144 | 145 | /************************************************************** 146 | * 147 | * Functions 148 | * 149 | **************************************************************/ 150 | 151 | 152 | /************************************************************** 153 | * 154 | * Initialization and utility functions 155 | * 156 | **************************************************************/ 157 | 158 | double 159 | gfloor( 160 | double f 161 | ) 162 | { 163 | return floor(f); 164 | } 165 | 166 | 167 | void 168 | init_sinCos( 169 | int n 170 | ) 171 | { 172 | int j; 173 | double e = TWOPI/n; 174 | 175 | if (n<=cur_run) 176 | return; 177 | cur_run = n; 178 | if (sinCos) 179 | free(sinCos); 180 | sinCos = (double *)malloc(sizeof(double)*(1+(n>>2))); 181 | for (j=0;j<=(n>>2);j++) 182 | { 183 | sinCos[j] = sin(e*j); 184 | } 185 | } 186 | 187 | 188 | double 189 | s_sin( 190 | int n 191 | ) 192 | { 193 | int seg = n/(cur_run>>2); 194 | 195 | switch (seg) 196 | { 197 | case 0: return(sinCos[n]); 198 | case 1: return(sinCos[(cur_run>>1)-n]); 199 | case 2: return(-sinCos[n-(cur_run>>1)]); 200 | case 3: return(-sinCos[cur_run-n]); 201 | } 202 | return 0; 203 | } 204 | 205 | 206 | double 207 | s_cos( 208 | int n 209 | ) 210 | { 211 | int quart = (cur_run>>2); 212 | 213 | if (n < quart) 214 | return(s_sin(n+quart)); 215 | return(-s_sin(n-quart)); 216 | } 217 | 218 | 219 | int 220 | gerr(void) 221 | { 222 | return(error); 223 | } 224 | 225 | 226 | giant 227 | popg ( 228 | void 229 | ) 230 | { 231 | int i; 232 | 233 | if (current_max_size <= 0) current_max_size = MAX_SHORTS; 234 | 235 | if (cur_stack_size == 0) { 236 | /* Initialize the stack if we're just starting out. 237 | * Note that all stack giants will be whatever current_max_size is 238 | * when newgiant() is first called. */ 239 | cur_stack_size = STACK_GROW; 240 | stack = (giant *) malloc (cur_stack_size * sizeof(giant)); 241 | for(i = 0; i < STACK_GROW; i++) 242 | stack[i] = NULL; 243 | if (stack_glen == 0) stack_glen = current_max_size; 244 | } else if (cur_stack_elem >= cur_stack_size) { 245 | /* Expand the stack if we need to. */ 246 | i = cur_stack_size; 247 | cur_stack_size += STACK_GROW; 248 | stack = (giant *) realloc (stack,cur_stack_size * sizeof(giant)); 249 | for (; i < cur_stack_size; i++) 250 | stack[i] = NULL; 251 | } else if (cur_stack_elem < cur_stack_size - 2*STACK_GROW) { 252 | /* Prune the stack if it's too big. Disabled, so the stack can only expand */ 253 | /* cur_stack_size -= STACK_GROW; 254 | for (i = cur_stack_size - STACK_GROW; i < cur_stack_size; i++) 255 | free(stack[i]); 256 | stack = (giant *) realloc (stack,cur_stack_size * sizeof(giant)); */ 257 | } 258 | 259 | /* Malloc our giant. */ 260 | if (stack[cur_stack_elem] == NULL) 261 | stack[cur_stack_elem] = (giant ) malloc(stack_glen*sizeof(short)+sizeof(int)); 262 | stack[cur_stack_elem]->sign = 0; 263 | 264 | return(stack[cur_stack_elem++]); 265 | } 266 | 267 | 268 | void 269 | pushg ( 270 | int a 271 | ) 272 | { 273 | if (a < 0) return; 274 | cur_stack_elem -= a; 275 | if (cur_stack_elem < 0) cur_stack_elem = 0; 276 | } 277 | 278 | 279 | giant 280 | newgiant( 281 | int numshorts 282 | ) 283 | { 284 | int size; 285 | giant thegiant; 286 | 287 | if (numshorts > MAX_SHORTS) { 288 | fprintf(stderr, "Requested giant too big.\n"); 289 | fflush(stderr); 290 | } 291 | if (numshorts<=0) 292 | numshorts = MAX_SHORTS; 293 | size = numshorts*sizeof(short)+sizeof(int); 294 | thegiant = (giant)malloc(size); 295 | thegiant->sign = 0; 296 | 297 | if (newmin(2*numshorts,MAX_SHORTS) > current_max_size) 298 | current_max_size = newmin(2*numshorts,MAX_SHORTS); 299 | 300 | /* If newgiant() is being called for the first time, set the 301 | * size of the stack giants. */ 302 | if (stack_glen == 0) stack_glen = current_max_size; 303 | 304 | return(thegiant); 305 | } 306 | 307 | 308 | gmatrix 309 | newgmatrix( 310 | void 311 | ) 312 | /* Allocates space for a gmatrix struct, but does not 313 | * allocate space for the giants. */ 314 | { 315 | return((gmatrix) malloc (4*sizeof(giant))); 316 | } 317 | 318 | int 319 | bitlen( 320 | giant n 321 | ) 322 | { 323 | int b = 16, c = 1<<15, w; 324 | 325 | if (isZero(n)) 326 | return(0); 327 | w = n->n[abs(n->sign) - 1]; 328 | while ((w&c) == 0) 329 | { 330 | b--; 331 | c >>= 1; 332 | } 333 | return (16*(abs(n->sign)-1) + b); 334 | } 335 | 336 | 337 | int 338 | bitval( 339 | giant n, 340 | int pos 341 | ) 342 | { 343 | int i = abs(pos)>>4, c = 1 << (pos&15); 344 | 345 | return (((n->n[i]) & c) != 0); 346 | } 347 | 348 | 349 | int 350 | isone( 351 | giant g 352 | ) 353 | { 354 | return((g->sign==1)&&(g->n[0]==1)); 355 | } 356 | 357 | 358 | int isZero( 359 | giant thegiant 360 | ) 361 | /* Returns TR if thegiant == 0. */ 362 | { 363 | register int count; 364 | int length = abs(thegiant->sign); 365 | register unsigned short * numpointer = thegiant->n; 366 | 367 | if (length) 368 | { 369 | for(count = 0; countsign)*sizeof(short); 387 | 388 | memcpy((char *)destgiant,(char *)srcgiant,numbytes); 389 | } 390 | 391 | 392 | void 393 | itog( 394 | int i, 395 | giant g 396 | ) 397 | /* The giant g becomes set to the integer value i. */ 398 | { 399 | unsigned int j = abs(i); 400 | 401 | if (i==0) 402 | { 403 | g->sign = 0; 404 | g->n[0] = 0; 405 | return; 406 | } 407 | g->n[0] = (unsigned short)(j & 0xFFFF); 408 | j >>= 16; 409 | if (j) 410 | { 411 | g->n[1] = (unsigned short)j; 412 | g->sign = 2; 413 | } 414 | else 415 | { 416 | g->sign = 1; 417 | } 418 | if (i<0) 419 | g->sign = -(g->sign); 420 | } 421 | 422 | 423 | signed int 424 | gtoi( 425 | giant x 426 | ) 427 | /* Calculate the value of an int-sized giant NOT exceeding 31 bits. */ 428 | { 429 | register int size = abs(x->sign); 430 | register int sign = (x->sign < 0) ? -1 : 1; 431 | 432 | switch(size) 433 | { 434 | case 0: 435 | break; 436 | case 1: 437 | return sign * x->n[0]; 438 | case 2: 439 | return sign * (x->n[0]+((x->n[1])<<16)); 440 | default: 441 | fprintf(stderr,"Giant too large for gtoi\n"); 442 | break; 443 | } 444 | return 0; 445 | } 446 | 447 | 448 | int 449 | gsign( 450 | giant g 451 | ) 452 | /* Returns the sign of g. */ 453 | { 454 | if (isZero(g)) 455 | return(0); 456 | if (g->sign >0) 457 | return(1); 458 | return(-1); 459 | } 460 | 461 | 462 | #if 0 463 | int gcompg(a,b) 464 | /* Returns -1,0,1 if ab, respectively. */ 465 | giant a,b; 466 | { 467 | int size = abs(a->sign); 468 | 469 | if(isZero(a)) size = 0; 470 | if (size == 0) { 471 | if (isZero(b)) return(0); else return(-gsign(b)); 472 | } 473 | 474 | if (b->sign == 0) return(gsign(a)); 475 | if (gsign(a)!=gsign(b)) return(gsign(a)); 476 | if (size>abs(b->sign)) return(gsign(a)); 477 | if (sizesign)) return(-gsign(a)); 478 | 479 | do { 480 | --size; 481 | if (a->n[size] > b->n[size]) return(gsign(a)); 482 | if (a->n[size] < b->n[size]) return(-gsign(a)); 483 | } while(size>0); 484 | 485 | return(0); 486 | } 487 | #else 488 | 489 | int 490 | gcompg( 491 | giant a, 492 | giant b 493 | ) 494 | /* Returns -1,0,1 if ab, respectively. */ 495 | { 496 | int sa = a->sign, j, sb = b->sign, va, vb, sgn; 497 | 498 | if(sa > sb) 499 | return(1); 500 | if(sa < sb) 501 | return(-1); 502 | if(sa < 0) 503 | { 504 | sa = -sa; /* Take absolute value of sa. */ 505 | sgn = -1; 506 | } 507 | else 508 | { 509 | sgn = 1; 510 | } 511 | for(j = sa-1; j >= 0; j--) 512 | { 513 | va = a->n[j]; 514 | vb = b->n[j]; 515 | if (va > vb) 516 | return(sgn); 517 | if (va < vb) 518 | return(-sgn); 519 | } 520 | return(0); 521 | } 522 | #endif 523 | 524 | 525 | void 526 | setmulmode( 527 | int mode 528 | ) 529 | { 530 | mulmode = mode; 531 | } 532 | 533 | 534 | /************************************************************** 535 | * 536 | * Private I/O Functions 537 | * 538 | **************************************************************/ 539 | 540 | 541 | int 542 | radixdiv( 543 | int base, 544 | int divisor, 545 | giant thegiant 546 | ) 547 | /* Divides giant of arbitrary base by divisor. 548 | * Returns remainder. Used by idivg and gread. */ 549 | { 550 | int first = TR; 551 | int finalsize = abs(thegiant->sign); 552 | int j = finalsize-1; 553 | unsigned short *digitpointer=&thegiant->n[j]; 554 | unsigned int num,rem=0; 555 | 556 | if (divisor == 0) 557 | { 558 | error = DIVIDEBYZERO; 559 | exit(error); 560 | } 561 | 562 | while (j>=0) 563 | { 564 | num=rem*base + *digitpointer; 565 | *digitpointer = (unsigned short)(num/divisor); 566 | if (first) 567 | { 568 | if (*digitpointer == 0) 569 | --finalsize; 570 | else 571 | first = FA; 572 | } 573 | rem = num % divisor; 574 | --digitpointer; 575 | --j; 576 | } 577 | 578 | if ((divisor<0) ^ (thegiant->sign<0)) 579 | finalsize=-finalsize; 580 | thegiant->sign=finalsize; 581 | return(rem); 582 | } 583 | 584 | 585 | void 586 | columnwrite( 587 | FILE *filepointer, 588 | short *column, 589 | const char *format, 590 | short arg, 591 | int newlines 592 | ) 593 | /* Used by gwriteln. */ 594 | { 595 | char outstring[10]; 596 | short i; 597 | 598 | sprintf(outstring,format,arg); 599 | for (i=0; outstring[i]!=0; ++i) 600 | { 601 | if (newlines) 602 | { 603 | if (*column >= COLUMNWIDTH) 604 | { 605 | fputs("\\\n",filepointer); 606 | *column = 0; 607 | } 608 | } 609 | fputc(outstring[i],filepointer); 610 | ++*column; 611 | } 612 | } 613 | 614 | 615 | void 616 | gwrite( 617 | giant thegiant, 618 | FILE *filepointer, 619 | int newlines 620 | ) 621 | /* Outputs thegiant to filepointer. Output is terminated by a newline. */ 622 | { 623 | short column; 624 | unsigned int i; 625 | unsigned short *numpointer; 626 | giant garbagegiant, basetengrand; 627 | 628 | basetengrand = popg(); 629 | garbagegiant = popg(); 630 | 631 | if (isZero(thegiant)) 632 | { 633 | fputs("0",filepointer); 634 | } 635 | else 636 | { 637 | numpointer = basetengrand->n; 638 | gtog(thegiant,garbagegiant); 639 | 640 | basetengrand->sign = 0; 641 | do 642 | { 643 | *numpointer = (unsigned short)idivg(10000,garbagegiant); 644 | ++numpointer; 645 | if (++basetengrand->sign >= current_max_size) 646 | { 647 | error = OVFLOW; 648 | exit(error); 649 | } 650 | } while (!isZero(garbagegiant)); 651 | 652 | if (!error) 653 | { 654 | i = basetengrand->sign-1; 655 | column = 0; 656 | if (thegiant->sign<0 && basetengrand->n[i]!=0) 657 | columnwrite(filepointer,&column,"-",0, newlines); 658 | columnwrite(filepointer,&column,"%d",basetengrand->n[i],newlines); 659 | for( ; i>0; ) 660 | { 661 | --i; 662 | columnwrite(filepointer,&column,"%04d",basetengrand->n[i],newlines); 663 | } 664 | } 665 | } 666 | pushg(2); 667 | } 668 | 669 | 670 | void 671 | gwriteln( 672 | giant theg, 673 | FILE *filepointer 674 | ) 675 | { 676 | gwrite(theg, filepointer, 1); 677 | fputc('\n',filepointer); 678 | } 679 | 680 | 681 | void 682 | gread( 683 | giant theg, 684 | FILE *filepointer 685 | ) 686 | { 687 | char currentchar; 688 | int isneg,size,backslash=FA,numdigits=0; 689 | unsigned short *numpointer; 690 | giant basetenthousand; 691 | static char *inbuf = NULL; 692 | 693 | basetenthousand = popg(); 694 | if (inbuf == NULL) 695 | inbuf = (char*)malloc(MAX_DIGITS); 696 | 697 | currentchar = (char)fgetc(filepointer); 698 | if (currentchar=='-') 699 | { 700 | isneg=TR; 701 | } 702 | else 703 | { 704 | isneg=FA; 705 | if (currentchar!='+') 706 | ungetc(currentchar,filepointer); 707 | } 708 | 709 | do 710 | { 711 | currentchar = (char)fgetc(filepointer); 712 | if ((currentchar>='0') && (currentchar<='9')) 713 | { 714 | inbuf[numdigits]=currentchar; 715 | if(++numdigits==MAX_DIGITS) 716 | break; 717 | backslash=FA; 718 | } 719 | else 720 | { 721 | if (currentchar=='\\') 722 | backslash=TR; 723 | } 724 | } while(((currentchar!=' ') && (currentchar!='\n') && 725 | (currentchar!='\t')) || (backslash) ); 726 | if (numdigits) 727 | { 728 | size = 0; 729 | do 730 | { 731 | inbuf[numdigits] = 0; 732 | numdigits-=4; 733 | if (numdigits<0) 734 | numdigits=0; 735 | basetenthousand->n[size] = (unsigned short)strtol(&inbuf[numdigits],NULL,10); 736 | ++size; 737 | } while (numdigits>0); 738 | 739 | basetenthousand->sign = size; 740 | theg->sign = 0; 741 | numpointer = theg->n; 742 | do 743 | { 744 | *numpointer = (unsigned short) 745 | radixdiv(10000,1<<(8*sizeof(short)),basetenthousand); 746 | ++numpointer; 747 | if (++theg->sign >= current_max_size) 748 | { 749 | error = OVFLOW; 750 | exit(error); 751 | } 752 | } while (!isZero(basetenthousand)); 753 | 754 | if (isneg) 755 | theg->sign = -theg->sign; 756 | } 757 | pushg(1); 758 | } 759 | 760 | 761 | 762 | /************************************************************** 763 | * 764 | * Private Math Functions 765 | * 766 | **************************************************************/ 767 | 768 | 769 | void 770 | negg( 771 | giant g 772 | ) 773 | /* g becomes -g. */ 774 | { 775 | g->sign = -g->sign; 776 | } 777 | 778 | 779 | void 780 | absg( 781 | giant g 782 | ) 783 | { 784 | /* g becomes the absolute value of g. */ 785 | if (g->sign <0) 786 | g->sign=-g->sign; 787 | } 788 | 789 | 790 | void 791 | iaddg( 792 | int i, 793 | giant g 794 | ) 795 | /* Giant g becomes g + (int)i. */ 796 | { 797 | int w,j=0,carry = 0, size = abs(g->sign); 798 | giant tmp; 799 | 800 | if (isZero(g)) 801 | { 802 | itog(i,g); 803 | } 804 | else if(g->sign < 0) { 805 | tmp = popg(); 806 | itog(i, tmp); 807 | addg(tmp, g); 808 | pushg(1); 809 | return; 810 | } 811 | else 812 | { 813 | w = g->n[0]+i; 814 | do 815 | { 816 | g->n[j] = (unsigned short) (w & 65535L); 817 | carry = w >> 16; 818 | w = g->n[++j]+carry; 819 | } while ((carry!=0) && (jsign; 824 | g->n[size] = (unsigned short)carry; 825 | } 826 | } 827 | 828 | 829 | /* New subtract routines. 830 | The basic subtract "subg()" uses the following logic table: 831 | 832 | a b if(b > a) if(a > b) 833 | 834 | + + b := b - a b := -(a - b) 835 | - + b := b + (-a) N.A. 836 | + - N.A. b := -((-b) + a) 837 | - - b := (-a) - (-b) b := -((-b) - (-a)) 838 | 839 | The basic addition routine "addg()" uses: 840 | 841 | a b if(b > -a) if(-a > b) 842 | 843 | + + b := b + a N.A. 844 | - + b := b - (-a) b := -((-a) - b) 845 | + - b := a - (-b) b := -((-b) - a) 846 | - - N.A. b := -((-b) + (-a)) 847 | 848 | In this way, internal routines "normal_addg," "normal_subg," 849 | and "reverse_subg;" each of which assumes non-negative 850 | operands and a non-negative result, are now used for greater 851 | efficiency. 852 | */ 853 | 854 | void 855 | normal_addg( 856 | giant a, 857 | giant b 858 | ) 859 | /* b := a + b, both a,b assumed non-negative. */ 860 | { 861 | int carry = 0; 862 | int asize = a->sign, bsize = b->sign; 863 | long k; 864 | int j=0; 865 | unsigned short *aptr = a->n, *bptr = b->n; 866 | 867 | if (asize < bsize) 868 | { 869 | for (j=0; j= 65536L) 874 | { 875 | k -= 65536L; 876 | ++carry; 877 | } 878 | *bptr++ = (unsigned short)k; 879 | } 880 | for (j=asize; j= 65536L) 885 | { 886 | k -= 65536L; 887 | ++carry; 888 | } 889 | *bptr++ = (unsigned short)k; 890 | } 891 | } 892 | else 893 | { 894 | for (j=0; j= 65536L) 899 | { 900 | k -= 65536L; 901 | ++carry; 902 | } 903 | *bptr++ = (unsigned short)k; 904 | } 905 | for (j=bsize; j= 65536L) 910 | { 911 | k -= 65536L; 912 | ++carry; 913 | } 914 | *bptr++ = (unsigned short)k; 915 | } 916 | } 917 | if (carry) 918 | { 919 | *bptr = 1; ++j; 920 | } 921 | b->sign = j; 922 | } 923 | 924 | 925 | void 926 | normal_subg( 927 | giant a, 928 | giant b 929 | ) 930 | /* b := b - a; requires b, a non-negative and b >= a. */ 931 | { 932 | int j, size = b->sign; 933 | unsigned int k; 934 | 935 | if (a->sign == 0) 936 | return; 937 | 938 | k = 0; 939 | for (j=0; jsign; ++j) 940 | { 941 | k += 0xffff - a->n[j] + b->n[j]; 942 | b->n[j] = (unsigned short)(k & 0xffff); 943 | k >>= 16; 944 | } 945 | for (j=a->sign; jn[j]; 948 | b->n[j] = (unsigned short)(k & 0xffff); 949 | k >>= 16; 950 | } 951 | 952 | if (b->n[0] == 0xffff) 953 | iaddg(1,b); 954 | else 955 | ++b->n[0]; 956 | 957 | while ((size-- > 0) && (b->n[size]==0)); 958 | 959 | b->sign = (b->n[size]==0) ? 0 : size+1; 960 | } 961 | 962 | 963 | void 964 | reverse_subg( 965 | giant a, 966 | giant b 967 | ) 968 | /* b := a - b; requires b, a non-negative and a >= b. */ 969 | { 970 | int j, size = a->sign; 971 | unsigned int k; 972 | 973 | k = 0; 974 | for (j=0; jsign; ++j) 975 | { 976 | k += 0xffff - b->n[j] + a->n[j]; 977 | b->n[j] = (unsigned short)(k & 0xffff); 978 | k >>= 16; 979 | } 980 | for (j=b->sign; jn[j]; 983 | b->n[j] = (unsigned short)(k & 0xffff); 984 | k >>= 16; 985 | } 986 | 987 | b->sign = size; /* REC, 21 Apr 1996. */ 988 | if (b->n[0] == 0xffff) 989 | iaddg(1,b); 990 | else 991 | ++b->n[0]; 992 | 993 | while (!b->n[--size]); 994 | 995 | b->sign = size+1; 996 | } 997 | 998 | void 999 | addg( 1000 | giant a, 1001 | giant b 1002 | ) 1003 | /* b := b + a, any signs any result. */ 1004 | { 1005 | int asgn = a->sign, bsgn = b->sign; 1006 | 1007 | if (asgn == 0) 1008 | return; 1009 | if (bsgn == 0) 1010 | { 1011 | gtog(a,b); 1012 | return; 1013 | } 1014 | if ((asgn < 0) == (bsgn < 0)) 1015 | { 1016 | if (bsgn > 0) 1017 | { 1018 | normal_addg(a,b); 1019 | return; 1020 | } 1021 | absg(b); 1022 | if(a != b) absg(a); 1023 | normal_addg(a,b); 1024 | negg(b); 1025 | if(a != b) negg(a); 1026 | return; 1027 | } 1028 | if(bsgn > 0) 1029 | { 1030 | negg(a); 1031 | if (gcompg(b,a) >= 0) 1032 | { 1033 | normal_subg(a,b); 1034 | negg(a); 1035 | return; 1036 | } 1037 | reverse_subg(a,b); 1038 | negg(a); 1039 | negg(b); 1040 | return; 1041 | } 1042 | negg(b); 1043 | if(gcompg(b,a) < 0) 1044 | { 1045 | reverse_subg(a,b); 1046 | return; 1047 | } 1048 | normal_subg(a,b); 1049 | negg(b); 1050 | return; 1051 | } 1052 | 1053 | void 1054 | subg( 1055 | giant a, 1056 | giant b 1057 | ) 1058 | /* b := b - a, any signs, any result. */ 1059 | { 1060 | int asgn = a->sign, bsgn = b->sign; 1061 | 1062 | if (asgn == 0) 1063 | return; 1064 | if (bsgn == 0) 1065 | { 1066 | gtog(a,b); 1067 | negg(b); 1068 | return; 1069 | } 1070 | if ((asgn < 0) != (bsgn < 0)) 1071 | { 1072 | if (bsgn > 0) 1073 | { 1074 | negg(a); 1075 | normal_addg(a,b); 1076 | negg(a); 1077 | return; 1078 | } 1079 | negg(b); 1080 | normal_addg(a,b); 1081 | negg(b); 1082 | return; 1083 | } 1084 | if (bsgn > 0) 1085 | { 1086 | if (gcompg(b,a) >= 0) 1087 | { 1088 | normal_subg(a,b); 1089 | return; 1090 | } 1091 | reverse_subg(a,b); 1092 | negg(b); 1093 | return; 1094 | } 1095 | negg(a); 1096 | negg(b); 1097 | if (gcompg(b,a) >= 0) 1098 | { 1099 | normal_subg(a,b); 1100 | negg(a); 1101 | negg(b); 1102 | return; 1103 | } 1104 | reverse_subg(a,b); 1105 | negg(a); 1106 | return; 1107 | } 1108 | 1109 | 1110 | int 1111 | numtrailzeros( 1112 | giant g 1113 | ) 1114 | /* Returns the number of trailing zero bits in g. */ 1115 | { 1116 | register int numshorts = abs(g->sign), j, bcount=0; 1117 | register unsigned short gshort, c; 1118 | 1119 | for (j=0;jn[j]; 1122 | c = 1; 1123 | for (bcount=0;bcount<16; bcount++) 1124 | { 1125 | if (c & gshort) 1126 | break; 1127 | c <<= 1; 1128 | } 1129 | if (bcount<16) 1130 | break; 1131 | } 1132 | return(bcount + 16*j); 1133 | } 1134 | 1135 | 1136 | void 1137 | bdivg( 1138 | giant v, 1139 | giant u 1140 | ) 1141 | /* u becomes greatest power of two not exceeding u/v. */ 1142 | { 1143 | int diff = bitlen(u) - bitlen(v); 1144 | giant scratch7; 1145 | 1146 | if (diff<0) 1147 | { 1148 | itog(0,u); 1149 | return; 1150 | } 1151 | scratch7 = popg(); 1152 | gtog(v, scratch7); 1153 | gshiftleft(diff,scratch7); 1154 | if (gcompg(u,scratch7) < 0) 1155 | diff--; 1156 | if (diff<0) 1157 | { 1158 | itog(0,u); 1159 | pushg(1); 1160 | return; 1161 | } 1162 | itog(1,u); 1163 | gshiftleft(diff,u); 1164 | 1165 | pushg(1); 1166 | } 1167 | 1168 | 1169 | int 1170 | binvaux( 1171 | giant p, 1172 | giant x 1173 | ) 1174 | /* Binary inverse method. Returns zero if no inverse exists, 1175 | * in which case x becomes GCD(x,p). */ 1176 | { 1177 | 1178 | giant scratch7, u0, u1, v0, v1; 1179 | 1180 | if (isone(x)) 1181 | return(1); 1182 | u0 = popg(); 1183 | u1 = popg(); 1184 | v0 = popg(); 1185 | v1 = popg(); 1186 | itog(1, v0); 1187 | gtog(x, v1); 1188 | itog(0,x); 1189 | gtog(p, u1); 1190 | 1191 | scratch7 = popg(); 1192 | while(!isZero(v1)) 1193 | { 1194 | gtog(u1, u0); 1195 | bdivg(v1, u0); 1196 | gtog(x, scratch7); 1197 | gtog(v0, x); 1198 | mulg(u0, v0); 1199 | subg(v0,scratch7); 1200 | gtog(scratch7, v0); 1201 | 1202 | gtog(u1, scratch7); 1203 | gtog(v1, u1); 1204 | mulg(u0, v1); 1205 | subg(v1,scratch7); 1206 | gtog(scratch7, v1); 1207 | } 1208 | 1209 | pushg(1); 1210 | 1211 | if (!isone(u1)) 1212 | { 1213 | gtog(u1,x); 1214 | if(x->sign<0) addg(p, x); 1215 | pushg(4); 1216 | return(0); 1217 | } 1218 | if(x->sign<0) 1219 | addg(p, x); 1220 | pushg(4); 1221 | return(1); 1222 | } 1223 | 1224 | 1225 | int 1226 | binvg( 1227 | giant p, 1228 | giant x 1229 | ) 1230 | { 1231 | modg(p, x); 1232 | return(binvaux(p,x)); 1233 | } 1234 | 1235 | 1236 | int 1237 | invg( 1238 | giant p, 1239 | giant x 1240 | ) 1241 | { 1242 | modg(p, x); 1243 | return(invaux(p,x)); 1244 | } 1245 | 1246 | int 1247 | invaux( 1248 | giant p, 1249 | giant x 1250 | ) 1251 | /* Returns zero if no inverse exists, in which case x becomes 1252 | * GCD(x,p). */ 1253 | { 1254 | 1255 | giant scratch7, u0, u1, v0, v1; 1256 | 1257 | if ((x->sign==1)&&(x->n[0]==1)) 1258 | return(1); 1259 | 1260 | u0 = popg(); 1261 | u1 = popg(); 1262 | v0 = popg(); 1263 | v1 = popg(); 1264 | 1265 | itog(1,u1); 1266 | gtog(p, v0); 1267 | gtog(x, v1); 1268 | itog(0,x); 1269 | 1270 | scratch7 = popg(); 1271 | while (!isZero(v1)) 1272 | { 1273 | gtog(v0, u0); 1274 | divg(v1, u0); 1275 | gtog(u0, scratch7); 1276 | mulg(v1, scratch7); 1277 | subg(v0, scratch7); 1278 | negg(scratch7); 1279 | gtog(v1, v0); 1280 | gtog(scratch7, v1); 1281 | gtog(u1, scratch7); 1282 | mulg(u0, scratch7); 1283 | subg(x, scratch7); 1284 | negg(scratch7); 1285 | gtog(u1,x); 1286 | gtog(scratch7, u1); 1287 | } 1288 | pushg(1); 1289 | 1290 | if ((v0->sign!=1)||(v0->n[0]!=1)) 1291 | { 1292 | gtog(v0,x); 1293 | pushg(4); 1294 | return(0); 1295 | } 1296 | if(x->sign<0) 1297 | addg(p, x); 1298 | pushg(4); 1299 | return(1); 1300 | } 1301 | 1302 | 1303 | int 1304 | mersenneinvg( 1305 | int q, 1306 | giant x 1307 | ) 1308 | { 1309 | int k; 1310 | giant u0, u1, v1; 1311 | 1312 | u0 = popg(); 1313 | u1 = popg(); 1314 | v1 = popg(); 1315 | 1316 | itog(1, u0); 1317 | itog(0, u1); 1318 | itog(1, v1); 1319 | gshiftleft(q, v1); 1320 | subg(u0, v1); 1321 | mersennemod(q, x); 1322 | while (1) 1323 | { 1324 | k = -1; 1325 | if (isZero(x)) 1326 | { 1327 | gtog(v1, x); 1328 | pushg(3); 1329 | return(0); 1330 | } 1331 | while (bitval(x, ++k) == 0); 1332 | 1333 | gshiftright(k, x); 1334 | if (k) 1335 | { 1336 | gshiftleft(q-k, u0); 1337 | mersennemod(q, u0); 1338 | } 1339 | if (isone(x)) 1340 | break; 1341 | addg(u1, u0); 1342 | mersennemod(q, u0); 1343 | negg(u1); 1344 | addg(u0, u1); 1345 | mersennemod(q, u1); 1346 | if (!gcompg(v1,x)) { 1347 | pushg(3); 1348 | return(0); 1349 | } 1350 | addg(v1, x); 1351 | negg(v1); 1352 | addg(x, v1); 1353 | mersennemod(q, v1); 1354 | } 1355 | gtog(u0, x); 1356 | mersennemod(q,x); 1357 | pushg(3); 1358 | return(1); 1359 | } 1360 | 1361 | 1362 | void 1363 | cgcdg( 1364 | giant a, 1365 | giant v 1366 | ) 1367 | /* Classical Euclid GCD. v becomes gcd(a, v). */ 1368 | { 1369 | giant u, r; 1370 | 1371 | v->sign = abs(v->sign); 1372 | if (isZero(a)) 1373 | return; 1374 | 1375 | u = popg(); 1376 | r = popg(); 1377 | gtog(a, u); 1378 | u->sign = abs(u->sign); 1379 | while (!isZero(v)) 1380 | { 1381 | gtog(u, r); 1382 | modg(v, r); 1383 | gtog(v, u); 1384 | gtog(r, v); 1385 | } 1386 | gtog(u,v); 1387 | pushg(2); 1388 | } 1389 | 1390 | 1391 | void 1392 | gcdg( 1393 | giant x, 1394 | giant y 1395 | ) 1396 | { 1397 | if (bitlen(y)<= GCDLIMIT) 1398 | bgcdg(x,y); 1399 | else 1400 | ggcd(x,y); 1401 | } 1402 | 1403 | void 1404 | bgcdg( 1405 | giant a, 1406 | giant b 1407 | ) 1408 | /* Binary form of the gcd. b becomes the gcd of a,b. */ 1409 | { 1410 | int k = isZero(b), m = isZero(a); 1411 | giant u, v, t; 1412 | 1413 | if (k || m) 1414 | { 1415 | if (m) 1416 | { 1417 | if (k) 1418 | itog(1,b); 1419 | return; 1420 | } 1421 | if (k) 1422 | { 1423 | if (m) 1424 | itog(1,b); 1425 | else 1426 | gtog(a,b); 1427 | return; 1428 | } 1429 | } 1430 | 1431 | u = popg(); 1432 | v = popg(); 1433 | t = popg(); 1434 | 1435 | /* Now neither a nor b is zero. */ 1436 | gtog(a, u); 1437 | u->sign = abs(a->sign); 1438 | gtog(b, v); 1439 | v->sign = abs(b->sign); 1440 | k = numtrailzeros(u); 1441 | m = numtrailzeros(v); 1442 | if (k>m) 1443 | k = m; 1444 | gshiftright(k,u); 1445 | gshiftright(k,v); 1446 | if (u->n[0] & 1) 1447 | { 1448 | gtog(v, t); 1449 | negg(t); 1450 | } 1451 | else 1452 | { 1453 | gtog(u,t); 1454 | } 1455 | 1456 | while (!isZero(t)) 1457 | { 1458 | m = numtrailzeros(t); 1459 | gshiftright(m, t); 1460 | if (t->sign > 0) 1461 | { 1462 | gtog(t, u); 1463 | subg(v,t); 1464 | } 1465 | else 1466 | { 1467 | gtog(t, v); 1468 | negg(v); 1469 | addg(u,t); 1470 | } 1471 | } 1472 | gtog(u,b); 1473 | gshiftleft(k, b); 1474 | pushg(3); 1475 | } 1476 | 1477 | 1478 | void 1479 | powerg( 1480 | int m, 1481 | int n, 1482 | giant g 1483 | ) 1484 | /* g becomes m^n, NO mod performed. */ 1485 | { 1486 | giant scratch2 = popg(); 1487 | 1488 | itog(1, g); 1489 | itog(m, scratch2); 1490 | while (n) 1491 | { 1492 | if (n & 1) 1493 | mulg(scratch2, g); 1494 | n >>= 1; 1495 | if (n) 1496 | squareg(scratch2); 1497 | } 1498 | pushg(1); 1499 | } 1500 | 1501 | #if 0 1502 | void 1503 | jtest( 1504 | giant n 1505 | ) 1506 | { 1507 | if (n->sign) 1508 | { 1509 | if (n->n[n->sign-1] == 0) 1510 | { 1511 | fprintf(stderr,"%d %d tilt",n->sign, (int)(n->n[n->sign-1])); 1512 | exit(7); 1513 | } 1514 | } 1515 | } 1516 | #endif 1517 | 1518 | 1519 | void 1520 | make_recip( 1521 | giant d, 1522 | giant r 1523 | ) 1524 | /* r becomes the steady-state reciprocal 1525 | * 2^(2b)/d, where b = bit-length of d-1. */ 1526 | { 1527 | int b; 1528 | giant tmp, tmp2; 1529 | 1530 | if (isZero(d) || (d->sign < 0)) 1531 | { 1532 | exit(SIGN); 1533 | } 1534 | tmp = popg(); 1535 | tmp2 = popg(); 1536 | itog(1, r); 1537 | subg(r, d); 1538 | b = bitlen(d); 1539 | addg(r, d); 1540 | gshiftleft(b, r); 1541 | gtog(r, tmp2); 1542 | while (1) 1543 | { 1544 | gtog(r, tmp); 1545 | squareg(tmp); 1546 | gshiftright(b, tmp); 1547 | mulg(d, tmp); 1548 | gshiftright(b, tmp); 1549 | addg(r, r); 1550 | subg(tmp, r); 1551 | if (gcompg(r, tmp2) <= 0) 1552 | break; 1553 | gtog(r, tmp2); 1554 | } 1555 | itog(1, tmp); 1556 | gshiftleft(2*b, tmp); 1557 | gtog(r, tmp2); 1558 | mulg(d, tmp2); 1559 | subg(tmp2, tmp); 1560 | itog(1, tmp2); 1561 | while (tmp->sign < 0) 1562 | { 1563 | subg(tmp2, r); 1564 | addg(d, tmp); 1565 | } 1566 | pushg(2); 1567 | } 1568 | 1569 | void 1570 | divg_via_recip( 1571 | giant d, 1572 | giant r, 1573 | giant n 1574 | ) 1575 | /* n := n/d, where r is the precalculated 1576 | * steady-state reciprocal of d. */ 1577 | { 1578 | int s = 2*(bitlen(r)-1), sign = gsign(n); 1579 | giant tmp, tmp2; 1580 | 1581 | if (isZero(d) || (d->sign < 0)) 1582 | { 1583 | exit(SIGN); 1584 | } 1585 | 1586 | tmp = popg(); 1587 | tmp2 = popg(); 1588 | 1589 | n->sign = abs(n->sign); 1590 | itog(0, tmp2); 1591 | while (1) 1592 | { 1593 | gtog(n, tmp); 1594 | mulg(r, tmp); 1595 | gshiftright(s, tmp); 1596 | addg(tmp, tmp2); 1597 | mulg(d, tmp); 1598 | subg(tmp, n); 1599 | if (gcompg(n,d) >= 0) 1600 | { 1601 | subg(d,n); 1602 | iaddg(1, tmp2); 1603 | } 1604 | if (gcompg(n,d) < 0) 1605 | break; 1606 | } 1607 | gtog(tmp2, n); 1608 | n->sign *= sign; 1609 | pushg(2); 1610 | } 1611 | 1612 | #if 1 1613 | void 1614 | modg_via_recip( 1615 | giant d, 1616 | giant r, 1617 | giant n 1618 | ) 1619 | /* This is the fastest mod of the present collection. 1620 | * n := n % d, where r is the precalculated 1621 | * steady-state reciprocal of d. */ 1622 | 1623 | { 1624 | int s = (bitlen(r)-1), sign = n->sign; 1625 | giant tmp; 1626 | 1627 | if (isZero(d) || (d->sign < 0)) 1628 | { 1629 | exit(SIGN); 1630 | } 1631 | 1632 | tmp = popg(); 1633 | popg(); 1634 | 1635 | n->sign = abs(n->sign); 1636 | while (1) 1637 | { 1638 | gtog(n, tmp); gshiftright(s-1, tmp); 1639 | mulg(r, tmp); 1640 | gshiftright(s+1, tmp); 1641 | mulg(d, tmp); 1642 | subg(tmp, n); 1643 | if (gcompg(n,d) >= 0) 1644 | subg(d,n); 1645 | if (gcompg(n,d) < 0) 1646 | break; 1647 | } 1648 | if (sign >= 0) 1649 | goto done; 1650 | if (isZero(n)) 1651 | goto done; 1652 | negg(n); 1653 | addg(d,n); 1654 | done: 1655 | pushg(2); 1656 | return; 1657 | } 1658 | 1659 | #else 1660 | void 1661 | modg_via_recip( 1662 | giant d, 1663 | giant r, 1664 | giant n 1665 | ) 1666 | { 1667 | int s = 2*(bitlen(r)-1), sign = n->sign; 1668 | giant tmp, tmp2; 1669 | 1670 | if (isZero(d) || (d->sign < 0)) 1671 | { 1672 | exit(SIGN); 1673 | } 1674 | 1675 | tmp = popg(); 1676 | tmp2 = popg() 1677 | 1678 | n->sign = abs(n->sign); 1679 | while (1) 1680 | { 1681 | gtog(n, tmp); 1682 | mulg(r, tmp); 1683 | gshiftright(s, tmp); 1684 | mulg(d, tmp); 1685 | subg(tmp, n); 1686 | if (gcompg(n,d) >= 0) 1687 | subg(d,n); 1688 | if (gcompg(n,d) < 0) 1689 | break; 1690 | } 1691 | if (sign >= 0) 1692 | goto done; 1693 | if (isZero(n)) 1694 | goto done; 1695 | negg(n); 1696 | addg(d,n); 1697 | done: 1698 | pushg(2); 1699 | return; 1700 | } 1701 | #endif 1702 | 1703 | void 1704 | modg( 1705 | giant d, 1706 | giant n 1707 | ) 1708 | /* n becomes n%d. n is arbitrary, but the denominator d must be positive! */ 1709 | { 1710 | if (cur_recip == NULL) { 1711 | cur_recip = newgiant(current_max_size); 1712 | cur_den = newgiant(current_max_size); 1713 | gtog(d, cur_den); 1714 | make_recip(d, cur_recip); 1715 | } else if (gcompg(d, cur_den)) { 1716 | gtog(d, cur_den); 1717 | make_recip(d, cur_recip); 1718 | } 1719 | modg_via_recip(d, cur_recip, n); 1720 | } 1721 | 1722 | 1723 | #if 0 1724 | int 1725 | feemulmod ( 1726 | giant a, 1727 | giant b, 1728 | int q, 1729 | int k 1730 | ) 1731 | /* a becomes (a*b) (mod 2^q-k) where q % 16 == 0 and k is "small" (0 < k < 65535). 1732 | * Returns 0 if unsuccessful, otherwise 1. */ 1733 | { 1734 | giant carry, kk, scratch; 1735 | int i, j; 1736 | int asize = abs(a->sign), bsize = abs(b->sign); 1737 | unsigned short *aptr,*bptr,*destptr; 1738 | unsigned int words; 1739 | int kpower, curk; 1740 | 1741 | if ((q % 16) || (k <= 0) || (k >= 65535)) { 1742 | return (0); 1743 | } 1744 | 1745 | carry = popg(); 1746 | kk = popg(); 1747 | scratch = popg(); 1748 | 1749 | for (i=0; in[i]=0; 1750 | 1751 | words = q >> 4; 1752 | 1753 | bptr = b->n; 1754 | for (i = 0; i < bsize; i++) { 1755 | mult = *bptr++; 1756 | if (mult) { 1757 | kpower = i/words; 1758 | 1759 | if (kpower >= 1) itog (kpower,kk); 1760 | for (j = 1; j < kpower; k++) smulg(kpower,kk); 1761 | 1762 | itog(0,carry); 1763 | 1764 | aptr = a->n; 1765 | for (j = 0; j < bsize; b++) { 1766 | gtog(kk,scratch); 1767 | smulg(*aptr++,scratch); 1768 | smulg(mult,scratch); 1769 | iaddg(*destptr,scratch); 1770 | addg(carry,scratch); 1771 | *destptr++ = scratch->n[0]; 1772 | gshiftright(scratch,16); 1773 | gtog(scratch,carry); 1774 | if (destptr - scratch->n >= words) { 1775 | smulg(k, carry); 1776 | smulg(k, kk); 1777 | destptr -= words; 1778 | } 1779 | } 1780 | } 1781 | } 1782 | 1783 | int i,j,m; 1784 | unsigned int prod,carry=0; 1785 | int asize = abs(a->sign), bsize = abs(b->sign); 1786 | unsigned short *aptr,*bptr,*destptr; 1787 | unsigned short mult; 1788 | int words, excess; 1789 | int temp; 1790 | giant scratch = popg(), scratch2 = popg(), scratch3 = popg(); 1791 | short *carryptr = scratch->n; 1792 | int kpower,kpowerlimit, curk; 1793 | 1794 | if ((q % 16) || (k <= 0) || (k >= 65535)) { 1795 | return (0); 1796 | } 1797 | 1798 | scratch 1799 | 1800 | for (i=0; in[i]=0; 1801 | 1802 | words = q >> 4; 1803 | 1804 | bptr = b->n; 1805 | for (i=0; in; 1812 | destptr = scratch->n + i; 1813 | 1814 | if (kpower == 0) { 1815 | carry = 0; 1816 | } else if (kpower <= kpowerlimit) { 1817 | carry = 0; 1818 | curk = k; 1819 | for (j = 1; j < kpower; j++) curk *= k; 1820 | } else { 1821 | itog (k,scratch); 1822 | for (j = 1; j < kpower; j++) smulg(k,scratch); 1823 | itog(0,scratch2); 1824 | } 1825 | 1826 | for (j = 0; j < asize; j++) { 1827 | if(kpower == 0) { 1828 | prod = *aptr++ * mult + *destptr + carry; 1829 | *destptr++ = (unsigned short)(prod & 0xFFFF); 1830 | carry = prod >> 16; 1831 | } else if (kpower < kpowerlimit) { 1832 | prod = kcur * *aptr++; 1833 | temp = prod >> 16; 1834 | prod &= 0xFFFF; 1835 | temp *= mult; 1836 | prod *= mult; 1837 | temp += prod >> 16; 1838 | prod &= 0xFFFF; 1839 | prod += *destptr + carry; 1840 | carry = prod >> 16 + temp; 1841 | *destptr++ = (unsigned short)(prod & 0xFFFF); 1842 | } else { 1843 | gtog(scratch,scratch3); 1844 | smulg(*aptr++,scratch3); 1845 | smulg(mult,scratch3); 1846 | iaddg(*destptr,scratch3); 1847 | addg(scratch3,scratch2); 1848 | *destptr++ = scratch2->n[0]; 1849 | memmove(scratch2->n,scratch2->n+1,2*(scratch2->size-1)); 1850 | scratch2->sign--; 1851 | } 1852 | if (destptr - scratch->n > words) { 1853 | if (kpower == 0) { 1854 | curk = k; 1855 | carry *= k; 1856 | } else if (kpower < kpowerlimit) { 1857 | curk *= k; 1858 | carry *= curk; 1859 | } else if (kpower == kpowerlimit) { 1860 | itog (k,scratch); 1861 | for (j = 1; j < kpower; j++) smulg(k,scratch); 1862 | itog(carry,scratch2); 1863 | smulg(k,scratch2); 1864 | } else { 1865 | smulg(k,scratch); 1866 | smulg(k,scratch2); 1867 | } 1868 | kpower++; 1869 | destptr -= words; 1870 | } 1871 | } 1872 | 1873 | /* Next, deal with the carry term. Needs to be improved to 1874 | handle overflow carry cases. */ 1875 | if (kpower <= kpowerlimit) { 1876 | iaddg(carry,scratch); 1877 | } else { 1878 | addg(scratch2,scratch); 1879 | } 1880 | while(scratch->sign > q) 1881 | gtog(scratch,scratch2) 1882 | } 1883 | } 1884 | scratch->sign = destptr - scratch->n; 1885 | if (!carry) 1886 | --(scratch->sign); 1887 | scratch->sign *= gsign(a)*gsign(b); 1888 | gtog(scratch,a); 1889 | pushg(3); 1890 | return (1); 1891 | } 1892 | #endif 1893 | 1894 | int 1895 | idivg( 1896 | int divisor, 1897 | giant theg 1898 | ) 1899 | { 1900 | /* theg becomes theg/divisor. Returns remainder. */ 1901 | int n; 1902 | int base = 1<<(8*sizeof(short)); 1903 | 1904 | n = radixdiv(base,divisor,theg); 1905 | return(n); 1906 | } 1907 | 1908 | 1909 | void 1910 | divg( 1911 | giant d, 1912 | giant n 1913 | ) 1914 | /* n becomes n/d. n is arbitrary, but the denominator d must be positive! */ 1915 | { 1916 | if (cur_recip == NULL) { 1917 | cur_recip = newgiant(current_max_size); 1918 | cur_den = newgiant(current_max_size); 1919 | gtog(d, cur_den); 1920 | make_recip(d, cur_recip); 1921 | } else if (gcompg(d, cur_den)) { 1922 | gtog(d, cur_den); 1923 | make_recip(d, cur_recip); 1924 | } 1925 | divg_via_recip(d, cur_recip, n); 1926 | } 1927 | 1928 | 1929 | void 1930 | powermod( 1931 | giant x, 1932 | int n, 1933 | giant g 1934 | ) 1935 | /* x becomes x^n (mod g). */ 1936 | { 1937 | giant scratch2 = popg(); 1938 | gtog(x, scratch2); 1939 | itog(1, x); 1940 | while (n) 1941 | { 1942 | if (n & 1) 1943 | { 1944 | mulg(scratch2, x); 1945 | modg(g, x); 1946 | } 1947 | n >>= 1; 1948 | if (n) 1949 | { 1950 | squareg(scratch2); 1951 | modg(g, scratch2); 1952 | } 1953 | } 1954 | pushg(1); 1955 | } 1956 | 1957 | 1958 | void 1959 | powermodg( 1960 | giant x, 1961 | giant n, 1962 | giant g 1963 | ) 1964 | /* x becomes x^n (mod g). */ 1965 | { 1966 | int len, pos; 1967 | giant scratch2 = popg(); 1968 | 1969 | gtog(x, scratch2); 1970 | itog(1, x); 1971 | len = bitlen(n); 1972 | pos = 0; 1973 | while (1) 1974 | { 1975 | if (bitval(n, pos++)) 1976 | { 1977 | mulg(scratch2, x); 1978 | modg(g, x); 1979 | } 1980 | if (pos>=len) 1981 | break; 1982 | squareg(scratch2); 1983 | modg(g, scratch2); 1984 | } 1985 | pushg(1); 1986 | } 1987 | 1988 | 1989 | void 1990 | fermatpowermod( 1991 | giant x, 1992 | int n, 1993 | int q 1994 | ) 1995 | /* x becomes x^n (mod 2^q+1). */ 1996 | { 1997 | giant scratch2 = popg(); 1998 | 1999 | gtog(x, scratch2); 2000 | itog(1, x); 2001 | while (n) 2002 | { 2003 | if (n & 1) 2004 | { 2005 | mulg(scratch2, x); 2006 | fermatmod(q, x); 2007 | } 2008 | n >>= 1; 2009 | if (n) 2010 | { 2011 | squareg(scratch2); 2012 | fermatmod(q, scratch2); 2013 | } 2014 | } 2015 | pushg(1); 2016 | } 2017 | 2018 | 2019 | void 2020 | fermatpowermodg( 2021 | giant x, 2022 | giant n, 2023 | int q 2024 | ) 2025 | /* x becomes x^n (mod 2^q+1). */ 2026 | { 2027 | giant scratch2 = popg(), scratch3 = popg(); 2028 | 2029 | gtog(x, scratch2); 2030 | gtog(n, scratch3); 2031 | itog(1, x); 2032 | while (!isZero(scratch3)) 2033 | { 2034 | if (bitval(scratch3, 0)) 2035 | { 2036 | mulg(scratch2, x); 2037 | fermatmod(q, x); 2038 | } 2039 | squareg(scratch2); 2040 | fermatmod(q, scratch2); 2041 | gshiftright(1, scratch3); 2042 | } 2043 | pushg(2); 2044 | } 2045 | 2046 | void 2047 | mersennepowermod( 2048 | giant x, 2049 | int n, 2050 | int q 2051 | ) 2052 | /* x becomes x^n (mod 2^q-1). */ 2053 | { 2054 | giant scratch2 = popg(); 2055 | 2056 | gtog(x, scratch2); 2057 | itog(1, x); 2058 | while (n) 2059 | { 2060 | if (n & 1) 2061 | { 2062 | mulg(scratch2, x); 2063 | mersennemod(q, x); 2064 | } 2065 | n >>= 1; 2066 | if (n) 2067 | { 2068 | squareg(scratch2); 2069 | mersennemod(q, scratch2); 2070 | } 2071 | } 2072 | pushg(1); 2073 | } 2074 | 2075 | 2076 | void 2077 | mersennepowermodg( 2078 | giant x, 2079 | giant n, 2080 | int q 2081 | ) 2082 | /* x becomes x^n (mod 2^q-1). */ 2083 | { 2084 | giant scratch2 = popg(), scratch3 = popg(); 2085 | 2086 | gtog(x, scratch2); 2087 | gtog(n, scratch3); 2088 | itog(1, x); 2089 | while (!isZero(scratch3)) 2090 | { 2091 | if (bitval(scratch3, 0)) 2092 | { 2093 | mulg(scratch2, x); 2094 | mersennemod(q, x); 2095 | } 2096 | squareg(scratch2); 2097 | mersennemod(q, scratch2); 2098 | gshiftright(1, scratch3); 2099 | } 2100 | pushg(1); 2101 | } 2102 | 2103 | void 2104 | gshiftleft( 2105 | int bits, 2106 | giant g 2107 | ) 2108 | /* shift g left bits bits. Equivalent to g = g*2^bits. */ 2109 | { 2110 | int rem = bits&15, crem = 16-rem, words = bits>>4; 2111 | int size = abs(g->sign), j, k, sign = gsign(g); 2112 | unsigned short carry, dat; 2113 | 2114 | if (!bits) 2115 | return; 2116 | if (!size) 2117 | return; 2118 | if (bits < 0) { 2119 | gshiftright(-bits,g); 2120 | return; 2121 | } 2122 | if (size+words+1 > current_max_size) { 2123 | error = OVFLOW; 2124 | exit(error); 2125 | } 2126 | if (rem == 0) { 2127 | memmove(g->n + words, g->n, size * sizeof(short)); 2128 | for (j = 0; j < words; j++) g->n[j] = 0; 2129 | g->sign += (g->sign < 0)?(-words):(words); 2130 | } else { 2131 | k = size+words; 2132 | carry = 0; 2133 | for (j=size-1; j>=0; j--) { 2134 | dat = g->n[j]; 2135 | g->n[k--] = (unsigned short)((dat >> crem) | carry); 2136 | carry = (unsigned short)(dat << rem); 2137 | } 2138 | do { 2139 | g->n[k--] = carry; 2140 | carry = 0; 2141 | } while(k>=0); 2142 | 2143 | k = size+words; 2144 | if (g->n[k] == 0) 2145 | --k; 2146 | g->sign = sign*(k+1); 2147 | } 2148 | } 2149 | 2150 | 2151 | void 2152 | gshiftright( 2153 | int bits, 2154 | giant g 2155 | ) 2156 | /* shift g right bits bits. Equivalent to g = g/2^bits. */ 2157 | { 2158 | register int j,size=abs(g->sign); 2159 | register unsigned int carry; 2160 | int words = bits >> 4; 2161 | int remain = bits & 15, cremain = (16-remain); 2162 | 2163 | if (bits==0) 2164 | return; 2165 | if (isZero(g)) 2166 | return; 2167 | if (bits < 0) { 2168 | gshiftleft(-bits,g); 2169 | return; 2170 | } 2171 | if (words >= size) { 2172 | g->sign = 0; 2173 | return; 2174 | } 2175 | if (remain == 0) { 2176 | memmove(g->n,g->n + words,(size - words) * sizeof(short)); 2177 | g->sign += (g->sign < 0)?(words):(-words); 2178 | } else { 2179 | size -= words; 2180 | 2181 | if (size) 2182 | { 2183 | for(j=0;jn[j+words+1] << cremain; 2186 | g->n[j] = (unsigned short)((g->n[j+words] >> remain ) | carry); 2187 | } 2188 | g->n[size-1] = (unsigned short)(g->n[size-1+words] >> remain); 2189 | } 2190 | 2191 | if (g->n[size-1] == 0) 2192 | --size; 2193 | 2194 | if (g->sign > 0) 2195 | g->sign = size; 2196 | else 2197 | g->sign = -size; 2198 | } 2199 | } 2200 | 2201 | 2202 | void 2203 | extractbits( 2204 | int n, 2205 | giant src, 2206 | giant dest 2207 | ) 2208 | /* dest becomes lowermost n bits of src. Equivalent to dest = src % 2^n. */ 2209 | { 2210 | register int words = n >> 4, numbytes = words*sizeof(short); 2211 | register int bits = n & 15; 2212 | 2213 | if (n<=0) 2214 | return; 2215 | if (words >= abs(src->sign)) 2216 | gtog(src,dest); 2217 | else 2218 | { 2219 | memcpy((char *)(dest->n), (char *)(src->n), numbytes); 2220 | if (bits) 2221 | { 2222 | dest->n[words] = (unsigned short)(src->n[words] & ((1<n[words-1] == 0) && (words > 0)) 2226 | { 2227 | --words; 2228 | } 2229 | if (src->sign<0) 2230 | dest->sign = -words; 2231 | else 2232 | dest->sign = words; 2233 | } 2234 | } 2235 | 2236 | 2237 | int 2238 | allzeros( 2239 | int shorts, 2240 | int bits, 2241 | giant g 2242 | ) 2243 | { 2244 | int i=shorts; 2245 | 2246 | while (i>0) 2247 | { 2248 | if (g->n[--i]) 2249 | return(0); 2250 | } 2251 | return((int)(!(g->n[shorts] & ((1<>4, 2263 | bits = n & 15, 2264 | i = shorts, 2265 | mask = 1<g->sign-1; --temp) 2269 | { 2270 | g->n[temp] = 0; 2271 | } 2272 | if (g->n[shorts] & mask) 2273 | { /* if high bit is set, -g = 1. */ 2274 | g->sign = 1; 2275 | g->n[0] = 1; 2276 | return; 2277 | } 2278 | if (allzeros(shorts,bits,g)) 2279 | return; /* if g=0, -g = 0. */ 2280 | 2281 | while (i>0) 2282 | { --i; 2283 | g->n[i] = (unsigned short)(~(g->n[i+1])); 2284 | } 2285 | g->n[shorts] ^= mask-1; 2286 | 2287 | carry = 2; 2288 | i = 0; 2289 | while (carry) 2290 | { 2291 | temp = g->n[i]+carry; 2292 | g->n[i++] = (unsigned short)(temp & 0xffff); 2293 | carry = temp>>16; 2294 | } 2295 | while(!g->n[shorts]) 2296 | { 2297 | --shorts; 2298 | } 2299 | g->sign = shorts+1; 2300 | } 2301 | 2302 | 2303 | void 2304 | mersennemod ( 2305 | int n, 2306 | giant g 2307 | ) 2308 | /* g := g (mod 2^n - 1) */ 2309 | { 2310 | giant scratch3 = popg(), scratch4 = popg(); 2311 | 2312 | while (bitlen(g) > n) { 2313 | gtog(g,scratch3); 2314 | gshiftright(n,scratch3); 2315 | addg(scratch3,g); 2316 | gshiftleft(n,scratch3); 2317 | subg(scratch3,g); 2318 | } 2319 | itog(1,scratch3); 2320 | gshiftleft(n,scratch3); 2321 | itog(1,scratch4); 2322 | subg(scratch4,scratch3); 2323 | if(gsign(g) < 0) addg(scratch3,g); 2324 | if(gcompg(g,scratch3) == 0) itog(0,g); 2325 | pushg(2); 2326 | } 2327 | 2328 | 2329 | void 2330 | fermatmod ( 2331 | int n, 2332 | giant g 2333 | ) 2334 | /* g := g (mod 2^n + 1), */ 2335 | { 2336 | giant scratch3 = popg(); 2337 | 2338 | while (bitlen(g) > n) { 2339 | gtog(g,scratch3); 2340 | gshiftright(n,scratch3); 2341 | subg(scratch3,g); 2342 | gshiftleft(n,scratch3); 2343 | subg(scratch3,g); 2344 | } 2345 | if(gsign(g) < 0) { 2346 | itog(1,scratch3); 2347 | gshiftleft(n,scratch3); 2348 | addg(scratch3,g); 2349 | iaddg(1,g); 2350 | } 2351 | pushg(1); 2352 | } 2353 | 2354 | void 2355 | fer_mod ( 2356 | int n, 2357 | giant g, 2358 | giant modulus 2359 | ) 2360 | /* Same as fermatmod(), except modulus = 2^n + 1 should be passed 2361 | if available (i.e. if already allocated and set). */ 2362 | { 2363 | giant scratch3 = popg(); 2364 | 2365 | while (bitlen(g) > n) { 2366 | gtog(g,scratch3); 2367 | gshiftright(n,scratch3); 2368 | subg(scratch3,g); 2369 | gshiftleft(n,scratch3); 2370 | subg(scratch3,g); 2371 | } 2372 | if(gsign(g) < 0) addg(modulus,g); 2373 | pushg(1); 2374 | } 2375 | 2376 | 2377 | void 2378 | smulg( 2379 | unsigned short i, 2380 | giant g 2381 | ) 2382 | /* g becomes g * i. */ 2383 | { 2384 | unsigned short carry = 0; 2385 | int size = abs(g->sign); 2386 | register int j,k,mul = abs(i); 2387 | unsigned short *digit = g->n; 2388 | 2389 | for (j=0; j>16); 2393 | *digit = (unsigned short)(k & 0xffff); 2394 | ++digit; 2395 | } 2396 | if (carry) 2397 | { 2398 | if (++j >= current_max_size) 2399 | { 2400 | error = OVFLOW; 2401 | exit(error); 2402 | } 2403 | *digit = carry; 2404 | } 2405 | 2406 | if ((g->sign>0) ^ (i>0)) 2407 | g->sign = -j; 2408 | else 2409 | g->sign = j; 2410 | } 2411 | 2412 | 2413 | void 2414 | squareg( 2415 | giant b 2416 | ) 2417 | /* b becomes b^2. */ 2418 | { 2419 | auxmulg(b,b); 2420 | } 2421 | 2422 | 2423 | void 2424 | mulg( 2425 | giant a, 2426 | giant b 2427 | ) 2428 | /* b becomes a*b. */ 2429 | { 2430 | auxmulg(a,b); 2431 | } 2432 | 2433 | 2434 | void 2435 | auxmulg( 2436 | giant a, 2437 | giant b 2438 | ) 2439 | /* Optimized general multiply, b becomes a*b. Modes are: 2440 | * AUTO_MUL: switch according to empirical speed criteria. 2441 | * GRAMMAR_MUL: force grammar-school algorithm. 2442 | * KARAT_MUL: force Karatsuba divide-conquer method. 2443 | * FFT_MUL: force floating point FFT method. */ 2444 | { 2445 | float grammartime; 2446 | int square = (a==b); 2447 | int sizea, sizeb; 2448 | 2449 | switch (mulmode) 2450 | { 2451 | case GRAMMAR_MUL: 2452 | if (square) grammarsquareg(b); 2453 | else grammarmulg(a,b); 2454 | break; 2455 | case FFT_MUL: 2456 | if (square) 2457 | FFTsquareg(b); 2458 | else 2459 | FFTmulg(a,b); 2460 | break; 2461 | case KARAT_MUL: 2462 | if (square) karatsquareg(b); 2463 | else karatmulg(a,b); 2464 | break; 2465 | case AUTO_MUL: 2466 | sizea = abs(a->sign); 2467 | sizeb = abs(b->sign); 2468 | if((sizea > KARAT_BREAK) && (sizea <= FFT_BREAK) && 2469 | (sizeb > KARAT_BREAK) && (sizeb <= FFT_BREAK)){ 2470 | if(square) karatsquareg(b); 2471 | else karatmulg(a,b); 2472 | 2473 | } else { 2474 | grammartime = (float)sizea; 2475 | grammartime *= (float)sizeb; 2476 | if (grammartime < FFT_BREAK * FFT_BREAK) 2477 | { 2478 | if (square) grammarsquareg(b); 2479 | else grammarmulg(a,b); 2480 | } 2481 | else 2482 | { 2483 | if (square) FFTsquareg(b); 2484 | else FFTmulg(a,b); 2485 | } 2486 | } 2487 | break; 2488 | } 2489 | } 2490 | 2491 | void 2492 | justg(giant x) { 2493 | int s = x->sign, sg = 1; 2494 | 2495 | if(s<0) { 2496 | sg = -1; 2497 | s = -s; 2498 | } 2499 | --s; 2500 | while(x->n[s] == 0) { 2501 | --s; 2502 | if(s < 0) break; 2503 | } 2504 | x->sign = sg*(s+1); 2505 | } 2506 | 2507 | /* Next, improved Karatsuba routines from A. Powell, 2508 | improvements by G. Woltman. */ 2509 | 2510 | void 2511 | karatmulg(giant x, giant y) 2512 | /* y becomes x*y. */ 2513 | { 2514 | int s = abs(x->sign), t = abs(y->sign), w, bits, 2515 | sg = gsign(x)*gsign(y); 2516 | giant a, b, c, d, e, f; 2517 | 2518 | if((s <= KARAT_BREAK) || (t <= KARAT_BREAK)) { 2519 | grammarmulg(x,y); 2520 | return; 2521 | } 2522 | w = (s + t + 2)/4; bits = 16*w; 2523 | a = popg(); b = popg(); c = popg(); 2524 | d = popg(); e = popg(); f = popg(); 2525 | gtog(x,a); absg(a); if (w <= s) {a->sign = w; justg(a);} 2526 | gtog(x,b); absg(b); 2527 | gshiftright(bits, b); 2528 | gtog(y,c); absg(c); if (w <= t) {c->sign = w; justg(c);} 2529 | gtog(y,d); absg(d); 2530 | gshiftright(bits,d); 2531 | gtog(a,e); normal_addg(b,e); /* e := (a + b) */ 2532 | gtog(c,f); normal_addg(d,f); /* f := (c + d) */ 2533 | karatmulg(e,f); /* f := (a + b)(c + d) */ 2534 | karatmulg(c,a); /* a := a c */ 2535 | karatmulg(d,b); /* b := b d */ 2536 | normal_subg(a,f); 2537 | /* f := (a + b)(c + d) - a c */ 2538 | normal_subg(b,f); 2539 | /* f := (a + b)(c + d) - a c - b d */ 2540 | gshiftleft(bits, b); 2541 | normal_addg(f, b); 2542 | gshiftleft(bits, b); 2543 | normal_addg(a, b); 2544 | gtog(b, y); y->sign *= sg; 2545 | pushg(6); 2546 | 2547 | return; 2548 | } 2549 | 2550 | void 2551 | karatsquareg(giant x) 2552 | /* x becomes x^2. */ 2553 | { 2554 | int s = abs(x->sign), w, bits; 2555 | giant a, b, c; 2556 | 2557 | if(s <= KARAT_BREAK) { 2558 | grammarsquareg(x); 2559 | return; 2560 | } 2561 | w = (s+1)/2; bits = 16*w; 2562 | a = popg(); b = popg(); c = popg(); 2563 | gtog(x, a); a->sign = w; justg(a); 2564 | gtog(x, b); absg(b); 2565 | gshiftright(bits, b); 2566 | gtog(a,c); normal_addg(b,c); 2567 | karatsquareg(c); 2568 | karatsquareg(a); 2569 | karatsquareg(b); 2570 | normal_subg(b, c); 2571 | normal_subg(a, c); 2572 | gshiftleft(bits, b); 2573 | normal_addg(c,b); 2574 | gshiftleft(bits, b); 2575 | normal_addg(a, b); 2576 | gtog(b, x); 2577 | pushg(3); 2578 | 2579 | return; 2580 | } 2581 | 2582 | void 2583 | grammarmulg( 2584 | giant a, 2585 | giant b 2586 | ) 2587 | /* b becomes a*b. */ 2588 | { 2589 | int i,j; 2590 | unsigned int prod,carry=0; 2591 | int asize = abs(a->sign), bsize = abs(b->sign); 2592 | unsigned short *aptr,*bptr,*destptr; 2593 | unsigned short mult; 2594 | giant scratch = popg(); 2595 | 2596 | for (i=0; in[i]=0; 2599 | } 2600 | 2601 | bptr = &(b->n[0]); 2602 | for (i=0; in[0]); 2609 | destptr = &(scratch->n[i]); 2610 | for (j=0; j> 16; 2615 | } 2616 | *destptr = (unsigned short)carry; 2617 | } 2618 | } 2619 | bsize+=asize; 2620 | if (!carry) 2621 | --bsize; 2622 | scratch->sign = gsign(a)*gsign(b)*bsize; 2623 | gtog(scratch,b); 2624 | pushg(1); 2625 | } 2626 | 2627 | 2628 | void 2629 | grammarsquareg ( 2630 | giant a 2631 | ) 2632 | /* a := a^2. */ 2633 | { 2634 | unsigned int cur_term; 2635 | unsigned int prod, carry=0, temp; 2636 | unsigned int asize = abs(a->sign); 2637 | unsigned int max = asize * 2 - 1; 2638 | unsigned short *ptr = a->n, *ptr1, *ptr2; 2639 | giant scratch; 2640 | 2641 | if(asize == 0) { 2642 | itog(0,a); 2643 | return; 2644 | } 2645 | 2646 | scratch = popg(); 2647 | 2648 | asize--; 2649 | 2650 | temp = *ptr; 2651 | temp *= temp; 2652 | scratch->n[0] = temp; 2653 | carry = temp >> 16; 2654 | 2655 | for (cur_term = 1; cur_term < max; cur_term++) { 2656 | ptr1 = ptr2 = ptr; 2657 | if (cur_term <= asize) { 2658 | ptr2 += cur_term; 2659 | } else { 2660 | ptr1 += cur_term - asize; 2661 | ptr2 += asize; 2662 | } 2663 | prod = carry & 0xFFFF; 2664 | carry >>= 16; 2665 | while(ptr1 < ptr2) { 2666 | temp = *ptr1++ * *ptr2--; 2667 | prod += (temp << 1) & 0xFFFF; 2668 | carry += (temp >> 15); 2669 | } 2670 | if (ptr1 == ptr2) { 2671 | temp = *ptr1; 2672 | temp *= temp; 2673 | prod += temp & 0xFFFF; 2674 | carry += (temp >> 16); 2675 | } 2676 | carry += prod >> 16; 2677 | scratch->n[cur_term] = (unsigned short) (prod); 2678 | } 2679 | if (carry) { 2680 | scratch->n[cur_term] = carry; 2681 | scratch->sign = cur_term+1; 2682 | } else scratch->sign = cur_term; 2683 | 2684 | gtog(scratch,a); 2685 | pushg(1); 2686 | } 2687 | 2688 | 2689 | /************************************************************** 2690 | * 2691 | * FFT multiply Functions 2692 | * 2693 | **************************************************************/ 2694 | 2695 | int initL = 0; 2696 | 2697 | int 2698 | lpt( 2699 | int n, 2700 | int *lambda 2701 | ) 2702 | /* Returns least power of two greater than n. */ 2703 | { 2704 | register int i = 1; 2705 | 2706 | *lambda = 0; 2707 | while (i maxFFTerror) 2736 | maxFFTerror = err; 2737 | } 2738 | z[j] =0; 2739 | k = 0; 2740 | do 2741 | { 2742 | g = gfloor(f*TWOM16); 2743 | z[j+k] += f-g*TWO16; 2744 | ++k; 2745 | f=g; 2746 | } while(f != 0.0); 2747 | } 2748 | car = 0; 2749 | for(j=0;j < last + 1;j++) 2750 | { 2751 | m = (int)(z[j]+car); 2752 | x->n[j] = (unsigned short)(m & 0xffff); 2753 | car = (m>>16); 2754 | } 2755 | if (car) 2756 | x->n[j] = (unsigned short)car; 2757 | else 2758 | --j; 2759 | 2760 | while(!(x->n[j])) --j; 2761 | 2762 | x->sign = j+1; 2763 | } 2764 | 2765 | 2766 | void 2767 | FFTsquareg( 2768 | giant x 2769 | ) 2770 | { 2771 | int j,size = abs(x->sign); 2772 | register int L; 2773 | 2774 | if (size<4) 2775 | { 2776 | grammarmulg(x,x); 2777 | return; 2778 | } 2779 | L = lpt(size+size, &j); 2780 | if(!z) z = (double *)malloc(MAX_SHORTS * sizeof(double)); 2781 | giant_to_double(x, size, z, L); 2782 | fft_real_to_hermitian(z, L); 2783 | square_hermitian(z, L); 2784 | fftinv_hermitian_to_real(z, L); 2785 | addsignal(x,z,L); 2786 | x->sign = abs(x->sign); 2787 | } 2788 | 2789 | 2790 | void 2791 | FFTmulg( 2792 | giant y, 2793 | giant x 2794 | ) 2795 | { 2796 | /* x becomes y*x. */ 2797 | int lambda, sizex = abs(x->sign), sizey = abs(y->sign); 2798 | int finalsign = gsign(x)*gsign(y); 2799 | register int L; 2800 | 2801 | if ((sizex<=4)||(sizey<=4)) 2802 | { 2803 | grammarmulg(y,x); 2804 | return; 2805 | } 2806 | L = lpt(sizex+sizey, &lambda); 2807 | if(!z) z = (double *)malloc(MAX_SHORTS * sizeof(double)); 2808 | if(!z2) z2 = (double *)malloc(MAX_SHORTS * sizeof(double)); 2809 | 2810 | giant_to_double(x, sizex, z, L); 2811 | giant_to_double(y, sizey, z2, L); 2812 | fft_real_to_hermitian(z, L); 2813 | fft_real_to_hermitian(z2, L); 2814 | mul_hermitian(z2, z, L); 2815 | fftinv_hermitian_to_real(z, L); 2816 | addsignal(x,z,L); 2817 | x->sign = finalsign*abs(x->sign); 2818 | } 2819 | 2820 | 2821 | void 2822 | scramble_real( 2823 | double *x, 2824 | int n 2825 | ) 2826 | { 2827 | register int i,j,k; 2828 | register double tmp; 2829 | 2830 | for (i=0,j=0;i>=1; 2843 | } 2844 | j += k; 2845 | } 2846 | } 2847 | 2848 | 2849 | void 2850 | fft_real_to_hermitian( 2851 | double *z, 2852 | int n 2853 | ) 2854 | /* Output is {Re(z^[0]),...,Re(z^[n/2),Im(z^[n/2-1]),...,Im(z^[1]). 2855 | * This is a decimation-in-time, split-radix algorithm. 2856 | */ 2857 | { 2858 | register double cc1, ss1, cc3, ss3; 2859 | register int is, id, i0, i1, i2, i3, i4, i5, i6, i7, i8, 2860 | a, a3, b, b3, nminus = n-1, dil, expand; 2861 | register double *x, e; 2862 | int nn = n>>1; 2863 | double t1, t2, t3, t4, t5, t6; 2864 | register int n2, n4, n8, i, j; 2865 | 2866 | init_sinCos(n); 2867 | expand = cur_run/n; 2868 | scramble_real(z, n); 2869 | x = z-1; /* FORTRAN compatibility. */ 2870 | is = 1; 2871 | id = 4; 2872 | do 2873 | { 2874 | for (i0=is;i0<=n;i0+=id) 2875 | { 2876 | i1 = i0+1; 2877 | e = x[i0]; 2878 | x[i0] = e + x[i1]; 2879 | x[i1] = e - x[i1]; 2880 | } 2881 | is = (id<<1)-1; 2882 | id <<= 2; 2883 | } while(is>=1) 2887 | { 2888 | n2 <<= 1; 2889 | n4 = n2>>2; 2890 | n8 = n2>>3; 2891 | is = 0; 2892 | id = n2<<1; 2893 | do 2894 | { 2895 | for (i=is;i>1; 2990 | double t1, t2, t3, t4, t5; 2991 | int n2, n4, n8, i, j; 2992 | 2993 | init_sinCos(n); 2994 | expand = cur_run/n; 2995 | x = z-1; 2996 | n2 = n<<1; 2997 | while(nn >>= 1) 2998 | { 2999 | is = 0; 3000 | id = n2; 3001 | n2 >>= 1; 3002 | n4 = n2>>2; 3003 | n8 = n4>>1; 3004 | do 3005 | { 3006 | for(i=is;i>1; 3112 | register double aa, bb, am, bm; 3113 | 3114 | b[0] *= a[0]; 3115 | b[half] *= a[half]; 3116 | for (k=1;k>1; 3135 | register double c, d; 3136 | 3137 | b[0] *= b[0]; 3138 | b[half] *= b[half]; 3139 | for (k=1;kn[j]; 3167 | } 3168 | } 3169 | 3170 | 3171 | void 3172 | gswap( 3173 | giant *p, 3174 | giant *q 3175 | ) 3176 | { 3177 | giant t; 3178 | 3179 | t = *p; 3180 | *p = *q; 3181 | *q = t; 3182 | } 3183 | 3184 | 3185 | void 3186 | onestep( 3187 | giant x, 3188 | giant y, 3189 | gmatrix A 3190 | ) 3191 | /* Do one step of the euclidean algorithm and modify 3192 | * the matrix A accordingly. */ 3193 | { 3194 | giant s4 = popg(); 3195 | 3196 | gtog(x,s4); 3197 | gtog(y,x); 3198 | gtog(s4,y); 3199 | divg(x,s4); 3200 | punch(s4,A); 3201 | mulg(x,s4); 3202 | subg(s4,y); 3203 | 3204 | pushg(1); 3205 | } 3206 | 3207 | 3208 | void 3209 | mulvM( 3210 | gmatrix A, 3211 | giant x, 3212 | giant y 3213 | ) 3214 | /* Multiply vector by Matrix; changes x,y. */ 3215 | { 3216 | giant s0 = popg(), s1 = popg(); 3217 | 3218 | gtog(A->ur,s0); 3219 | gtog( A->lr,s1); 3220 | dotproduct(x,y,A->ul,s0); 3221 | dotproduct(x,y,A->ll,s1); 3222 | gtog(s0,x); 3223 | gtog(s1,y); 3224 | 3225 | pushg(2); 3226 | } 3227 | 3228 | 3229 | void 3230 | mulmM( 3231 | gmatrix A, 3232 | gmatrix B 3233 | ) 3234 | /* Multiply matrix by Matrix; changes second matrix. */ 3235 | { 3236 | giant s0 = popg(); 3237 | giant s1 = popg(); 3238 | giant s2 = popg(); 3239 | giant s3 = popg(); 3240 | 3241 | gtog(B->ul,s0); 3242 | gtog(B->ur,s1); 3243 | gtog(B->ll,s2); 3244 | gtog(B->lr,s3); 3245 | dotproduct(A->ur,A->ul,B->ll,s0); 3246 | dotproduct(A->ur,A->ul,B->lr,s1); 3247 | dotproduct(A->ll,A->lr,B->ul,s2); 3248 | dotproduct(A->ll,A->lr,B->ur,s3); 3249 | gtog(s0,B->ul); 3250 | gtog(s1,B->ur); 3251 | gtog(s2,B->ll); 3252 | gtog(s3,B->lr); 3253 | 3254 | pushg(4); 3255 | } 3256 | 3257 | 3258 | void 3259 | writeM( 3260 | gmatrix A 3261 | ) 3262 | { 3263 | printf(" ul:"); 3264 | gout(A->ul); 3265 | printf(" ur:"); 3266 | gout(A->ur); 3267 | printf(" ll:"); 3268 | gout(A->ll); 3269 | printf(" lr:"); 3270 | gout(A->lr); 3271 | } 3272 | 3273 | 3274 | void 3275 | punch( 3276 | giant q, 3277 | gmatrix A 3278 | ) 3279 | /* Multiply the matrix A on the left by [0,1,1,-q]. */ 3280 | { 3281 | giant s0 = popg(); 3282 | 3283 | gtog(A->ll,s0); 3284 | mulg(q,A->ll); 3285 | gswap(&A->ul,&A->ll); 3286 | subg(A->ul,A->ll); 3287 | gtog(s0,A->ul); 3288 | gtog(A->lr,s0); 3289 | mulg(q,A->lr); 3290 | gswap(&A->ur,&A->lr); 3291 | subg(A->ur,A->lr); 3292 | gtog(s0,A->ur); 3293 | 3294 | pushg(1); 3295 | } 3296 | 3297 | 3298 | static void 3299 | dotproduct( 3300 | giant a, 3301 | giant b, 3302 | giant c, 3303 | giant d 3304 | ) 3305 | /* Replace last argument with the dot product of two 2-vectors. */ 3306 | { 3307 | giant s4 = popg(); 3308 | 3309 | gtog(c,s4); 3310 | mulg(a, s4); 3311 | mulg(b,d); 3312 | addg(s4,d); 3313 | 3314 | pushg(1); 3315 | } 3316 | 3317 | 3318 | void 3319 | ggcd( 3320 | giant xx, 3321 | giant yy 3322 | ) 3323 | /* A giant gcd. Modifies its arguments. */ 3324 | { 3325 | giant x = popg(), y = popg(); 3326 | gmatrix A = newgmatrix(); 3327 | 3328 | gtog(xx,x); gtog(yy,y); 3329 | for(;;) 3330 | { 3331 | fix(&x,&y); 3332 | if (bitlen(y) <= GCDLIMIT ) 3333 | break; 3334 | A->ul = popg(); 3335 | A->ur = popg(); 3336 | A->ll = popg(); 3337 | A->lr = popg(); 3338 | itog(1,A->ul); 3339 | itog(0,A->ur); 3340 | itog(0,A->ll); 3341 | itog(1,A->lr); 3342 | hgcd(0,x,y,A); 3343 | mulvM(A,x,y); 3344 | pushg(4); 3345 | fix(&x,&y); 3346 | if (bitlen(y) <= GCDLIMIT ) 3347 | break; 3348 | modg(y,x); 3349 | gswap(&x,&y); 3350 | } 3351 | bgcdg(x,y); 3352 | gtog(y,yy); 3353 | pushg(2); 3354 | free(A); 3355 | } 3356 | 3357 | 3358 | void 3359 | fix( 3360 | giant *p, 3361 | giant *q 3362 | ) 3363 | /* Insure that x > y >= 0. */ 3364 | { 3365 | if( gsign(*p) < 0 ) 3366 | negg(*p); 3367 | if( gsign(*q) < 0 ) 3368 | negg(*q); 3369 | if( gcompg(*p,*q) < 0 ) 3370 | gswap(p,q); 3371 | } 3372 | 3373 | 3374 | void 3375 | hgcd( 3376 | int n, 3377 | giant xx, 3378 | giant yy, 3379 | gmatrix A 3380 | ) 3381 | /* hgcd(n,x,y,A) chops n bits off x and y and computes th 3382 | * 2 by 2 matrix A such that A[x y] is the pair of terms 3383 | * in the remainder sequence starting with x,y that is 3384 | * half the size of x. Note that the argument A is modified 3385 | * but that the arguments xx and yy are left unchanged. 3386 | */ 3387 | { 3388 | giant x, y; 3389 | 3390 | if (isZero(yy)) 3391 | return; 3392 | 3393 | x = popg(); 3394 | y = popg(); 3395 | gtog(xx,x); 3396 | gtog(yy,y); 3397 | gshiftright(n,x); 3398 | gshiftright(n,y); 3399 | if (bitlen(x) <= INTLIMIT ) 3400 | { 3401 | shgcd(gtoi(x),gtoi(y),A); 3402 | } 3403 | else 3404 | { 3405 | gmatrix B = newgmatrix(); 3406 | int m = bitlen(x)/2; 3407 | 3408 | hgcd(m,x,y,A); 3409 | mulvM(A,x,y); 3410 | if (gsign(x) < 0) 3411 | { 3412 | negg(x); negg(A->ul); negg(A->ur); 3413 | } 3414 | if (gsign(y) < 0) 3415 | { 3416 | negg(y); negg(A->ll); negg(A->lr); 3417 | } 3418 | if (gcompg(x,y) < 0) 3419 | { 3420 | gswap(&x,&y); 3421 | gswap(&A->ul,&A->ll); 3422 | gswap(&A->ur,&A->lr); 3423 | } 3424 | if (!isZero(y)) 3425 | { 3426 | onestep(x,y,A); 3427 | m /= 2; 3428 | B->ul = popg(); 3429 | B->ur = popg(); 3430 | B->ll = popg(); 3431 | B->lr = popg(); 3432 | itog(1,B->ul); 3433 | itog(0,B->ur); 3434 | itog(0,B->ll); 3435 | itog(1,B->lr); 3436 | hgcd(m,x,y,B); 3437 | mulmM(B,A); 3438 | pushg(4); 3439 | } 3440 | free(B); 3441 | } 3442 | pushg(2); 3443 | } 3444 | 3445 | 3446 | void 3447 | shgcd( 3448 | register int x, 3449 | register int y, 3450 | gmatrix A 3451 | ) 3452 | /* 3453 | * Do a half gcd on the integers a and b, putting the result in A 3454 | * It is fairly easy to use the 2 by 2 matrix description of the 3455 | * extended Euclidean algorithm to prove that the quantity q*t 3456 | * never overflows. 3457 | */ 3458 | { 3459 | register int q, t, start = x; 3460 | int Aul = 1, Aur = 0, All = 0, Alr = 1; 3461 | 3462 | while (y != 0 && y > start/y) 3463 | { 3464 | q = x/y; 3465 | t = y; 3466 | y = x%y; 3467 | x = t; 3468 | t = All; 3469 | All = Aul-q*t; 3470 | Aul = t; 3471 | t = Alr; 3472 | Alr = Aur-q*t; 3473 | Aur = t; 3474 | } 3475 | itog(Aul,A->ul); 3476 | itog(Aur,A->ur); 3477 | itog(All,A->ll); 3478 | itog(Alr,A->lr); 3479 | } 3480 | --------------------------------------------------------------------------------