Add files via upload
This commit is contained in:
35 files changed
+14482
No files matched your search
@@ -0,0 +1,162 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace sppm {
|
||||
|
||||
constexpr std::uint16_t kWidth = 640;
|
||||
constexpr std::uint16_t kHeight = 360;
|
||||
constexpr std::size_t kPixelsPerLayer = static_cast<std::size_t>(kWidth) * kHeight;
|
||||
constexpr std::size_t kLayerCount = 4;
|
||||
constexpr std::size_t kPaletteSize = 256;
|
||||
constexpr std::size_t kMaxFrames = 9999;
|
||||
constexpr std::size_t kMaxAudioTracks = 4;
|
||||
|
||||
struct Color {
|
||||
std::uint8_t r = 0;
|
||||
std::uint8_t g = 0;
|
||||
std::uint8_t b = 0;
|
||||
std::uint8_t a = 255;
|
||||
};
|
||||
|
||||
using Palette = std::array<Color, kPaletteSize>;
|
||||
|
||||
// Palette index 0 is transparent. Other entries can be changed by the editor.
|
||||
Palette defaultPalette();
|
||||
|
||||
struct Frame {
|
||||
// A, B, C, D from front to back; one palette index per 640x360 pixel.
|
||||
std::array<std::vector<std::uint8_t>, kLayerCount> layers;
|
||||
Frame();
|
||||
};
|
||||
|
||||
struct AudioTrack {
|
||||
std::string name; // e.g. BGM, SE1, SE2, SE3
|
||||
std::uint32_t sampleRate = 0; // 8000..48000 Hz
|
||||
std::uint8_t channels = 1; // 1 or 2
|
||||
std::uint8_t referenceFps = 0; // BGM's native animation speed; 0 means use the note's speed
|
||||
std::uint8_t referenceSpeed = 0; // SPPM v3 BGM speed index (1..8); 0 means legacy fps
|
||||
std::vector<std::uint16_t> frameTriggers; // SE cues; BGM always starts at frame 0
|
||||
std::vector<std::int16_t> pcm; // interleaved signed 16-bit samples
|
||||
};
|
||||
|
||||
// A public identity is safe to put in an .sppm file. It contains an Ed25519
|
||||
// verification key and a one-way, app-specific device tag; neither field
|
||||
// exposes a raw console identifier.
|
||||
struct PublicIdentity {
|
||||
std::array<std::uint8_t, 32> key{};
|
||||
std::array<std::uint8_t, 16> deviceTag{};
|
||||
};
|
||||
|
||||
struct SigningIdentity {
|
||||
PublicIdentity publicIdentity;
|
||||
std::array<std::uint8_t, 64> secretKey{};
|
||||
// Present only to keep validating pre-v3 console-HMAC files after migration.
|
||||
std::array<std::uint8_t, 32> legacyHmacKey{};
|
||||
};
|
||||
|
||||
struct Metadata {
|
||||
std::string title;
|
||||
std::string description;
|
||||
std::string authorName;
|
||||
std::string originalAuthorName;
|
||||
std::string lastEditorName;
|
||||
|
||||
// Creator identities, not file IDs. Exactly 16 uppercase hexadecimal chars.
|
||||
std::string authorFsid;
|
||||
std::string originalAuthorFsid;
|
||||
std::string lastEditorFsid;
|
||||
|
||||
// Present for v3 public-key-signed files. Zero values indicate a legacy
|
||||
// author record which cannot be retrospectively cryptographically bound.
|
||||
PublicIdentity authorIdentity;
|
||||
PublicIdentity originalAuthorIdentity;
|
||||
PublicIdentity lastEditorIdentity;
|
||||
|
||||
// File lineage IDs. parentId is empty only for an original Switchnote.
|
||||
std::string currentId;
|
||||
std::string rootId;
|
||||
std::string parentId;
|
||||
|
||||
std::uint64_t createdUnixSeconds = 0;
|
||||
std::uint64_t modifiedUnixSeconds = 0;
|
||||
std::uint32_t coverFrame = 0;
|
||||
std::uint8_t fps = 12;
|
||||
std::uint8_t speed = 0; // SPPM v3 DSi speed index (1..8); 0 means legacy fps
|
||||
bool locked = false;
|
||||
bool allowSpinoffs = true;
|
||||
bool bgmFollowsSpeed = true;
|
||||
bool loopPlayback = true;
|
||||
};
|
||||
|
||||
struct Document {
|
||||
Metadata metadata;
|
||||
Palette palette = defaultPalette();
|
||||
std::vector<Frame> frames;
|
||||
std::vector<AudioTrack> audioTracks;
|
||||
};
|
||||
|
||||
bool isValidFsid(std::string_view fsid);
|
||||
bool hasPublicIdentity(const PublicIdentity& identity);
|
||||
std::string deriveFsid(const PublicIdentity& identity);
|
||||
std::string identityFingerprint(const PublicIdentity& identity);
|
||||
std::array<std::uint8_t, 16> deriveDeviceTag(const std::vector<std::uint8_t>& deviceMaterial);
|
||||
std::array<std::uint8_t, 32> deriveDeviceWrapKey(const std::vector<std::uint8_t>& deviceMaterial,
|
||||
const std::array<std::uint8_t, 16>& salt);
|
||||
bool createSigningIdentity(const std::array<std::uint8_t, 16>& deviceTag,
|
||||
SigningIdentity& identity, std::string& error);
|
||||
bool sealSigningSecret(const SigningIdentity& identity,
|
||||
const std::array<std::uint8_t, 32>& wrapKey,
|
||||
const std::array<std::uint8_t, 24>& nonce,
|
||||
std::array<std::uint8_t, 128>& sealed, std::string& error);
|
||||
bool unsealSigningSecret(const std::array<std::uint8_t, 128>& sealed,
|
||||
const std::array<std::uint8_t, 32>& wrapKey,
|
||||
const std::array<std::uint8_t, 24>& nonce,
|
||||
SigningIdentity& identity, std::string& error);
|
||||
|
||||
// Domain-separated 64-bit ID helper used for non-identity note and lineage IDs.
|
||||
// Creator FSIDs are instead derived from PublicIdentity.
|
||||
std::string deriveFsid(const std::array<std::uint8_t, 32>& secret,
|
||||
const std::array<std::uint8_t, 16>& nonce,
|
||||
std::string_view domain);
|
||||
|
||||
bool validate(const Document& document, std::string& error);
|
||||
double frameRate(const Metadata& metadata);
|
||||
bool serialize(const Document& document, std::vector<std::uint8_t>& bytes,
|
||||
std::string& error);
|
||||
bool deserialize(const std::vector<std::uint8_t>& bytes, Document& document,
|
||||
std::string& error);
|
||||
bool loadFile(const std::string& path, Document& document, std::string& error);
|
||||
bool saveFile(const std::string& path, const Document& document, std::string& error);
|
||||
// Console-local authenticated .sppm envelopes. Legacy v1 notes remain readable;
|
||||
// new saves include a 256-bit HMAC-SHA-256 footer verified with the local key.
|
||||
bool deserializeSigned(const std::vector<std::uint8_t>& bytes, Document& document,
|
||||
const std::array<std::uint8_t, 32>& signingKey,
|
||||
std::string& error);
|
||||
bool loadSignedFile(const std::string& path, Document& document,
|
||||
const std::array<std::uint8_t, 32>& signingKey,
|
||||
std::string& error);
|
||||
bool saveSignedFile(const std::string& path, const Document& document,
|
||||
const std::array<std::uint8_t, 32>& signingKey,
|
||||
std::string& error);
|
||||
// v3 is publicly verifiable: no console-local secret is needed to validate a
|
||||
// received file. It signs a domain-separated SHA-256 digest with Ed25519.
|
||||
bool savePublicSignedFile(const std::string& path, const Document& document,
|
||||
const SigningIdentity& identity, std::string& error);
|
||||
bool signMessage(const SigningIdentity& identity, const std::uint8_t* message,
|
||||
std::size_t messageSize, std::array<std::uint8_t, 64>& signature,
|
||||
std::string& error);
|
||||
|
||||
// Preserves the original author and root ID, while giving the fork a new
|
||||
// current ID, parent ID, author, creation time and editable state.
|
||||
bool createSpinoff(const Document& parent, std::string_view newAuthorName,
|
||||
std::string_view newAuthorFsid, std::string_view newCurrentId,
|
||||
std::uint64_t nowUnixSeconds, Document& child,
|
||||
std::string& error);
|
||||
|
||||
} // namespace sppm
|
||||
Reference in new issue
Block a user
