Skip to content

Commit

Permalink
Literal port of python code for checksum
Browse files Browse the repository at this point in the history
  • Loading branch information
AngheloAlf committed Dec 15, 2023
1 parent 4ae9083 commit a96b463
Show file tree
Hide file tree
Showing 4 changed files with 265 additions and 30 deletions.
200 changes: 200 additions & 0 deletions src/rs/checksum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/* SPDX-FileCopyrightText: © 2023 Decompollaborate */
/* SPDX-License-Identifier: MIT */

#[cfg(feature = "python_bindings")]
use pyo3::prelude::*;

use crate::cickinds::CICKind;
use crate::utils;


fn readWordFromRam(romWords: &[u32], entrypointRam: u32, ramAddr: u32) -> u32 {
//return romWords[utils.u32(ramAddr - entrypointRam + 0x1000) / 4]
romWords[((ramAddr - entrypointRam + 0x1000) / 4) as usize]
}


pub fn calculateChecksum(romBytes: &[u8], kind: &CICKind) -> Option<(u32, u32)> {
/*
Calculates the checksum required by an official CIC of a N64 ROM.
Args:
romBytes (bytes): The bytes of the N64 ROM in big endian format. It must have a minimum size of 0x101000 bytes.
kind (CICKind): The CIC kind variation used to calculate the checksum.
Returns:
tuple[int, int]|None: If no error happens then the calculated checksum is returned, stored as a tuple
containing two 32-bits words. Otherwise, `None` is returned. Possible errors:
- `romBytes` not being big enough
*/

if romBytes.len() < 0x101000 {
return None;
}

let romWords = utils::read_u32_vec(romBytes, 0, 0x101000);

let seed = kind.get_seed();
let magic = kind.get_magic();

let mut s6 = seed;

let mut a0 = romWords[8/4];
if *kind == CICKind::CIC_X103 {
a0 -= 0x100000;
}
if *kind == CICKind::CIC_X106 {
a0 -= 0x200000;
}
let entrypointRam = a0;

let mut at = magic;
let mut lo = s6 * at;

if *kind == CICKind::CIC_X105 {
s6 = 0xA0000200;
}

let mut ra = 0x100000;

let mut v1 = 0;
let mut t0 = 0;

let mut t1 = a0;

let mut t5 = 0x20;

//let mut v0 = utils.u32(lo);
let mut v0 = lo;
v0 += 1;

let mut a3 = v0;
let mut t2 = v0;
let mut t3 = v0;
let mut s0 = v0;
let mut a2 = v0;
let mut t4 = v0;

// poor man's do while
let mut LA40005F0_loop = true;
while LA40005F0_loop {
// v0 = *t1
v0 = readWordFromRam(&romWords, entrypointRam, t1);

//v1 = utils.u32(a3 + v0);
v1 = a3 + v0;

//at = utils.u32(v1) < utils.u32(a3);
at = if v1 < a3 { 1 } else { 0 };

let a1 = v1;
// if (at == 0) goto LA4000608;

if at != 0 {
//t2 = utils.u32(t2 + 0x1)
t2 = t2 + 0x1;
}

// LA4000608
v1 = v0 & 0x1F;
//t7 = utils.u32(t5 - v1)
let t7 = t5 - v1;


//let t8 = utils.u32(v0 >> t7)
//let t6 = utils.u32(v0 << v1)
let t8 = v0 >> t7;
let t6 = v0 << v1;

a0 = t6 | t8;
// at = utils.u32(a2) < utils.u32(v0);
at = if a2 < v0 { 1 } else { 0 };
a3 = a1;

t3 = t3 ^ v0;

//s0 = utils.u32(s0 + a0)
s0 = s0 + a0;
// if (at == 0) goto LA400063C;
if at != 0 {
let t9 = a3 ^ v0;

a2 = t9 ^ a2;
// goto LA4000640;

// LA400063C:
} else {
a2 = a2 ^ a0;
}


// LA4000640:
if *kind == CICKind::CIC_X105 {
// ipl3 6105 copies 0x330 bytes from the ROM's offset 0x000554 (or offset 0x000514 into IPL3) to vram 0xA0000004
let mut t7 = romWords[((s6 - 0xA0000004 + 0x000554) / 4) as usize];

//t0 = utils.u32(t0 + 0x4);
//s6 = utils.u32(s6 + 0x4);
t0 = t0 + 0x4;
s6 = s6 + 0x4;

t7 = v0 ^ t7;

// t4 = utils.u32(t7 + t4);
t4 = t7 + t4;

t7 = 0xA00002FF;

// t1 = utils.u32(t1 + 0x4);
t1 = t1 + 0x4;

// s6 = utils.u32(s6 & t7);
s6 = s6 & t7;
} else {
// t0 = utils.u32(t0 + 0x4);
t0 = t0 + 0x4;

let t7 = v0 ^ s0;

// t1 = utils.u32(t1 + 0x4);
t1 = t1 + 0x4;

// t4 = utils.u32(t7 + t4);
t4 = t7 + t4;
}


// if (t0 != ra) goto LA40005F0;
if t0 == ra {
LA40005F0_loop = false;
}
}

if *kind == CICKind::CIC_X103 {
let t6 = a3 ^ t2;
// a3 = utils.u32(t6 + t3);
a3 = t6 + t3;

let t8 = s0 ^ a2;
// s0 = utils.u32(t8 + t4);
s0 = t8 + t4;
} else if *kind == CICKind::CIC_X106 {
/*
let t6 = utils.u32(a3 * t2);
a3 = utils.u32(t6 + t3);
let t8 = utils.u32(s0 * a2);
s0 = utils.u32(t8 + t4);
*/
let t6 = a3 * t2;
a3 = t6 + t3;
let t8 = s0 * a2;
s0 = t8 + t4;
} else {
let t6 = a3 ^ t2;
a3 = t6 ^ t3;
let t8 = s0 ^ a2;
s0 = t8 ^ t4;
}

return Some((a3, s0))
}
61 changes: 31 additions & 30 deletions src/rs/cickinds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,48 +6,49 @@ use pyo3::prelude::*;

