Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mia: improve CIC detection algorithm #1296

Merged
merged 1 commit into from
Nov 21, 2023

Conversation

rasky
Copy link
Collaborator

@rasky rasky commented Nov 19, 2023

Currently, we detect the CIC to emulate by calculating a CRC32 over IPL3 bootcode in ROM, and keeping a database of the known IPL3s. This works because right now there are only a handful of IPL3 variants (exactly one per CIC).

In preparation for libdragon releasing an open source IPL3 that could evolve and be forked an unbounded number of times, we must stop keeping a database of IPL3s.

This commit changes strategy: it simulates the IPL2 checksum hash over IPL3 (which is exactly what a real N64 does at boot) and verifies if the checksum matches that expected by any of the known CIC variants. This works because open source IPL3 variants must anyway have a checksum that collides with that of CICs (which must be obtained via a second preimage attack, bruteforced on GPUs), otherwise they would not work on real hardware nor on Ares itself (which correctly simulates the boot sequence and would refuse to boot an "unsigned" IPL3).

auto Nintendo64::ipl2checksum(u32 seed, array_view<u8> rom) -> u64
{
auto rotl = [](u32 value, u32 shift) -> u32 {
return (value << shift) | (value >> (32 - shift));
Copy link
Contributor

@invertego invertego Nov 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shifting a u32 by 32 bits is UB. Same for rotr.

Might be good to move the rotate helpers to nall/bit.hpp. We can eventually just switch to the C++ standard library implementation when we move to C++20.

https://en.cppreference.com/w/cpp/numeric/rotl

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, but I don't want to move it to nall as I don't want to think now how to make that a template.

Copy link
Contributor

@invertego invertego left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just some minor suggestions.

while (1) {
loop++;
dataLast = data;
data = read(dataIndex);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, array_view has a built-in helper for big endian reads.

      data = rom.readm(4);
      rom += 4;

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, though readm already advances the pointer

};

auto Nintendo64::ipl2checksum(u32 seed, array_view<u8> rom) -> u64
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: brace style

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

for (auto &b : buf) b = state[0];

for (loop = 0; loop < 16; loop++)
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: brace style

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Currently, we detect the CIC to emulate by calculating a CRC32 over
IPL3 bootcode in ROM, and keeping a database of the known IPL3s. This
works because right now there are only a handful of IPL3 variants
(exactly one per CIC).

In preparation for libdragon releasing an open source IPL3 that could
evolve and be forked an unbounded number of times, we must stop keeping
a database of IPL3s.

This commit changes strategy: it simulates the IPL2 checksum hash over
IPL3 (which is exactly what a real N64 does at boot) and verifies
if the checksum matches that expected by any of the known CIC variants.
This works because open source IPL3 variants must anyway have a checksum
that collides with that of CICs (which must be obtained via a second
preimage attack, bruteforced on GPUs), otherwise they would not work
on real hardware nor on Ares itself (which correctly simulates the boot
sequence and would refuse to boot an "unsigned" IPL3).
@LukeUsher LukeUsher merged commit 67c6bfa into ares-emulator:master Nov 21, 2023
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants