Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend: implement Silent Payments sending #284

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
<HintPath>..\..\packages\Microsoft.Extensions.Logging.Abstractions.1.0.2\lib\netstandard1.1\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
</Reference>
<Reference Include="NBitcoin">
<HintPath>..\..\packages\NBitcoin.6.0.17\lib\net461\NBitcoin.dll</HintPath>
<HintPath>..\..\packages\NBitcoin.7.0.13\lib\netstandard2.0\NBitcoin.dll</HintPath>
</Reference>
<Reference Include="System.Runtime">
<HintPath>..\..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll</HintPath>
Expand Down
2 changes: 2 additions & 0 deletions src/GWallet.Backend.Tests/GWallet.Backend.Tests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<Compile Include="Deserialization.fs" />
<Compile Include="ExceptionMarshalling.fs" />
<Compile Include="MetaMarshalling.fs" />
<Compile Include="SilentPayments.fs" />
<Compile Include="Program.fs" />
</ItemGroup>
<ItemGroup>
Expand All @@ -38,6 +39,7 @@
<ProjectReference Include="..\GWallet.Backend\GWallet.Backend.fsproj" />
</ItemGroup>
<ItemGroup>
<Content Include="data\send_and_receive_test_vectors.json" />
<EmbeddedResource Include="data\basicException.json" />
<EmbeddedResource Include="data\customFSharpException.json" />
<EmbeddedResource Include="data\realException.json" />
Expand Down
112 changes: 112 additions & 0 deletions src/GWallet.Backend.Tests/SilentPayments.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
namespace GWallet.Backend.Tests

open System.IO
open System.Reflection
open System.Text.Json

open NUnit.Framework
open NBitcoin

open GWallet.Backend.UtxoCoin


type private TestInput =
{
TxId: string
Vout: int
ScriptSig: string
TxInWitness: string
ScriptPubKey: string
PrivateKey: string
}
static member FromJsonElement(jsonElement: JsonElement) =
{
TxId = jsonElement.GetProperty("txid").GetString()
Vout = jsonElement.GetProperty("vout").GetInt32()
ScriptSig = jsonElement.GetProperty("scriptSig").GetString()
TxInWitness = jsonElement.GetProperty("txinwitness").GetString()
ScriptPubKey = jsonElement.GetProperty("prevout").GetProperty("scriptPubKey").GetProperty("hex").GetString()
PrivateKey = jsonElement.GetProperty("private_key").GetString()
}

[<TestFixture>]
type SilentPayments() =

let executingAssembly = Assembly.GetExecutingAssembly()
let binPath = executingAssembly.Location |> FileInfo
let projectDirPath = Path.Combine(binPath.Directory.FullName, "..", "..", "..")
let dataDir = Path.Combine(projectDirPath, "data") |> DirectoryInfo

[<Test>]
member __.``Test creating outputs using test vectors from BIP-352``() =
// https://github.com/bitcoin/bips/blob/master/bip-0352/send_and_receive_test_vectors.json

let testVectorsFileName = "send_and_receive_test_vectors.json"
let testVectorsJson = JsonDocument.Parse(File.ReadAllText(Path.Combine(dataDir.FullName, testVectorsFileName)))

for testCase in testVectorsJson.RootElement.EnumerateArray() do
let testCaseName = testCase.GetProperty("comment").GetString()
let sending = testCase.GetProperty("sending").[0]
let expectedOutputs =
sending.GetProperty("expected").GetProperty("outputs").EnumerateArray()
|> Seq.map (fun each -> each.EnumerateArray() |> Seq.toArray)
|> Seq.toArray
let given = sending.GetProperty "given"
let inputs = given.GetProperty("vin").EnumerateArray() |> Seq.map TestInput.FromJsonElement |> Seq.toList
let recipients =
given.GetProperty("recipients").EnumerateArray()
|> Seq.map (fun each -> each.GetString() |> SilentPaymentAddress.Decode)
|> Seq.toList

if expectedOutputs.Length > 1 || (expectedOutputs.Length = 1 && expectedOutputs.[0].Length > 1) || recipients.Length > 1 then
printfn "Skipping BIP-352 test case '%s'" testCaseName
else
printfn "Running BIP-352 test case '%s'" testCaseName

let expectedOutput = expectedOutputs.[0] |> Array.tryHead |> Option.map (fun elem -> elem.GetString())

let spInputs =
inputs
|> List.map (
fun input ->
let witness =
match input.TxInWitness with
| "" -> None
| hex ->
let stream = BitcoinStream(DataEncoders.Encoders.Hex.DecodeData hex)
Some <| WitScript.Load stream
let spInput =
SilentPayments.ConvertToSilentPaymentInput
(Script.FromHex input.ScriptPubKey)
(DataEncoders.Encoders.Hex.DecodeData input.ScriptSig)
witness
input, spInput)

let maybePrivateKeys, outpoints =
spInputs
|> List.choose
(fun (input, spInput) ->
let privKey = new Key(DataEncoders.Encoders.Hex.DecodeData input.PrivateKey)
let outPoint = OutPoint(uint256.Parse input.TxId, input.Vout)
match spInput with
| InputForSharedSecretDerivation(_pubKey) ->
let isTapRoot = (Script.FromHex input.ScriptPubKey).IsScriptType ScriptType.Taproot
Some (Some(privKey, isTapRoot), outPoint)
| InputJustForSpending ->
Some(None, outPoint)
| _ -> None)
|> List.unzip

let privateKeys = maybePrivateKeys |> List.choose id

match privateKeys, expectedOutput with
| [], None -> ()
| [], Some _ ->
Assert.Fail(sprintf "No inputs for shared secret derivation in test case '%s'" testCaseName)
| _, Some expectedOutputString ->
let output = SilentPayments.CreateOutput privateKeys outpoints recipients.[0]
let outputString = output.GetEncoded() |> DataEncoders.Encoders.Hex.EncodeData
Assert.AreEqual(expectedOutputString, outputString, sprintf "Failure in test case '%s'" testCaseName)
| _, None ->
Assert.Throws(fun () -> SilentPayments.CreateOutput privateKeys outpoints recipients.[0] |> ignore)
|> ignore
Loading
Loading