diff --git a/Sources/TorusUtils/Helpers/LangrangeInterpolatePoly.swift b/Sources/TorusUtils/Helpers/LangrangeInterpolatePoly.swift index a284bc23..e9e29ee1 100644 --- a/Sources/TorusUtils/Helpers/LangrangeInterpolatePoly.swift +++ b/Sources/TorusUtils/Helpers/LangrangeInterpolatePoly.swift @@ -24,6 +24,67 @@ func modInverse(_ a: BigInt, _ m: BigInt) -> BigInt? { return t } +extension BigUInt { + /// Initializes an integer from the bits stored inside a piece of `Data`. + /// The data is assumed to be in network (big-endian) byte order. + public init(_ data: Data) { + // This assumes Word is binary. + precondition(Word.bitWidth % 8 == 0) + + self.init() + + let length = data.count + guard length > 0 else { return } + let bytesPerDigit = Word.bitWidth / 8 + var index = length / bytesPerDigit + var c = bytesPerDigit - length % bytesPerDigit + if c == bytesPerDigit { + c = 0 + index -= 1 + } + let word: Word = data.withUnsafeBytes { buffPtr in + var word: Word = 0 + let p = buffPtr.bindMemory(to: UInt8.self) + for byte in p { + word <<= 8 + word += Word(byte) + c += 1 + if c == bytesPerDigit { + self[bitAt: index] = (word != 0) + index -= 1 + c = 0 + word = 0 + } + } + return word + } + assert(c == 0 && word == 0 && index == -1) + } +} + +extension BigInt { + public init(_ data: Data) { + // This assumes Word is binary. + // This is the same assumption made when initializing BigUInt from Data + precondition(Word.bitWidth % 8 == 0) + + self.init() + + // Serialized data for a BigInt should contain at least 2 bytes: one representing + // the sign, and another for the non-zero magnitude. Zero is represented by an + // empty Data struct, and negative zero is not supported. + guard data.count > 1, let firstByte = data.first else { return } + + // The first byte gives the sign + // This byte is compared to a bitmask to allow additional functionality to be added + // to this byte in the future. + self.sign = firstByte & 0b1 == 0 ? .plus : .minus + + // The remaining bytes are read and stored as the magnitude + self.magnitude = BigUInt(data.dropFirst(1)) + } +} + func generatePrivateExcludingIndexes(shareIndexes: [BigInt]) throws -> BigInt { let key = BigInt(Data(hex: try SecretKey().serialize().addLeading0sForLength64())) if shareIndexes.contains(where: { $0 == key }) {