cAuxSrv aux;
#endif
//
- void MakePrime(BIGNUM *n, unsigned char *residues);
+ void MakePrime(unsigned char *residues, bool strong);
protected:
virtual bool Map(int f, unsigned char *data, int l);
};
{ 14668,15091,15519,15947,16370,16798,17221,17654,18082,18505,18933,19356,19784,20212,20640,21068,21491 },
};
-void cMap0101::MakePrime(BIGNUM *n, unsigned char *residues)
+void cMap0101::MakePrime(unsigned char *residues, bool strong)
{
bool isPrime;
- cycles+=1290;
+ AddMapCycles(strong?462:258);
+ BN_copy(D,B);
+ AddMapCycles(240);
+ BN_zero(A);
+ AddMapCycles(41);
+ BN_set_word(A,2);
+ A.SetPos(1);
+ AddMapCycles(12);
+ for(int i=2; i<=8; i++) { A.SetPos(i); AddMapCycles(9); }
+ A.SetPos(0);
+ AddMapCycles(8);
+ if(strong) D.GetLE(residues+53,8);
+ unsigned int counts[3] = { 0 };
+ bool first=true;
do {
- cycles+=1465;
- BN_add_word(n,2);
+ counts[0]++;;
+ BN_add_word(B,2);
+ if(first) { first=false; AddMapCycles(1600); }
isPrime=true;
for(int i=0; i<53; i++) {
residues[i]+=2;
unsigned char denom=primes[i];
if(num>denom) {
unsigned char r=0;
- while(denom>=r) { cycles+=1; r=(r<<1)|((num&0x80)>>7); num<<=1; }
+ while(denom>=r) { counts[1]++; r=(r<<1)|((num&0x80)>>7); num<<=1; }
}
residues[i]%=primes[i];
- if(residues[i]==0) { cycles+=13; isPrime=false; }
+ if(residues[i]==0) { counts[2]++; isPrime=false; }
}
} while(!isPrime);
+ cycles=1290+1465*counts[0]+counts[1]+13*counts[2];
}
bool cMap0101::Map(int f, unsigned char *data, int l)
cycles=898;
break;
case 0x22:
-// START INCOMPLETE FIX
- BN_zero(B);
- BN_set_bit(B,80);
- AddMapCycles(644);
- BN_zero(B);
- BN_set_bit(B,96);
- AddMapCycles(76);
-// END INCOMPLETE FIX
if(BN_is_zero(D)) { cycles=639-6; break; }
l&=0x1fff;
+ AddMapCycles(376);
+ BN_zero(B);
+ AddMapCycles(l>=(BN_num_bits(D)-1)/64*64 ? 244 : 210);
BN_one(B);
+ B.SetPos(1);
+ AddMapCycles(17);
+ for(int i=2; i<=8; i++) { B.SetPos(i); AddMapCycles(9); }
+ AddMapCycles(44);
BN_mod_lshift(B,B,l,D,ctx);
- if(l<64)
- cycles=927+(l&7)*9;
- else {
- div_t val=div(l-64,2046);
- int j=16*((val.rem+1)/2) + (val.rem>4?val.rem-7:val.rem-12)/4;
- cycles=1086 + j - ((j-2)%5) + 16923*val.quot - ((4*val.quot-2)%5);
- }
break;
case 0x23:
-// START FIX
- {
- cBN s,x,y;
- BN_copy(s,D);
- BN_rshift(s,s,64+ 1 *8);
- BN_lshift(s,s,64);
- BN_copy(x,D);
- BN_mask_bits(x,64);
- BN_copy(y,D);
- BN_rshift(y,y,64);
- BN_mask_bits(y,1*8);
- BN_lshift(y,y,128-1*8);
- BN_copy(D,s);
- BN_add(D,D,x);
- BN_add(D,D,y);
- }
- BN_zero(B);
- BN_set_bit(B,88);
-// END FIX
+ AddMapCycles(169);
+ IMonInit0();
break;
case 0x25:
AddMapCycles(254);
{
BN_add(B,B,C);
bool b=BN_is_bit_set(B,wordsize<<6);
- if(data) data[0]=b;
if(b) BN_mask_bits(B,wordsize<<6);
+ if(data) data[0]=b;
cycles=501+(8*wordsize+3)/5*5-6;
break;
}
break;
}
case 0x2e:
-// START INCOMPLETE FIX
- H.GetLE(data,16);
- BN_rshift(H,H,64);
- BN_lshift(H,H,64);
- BN_add(H,J,H);
- BN_rshift(H,H,1<<3);
- BN_copy(J,H);
- BN_mask_bits(J,64);
- cycles=864;
-// END INCOMPLETE FIX
- break;
case 0x2F:
-// START INCOMPLETE FIX
- H.GetLE(data,16);
- BN_rshift(H,H,64);
- BN_lshift(H,H,64);
- BN_add(H,H,J);
- BN_rshift(J,H,8);
- BN_mask_bits(J,64);
- cycles=808;
-// END INCOMPLETE FIX
+ if(l<=0) { cycles+=4; l=wordsize; }
+ else if(l>17) { cycles+=5; l=17; }
+ scalar.GetLE(data,l<<3);
+ AddMapCycles(617+30*wordsize);
+ for(int i=0; i<l; i++) {
+ if(i&1) {
+ unsigned char buf[8];
+ J.PutLE(buf,8);
+ AddMapCycles(10);
+ for(int j=0; j<8; j++) {
+ buf[j]=data[i*8+j];
+ J.GetLE(buf,8);
+ J.SetPos(j+1);
+ AddMapCycles(14);
+ }
+ J.SetPos(0);
+ AddMapCycles(12);
+ }
+ else
+ AddMapCycles(114);
+ }
+ AddMapCycles(3);
+ BN_mul(D,scalar,B,ctx);
+ if(f&1) BN_add(D,D,C);
+ BN_rshift(C,D,l<<6);
+ BN_mask_bits(D,l<<6);
+ D.Commit(l);
+ BN_mask_bits(C,wordsize<<6);
break;
case 0x30:
case 0x31:
BN_sqr(D,B,ctx);
- BN_rshift(J,B,((wordsize+1)/2)*128-64);
- BN_mask_bits(J,64);
if((f&1)) BN_add(D,D,C);
BN_rshift(C,D,wordsize<<6);
- BN_mask_bits(C,wordsize<<6);
- BN_mask_bits(D,wordsize<<6);
+ BN_rshift(J,B,((wordsize+1)/2)*128-64);
+ BN_mask_bits(J,64);
break;
case 0x32:
+ AddMapCycles(1000);
l=min(34,l);
if(!BN_is_zero(D)) {
- A.GetLE(data,l<<3);
- BN_div(C,B,A,D,ctx);
+ scalar.GetLE(data,l<<3);
+ BN_div(C,B,scalar,D,ctx);
BN_rshift(A,C,17*64);
- BN_mask_bits(C,17*64);
A.Commit(17);
C.Commit(17);
}
AddMapCycles(102);
MonFin(B,D);
break;
- case 0x3a:
-// START INCOMPLETE FIX (this map is normaly in nagra2.c)
- AddMapCycles(192);
- IMonInit();
- MonMul(B,A,B);
- //MonMul(B,A,B);
- BN_zero(B);
-// END INCOMPLETE FIX
- break;
case 0x3b:
AddMapCycles(441);
IMakeJ();
-// START FIX
- AddMapCycles(327);
- BN_zero(B);
- BN_set_bit(B,104);
- AddMapCycles(46-373);
-// END FIX
+ AddMapCycles(46);
IMonInit0(wordsize*60+4*l);
- I.GetLE(data,l<<3);
- MonMul(B,I,B,l);
+ scalar.GetLE(data,l<<3);
+ MonMul(B,scalar,B,l);
cycles=tim3b[wordsize-1][l-1]-6;
break;
case 0x3d:
-// START INCOMPLETE FIX
- D.GetLE(data,l<<3);
- MakeJ0(J,D,C);
- BN_rshift(A,A,64);
- BN_mask_bits(A,64);
- BN_lshift(A,A,64);
- BN_add(C,A,C);
- //MonMul0(C,B,B,C,D,J,0);
-// END INCOMPLETE FIX
+ AddMapCycles(652);
+ D.GetLE(data,wordsize<<3);
+ AddMapCycles(514);
+ IMakeJ();
+ AddMapCycles(35);
+ MonMul0(C,B,B,C,D,J,wordsize);
+ AddMapCycles(143);
+ BN_copy(A,B);
+ AddMapCycles(73);
+ MonExpNeg();
+ MonMul(B,A,B);
+ BN_zero(C);
+ cycles+=rand()%(wordsize*20000)+2000;
break;
case 0x3c:
case 0x3e:
+ case 0x46:
{
- if(sl==0) cycles+=4;
- if(l>wordsize) { l=wordsize; cycles+=l>17 ? 9:4; }
- cBN scalar;
+ if(f==0x46) l=1; else l=sl;
+ if(l<=0) { l=wordsize; cycles+=4; }
+ else if(l>wordsize) { l=wordsize; cycles+=l>17 ? 9:4; }
scalar.GetLE(data,l<<3);
- AddMapCycles(441);
+ int sbits=BN_num_bits(scalar);
+ cycles+=3848+((sbits-1)/8)*650 - 11;
+ int msb=data[(sbits-1)/8];
+ for(int i=7; i>=1; --i) if(msb&(1<<i)) { cycles+=i*75-15; break; }
+ for(int i=0; i<sbits; ++i) if(BN_is_bit_set(scalar,i)) cycles+=88;
+ AddMapCycles(f==0x46 ? 400:441);
if(BN_is_zero(scalar) || BN_num_bits(D)<=1) {
IMakeJ();
if(BN_num_bits(D)==1 || !BN_is_zero(scalar)) BN_zero(B);
MonMul0(B,A,B,C,D,J,0);
if(f==0x3c) AddMapCycles(2200+(rand()%(wordsize*2000)));
MonFin(B,D);
- MonExp(scalar);
}
BN_zero(C);
- int sbits=BN_num_bits(scalar);
- cycles+=3848+((sbits-1)/8)*650 - 11;
- int msb=data[(sbits-1)/8];
- for(int i=7; i>=1; --i) if(msb&(1<<i)) { cycles+=i*75-15; break; }
- for(int i=0; i<sbits; ++i) if(BN_is_bit_set(scalar,i)) cycles+=88;
- break;
+ if(f==0x46) cycles-=37;
}
- case 0x46:
-// START INCOMPLETE FIX
- AddMapCycles(328);
- IMonInit();
-// END INCOMPLETE FIX
break;
case 0x4d:
if(-0x018000==l)
}
BN_set_bit(B,0);
for(int i=0; i<53; i++) data[i]=BN_mod_word(B,primes[i]);
+ BN_copy(A,B);
+ BN_zero(C); BN_zero(D); BN_zero(J);
break;
case 0x4e:
-// START INCOMPLETE FIX
- //MakePrime(B,data);
- BN_copy(D,B);
-// END INCOMPLETE FIX
- break;
case 0x4f:
-// START INCOMPLETE FIX
- BN_set_word(A,2);
- BN_add(B,B,A);
-// END INCOMPLETE FIX
+ MakePrime(data,f==0x4f);
break;
case 0x57:
#ifdef HAS_AUXSRV
}
#endif
{
- cBN a, b, x, y, scalar;
+ cBN a, b, x, y;
if(l<2 || l>4) l=4;
WS_START(l);
l<<=3;
BN_zero(Px);
BN_copy(Py,y);
BN_zero(Qz);
+ MakeJ0(J,D);
}
else {
CurveInit(a);
BN_mask_bits(Px,32);
BN_lshift(b,Qz,32);
BN_add(Px,Px,b);
- BN_mask_bits(Px,128);
+ BN_mask_bits(Px,l<<3);
AddP(0);
}
}
BN_copy(Px,x);
BN_copy(Py,y);
BN_zero(Qz);
+ MakeJ0(J,D);
}
memset(data,0,0x40);
Px.PutLE(&data[0x00],l);
unsigned char keyNr=(algo>>5)&0x01;
unsigned char mecmCode[256];
- GetMem(mecmAddr[keyNr],mecmCode,256,0x80);
+ GetMem(mecmAddr[keyNr],mecmCode,sizeof(mecmCode),0x80);
cPlainKey *pk;
unsigned char ideaKey[16];
if(!(pk=keys.FindKey('N',mecmKeyId,keyNr,sizeof(ideaKey)))) {
}
pk->Get(ideaKey);
idea.SetEncKey(ideaKey,&ks);
- for(int i=0x100-8; i>=8; i-=8) {
- idea.Encrypt(mecmCode+i,8,mecmCode+i,&ks,0);
- xxor(mecmCode+i,8,mecmCode+i,mecmCode+i-8);
- }
- idea.Encrypt(mecmCode,8,mecmCode,&ks,0);
+ idea.Decrypt(mecmCode,sizeof(mecmCode),&ks,0);
HEXDUMP(L_SYS_RAWECM,mecmCode,sizeof(mecmCode),"decrypted MECM code");
// check signature
unsigned char data[256];
SHA1(data,sizeof(data)-8,data);
RotateBytes(data,20);
if(memcmp(data,mecmCode,8)) {
- PRINTF(L_SYS_ECM,"%04X: MECM %02x decrypt signature failed",id,keyNr);
- return false;
+ PRINTF(L_SYS_ECM,"%04X: MECM %02x decrypt signature failed",id,keyNr);
+ return false;
}
memcpy(hw,hd,seedSize);
DoMap(f);
break;
case 0x22:
- DoMap(f,tmp,(Get(0x48)<<16)|(Get(0x4a)<<8)|Get(0x49));
+ DoMap(f,0,(Get(0x4a)<<8)|Get(0x49));
break;
case 0x29:
case 0x2a:
case 0x38:
case 0x3a:
case 0x43:
- case 0x4f:
DoMap(f);
break;
case 0x44:
case 0x45:
GetMem(0x400,tmp,64,0);
+ GetMem(0x440,tmp+64,28,0);
DoMap(f,tmp,l);
- SetMem(0x440,tmp,20,0);
- break;
+ SetMem(0x400,tmp,64,0);
+ SetMem(0x440,tmp+64,28,0);
+ break;
case 0x46:
GetMem(HILO(0x44),tmp,8,0);
- DoMap(f,tmp,l);
+ DoMap(f,tmp);
break;
case 0x4d:
- DoMap(f,tmp,-((Get(0x48)<<16)|(Get(0x49)<<8)|Get(0x4a)));
- SetMem(0x400,tmp,53,0);
+ DoMap(f,tmp,-((Get(0x48)<<16)|(Get(0x4a)<<8)|Get(0x49)));
+ if(*tmp==0xff)
+ Set(0x4b,0x00);
+ else {
+ Set(0x4b,*tmp);
+ SetMem(0x400,tmp+1,wordsize*8>53?wordsize*8:53,0x00);
+ }
break;
case 0x4e:
- GetMem(0x400,tmp,53,0);
+ case 0x4f:
+ GetMem(0x400,tmp+1,53,0);
+ if(f==0x4f) GetMem(HILO(0x44),tmp+54,8,0);
DoMap(f,tmp);
- SetMem(0x400,tmp,53,0);
+ Set(0x4b,*tmp);
+ SetMem(0x400,tmp+1,53,0);
break;
case 0x57:
addr=HILO(0x46);
{
if(hwMapper) {
int mask=hwMapper->AddCycles(num);
+ if(mask) DisableTimers(13);
for(int t=0; mask; mask>>=1,t++)
if(mask&1) {
- DisableTimers(11);
if(t==2) {
PRINTF(L_SYS_EMU,"0101: Timer interrupt %u @ %04x",t,GetPc());
RaiseException(9);
#include <stdlib.h>
#include <string.h>
+#include <math.h>
#include "system.h"
#include "opts.h"
cN2Timer::cN2Timer(void)
{
- cycles=0; ctrl=0; divisor=1; remainder=-1; latch=0xFF;
+ cycles=intrCycles=delayInterrupt=0; ctrl=0; val=0; divisor=0; invDivisor=0; latch=0xFF;
+ timerBugged=false;
}
bool cN2Timer::AddCycles(unsigned int count)
{
- bool irq=false;
if(Running()) {
- bool stop=false;
- remainder+=count;
- if(remainder>=divisor) {
- cycles-=remainder/divisor;
- remainder%=divisor;
+ cycles+=count;
+ if(!delayInterrupt && InterruptSet() && cycles>=intrCycles) {
+ delayInterrupt=intrCycles-cycles+3;
+ if(delayInterrupt<0) delayInterrupt=count; else delayInterrupt+=count;
+ intrCycles=0;
+ if((ctrl&tmCONTINUOUS)) Update();
}
- if(cycles<0 || (cycles==0 && remainder>=2))
- stop=true;
- if(ctrl&tmCONTINUOUS) {
- while(cycles<0) cycles+=latch+1;
+ }
+ if(delayInterrupt) {
+ delayInterrupt-=count;
+ if(delayInterrupt<0) delayInterrupt=0;
+ if(!delayInterrupt) {
+ Update();
+ return true;
}
- else if(stop) {
- PRINTF(L_SYS_EMU,"n2timer %d: timer stop (cycles=%d remainder=%d)",nr,cycles,remainder);
- cycles=0;
- Stop();
+ }
+ return false;
+}
+
+double cN2Timer::GetDivisor(void)
+{
+ int prescalar=((ctrl&0x38)>>3)+1;
+ double divisor=pow(4.0,prescalar);
+ double multiplier;
+ // multipliers for 0 and 2 aren't correct yet
+ switch((ctrl&0xc0)>>6) {
+ case 0: multiplier=10.3f; break;
+ case 1: multiplier= 1.0f; break;
+ case 2: multiplier=6.375f; break;
+ default:multiplier=0;
+ }
+ return divisor*multiplier;
+}
+
+void cN2Timer::Update(void)
+{
+ int rlatch=latch;
+ if(divisor) {
+ if(timerBugged && cycles>=0x100*divisor) {
+ timerBugged=false;
+ cycles-=0x101*divisor;
}
- if((ctrl&tmINTERRUPT) && stop) {
- PRINTF(L_SYS_EMU,"n2timer %d: IRQ triggered",nr);
- irq=true;
+ if(timerBugged) rlatch=0x100;
+
+ int v=cycles*invDivisor;
+ if(ctrl&tmCONTINUOUS) {
+ val=rlatch-(v % (rlatch+1));
+ if(InterruptSet() && val==0)
+ intrCycles = cycles + (unsigned int)((val?val:latch)*divisor);
+ }
+ else {
+ // one-shot
+ if(v>=rlatch) {
+ val=0;
+ if(Running() && ((cycles-2)*invDivisor)>=rlatch) Stop();
+ }
+ else
+ val=rlatch-v;
}
}
- return irq;
+ else val=0;
+}
+
+unsigned int cN2Timer::Cycles(void)
+{
+ if(Running()) Update();
+ PRINTF(L_SYS_EMU,"n2timer %d: read %u %02x %02x = %02x",nr,cycles,ctrl&0xff,latch&0xff,val);
+ return val;
+}
+
+unsigned char cN2Timer::Ctrl(void)
+{
+ if(Running()) Update();
+ return ctrl;
}
void cN2Timer::Latch(unsigned char val)
{
if(!Running()) {
latch=val; if(latch==0) latch=0x100;
- cycles=latch; remainder=0;
+ cycles=0;
ctrl|=tmLATCHED;
+ timerBugged=false;
}
}
ctrl=(ctrl&~tmRUNNING) | (val&tmRUNNING);
if(!Running()) {
Stop();
- PRINTF(L_SYS_EMU,"n2timer %d: stopped cycles=%x ctrl=%x",nr,cycles,ctrl);
+ --cycles;
+ Update();
+ PRINTF(L_SYS_EMU,"n2timer %d: stopped cycles=%d (%02x) ctrl=%02x latch=%02x\n",nr,cycles,val,ctrl,latch&0xff);
}
}
else {
ctrl=(ctrl&~tmMASK) | (val&tmMASK);
+ divisor=GetDivisor();
+ if(divisor) invDivisor=1.0/divisor;
if(Running()) {
- if((ctrl&0xc0)==0x40) divisor=1 << (2 *(1 + ((ctrl & 0x38) >> 3)));
- else divisor=4; // This is wrong, but we haven't figured the right value out yet
- if(divisor<=0) divisor=1; // sanity
- if(!(ctrl&tmLATCHED)) cycles=(unsigned int)(cycles-1)&0xFF;
- PRINTF(L_SYS_EMU,"n2timer %d: started latch=%x div=%d cycles=%x ctrl=%x",nr,latch,divisor,cycles,ctrl);
- remainder=-1;
- if(!(ctrl&tmCONTINUOUS) && cycles==0) ctrl&=~tmRUNNING;
+ if(!(ctrl&tmLATCHED) && divisor>0) {
+ if(this->val==0) {
+ timerBugged=true;
+ cycles=(unsigned int)divisor;
+ }
+ else {
+ cycles=(unsigned int)(((timerBugged?0x100:latch)-this->val+1) * divisor);
+ }
+ }
+ if((ctrl&tmINTERRUPT)) {
+ intrCycles=cycles+(unsigned int)((timerBugged?0x101:this->val?this->val:latch)*divisor);
+ if(nr==2) PRINTF(L_SYS_EMU,"n2timer %d: set for %u cycles (%02x %02x)",nr,intrCycles-cycles,Latch(),ctrl&0xff);
+ }
+ ctrl&=~tmLATCHED;
}
}
}
void cN2Timer::Stop(void)
{
ctrl&=~(tmRUNNING|tmLATCHED);
+ if(delayInterrupt>=3) delayInterrupt=0;
}
// -- cN2CRC -------------------------------------------------------------------
// -- cMapReg ------------------------------------------------------------------
-cMapReg::cMapReg(int *_defwordsize, int _maxwordsize)
+cMapReg::cMapReg(int &_pos, int *_defwordsize, int _maxwordsize)
+:pos(_pos)
{
SetDefWordSize(_defwordsize);
SetMaxWordSize(_maxwordsize);
if(wordsize>wsize) Commit();
reg.GetLE(in,wsize*8);
Commit(wsize);
+ pos=0;
}
void cMapReg::PutLE(unsigned char *out, int n)
int wsize=OpWordSize(n<=0?n:(n+7)/8);
Commit();
fullreg.PutLE(out,wsize*8);
+ if(pos&7) {
+ int s=pos/8*8;
+ for(int i=0; i<(pos&7); i++) {
+ unsigned char c=out[s];
+ memmove(out+s,out+s+1,7);
+ out[s+7]=c;
+ }
+ }
}
void cMapReg::Set(BIGNUM *val, int wsize)
// -- cMapMath -----------------------------------------------------------------
cMapMath::cMapMath(void)
-:A(&wordsize),B(&wordsize),C(&wordsize),D(&wordsize),J(0,1),I(&wordsize)
+:A(regpos,&wordsize),B(regpos,&wordsize),C(regpos,&wordsize),D(regpos,&wordsize),J(regpos,0,1),I(regpos,&wordsize)
{
wordsize=DEF_WORDSIZE; words=-1;
+ regpos=0;
}
bool cMapMath::ModAdd(BIGNUM *r, BIGNUM *a, BIGNUM *b, BIGNUM *d)
void cMapCore::IMonInit0(int bits)
{
- AddMapCycles(132+(wordsize*8+3)/5*5);
- if(BN_num_bits(D)>1) AddMapCycles(54);
+ AddMapCycles(114+(wordsize*8+3)/5*5);
+ D.SetPos(2);
+ AddMapCycles(18);
+ if(BN_num_bits(D)>1)
+ for(int i=3; i<=8; i++) {
+ D.SetPos(i);
+ AddMapCycles(9);
+ }
+ D.SetPos(0);
if(!BN_is_zero(D)) {
AddMapCycles(54);
BN_zero(I);
BN_set_bit(I,bits ? bits : 68*wordsize);
BN_zero(B);
- AddMapCycles(141+(wordsize*8+3)/5*5);
- //BN_set_bit(B,64*(wordsize-1));
- // TEMP or not?
- BN_set_bit(B,64*(wordsize-1)+bits);
- AddMapCycles(92+72*wordsize);
+ AddMapCycles(157+(wordsize*8+3)/5*5+72*(wordsize-1));
+ BN_set_bit(B,64*(wordsize-1));
+ B.SetPos(8*(wordsize-1)+1);
+ AddMapCycles(17);
+ for(int i=8*(wordsize-1)+2; i<=8*wordsize; i++) {
+ B.SetPos(i);
+ AddMapCycles(9);
+ }
+ B.SetPos(0);
+ AddMapCycles(68);
BN_mod(B,I,D,ctx);
AddMapCycles(639);
}
- AddMapCycles(52);
- for(int i=0; i<4; i++) {
- MonMul0(B,B,B,C,D,J,0);
- AddMapCycles(96+6*(i>0));
- MonFin(B,D);
- }
+ AddMapCycles(52);
+ for(int i=0; i<4; i++) {
+ MonMul0(B,B,B,C,D,J,0);
+ AddMapCycles(96+6*(i>0));
+ MonFin(B,D);
+ }
}
void cMapCore::IMonInit(int bits)
void cMapCore::MonInit(int bits)
{
// Calculate J0 & H montgomery elements in J and B
- MakeJ0(J,D);
- BN_zero(I);
- BN_set_bit(I,bits ? bits : 68*wordsize);
- BN_mod(B,I,D,ctx);
+ MakeJ0(J,D,C);
+ if(!BN_is_zero(D)) {
+ BN_zero(I);
+ BN_set_bit(I,bits ? bits : 68*wordsize);
+ BN_mod(B,I,D,ctx);
+ }
for(int i=0; i<4; i++) MonMul(B,B,B);
}
void cMapCore::MonExpNeg(void)
{
- if(BN_is_zero(D)) { BN_set_word(A,1); return; }
+ if(BN_is_zero(D) || BN_is_word(D,2)) {
+ BN_one(A);
+ if(!BN_is_zero(D)) BN_zero(B);
+ return;
+ }
+ int bits=0;
+ for(int i=BN_num_bits(D)-1; i>=0; i--) if(BN_is_bit_set(D,i)) bits++;
BN_copy(e,D);
BN_mask_bits(e,8); // check LSB
unsigned int n=BN_get_word(e);
if(n) BN_sub_word(e,0x02); // N -2
else BN_add_word(e,0xFE); // N + 254 ('carryless' -2)
BN_copy(A,B);
- for(int i=BN_num_bits(e)-2; i>-1; i--) {
+ for(int i=BN_num_bits(e)-2+(bits==1 && BN_num_bits(D)<=8); i>-1; i--) {
MonMul(B,B,B);
if(BN_is_bit_set(e,i)) MonMul(B,A,B);
}
- if(BN_is_bit_set(D,0)) {
- int i;
- for(i=BN_num_bits(D)-2; i>0; i--) if(BN_is_bit_set(D,i)) break;
- if(i<=0) {
- MonMul(B,B,B);
- MonMul(B,A,B);
- }
+ if(bits==2 && BN_is_bit_set(D,0)) {
+ MonMul(B,B,B);
+ MonMul(B,A,B);
}
- BN_set_word(A,1);
+ BN_one(A);
MonMul(B,A,B);
}
interrupted=false; interruptible=true;
try {
if(!Map(f,data,l) && !MapGeneric(f,data,l))
- PRINTF(L_SYS_MAP,"%04x: unsupported call %02x",mapid,f);
+ PRINTF(L_SYS_MAP,"%04x: unsupported map call %02x",mapid,f);
if(cycles) {
unsigned int elapsed=CpuCycles()-startcycles;
if(cycles>elapsed) AddMapCycles(cycles-elapsed);
case IMPORT_LAST:
if(l>16) { l=1; cycles+=5; }
else if(l<=0) l=1;
- cycles=656+160*l-6;
+ cycles+=656+160*l-6;
regs[last]->GetLE(data,(last==0?1:l)<<3);
break;
case EXPORT_D:
if(l>17) { l=17; cycles+=5; }
else if(l<=0) { l=wordsize; cycles+=4; }
- cycles=778+160*l-6;
+ cycles+=778+160*l-6;
last=f-EXPORT_J;
regs[last]->PutLE(data,l<<3);
break;
case EXPORT_LAST:
if(l>16) { l=1; cycles+=5; }
else if(l<=0) l=1;
- cycles=668+160*l-6;
+ cycles+=668+160*l-6;
regs[last]->PutLE(data,(last==0?1:l)<<3);
break;
AddMapCycles(f==0x39?433:192);
IMonInit();
if(f==0x39) {
- I.GetLE(data,wordsize<<3);
- MonMul(B,I,B);
+ scalar.GetLE(data,wordsize<<3);
+ MonMul(B,scalar,B);
}
else
MonMul(B,A,B);
+ AddMapCycles(137);
MonMul(B,A,B);
break;
case 0x43: // init SHA1
- SHA1_Init(&sctx);
- break;
case 0x44: // add 64 bytes to SHA1 buffer
- RotateBytes(data,64);
- SHA1_Update(&sctx,data,64);
- BYTE4_LE(data ,sctx.h4);
- BYTE4_LE(data+4 ,sctx.h3);
- BYTE4_LE(data+8 ,sctx.h2);
- BYTE4_LE(data+12,sctx.h1);
- BYTE4_LE(data+16,sctx.h0);
+ if(f==0x43) {
+ l=0;
+ SHA1_Init(&sctx);
+ cycles=885;
+ }
+ else {
+ l=64;
+ RotateBytes(data,l);
+ sctx.h4=UINT32_LE(data+l+0x00);
+ sctx.h3=UINT32_LE(data+l+0x04);
+ sctx.h2=UINT32_LE(data+l+0x08);
+ sctx.h1=UINT32_LE(data+l+0x0c);
+ sctx.h0=UINT32_LE(data+l+0x10);
+ sctx.Nl=UINT32_LE(data+l+0x14);
+ sctx.Nh=UINT32_LE(data+l+0x18);
+ sctx.num=0;
+ SHA1_Update(&sctx,data,l);
+ memset(data,0,l);
+ cycles=65309;
+ }
+ if(data) {
+ BYTE4_LE(data+l+0x00,sctx.h4);
+ BYTE4_LE(data+l+0x04,sctx.h3);
+ BYTE4_LE(data+l+0x08,sctx.h2);
+ BYTE4_LE(data+l+0x0c,sctx.h1);
+ BYTE4_LE(data+l+0x10,sctx.h0);
+ BYTE4_LE(data+l+0x14,sctx.Nl);
+ BYTE4_LE(data+l+0x18,sctx.Nh);
+ }
break;
- case 0x45: // add wordsize bytes to SHA1 buffer and finalize SHA result
- if(dl) {
- if(dl>1) RotateBytes(data,dl);
- SHA1_Update(&sctx,data,dl);
+ case 0x45: // add l bytes to SHA1 buffer and finalize SHA result
+ if(l<=0 || l>64)
+ cycles=465+5*(l>64);
+ else {
+ sctx.h4=UINT32_LE(data+0x40);
+ sctx.h3=UINT32_LE(data+0x44);
+ sctx.h2=UINT32_LE(data+0x48);
+ sctx.h1=UINT32_LE(data+0x4c);
+ sctx.h0=UINT32_LE(data+0x50);
+ sctx.Nl=UINT32_LE(data+0x54);
+ sctx.Nh=UINT32_LE(data+0x58);
+ sctx.Nl&=~0xff;
+ sctx.num=0;
+ if(l>1) RotateBytes(data,l);
+ SHA1_Update(&sctx,data,l);
+ SHA1_Final(data+0x40,&sctx);
+ RotateBytes(data+0x40,20);
+ BYTE4_LE(data+0x54,sctx.Nl);
+ BYTE4_LE(data+0x58,sctx.Nh);
+ memset(data,0,64);
+ cycles=65519+(64-l)*12+(l>=56)*64681-16*(l==64);
}
- SHA1_Final(data,&sctx);
- RotateBytes(data,20);
break;
default:
return false;
if(emmP) emmP->PostDecrypt(false);
HEXDUMP(L_SYS_RAWEMM,emmdata,cmdLen,"Nagra2 RAWEMM");
- id=(emmdata[8]<<8)+emmdata[9];
+ if(buffer[0]==0x82) id=(emmdata[8]<<8)+emmdata[9];
LBSTARTF(L_SYS_EMM);
bool contFail=false;
for(int i=8+2+4+4; i<cmdLen-22; ) {
}
break;
}
+ case 0xA0: i+=5; break; // CamID target update
+ case 0xA3: i+=4; break; // Cam group target update
case 0xA4: i+=emmdata[i+1]+2+4; break; // conditional (always no match assumed for now)
- case 0xA6: i+=15; break;
+ case 0xA6: // updates tier/blackout
+ if(emmdata[i+4]==0xFD && emmdata[i+5]==0x98) i+=(emmdata[i+1]+emmdata[i+3]+4);
+ else i+=15;
+ break;
case 0xAA: i+=emmdata[i+1]+5; break;
case 0xAD: i+=emmdata[i+1]+2; break;
case 0xA2:
- case 0xAE: i+=11;break;
+ case 0xAE: i+=11; break;
+ case 0x01: i+=3; break;
+ case 0x10: i+=18; break;
case 0x12: i+=emmdata[i+1]+2; break; // create tier
case 0x20: i+=19; break; // modify tier
case 0x9F: i+=6; break;
}
break;
}
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x85:
case 0xE1:
case 0xE2:
case 0x00: i=cmdLen; break; // end of processing