Skip to content

Latest commit

 

History

History
199 lines (150 loc) · 5.38 KB

phz.adoc

File metadata and controls

199 lines (150 loc) · 5.38 KB

PHZ file format

This document describes the file layout and record format for the phz filetype used by the Phrozen Sonic Mini 3D printer.

Relationship with ctb

The phz format is closely related to the ctb format, which I have previously described. Please study that format first. This document will focus on the deviations.

Unified header format

phz contains an evolved version of the file header from ctb/cbddlp. Some of the oddities and historical details have been cleaned up, and the information has been collapsed into a single record.

The fields play exactly the same roles as in ctb, just rearranged. As such, I’m not going to discuss them in detail beyond their layout.

The newly unified file header record is 0xD8 / 216 bytes in length, with several areas zeroed, either encoding yet-unobserved features, or reserved for expansion.

Table 1. File header layout

x0

x4

x8

xC

0x

magic

version

layer_height_mm

exposure_s

1x

bot_exposure_s

bot_layer_count

resolution.x

resolution.y

2x

large_preview_offset

layer_table_offset

layer_table_count

small_preview_offset

3x

print_time_s

projection

level_set_count

pwm_level

bot_pwm_level

4x

zero

overall_height_mm

printer_out_mm.x

5x

printer_out_mm.y

printer_out_mm.z

encryption_key

bot_light_off_time_s

6x

light_off_time_s

bot_layer_count_again

zero

bot_lift_dist_mm

7x

bot_lift_speed_mmpm

lift_dist_mm

lift_speed_mmpm

retract_speed_mmpm

8x

resin_volume_ml

resin_mass_g

resin_cost

zero

9x

machine_type_offset

machine_type_len

zero

Ax

zero

Bx

encryption_mode

mysterious_id

antialias_level

software_version

Cx

zero

Dx

zero

(start of next record)

Note
encryption_mode seems to be reliably set to 0x1c for the Phrozen Sonic Mini. Changing it makes files unreadable.

The encoding of the preview images and layer table are identical to those in ctb.

Layer data encoding

Layers are encoded as 7bpp images using yet another RLE scheme. This scheme, which is called RLE7a in the Catibo sources because it’s our second 7-bit scheme, works as follows:

  • A byte with MSB set represents a pixel in bits 6:0.

  • A byte with MSB clear represents a repeat count for the last generated pixel.

Thus, 0x80 encodes a single zero pixel, and 0x80 0x7f encodes 128 zero pixels.

Quirks observed in the wild:

  • The repeat count generated by proprietary software never exceeds 0x7d, so you can recognize this encoding by looking for long runs of 0x7d. It’s not clear whether 0x7e/0x7f are somehow reserved, or if this is an off-by-one error in the encoder, but Catibo currently mimics this behavior.

  • Unlike the other RLE schemes, the encoder for "7a" takes care to terminate runs at each half scanline — so for a 1080-pixel wide scanline, it will generate two runs of 540, neither of which overlaps the ends of the lines. It’s not clear whether this behavior is necessary, but Catibo currently mimics it. (If someone with access to an actual Phrozen Sonic Mini could try it and report back, I’d appreciate it. It inflates file sizes by 10+%.)

Layer data encryption

Like ctb, the phz format encrypts layer data for some goddamn reason. Which is why I took a look at the format, despite not having a compatible printer.

Fortunately for owners of the Sonic Mini, the encryption is straightforward. It’s another 32-bit block XOR cipher. See the ctb doc for details and ranting.

I’m referring to this cipher as the "9f Cipher," named after the initial byte of files that use it.

Here’s the concise version, showing just which parameters vary. The keystream X[n] is produced by:

c = (key % 0x4324) * 0x34a3_2231
X[0] = (iv ^ 0x3fad_2212) * (key % 0x4324) * 0x4910_913d
X[n + 1] = X[n] + c

(Where + and * are addition and multiplication mod 232, respectively, and % is unsigned remainder.)

Each block of data is simply XOR’d with the keystream, as in ctb.

A key of 0 causes the desktop software to accept unencrypted files. This may or may not have been deliberate: there is a class of weak keys for this cipher that includes any number that is 0 mod 0x4324; all these keys result in a zero keystream, disabling encryption.

(However, note that ctb seems to have deliberately skipped encryption or keys of 0, so it might be deliberate here too.)

Tip
The proprietary desktop software does not appear to check for these weak keys when selecting its output keys, so it produces unencrypted output with a probability of 5.818e-5.

Analysis

I kept commentary to a minimum in the cbddlp doc, but this is the third variation on the file format I’ve analyzed, and I have thoughts.

On the new unified header format: This is a great improvement. It really cleans things up.

On the new RLE scheme: In practice, layer images will tend to include long runs of fully empty and fully solid pixels. In cases like that, this scheme achieves strictly worse compression than RLE7. Using catibo-convert to recompress a sample phz file as ctb produces an output file 0.1x the size. I have to assume that the RLE scheme was dictated by whatever image processor Phrozen used to drive their display — otherwise I can’t imagine why this would be chosen over their previous RLE7 scheme.

On the new cipher: Don’t get me started.