From 0615ffa131d9bfa0d2da937b390860fb9da516fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20A=2EP?= <53834183+Jossec101@users.noreply.github.com> Date: Thu, 12 Jan 2023 14:27:36 +0100 Subject: [PATCH] Delete signer directory --- .../FundsManagerSigner.Tests/FunctionTest.cs | 175 -------------- signer/FundsManagerSigner/Function.cs | 221 ------------------ 2 files changed, 396 deletions(-) delete mode 100644 signer/FundsManagerSigner.Tests/FunctionTest.cs delete mode 100644 signer/FundsManagerSigner/Function.cs diff --git a/signer/FundsManagerSigner.Tests/FunctionTest.cs b/signer/FundsManagerSigner.Tests/FunctionTest.cs deleted file mode 100644 index ecaa85b0..00000000 --- a/signer/FundsManagerSigner.Tests/FunctionTest.cs +++ /dev/null @@ -1,175 +0,0 @@ -using System.Text.Json; -using Amazon.Lambda.APIGatewayEvents; -using Xunit; -using Amazon.Lambda.Core; -using Amazon.Lambda.TestUtilities; -using FluentAssertions; -using NBitcoin; - -namespace FundsManagerSigner.Tests; - -public class FunctionTest : IDisposable -{ - /// - /// Aux method that sets the env vars for tests - /// - /// - public FunctionTest() - { - var config = new SignPSBTConfig - { - AwsKmsKeyId = "mrk-cec3e3ef59bc4616a6f44da60bfea0ba", - EncryptedSeedphrase = - "AQICAHheBtxW+2iTBvvhvmRXaxaScHh6up1/VWCRSMlopexrdwE1C/ylXBL5pmjJ3P/UG7XnAAABBzCCAQMGCSqGSIb3DQEHBqCB9TCB8gIBADCB7AYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAxPlkxPX65p7aRcXykCARCAgb4En2Bb/nWQ6m4i3JDP+KGjaGDAVF4LR6+2Ljl7orp6pfZbCCxK6e89OBpJWi7elQM670vD/SWkYSZ9MUWUshU8n7NyBJZuZgBhtaH6j6yDhgHtBv7cwJngv0d72QEaTrH2YqLCVuoddEKEpB13ezfkf56230QD134kcJze4fITQGA6sXxQ0x+WjKOeYltpB+Shk4+kaNja42ZM0MMjyrMOmQtXCkgdoTUVi6twiqU+qr8mQEEq0aNdZzlLCI/v" - }; - var configJSon = JsonSerializer.Serialize(config); - Environment.SetEnvironmentVariable("ed0210c8", configJSon); - } - - public void Dispose() - { - Environment.SetEnvironmentVariable("ed0210c8", null); - } - - [Fact] - public async Task SignTest() - { - //Arrange - var function = new Function(); - var context = new TestLambdaContext(); - - //Test PSBT with 1 partial sig on input 0 - //JSON - //{ "Psbt":"cHNidP8BAF4BAAAAAWAvqvtTSjdcNjNuK8YKWQg7RM1S8LFDdIXg3KU34l6/AQAAAAD/////AYSRNXcAAAAAIgAguNLINpkV//IIFd1ti2ig15\u002B6mPOhNWykV0mwsneO9FcAAAAATwEENYfPAy8RJCyAAAAB/DvuQjoBjOttImoGYyiO0Pte4PqdeQqzcNAw4Ecw5sgDgI4uHNSCvdBxlpQ8WoEz0WmvhgIra7A4F3FkTsB0RNcQH8zk3jAAAIABAACAAQAAgE8BBDWHzwNWrAP0gAAAAfkIrkpmsP\u002BhqxS1WvDOSPKnAiXLkBCQLWkBr5C5Po\u002BBAlGvFeBbuLfqwYlbP19H/\u002B/s2DIaAu8iKY\u002BJ0KIDffBgEGDzoLMwAACAAQAAgAEAAIBPAQQ1h88DfblGjYAAAAH1InDHaHo6\u002BzUe9PG5owwQ87bTkhcGg66pSIwTmhHJmAMiI4UjOOpn\u002B/2Nw1KrJiXnmid2RiEja/HAITCQ00ienxDtAhDIMAAAgAEAAIABAACAAAEBKwCUNXcAAAAAIgAgs1MYpDJWIIGz/LeRwb5D/c1wgjKmSotvf8QyY3nsEMQiAgLYVMVgz\u002BbATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssUcwRAIgKsJYoVeZWSHLhJIIELCGqDZXBWF2JcYFgYUbTSg31gYCIAbh5LXC9mmOKmqjB3kW3rgBbHrht4B3Vz5jDXmrS\u002Bn7AgEDBAIAAAABBWlSIQLYVMVgz\u002BbATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssSEDAmf/CxGXSG9xiPljcG/e5CXFnnukFn0pJ64Q9U2aNL8hAxpTd/JawX43QWk3yFK6wOPpsRK931hHnT2R2BYwsouPU64iBgLYVMVgz\u002BbATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssRgfzOTeMAAAgAEAAIABAACAAAAAAAAAAAAiBgMCZ/8LEZdIb3GI\u002BWNwb97kJcWee6QWfSknrhD1TZo0vxhg86CzMAAAgAEAAIABAACAAAAAAAAAAAAiBgMaU3fyWsF\u002BN0FpN8hSusDj6bESvd9YR509kdgWMLKLjxjtAhDIMAAAgAEAAIABAACAAAAAAAAAAAAAAA==","Fingerprint":"ed0210c8","AccountDerivationPath":"m/48\u0027/1\u0027/1\u0027","AddressDerivationPath":"0/0","EnforcedSighash":1,"Network":"Regtest","AwsKmsKeyId":"mrk-cec3e3ef59bc4616a6f44da60bfea0ba"} - var input = new SignPSBTRequest( - "cHNidP8BAF4BAAAAAWAvqvtTSjdcNjNuK8YKWQg7RM1S8LFDdIXg3KU34l6/AQAAAAD/////AYSRNXcAAAAAIgAguNLINpkV//IIFd1ti2ig15+6mPOhNWykV0mwsneO9FcAAAAATwEENYfPAy8RJCyAAAAB/DvuQjoBjOttImoGYyiO0Pte4PqdeQqzcNAw4Ecw5sgDgI4uHNSCvdBxlpQ8WoEz0WmvhgIra7A4F3FkTsB0RNcQH8zk3jAAAIABAACAAQAAgE8BBDWHzwNWrAP0gAAAAfkIrkpmsP+hqxS1WvDOSPKnAiXLkBCQLWkBr5C5Po+BAlGvFeBbuLfqwYlbP19H/+/s2DIaAu8iKY+J0KIDffBgEGDzoLMwAACAAQAAgAEAAIBPAQQ1h88DfblGjYAAAAH1InDHaHo6+zUe9PG5owwQ87bTkhcGg66pSIwTmhHJmAMiI4UjOOpn+/2Nw1KrJiXnmid2RiEja/HAITCQ00ienxDtAhDIMAAAgAEAAIABAACAAAEBKwCUNXcAAAAAIgAgs1MYpDJWIIGz/LeRwb5D/c1wgjKmSotvf8QyY3nsEMQiAgLYVMVgz+bATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssUcwRAIgKsJYoVeZWSHLhJIIELCGqDZXBWF2JcYFgYUbTSg31gYCIAbh5LXC9mmOKmqjB3kW3rgBbHrht4B3Vz5jDXmrS+n7AgEDBAIAAAABBWlSIQLYVMVgz+bATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssSEDAmf/CxGXSG9xiPljcG/e5CXFnnukFn0pJ64Q9U2aNL8hAxpTd/JawX43QWk3yFK6wOPpsRK931hHnT2R2BYwsouPU64iBgLYVMVgz+bATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssRgfzOTeMAAAgAEAAIABAACAAAAAAAAAAAAiBgMCZ/8LEZdIb3GI+WNwb97kJcWee6QWfSknrhD1TZo0vxhg86CzMAAAgAEAAIABAACAAAAAAAAAAAAiBgMaU3fyWsF+N0FpN8hSusDj6bESvd9YR509kdgWMLKLjxjtAhDIMAAAgAEAAIABAACAAAAAAAAAAAAAAA==", - SigHash.All, - "Regtest"); - - var initialPSBT = PSBT.Parse(input.Psbt, Network.RegTest); - - var inputJson = JsonSerializer.Serialize(input); - - var request = new APIGatewayHttpApiV2ProxyRequest - { - Body = inputJson - }; - //Act - var result = await function.FunctionHandler(request, context); - - var responseBody = JsonSerializer.Deserialize(result.Body); - - var parsedPSBT = PSBT.Parse(responseBody.Psbt ?? throw new InvalidOperationException(), Network.RegTest); - - //Assert - responseBody.Should().NotBeNull(); - parsedPSBT.Inputs.All(x => x.PartialSigs.Count > initialPSBT.Inputs[(int) x.Index].PartialSigs.Count).Should().BeTrue(); - parsedPSBT.Inputs.All(x => x.SighashType == input.EnforcedSighash).Should().BeTrue(); - } - - [Fact] - public async Task FailedSignTest_InvalidDerivationPath() - { - //Arrange - var function = new Function(); - var context = new TestLambdaContext(); - - //Test PSBT with 1 partial sig on input 0 - //JSON - //{ "Psbt":"cHNidP8BAF4BAAAAAWAvqvtTSjdcNjNuK8YKWQg7RM1S8LFDdIXg3KU34l6/AQAAAAD/////AYSRNXcAAAAAIgAguNLINpkV//IIFd1ti2ig15\u002B6mPOhNWykV0mwsneO9FcAAAAATwEENYfPAy8RJCyAAAAB/DvuQjoBjOttImoGYyiO0Pte4PqdeQqzcNAw4Ecw5sgDgI4uHNSCvdBxlpQ8WoEz0WmvhgIra7A4F3FkTsB0RNcQH8zk3jAAAIABAACAAQAAgE8BBDWHzwNWrAP0gAAAAfkIrkpmsP\u002BhqxS1WvDOSPKnAiXLkBCQLWkBr5C5Po\u002BBAlGvFeBbuLfqwYlbP19H/\u002B/s2DIaAu8iKY\u002BJ0KIDffBgEGDzoLMwAACAAQAAgAEAAIBPAQQ1h88DfblGjYAAAAH1InDHaHo6\u002BzUe9PG5owwQ87bTkhcGg66pSIwTmhHJmAMiI4UjOOpn\u002B/2Nw1KrJiXnmid2RiEja/HAITCQ00ienxDtAhDIMAAAgAEAAIABAACAAAEBKwCUNXcAAAAAIgAgs1MYpDJWIIGz/LeRwb5D/c1wgjKmSotvf8QyY3nsEMQiAgLYVMVgz\u002BbATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssUcwRAIgKsJYoVeZWSHLhJIIELCGqDZXBWF2JcYFgYUbTSg31gYCIAbh5LXC9mmOKmqjB3kW3rgBbHrht4B3Vz5jDXmrS\u002Bn7AgEDBAIAAAABBWlSIQLYVMVgz\u002BbATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssSEDAmf/CxGXSG9xiPljcG/e5CXFnnukFn0pJ64Q9U2aNL8hAxpTd/JawX43QWk3yFK6wOPpsRK931hHnT2R2BYwsouPU64iBgLYVMVgz\u002BbATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssRgfzOTeMAAAgAEAAIABAACAAAAAAAAAAAAiBgMCZ/8LEZdIb3GI\u002BWNwb97kJcWee6QWfSknrhD1TZo0vxhg86CzMAAAgAEAAIABAACAAAAAAAAAAAAiBgMaU3fyWsF\u002BN0FpN8hSusDj6bESvd9YR509kdgWMLKLjxjtAhDIMAAAgAEAAIABAACAAAAAAAAAAAAAAA==","Fingerprint":"ed0210c8","AccountDerivationPath":"m/48\u0027/1\u0027/1\u0027","AddressDerivationPath":"0/0","EnforcedSighash":1,"Network":"Regtest","AwsKmsKeyId":"mrk-cec3e3ef59bc4616a6f44da60bfea0ba"} - var psbtBase64 = "cHNidP8BAF4BAAAAAWAvqvtTSjdcNjNuK8YKWQg7RM1S8LFDdIXg3KU34l6/AQAAAAD/////AYSRNXcAAAAAIgAguNLINpkV//IIFd1ti2ig15+6mPOhNWykV0mwsneO9FcAAAAATwEENYfPAy8RJCyAAAAB/DvuQjoBjOttImoGYyiO0Pte4PqdeQqzcNAw4Ecw5sgDgI4uHNSCvdBxlpQ8WoEz0WmvhgIra7A4F3FkTsB0RNcQH8zk3jAAAIABAACAAQAAgE8BBDWHzwNWrAP0gAAAAfkIrkpmsP+hqxS1WvDOSPKnAiXLkBCQLWkBr5C5Po+BAlGvFeBbuLfqwYlbP19H/+/s2DIaAu8iKY+J0KIDffBgEGDzoLMwAACAAQAAgAEAAIBPAQQ1h88DfblGjYAAAAH1InDHaHo6+zUe9PG5owwQ87bTkhcGg66pSIwTmhHJmAMiI4UjOOpn+/2Nw1KrJiXnmid2RiEja/HAITCQ00ienxDtAhDIMAAAgAEAAIABAACAAAEBKwCUNXcAAAAAIgAgs1MYpDJWIIGz/LeRwb5D/c1wgjKmSotvf8QyY3nsEMQiAgLYVMVgz+bATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssUcwRAIgKsJYoVeZWSHLhJIIELCGqDZXBWF2JcYFgYUbTSg31gYCIAbh5LXC9mmOKmqjB3kW3rgBbHrht4B3Vz5jDXmrS+n7AgEDBAIAAAABBWlSIQLYVMVgz+bATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssSEDAmf/CxGXSG9xiPljcG/e5CXFnnukFn0pJ64Q9U2aNL8hAxpTd/JawX43QWk3yFK6wOPpsRK931hHnT2R2BYwsouPU64iBgLYVMVgz+bATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssRgfzOTeMAAAgAEAAIABAACAAAAAAAAAAAAiBgMCZ/8LEZdIb3GI+WNwb97kJcWee6QWfSknrhD1TZo0vxhg86CzMAAAgAEAAIABAACAAAAAAAAAAAAiBgMaU3fyWsF+N0FpN8hSusDj6bESvd9YR509kdgWMLKLjxjtAhDIMAAAgAEAAIABAACAAAAAAAAAAAAAAA=="; - - var psbt = PSBT.Parse(psbtBase64, Network.RegTest); - - foreach (var psbtInput in psbt.Inputs) - { - var temp = psbtInput.HDKeyPaths; - psbtInput.HDKeyPaths.Clear(); ; - foreach (var rootedKeyPath in temp) - { - psbtInput.AddKeyPath(rootedKeyPath.Key, new RootedKeyPath(rootedKeyPath.Value.MasterFingerprint, new KeyPath("m/48'"))); - } - } - - var input = new SignPSBTRequest( - psbt.ToBase64(), - SigHash.All, - "Regtest"); - - var inputJson = JsonSerializer.Serialize(input); - - var request = new APIGatewayHttpApiV2ProxyRequest - { - Body = inputJson - }; - //Act - var result = await function.FunctionHandler(request, context); - - //Assert - result.StatusCode.Should().Be(500); - result.Body.Should().Contain("derivation"); - } - - [Fact] - public async Task FailedSignTest_NoAddedPartialSig() - { - //Arrange - var function = new Function(); - var context = new TestLambdaContext(); - - //Test PSBT with 1 partial sig on input 0 - //JSON - //{ "Psbt":"cHNidP8BAF4BAAAAAWAvqvtTSjdcNjNuK8YKWQg7RM1S8LFDdIXg3KU34l6/AQAAAAD/////AYSRNXcAAAAAIgAguNLINpkV//IIFd1ti2ig15\u002B6mPOhNWykV0mwsneO9FcAAAAATwEENYfPAy8RJCyAAAAB/DvuQjoBjOttImoGYyiO0Pte4PqdeQqzcNAw4Ecw5sgDgI4uHNSCvdBxlpQ8WoEz0WmvhgIra7A4F3FkTsB0RNcQH8zk3jAAAIABAACAAQAAgE8BBDWHzwNWrAP0gAAAAfkIrkpmsP\u002BhqxS1WvDOSPKnAiXLkBCQLWkBr5C5Po\u002BBAlGvFeBbuLfqwYlbP19H/\u002B/s2DIaAu8iKY\u002BJ0KIDffBgEGDzoLMwAACAAQAAgAEAAIBPAQQ1h88DfblGjYAAAAH1InDHaHo6\u002BzUe9PG5owwQ87bTkhcGg66pSIwTmhHJmAMiI4UjOOpn\u002B/2Nw1KrJiXnmid2RiEja/HAITCQ00ienxDtAhDIMAAAgAEAAIABAACAAAEBKwCUNXcAAAAAIgAgs1MYpDJWIIGz/LeRwb5D/c1wgjKmSotvf8QyY3nsEMQiAgLYVMVgz\u002BbATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssUcwRAIgKsJYoVeZWSHLhJIIELCGqDZXBWF2JcYFgYUbTSg31gYCIAbh5LXC9mmOKmqjB3kW3rgBbHrht4B3Vz5jDXmrS\u002Bn7AgEDBAIAAAABBWlSIQLYVMVgz\u002BbATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssSEDAmf/CxGXSG9xiPljcG/e5CXFnnukFn0pJ64Q9U2aNL8hAxpTd/JawX43QWk3yFK6wOPpsRK931hHnT2R2BYwsouPU64iBgLYVMVgz\u002BbATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssRgfzOTeMAAAgAEAAIABAACAAAAAAAAAAAAiBgMCZ/8LEZdIb3GI\u002BWNwb97kJcWee6QWfSknrhD1TZo0vxhg86CzMAAAgAEAAIABAACAAAAAAAAAAAAiBgMaU3fyWsF\u002BN0FpN8hSusDj6bESvd9YR509kdgWMLKLjxjtAhDIMAAAgAEAAIABAACAAAAAAAAAAAAAAA==","Fingerprint":"ed0210c8","AccountDerivationPath":"m/48\u0027/1\u0027/1\u0027","AddressDerivationPath":"0/0","EnforcedSighash":1,"Network":"Regtest","AwsKmsKeyId":"mrk-cec3e3ef59bc4616a6f44da60bfea0ba"} - var psbtBase64 = "cHNidP8BAF4BAAAAAWAvqvtTSjdcNjNuK8YKWQg7RM1S8LFDdIXg3KU34l6/AQAAAAD/////AYSRNXcAAAAAIgAguNLINpkV//IIFd1ti2ig15+6mPOhNWykV0mwsneO9FcAAAAATwEENYfPAy8RJCyAAAAB/DvuQjoBjOttImoGYyiO0Pte4PqdeQqzcNAw4Ecw5sgDgI4uHNSCvdBxlpQ8WoEz0WmvhgIra7A4F3FkTsB0RNcQH8zk3jAAAIABAACAAQAAgE8BBDWHzwNWrAP0gAAAAfkIrkpmsP+hqxS1WvDOSPKnAiXLkBCQLWkBr5C5Po+BAlGvFeBbuLfqwYlbP19H/+/s2DIaAu8iKY+J0KIDffBgEGDzoLMwAACAAQAAgAEAAIBPAQQ1h88DfblGjYAAAAH1InDHaHo6+zUe9PG5owwQ87bTkhcGg66pSIwTmhHJmAMiI4UjOOpn+/2Nw1KrJiXnmid2RiEja/HAITCQ00ienxDtAhDIMAAAgAEAAIABAACAAAEBKwCUNXcAAAAAIgAgs1MYpDJWIIGz/LeRwb5D/c1wgjKmSotvf8QyY3nsEMQiAgLYVMVgz+bATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssUcwRAIgKsJYoVeZWSHLhJIIELCGqDZXBWF2JcYFgYUbTSg31gYCIAbh5LXC9mmOKmqjB3kW3rgBbHrht4B3Vz5jDXmrS+n7AgEDBAIAAAABBWlSIQLYVMVgz+bATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssSEDAmf/CxGXSG9xiPljcG/e5CXFnnukFn0pJ64Q9U2aNL8hAxpTd/JawX43QWk3yFK6wOPpsRK931hHnT2R2BYwsouPU64iBgLYVMVgz+bATgvrRDQbanlASVXtiUwPt9yCgkQfv2kssRgfzOTeMAAAgAEAAIABAACAAAAAAAAAAAAiBgMCZ/8LEZdIb3GI+WNwb97kJcWee6QWfSknrhD1TZo0vxhg86CzMAAAgAEAAIABAACAAAAAAAAAAAAiBgMaU3fyWsF+N0FpN8hSusDj6bESvd9YR509kdgWMLKLjxjtAhDIMAAAgAEAAIABAACAAAAAAAAAAAAAAA=="; - - var psbt = PSBT.Parse(psbtBase64, Network.RegTest); - - foreach (var psbtInput in psbt.Inputs) - { - var temp = psbtInput.HDKeyPaths.ToList(); - psbtInput.HDKeyPaths.Clear(); ; - foreach (var rootedKeyPath in temp) - { - psbtInput.AddKeyPath(rootedKeyPath.Key, new RootedKeyPath(rootedKeyPath.Value.MasterFingerprint, new KeyPath("m/48'"))); - } - } - - var input = new SignPSBTRequest( - psbt.ToBase64(), - SigHash.All, - "Regtest"); - - var inputJson = JsonSerializer.Serialize(input); - - var request = new APIGatewayHttpApiV2ProxyRequest - { - Body = inputJson - }; - //Act - var result = await function.FunctionHandler(request, context); - - //Assert - result.StatusCode.Should().Be(500); - result.Body.Should().Contain("partial"); - } - - [Fact] - public async Task GenerateEncryptedSeedTest() - { - //Arrange - var function = new Function(); - var context = new TestLambdaContext(); - - var mnemonicString = - "middle teach digital prefer fiscal theory syrup enter crash muffin easily anxiety ill barely eagle swim volume consider dynamic unaware deputy middle into physical"; - - var keyId = "mrk-cec3e3ef59bc4616a6f44da60bfea0ba"; - //Act - var result = await function.EncryptSeedphrase(mnemonicString, keyId); - var base64Decoding = Convert.FromBase64String(result); - //Assert - result.Should().NotBeEmpty(); - - base64Decoding.Should().NotBeEmpty(); - } -} \ No newline at end of file diff --git a/signer/FundsManagerSigner/Function.cs b/signer/FundsManagerSigner/Function.cs deleted file mode 100644 index a199216f..00000000 --- a/signer/FundsManagerSigner/Function.cs +++ /dev/null @@ -1,221 +0,0 @@ -using System.Text; -using System.Text.Json; -using System.Text.Json.Serialization; -using Amazon.KeyManagementService; -using Amazon.KeyManagementService.Model; -using Amazon.Lambda.APIGatewayEvents; -using Amazon.Lambda.Core; -using Amazon.Lambda.Serialization.SystemTextJson; -using NBitcoin; - -[assembly: - LambdaSerializer(typeof(SourceGeneratorLambdaJsonSerializer))] - -namespace FundsManagerSigner; - -[JsonSerializable(typeof(APIGatewayHttpApiV2ProxyRequest))] -[JsonSerializable(typeof(APIGatewayHttpApiV2ProxyResponse))] -public partial class HttpApiJsonSerializerContext : JsonSerializerContext -{ -} - -/// -/// DTO used to deserialize the env var value which key is a master fingerprint of the PSBT -/// -public class SignPSBTConfig -{ - /// - /// Encrypted seed phrase - /// - public string EncryptedSeedphrase { get; set; } - - /// - /// AWS KMS Key Id used to decrypt the encrypted seedphrase - /// - public string AwsKmsKeyId { get; set; } -} - -public class Function -{ - /// - /// A lambda function that takes a psbt and signs it - /// - /// - /// - /// - public async Task FunctionHandler(APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context) - { - var response = new APIGatewayHttpApiV2ProxyResponse(); - - try - { - var requestBody = JsonSerializer.Deserialize(request.Body); - if (requestBody == null) throw new ArgumentNullException(nameof(requestBody), "Request body not found"); - - var kmsClient = new AmazonKeyManagementServiceClient(); - - var network = requestBody.Network.ToUpper() switch - { - "REGTEST" => Network.RegTest, - "MAINNET" => Network.Main, - "TESTNET" => Network.TestNet, - _ => throw new ArgumentException("Network not recognized") - }; - - var result = new SignPSBTResponse(null); - - if (PSBT.TryParse(requestBody.Psbt, network, out var parsedPSBT)) - { - foreach (var psbtInput in parsedPSBT.Inputs) - { - //We search for a fingerprint that can be used as a key for getting the config (env-var) - //Ideally, only fingerprints of the FundsManager signer wallet are set as env vars - var derivationPath = psbtInput.HDKeyPaths.Values.SingleOrDefault(x => - Environment.GetEnvironmentVariable($"MF_{x.MasterFingerprint.ToString()}") != null); - - if (derivationPath == null) - { - throw new ArgumentException( - "Invalid PSBT, the derivation path and the signing configuration cannot be found for none of the master fingerprints of all the pub keys", - nameof(derivationPath)); - } - - var inputPSBTMasterFingerPrint = derivationPath.MasterFingerprint; - - var masterFingerPrint = $"MF_{inputPSBTMasterFingerPrint}"; - var configJson = Environment.GetEnvironmentVariable(masterFingerPrint); - - var config = JsonSerializer.Deserialize(configJson); - - var decryptedSeed = await kmsClient.DecryptAsync(new DecryptRequest - { - CiphertextBlob = new MemoryStream(Convert.FromBase64String(config.EncryptedSeedphrase)), - EncryptionAlgorithm = EncryptionAlgorithmSpec.SYMMETRIC_DEFAULT, - KeyId = config.AwsKmsKeyId - }); - - if (decryptedSeed == null) - { - throw new ArgumentException("The seedphrase could not be decrypted / found", nameof(decryptedSeed)); - } - - var array = decryptedSeed.Plaintext.ToArray(); - - //The seedphrase words were originally splitted with @ instead of whitespaces due to AWS removing them on encryption - var seed = Encoding.UTF8.GetString(array).Replace("@", " "); - - var extKey = new Mnemonic(seed).DeriveExtKey(); - var bitcoinExtKey = extKey.GetWif(network); - - var fingerPrint = bitcoinExtKey.GetPublicKey().GetHDFingerPrint(); - - if (fingerPrint != inputPSBTMasterFingerPrint) - { - var mismatchingFingerprint = - $"The master fingerprint from the input does not match the master fingerprint from the encrypted seedphrase master fingerprint"; - - throw new ArgumentException(mismatchingFingerprint, nameof(fingerPrint)); - } - - var partialSigsCount = parsedPSBT.Inputs.Sum(x => x.PartialSigs.Count); - //We can enforce the sighash for all the inputs in the request in case the PSBT was not modified or serialized correctly. - if (requestBody.EnforcedSighash != null) - { - psbtInput.SighashType = requestBody.EnforcedSighash; - - Console.WriteLine($"Enforced sighash: {psbtInput.SighashType:G}"); - } - - var key = bitcoinExtKey - .Derive(derivationPath.KeyPath) - .PrivateKey; - psbtInput.Sign(key); - - //We check that the partial signatures number has changed, otherwise finalize inmediately - var partialSigsCountAfterSignature = - parsedPSBT.Inputs.Sum(x => x.PartialSigs.Count); - - if (partialSigsCountAfterSignature == 0 || - partialSigsCountAfterSignature <= partialSigsCount) - { - var invalidNoOfPartialSignatures = - $"Invalid expected number of partial signatures after signing the PSBT"; - - throw new ArgumentException( - invalidNoOfPartialSignatures); - } - - result = new SignPSBTResponse(parsedPSBT.ToBase64()); - - response = new APIGatewayHttpApiV2ProxyResponse() - { - Body = JsonSerializer.Serialize(result), - IsBase64Encoded = false, - StatusCode = 200 - }; - } - } - Console.WriteLine($"Signing request finished"); - } - catch (Exception e) - { - await Console.Error.WriteLineAsync(e.Message); - response = new APIGatewayHttpApiV2ProxyResponse - { - Body = e.Message, - IsBase64Encoded = false, - StatusCode = 500 - }; - } - - return response; - } - - /// - /// Aux method used to generate an encrypted seed, it is added for generating new ones with a unit test - /// - /// - /// - /// Base64 encrypted seedphrase - public async Task EncryptSeedphrase(string mnemonicString, string keyId) - { - if (string.IsNullOrWhiteSpace(mnemonicString)) - throw new ArgumentException("Value cannot be null or whitespace.", nameof(mnemonicString)); - if (string.IsNullOrWhiteSpace(keyId)) - throw new ArgumentException("Value cannot be null or whitespace.", nameof(keyId)); - - try - { - var mnemonic = new Mnemonic(mnemonicString); - } - catch (Exception e) - { - const string invalidMnemonicItContainsWhitespaces = "Invalid mnemonic"; - - await Console.Error.WriteLineAsync(invalidMnemonicItContainsWhitespaces); - - await Console.Error.WriteLineAsync(e.Message); - - throw; - } - - var kmsClient = new AmazonKeyManagementServiceClient(); - - //To avoid KMS removing whitespaces and dismantling the seedphrase - mnemonicString = mnemonicString.Replace(" ", "@"); - - var encryptedSeed = await kmsClient.EncryptAsync(new EncryptRequest - { - EncryptionAlgorithm = EncryptionAlgorithmSpec.SYMMETRIC_DEFAULT, - Plaintext = new MemoryStream(Encoding.UTF8.GetBytes(mnemonicString)), //UTF8 Encoding - KeyId = keyId - }); - - var encryptedSeedBase64 = Convert.ToBase64String(encryptedSeed.CiphertextBlob.ToArray()); - - return encryptedSeedBase64; - } -} - -public record SignPSBTRequest(string Psbt, SigHash? EnforcedSighash, string Network); -public record SignPSBTResponse(string? Psbt); \ No newline at end of file