#[cfg_attr(feature = "python_bindings", pyclass(module = "ipl3checksum"))]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[allow(non_camel_case_types)]
pub enum CICKind {
Cic6101,
Cic6102_7101,
Cic7102,
CicX103, // Both 6103 and 7103
CIC_6101,
CIC_6102_7101,
CIC_7102,
CIC_X103, // Both 6103 and 7103
// 6104/7104 does not exist
CicX105, // Both 6105 and 7105
CicX106, // Both 6106 and 7106
CIC_X105, // Both 6105 and 7105
CIC_X106, // Both 6106 and 7106
}

#[cfg_attr(feature = "python_bindings", pymethods)]
impl CICKind {
pub fn get_seed(&self) -> u32 {
match self {
CICKind::Cic6101 => 0x3F,
CICKind::Cic6102_7101 => 0x3F,
CICKind::Cic7102 => 0x3F,
CICKind::CicX103 => 0x78,
CICKind::CicX105 => 0x91,
CICKind::CicX106 => 0x85,
CICKind::CIC_6101 => 0x3F,
CICKind::CIC_6102_7101 => 0x3F,
CICKind::CIC_7102 => 0x3F,
CICKind::CIC_X103 => 0x78,
CICKind::CIC_X105 => 0x91,
CICKind::CIC_X106 => 0x85,
}
}

pub fn get_magic(&self) -> u32 {
match self {
CICKind::Cic6101 => 0x5D588B65,
CICKind::Cic6102_7101 => 0x5D588B65,
CICKind::Cic7102 => 0x5D588B65,
CICKind::CicX103 => 0x6C078965,
CICKind::CicX105 => 0x5D588B65,
CICKind::CicX106 => 0x6C078965,
CICKind::CIC_6101 => 0x5D588B65,
CICKind::CIC_6102_7101 => 0x5D588B65,
CICKind::CIC_7102 => 0x5D588B65,
CICKind::CIC_X103 => 0x6C078965,
CICKind::CIC_X105 => 0x5D588B65,
CICKind::CIC_X106 => 0x6C078965,
}
}

pub fn get_hash_md5(&self) -> &str {
match self {
CICKind::Cic6101 => "900b4a5b68edb71f4c7ed52acd814fc5",
CICKind::Cic6102_7101 => "e24dd796b2fa16511521139d28c8356b",
CICKind::Cic7102 => "955894c2e40a698bf98a67b78a4e28fa",
CICKind::CicX103 => "319038097346e12c26c3c21b56f86f23",
CICKind::CicX105 => "ff22a296e55d34ab0a077dc2ba5f5796",
CICKind::CicX106 => "6460387749ac0bd925aa5430bc7864fe",
CICKind::CIC_6101 => "900b4a5b68edb71f4c7ed52acd814fc5",
CICKind::CIC_6102_7101 => "e24dd796b2fa16511521139d28c8356b",
CICKind::CIC_7102 => "955894c2e40a698bf98a67b78a4e28fa",
CICKind::CIC_X103 => "319038097346e12c26c3c21b56f86f23",
CICKind::CIC_X105 => "ff22a296e55d34ab0a077dc2ba5f5796",
CICKind::CIC_X106 => "6460387749ac0bd925aa5430bc7864fe",
}
}

Expand All @@ -66,12 +67,12 @@ impl CICKind {
impl CICKind {
fn from_value_impl(value: usize) -> Option<CICKind> {
match value {
6101 => Some(CICKind::Cic6101),
6102 | 7101 => Some(CICKind::Cic6102_7101),
7102 => Some(CICKind::Cic7102),
6103 | 7103 => Some(CICKind::CicX103),
6105 | 7105 => Some(CICKind::CicX105),
6106 | 7106 => Some(CICKind::CicX106),
6101 => Some(CICKind::CIC_6101),
6102 | 7101 => Some(CICKind::CIC_6102_7101),
7102 => Some(CICKind::CIC_7102),
6103 | 7103 => Some(CICKind::CIC_X103),
6105 | 7105 => Some(CICKind::CIC_X105),
6106 | 7106 => Some(CICKind::CIC_X106),
_ => None
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/rs/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
/* SPDX-License-Identifier: MIT */

pub mod cickinds;
pub mod checksum;

mod utils;

#[cfg(feature = "python_bindings")]
use pyo3::prelude::*;
Expand Down
31 changes: 31 additions & 0 deletions src/rs/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* SPDX-FileCopyrightText: © 2023 Decompollaborate */
/* SPDX-License-Identifier: MIT */

pub(crate) fn read_u32(bytes: &[u8], offset: usize) -> u32 {
if offset % 4 != 0 {
panic!("Unaligned read");
}

if offset + 4 > bytes.len() {
panic!("Out of bounds");
}

/*
match bytes[offset..offset + 4].try_into() {
Ok(bytes) => u32::from_be_bytes(bytes),
Err(_error) => todo!(),
}
*/

u32::from_be_bytes(bytes[offset..offset + 4].try_into().unwrap())
}

pub(crate) fn read_u32_vec(bytes: &[u8], offset: usize, len: usize) -> Vec<u32> {
let mut ret = vec![0;len];

for i in 0..(len*4) {
ret[i] = read_u32(bytes, offset + i);
}

ret
}

0 comments on commit a96b463

Please sign in to comment.