diff --git a/Sources/zkp/Surjection.swift b/Sources/zkp/Surjection.swift new file mode 100644 index 00000000..714c35bd --- /dev/null +++ b/Sources/zkp/Surjection.swift @@ -0,0 +1,208 @@ +// +// Surjection.swift +// GigaBitcoin/secp256k1.swift +// +// Copyright (c) 2023 GigaBitcoin LLC +// Distributed under the MIT software license +// +// See the accompanying file LICENSE for information +// + +import Foundation +import zkp_bindings + +// MARK: - secp256k1 + SurjectionProof + +public extension secp256k1 { + enum Surjection { + struct Proof { + let length = Int(32 * (1 + SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS)) + /// Total number of input asset tags + public let nInputs: Int + /// Bitmap of which input tags are used in the surjection proof + public let usedInputs: Data + /// Borromean signature: e0, scalars + public let rawRepresentation: Data + /// The index of the actual input that is secretly mapped to the output + public let inputIndex: Int + /// The ephemeral asset tag of the output + public let ephemeralOutputTag: Data + /// the blinding key of the output + public let blindingKey: [UInt8] + + /// Surjection proof initialization and generation functions + @usableFromInline init( + fixedInputTags: [secp256k1_fixed_asset_tag], + ephemeralInputTags: [secp256k1_generator], + inputBlindingKey: [UInt8] + ) throws { + var outSurjectionProof = secp256k1_surjectionproof() + var ephemeralOutputTag = secp256k1_generator() + var outputBlindingKey = [UInt8](repeating: 0, count: 64) + var outInputIndex = 0 + var fixedOutputTag = secp256k1_fixed_asset_tag() + var randomSeed: Int8 = 3 + var proofData = [UInt8](repeating: 0, count: length) + + guard secp256k1_surjectionproof_initialize( + secp256k1.Context.raw, + &outSurjectionProof, + &outInputIndex, + fixedInputTags, + fixedInputTags.count, + fixedInputTags.count, + &fixedOutputTag, + 100, + &randomSeed + ).boolValue, + secp256k1_surjectionproof_generate( + secp256k1.Context.raw, + &outSurjectionProof, + ephemeralInputTags, + ephemeralInputTags.count, + &ephemeralOutputTag, + outInputIndex, + inputBlindingKey, + &outputBlindingKey + ).boolValue else { + throw secp256k1Error.underlyingCryptoError + } + + secp256k1_swift_surjection_proof_parse(&proofData, outSurjectionProof) + + self.blindingKey = outputBlindingKey + self.nInputs = outSurjectionProof.n_inputs + self.inputIndex = outInputIndex + self.usedInputs = Data(outSurjectionProof.used_inputs) + self.rawRepresentation = Data(proofData) + self.ephemeralOutputTag = Data(ephemeralOutputTag.data) + } + + static func verify( + proof: inout secp256k1_surjectionproof, + ephemeralInputTags: [secp256k1_generator], + ephemeralOutputTag: inout secp256k1_generator + ) -> Bool { + secp256k1_surjectionproof_verify( + secp256k1.Context.raw, + &proof, + ephemeralInputTags, + ephemeralInputTags.count, + &ephemeralOutputTag + ).boolValue + } + } + } +} + +internal extension Data { + init(_ usedInputs: UsedInputsType) { + self = Data(Swift.withUnsafeBytes(of: usedInputs) { [UInt8]($0) }) + } + + init(_ ephemeralTag: EphemeralTagType) { + self = Data(Swift.withUnsafeBytes(of: ephemeralTag) { [UInt8]($0) }) + } +} + +typealias UsedInputsType = ( + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8 +) + +typealias EphemeralTagType = ( + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8, + UInt8 +) diff --git a/Sources/zkp_bindings/include/Utility.h b/Sources/zkp_bindings/include/secp256k1_swift.h similarity index 58% rename from Sources/zkp_bindings/include/Utility.h rename to Sources/zkp_bindings/include/secp256k1_swift.h index 20b98106..138bda94 100644 --- a/Sources/zkp_bindings/include/Utility.h +++ b/Sources/zkp_bindings/include/secp256k1_swift.h @@ -1,5 +1,5 @@ // -// Utility.h +// secp256k1_swift.h // GigaBitcoin/secp256k1.swift // // Copyright (c) 2021 GigaBitcoin LLC @@ -9,6 +9,7 @@ // #include "./secp256k1.h" +#include "./secp256k1_surjectionproof.h" /// Exposes secp256k1 memczero implementation to the bindings target /// @param s pointer to an array to be zero'd by the function @@ -21,3 +22,13 @@ void secp256k1_swift_memczero(void *s, size_t len, int flag); /// @param input a pointer to the data to be hashed /// @param len the length of the data to be hashed void secp256k1_swift_sha256(unsigned char *output, const unsigned char *input, size_t len); + +/// Parse a surjection proof +/// @param data Borromean signature: e0, scalars +/// @param proof data structure that holds a parsed surjection proof +void secp256k1_swift_surjection_proof_parse(const unsigned char *data, secp256k1_surjectionproof proof); + +/// Serialize a surjection proof +/// @param proof data structure that holds a parsed surjection proof +/// @param data Borromean signature: e0, scalars +void secp256k1_swift_surjection_proof_serialize(secp256k1_surjectionproof proof, const unsigned char *data); diff --git a/Sources/zkp_bindings/src/Utility.c b/Sources/zkp_bindings/src/Utility.c deleted file mode 100644 index 94d8c055..00000000 --- a/Sources/zkp_bindings/src/Utility.c +++ /dev/null @@ -1,31 +0,0 @@ -// -// Utility.c -// GigaBitcoin/secp256k1.swift -// -// Copyright (c) 2021 GigaBitcoin LLC -// Distributed under the MIT software license -// -// See the accompanying file LICENSE for information -// - -#include "../include/Utility.h" -#include "../src/hash_impl.h" - -/// Exposes secp256k1 memczero implementation to the bindings target -/// @param s pointer to an array to be zero'd by the function -/// @param len the length of the data to be zero'd -/// @param flag zero memory if flag == 1. Flag must be 0 or 1. Constant time. -void secp256k1_swift_memczero(void *s, size_t len, int flag) { - secp256k1_memczero(s, len, flag); -} - -/// Exposes secp256k1 SHA256 implementation to the bindings target -/// @param output pointer to an array to be filled by the function -/// @param input a pointer to the data to be hashed -/// @param len the length of the data to be hashed -void secp256k1_swift_sha256(unsigned char *output, const unsigned char *input, size_t len) { - secp256k1_sha256 hasher; - secp256k1_sha256_initialize(&hasher); - secp256k1_sha256_write(&hasher, input, len); - secp256k1_sha256_finalize(&hasher, output); -} diff --git a/Sources/zkp_bindings/src/secp256k1_swift.c b/Sources/zkp_bindings/src/secp256k1_swift.c new file mode 100644 index 00000000..55629031 --- /dev/null +++ b/Sources/zkp_bindings/src/secp256k1_swift.c @@ -0,0 +1,45 @@ +// +// secp256k1_swift.c +// GigaBitcoin/secp256k1.swift +// +// Copyright (c) 2021 GigaBitcoin LLC +// Distributed under the MIT software license +// +// See the accompanying file LICENSE for information +// + +#include "../include/secp256k1_swift.h" +#include "../src/hash_impl.h" + +/// Exposes secp256k1 memczero implementation to the bindings target +/// @param s pointer to an array to be zero'd by the function +/// @param len the length of the data to be zero'd +/// @param flag zero memory if flag == 1. Flag must be 0 or 1. Constant time. +void secp256k1_swift_memczero(void *s, size_t len, int flag) { + secp256k1_memczero(s, len, flag); +} + +/// Exposes secp256k1 SHA256 implementation to the bindings target +/// @param output pointer to an array to be filled by the function +/// @param input a pointer to the data to be hashed +/// @param len the length of the data to be hashed +void secp256k1_swift_sha256(unsigned char *output, const unsigned char *input, size_t len) { + secp256k1_sha256 hasher; + secp256k1_sha256_initialize(&hasher); + secp256k1_sha256_write(&hasher, input, len); + secp256k1_sha256_finalize(&hasher, output); +} + +/// Parse a surjection proof +/// @param data Borromean signature: e0, scalars +/// @param proof data structure that holds a parsed surjection proof +void secp256k1_swift_surjection_proof_parse(const unsigned char *data, secp256k1_surjectionproof proof) { + data = proof.data; +} + +/// Serialize a surjection proof +/// @param proof data structure that holds a parsed surjection proof +/// @param data Borromean signature: e0, scalars +void secp256k1_swift_surjection_proof_serialize(secp256k1_surjectionproof proof, const unsigned char *data) { + memcpy(proof.data, &data, sizeof data); +}