Files
2026-09-13 12:15:36 -07:00

104 lines
3.7 KiB
Swift

//
// BigUIntPaddingTests.swift
// PortalKitTests
//
// Verification of BigUInt 256-byte padding, truncation, and hex conversion edge cases.
//
import XCTest
@testable import PortalKit
final class BigUIntPaddingTests: XCTestCase {
func testZeroPaddingTo256Bytes() {
let zero = BigUInt(0)
let padded = zero.toPadded256Data()
XCTAssertEqual(padded.count, 256, "Zero must produce exactly 256 bytes")
XCTAssertEqual(padded, Data(repeating: 0, count: 256))
}
func testSmallNumberPadding() {
let one = BigUInt(1)
let padded = one.toPadded256Data()
XCTAssertEqual(padded.count, 256)
XCTAssertEqual(padded.prefix(255), Data(repeating: 0, count: 255))
XCTAssertEqual(padded.last, 1)
let value = BigUInt(0x12345678)
let paddedValue = value.toPadded256Data()
XCTAssertEqual(paddedValue.count, 256)
XCTAssertEqual(paddedValue.suffix(4), Data([0x12, 0x34, 0x56, 0x78]))
}
func testExact256ByteValue() {
// Portal TV 2048-bit prime N is exactly 256 bytes
let N = PortalSrpClient.N
let paddedN = N.toPadded256Data()
XCTAssertEqual(paddedN.count, 256)
XCTAssertEqual(paddedN.first, 0xFF)
XCTAssertEqual(paddedN.last, 0xFF)
// Raw serialize count for 2048-bit N starting with 0xFF is 256 bytes
XCTAssertEqual(N.serialize().count, 256)
XCTAssertEqual(paddedN, N.serialize())
}
func testVariableLengthPadding() {
let val = BigUInt(0xAABB)
// Pad to 4 bytes: 00 00 AA BB
let p4 = val.toPaddedData(byteCount: 4)
XCTAssertEqual(p4, Data([0x00, 0x00, 0xAA, 0xBB]))
// Pad to 2 bytes: AA BB
let p2 = val.toPaddedData(byteCount: 2)
XCTAssertEqual(p2, Data([0xAA, 0xBB]))
// Truncate to 1 byte: BB (suffix)
let p1 = val.toPaddedData(byteCount: 1)
XCTAssertEqual(p1, Data([0xBB]))
}
func testHexConversionEdgeCases() {
// Empty data
XCTAssertEqual(SrpFormat.bytesToHex(Data()), "")
XCTAssertEqual(SrpFormat.hexToBytes(""), Data())
// Leading zero single byte
XCTAssertEqual(SrpFormat.bytesToHex(Data([0x05])), "05")
XCTAssertEqual(SrpFormat.hexToBytes("05"), Data([0x05]))
// High nybble / low nybble
XCTAssertEqual(SrpFormat.bytesToHex(Data([0xF0, 0x0F])), "f00f")
XCTAssertEqual(SrpFormat.hexToBytes("f00f"), Data([0xF0, 0x0F]))
XCTAssertEqual(SrpFormat.hexToBytes("F00F"), Data([0xF0, 0x0F])) // case insensitive
// Whitespace and newline tolerance
let spacedHex = " f0 0f \n 12\t 34 \r\n"
XCTAssertEqual(SrpFormat.hexToBytes(spacedHex), Data([0xF0, 0x0F, 0x12, 0x34]))
// Invalid: odd length
XCTAssertNil(SrpFormat.hexToBytes("123"))
XCTAssertNil(SrpFormat.hexToBytes("f"))
// Invalid: non-hex characters
XCTAssertNil(SrpFormat.hexToBytes("123g"))
XCTAssertNil(SrpFormat.hexToBytes("zz"))
XCTAssertNil(SrpFormat.hexToBytes("!!"))
}
func testConstantTimeEqualsEdgeCases() {
let a = Data([0x01, 0x02, 0x03, 0x04])
let b = Data([0x01, 0x02, 0x03, 0x04])
let diffStart = Data([0xFF, 0x02, 0x03, 0x04])
let diffMid = Data([0x01, 0xFF, 0x03, 0x04])
let diffEnd = Data([0x01, 0x02, 0x03, 0xFF])
let diffLength = Data([0x01, 0x02, 0x03])
XCTAssertTrue(SrpFormat.constantTimeEquals(a, b))
XCTAssertTrue(SrpFormat.constantTimeEquals(Data(), Data()))
XCTAssertFalse(SrpFormat.constantTimeEquals(a, diffStart))
XCTAssertFalse(SrpFormat.constantTimeEquals(a, diffMid))
XCTAssertFalse(SrpFormat.constantTimeEquals(a, diffEnd))
XCTAssertFalse(SrpFormat.constantTimeEquals(a, diffLength))
}
}