1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftCrypto open source project
//
// Copyright (c) 2019 Apple Inc. and the SwiftCrypto project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.md for the list of SwiftCrypto project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
#if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API
@_exported import CryptoKit
#else
@_implementationOnly import CCryptoBoringSSL
import Foundation
/// A context for performing mathematical operations on ArbitraryPrecisionIntegers over a finite field.
///
/// A common part of elliptic curve mathematics is to perform arithmetic operations over a finite field. These require
/// performing modular arithmetic, and cannot be processed in the same way as regular math on these integers.
///
/// Most operations we perform over finite fields are part of repeated, larger arithmetic operations, so this object also
/// manages the lifetime of a `BN_CTX`. While `BN_CTX` is a silly data type, it does still have the effect of caching existing
/// `BIGNUM`s, so it's not a terrible idea to use it here.
///
/// Annoyingly, because of the way we have implemented ArbitraryPrecisionInteger, we can't actually use these temporary bignums
/// ourselves.
@usableFromInline
class FiniteFieldArithmeticContext {
private var fieldSize: ArbitraryPrecisionInteger
private var bnCtx: OpaquePointer
@usableFromInline
init(fieldSize: ArbitraryPrecisionInteger) throws {
self.fieldSize = fieldSize
guard let bnCtx = CCryptoBoringSSL_BN_CTX_new() else {
throw CryptoKitError.internalBoringSSLError()
}
CCryptoBoringSSL_BN_CTX_start(bnCtx)
self.bnCtx = bnCtx
}
deinit {
CCryptoBoringSSL_BN_CTX_end(self.bnCtx)
CCryptoBoringSSL_BN_CTX_free(self.bnCtx)
}
}
// MARK: - Arithmetic operations
extension FiniteFieldArithmeticContext {
@usableFromInline
func square(_ input: ArbitraryPrecisionInteger) throws -> ArbitraryPrecisionInteger {
var output = ArbitraryPrecisionInteger()
let rc = input.withUnsafeBignumPointer { inputPointer in
self.fieldSize.withUnsafeBignumPointer { fieldSizePointer in
output.withUnsafeMutableBignumPointer { outputPointer in
CCryptoBoringSSL_BN_mod_sqr(outputPointer, inputPointer, fieldSizePointer, self.bnCtx)
}
}
}
guard rc == 1 else {
throw CryptoKitError.internalBoringSSLError()
}
return output
}
@usableFromInline
func multiply(_ x: ArbitraryPrecisionInteger, _ y: ArbitraryPrecisionInteger) throws -> ArbitraryPrecisionInteger {
var output = ArbitraryPrecisionInteger()
let rc = x.withUnsafeBignumPointer { xPointer in
y.withUnsafeBignumPointer { yPointer in
self.fieldSize.withUnsafeBignumPointer { fieldSizePointer in
output.withUnsafeMutableBignumPointer { outputPointer in
CCryptoBoringSSL_BN_mod_mul(outputPointer, xPointer, yPointer, fieldSizePointer, self.bnCtx)
}
}
}
}
guard rc == 1 else {
throw CryptoKitError.internalBoringSSLError()
}
return output
}
@usableFromInline
func add(_ x: ArbitraryPrecisionInteger, _ y: ArbitraryPrecisionInteger) throws -> ArbitraryPrecisionInteger {
var output = ArbitraryPrecisionInteger()
let rc = x.withUnsafeBignumPointer { xPointer in
y.withUnsafeBignumPointer { yPointer in
self.fieldSize.withUnsafeBignumPointer { fieldSizePointer in
output.withUnsafeMutableBignumPointer { outputPointer in
CCryptoBoringSSL_BN_mod_add(outputPointer, xPointer, yPointer, fieldSizePointer, self.bnCtx)
}
}
}
}
guard rc == 1 else {
throw CryptoKitError.internalBoringSSLError()
}
return output
}
@usableFromInline
func subtract(_ x: ArbitraryPrecisionInteger, from y: ArbitraryPrecisionInteger) throws -> ArbitraryPrecisionInteger {
var output = ArbitraryPrecisionInteger()
let rc = x.withUnsafeBignumPointer { xPointer in
y.withUnsafeBignumPointer { yPointer in
self.fieldSize.withUnsafeBignumPointer { fieldSizePointer in
output.withUnsafeMutableBignumPointer { outputPointer in
// Note the order of y and x.
CCryptoBoringSSL_BN_mod_sub(outputPointer, yPointer, xPointer, fieldSizePointer, self.bnCtx)
}
}
}
}
guard rc == 1 else {
throw CryptoKitError.internalBoringSSLError()
}
return output
}
@usableFromInline
func positiveSquareRoot(_ x: ArbitraryPrecisionInteger) throws -> ArbitraryPrecisionInteger {
let outputPointer = x.withUnsafeBignumPointer { xPointer in
self.fieldSize.withUnsafeBignumPointer { fieldSizePointer in
// We can't pass a pointer in as BN_mod_sqrt may attempt to free it.
CCryptoBoringSSL_BN_mod_sqrt(nil, xPointer, fieldSizePointer, self.bnCtx)
}
}
guard let actualOutputPointer = outputPointer else {
throw CryptoKitError.internalBoringSSLError()
}
// Ok, we own this pointer now.
defer {
CCryptoBoringSSL_BN_free(outputPointer)
}
return try ArbitraryPrecisionInteger(copying: actualOutputPointer)
}
}
#endif // CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API
|