mirror of
https://github.com/Smaug123/dotnet-classical-ciphers
synced 2025-10-08 22:18:40 +00:00
Initial commit
This commit is contained in:
12
.config/dotnet-tools.json
Normal file
12
.config/dotnet-tools.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"fantomas": {
|
||||
"version": "5.2.0-alpha-008",
|
||||
"commands": [
|
||||
"fantomas"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
41
.editorconfig
Normal file
41
.editorconfig
Normal file
@@ -0,0 +1,41 @@
|
||||
root=true
|
||||
|
||||
[*]
|
||||
charset=utf-8
|
||||
end_of_line=crlf
|
||||
trim_trailing_whitespace=true
|
||||
insert_final_newline=true
|
||||
indent_style=space
|
||||
indent_size=4
|
||||
|
||||
# ReSharper properties
|
||||
resharper_xml_indent_size=2
|
||||
resharper_xml_max_line_length=100
|
||||
resharper_xml_tab_width=2
|
||||
|
||||
[*.{csproj,fsproj,sqlproj,targets,props,ts,tsx,css,json}]
|
||||
indent_style=space
|
||||
indent_size=2
|
||||
|
||||
[*.{fs,fsi}]
|
||||
fsharp_bar_before_discriminated_union_declaration=true
|
||||
fsharp_space_before_uppercase_invocation=true
|
||||
fsharp_space_before_class_constructor=true
|
||||
fsharp_space_before_member=true
|
||||
fsharp_space_before_colon=true
|
||||
fsharp_space_before_semicolon=true
|
||||
fsharp_multiline_block_brackets_on_same_column=true
|
||||
fsharp_newline_between_type_definition_and_members=true
|
||||
fsharp_align_function_signature_to_indentation=true
|
||||
fsharp_alternative_long_member_definitions=true
|
||||
fsharp_multi_line_lambda_closing_newline=true
|
||||
fsharp_experimental_keep_indent_in_branch=true
|
||||
fsharp_max_value_binding_width=80
|
||||
fsharp_max_record_width=0
|
||||
max_line_length=120
|
||||
end_of_line=lf
|
||||
|
||||
[*.{appxmanifest,build,dtd,nuspec,xaml,xamlx,xoml,xsd}]
|
||||
indent_style=space
|
||||
indent_size=2
|
||||
tab_width=2
|
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
* eol=auto
|
||||
*.sh text eol=lf
|
20
.github/dependabot.yml
vendored
Normal file
20
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "nuget"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
ignore:
|
||||
# Target the lowest version of FSharp.Core, for max compat
|
||||
- dependency-name: "FSharp.Core"
|
97
.github/workflows/dotnet.yaml
vendored
Normal file
97
.github/workflows/dotnet.yaml
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
name: .NET
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: true
|
||||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
|
||||
NUGET_XMLDOC_MODE: ''
|
||||
DOTNET_MULTILEVEL_LOOKUP: 0
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
- Release
|
||||
- Debug
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Build
|
||||
run: dotnet build --no-restore --configuration ${{matrix.config}}
|
||||
- name: Test
|
||||
run: dotnet test --no-build --verbosity normal --configuration ${{matrix.config}}
|
||||
|
||||
build-nix:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v18
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build
|
||||
|
||||
check-dotnet-format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v18
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Run Fantomas
|
||||
run: nix run .#fantomas -- -r --check .
|
||||
|
||||
check-nix-format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v18
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Run Alejandra
|
||||
run: nix develop --command alejandra --check .
|
||||
|
||||
linkcheck:
|
||||
name: Check links
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v18
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Run link checker
|
||||
run: nix develop --command markdown-link-check README.md
|
||||
|
||||
all-required-checks-complete:
|
||||
needs: [check-dotnet-format, check-nix-format, build, build-nix, linkcheck]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "All required checks complete."
|
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
bin/
|
||||
obj/
|
||||
/packages/
|
||||
riderModule.iml
|
||||
/_ReSharper.Caches/
|
||||
.idea/
|
||||
*.user
|
||||
*.DotSettings
|
||||
.DS_Store
|
||||
result
|
||||
.profile*
|
29
CipherSuite.Test/CipherSuite.Test.fsproj
Normal file
29
CipherSuite.Test/CipherSuite.Test.fsproj
Normal file
@@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="String.fs" />
|
||||
<Compile Include="Examples.fs" />
|
||||
<Compile Include="TestMonoalphabetic.fs" />
|
||||
<Compile Include="TestCaesar.fs" />
|
||||
<Compile Include="TestAffine.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FsUnit" Version="5.2.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.3.1" />
|
||||
<PackageReference Include="NUnit.Analyzers" Version="3.5.0" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CipherSuite\CipherSuite.fsproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
69
CipherSuite.Test/Examples.fs
Normal file
69
CipherSuite.Test/Examples.fs
Normal file
@@ -0,0 +1,69 @@
|
||||
namespace CipherSuite.Test
|
||||
|
||||
/// Examples from the 2022 National Cipher Challenge.
|
||||
[<RequireQualifiedAccess>]
|
||||
module Examples =
|
||||
|
||||
[<Literal>]
|
||||
let challenge1A =
|
||||
"""P DHZ OVWPUN P DVBSK MPUK FVB OLYL. DPAOVBA AOL VMMPJPHS ZBWWVYA VM IVZZ, PA PZ NVPUN AV IL OHYK AV AYHJR QVKPL KVDU HUK P HT NVPUN AV ULLK FVBY OLSW.
|
||||
|
||||
P ZAVSL AOL HAAHJOLK UVAL (UVA ZBYL AOLYL PZ H ILAALY DHF AV WBA AOHA NPCLU AOHA AOPZ VWLYHAPVU PZ ZAYPJASF VMM AOL IVVRZ) MYVT SFUU MYHUR'Z VMMPJL, HUK P AOPUR PA PZ MYVT QVKPL. AOL DVYK ULPNOIVBYOVVK ZBNNLZAZ PA DHZ DYPAALU IF H UHAPCL LUNSPZO ZWLHRLY YHAOLY AOHU HU HTLYPJHU, HUK PA PZ ZPNULK VMM JPMYHY HNHPU. P JHSSLK AOHA HU HSPIP ILMVYL, IBA THFIL UVT KL NBLYYL PZ TVYL HWWYVWYPHAL.
|
||||
|
||||
P ULLK APTL AV KLJPWOLY AOL YLWSF, IBA LCLU AOL WHWLY PA PZ DYPAALU VU PZ H JSBL. PA PZ AOL ZVYA FVB MPUK PU AOL MHUJF OVALSZ, ZV P DPSS ZAHYA SVVRPUN AOLYL. AOLF HYL UVA YLHSSF QVKPL'Z ZAFSL, IBA PM ZOL PZ MYLLSHUJPUN MVY IHURZ, ZOL DPSS DHUA AV NPCL AOL YPNOA PTWYLZZPVU. DOPJO NPCLZ TL HU PKLH. P AOPUR P DPSS AHRL H TBJO JSVZLY SVVR HA AOHA SLAALY.
|
||||
"""
|
||||
|
||||
[<Literal>]
|
||||
let challenge1B =
|
||||
"""WXTK FL YKTGD,
|
||||
|
||||
BM PTL ZKXTM FXXMBGZ RHN TGW B TF IEXTLXW MH TVVXIM MAX VHGMKTVM MH BGOXLMBZTMX MAX LMKTGZX VBKVNFLMTGVXL TM VNEIXIXK VHNGMR UTGD.
|
||||
|
||||
TL WBLVNLLXW, B PBEE GXXW YNEE TVVXLL MH MAX UTGD MKTGLTVMBHG KXVHKWL, MAX VNKKXGM TGW KXVXGM LMTYY YBEXL, TGW TGR LNKOXBEETGVX YHHMTZX MATM RHN VTG IKHOBWX, XBMAXK YKHF MAX UTGD, MAX LMKXXML HNMLBWX HK YKHF GXBZAUHNKAHHW LMHKXL.
|
||||
|
||||
B XQTFBGXW MAX UHQ MATM RHN YHNGW HG MAX YEHHK HY MAX OTNEM TGW GXXW MH VHKKXVM RHN HG HGX MABGZ. BM PTL GHM XFIMR. MAX BGLBWX HY MAX EBW ATW T LAXXM HY OXEENF ITIXK EBZAMER YBQXW MH BM TGW PAXG B KXFHOXW MATM B YHNGW GBGX VABGXLX VATKTVMXKL BGLVKBUXW BG T LJNTKX ITMMXKG HG MAX KXOXKLX. B MKTVXW MAXF HGMH MAX TMMTVAXW VHOXK LAXXM TGW PHNEW UX ZKTMXYNE BY RHN VHNEW TLD MAX UTGD HYYBVBTEL PAXMAXK MAXR KXVHZGBLX MAXF. BM BL IHLLBUEX MATM MAX ITIXK PTL ZENXW BG PAXG MAX UHQ PTL FTWX, BM PTL VXKMTBGER BGMXGWXW MH EHHD EBDX MATM, UNM ZBOXG MAX TULXGVX HY TGR HMAXK VENXL TM MABL IHBGM B MABGD BM BL PHKMA VAXVDBGZ BY MABL VHNEW ATOX TGR LBZGBYBVTGVX.
|
||||
|
||||
RHN VTG VHGMTVM FX TM MAX KV; B PBEE UX FHOBGZ MAXKX MABL TYMXKGHHG TGW MAXR TKX XQIXVMBGZ T VTEE YKHF RHN MH TKKTGZX MAX XQIXGLXL YTVBEBMR MATM RHN HYYXKXW.
|
||||
|
||||
B EHHD YHKPTKW MH RHNK KXIER.
|
||||
|
||||
CTWX VBYKTK"""
|
||||
|
||||
[<Literal>]
|
||||
let challenge2A =
|
||||
"K EWJWAQL NO NDWGQ PWLQ/POLKQ NO W ISKNQ WN W FKAF-GZWII FONQZ LOCJNOCJ. NFQ IODN OV TZWGQ OJZM W BWJU GOSZL WVVODL, WJL K GOSZLJ’N INWM NFQDQ EMIQZV, QXQJ KV K CWI OJ QHTQJIQI. K NFKJU KN COSZL FWXQ BQQJ NQETNKJA VWNQ WJMCWM. KV K GWJ VKJL POLKQ, K WE ISDQ IFQ GWJ VKJL EQ. IOEQNFKJA KJ FQD ZQNNQD NQZZI EQ IFQ WZDQWLM FWI. KJ WJM GWIQ, K LQGKLQL NO UQQT W ZOJA NWKZ OJ FQD, KV OJZM NO WXOKL ITOOUKJA WJMOJQ QZIQ CFO EKAFN BQ VOZZOCKJA FQD. K WE VOGSIKJA OJ KJNQDGQTNKJA FQD GOEEI CKNF ZMJJ VDWJU. NFQM WDQ INKZZ SIKJA VWKDZM ZKAFN QJGDMTNKOJ, WJL KN KI QWIKQD NO AQN WGGQII NO EI VDWJU’I OVVKGQ NFWJ KN COSZL BQ NO KJVKZNDWNQ POLKQ’I DOOE WN NFQ FONQZ. NFOIQ TZWGQI NWUQ NFQ IQGSDKNM OV NFQKD GZKQJNI QXQJ EODQ IQDKOSIZM NFWJ NFQ BWJUI. NFQ WNNWGFQL ZQNNQD IFOCI NFWN POLKQ KI AQNNKJA EODQ GWSNKOSI, BSN KN WZIO IQQEI NO BQ WJ KJXKNWNKOJ NO AQN KJXOZXQL. K WE JON ISDQ CFQDQ NO AO VDOE FQDQ. WI POLKQ IWMI KJ NFQ ZQNNQD, NFQ JSEBQDI KJ NFQ IKAJ-KJ BOOU ISAAQIN IOEQNFKJA OLL, BSN SJZKUQ POLKQ K COJ’N FWXQ WGGQII NO NFQ XWSZN NO GFQGU KN. KI IFQ FKJNKJA NFWN CQ IFOSZL NQWE ST, OD CWDJKJA EQ NFWN IFQ UJOCI K WE FQDQ WJL IFOSZL UQQT WCWM? (KV MOS WDQ JON ISDQ CFWN K WE NWZUKJA WBOSN, NWUQ W XQDM GWDQVSZ ZOOU WN MOSD LQGDMTN OV FQD ZQNNQD. MOS IFOSZL VKJL W FKLLQJ EQIIWAQ.) BM NFQ CWM, NFQDQ KI IOEQNFKJA JWAAKJA WN EQ NFWN K GWJ’N YSKNQ TZWGQ. NFQDQ KI W JWEQ KJ NFQ IKAJ-KJ BOOU NFWN, KJ EM FQWL WN ZQWIN, KI GOJJQGNQL KJ IOEQ CWM NO NFQ JWEQ OV NFQ BWJU, WJL K GWJ’N DQEQEBQD CFWN NFWN GOJJQGNKOJ KI. EWMBQ KN KI JON KETODNWJN, BSN K COJ’N IZQQT TDOTQDZM SJNKZ K GWJ VKASDQ KN OSN. OJGQ MOS FWXQ GDWGUQL POLKQ’I ZQNNQD, FQWL OXQD NO NFQ GWIQ VKZQI WJL NWUQ W ZOOU WN NFQ IKAJWNSDQI. EWMBQ MOS GWJ VKASDQ KN OSN VOD EQ. FWDDM"
|
||||
|
||||
[<Literal>]
|
||||
let challenge2B =
|
||||
"""GPFC JL YCFSR,
|
||||
|
||||
QBKP NBD QFG F HBBG VPPRPSG. UQFSR NBD YBC UQP LFYPUN GPKBLZU OBE FXXPLL CPXBCGL NBD LPSU, UQBDHQ XFS Z LDHHPLU UQFU ZS UQP YDUDCP VP DLP F QZHQPC APMPA BY LPXDCZUN? PMPS YFZCAN ZSPEKPCZPSXPG XCZJZSFAL XFS OP YFJZAZFC VZUQ UQPLP XZKQPCL, FSG VP GBS’U RSBV VQB JZHQU OP JBSZUBCZSH NBDC XBJJDSZXFUZBS XQFSSPAL.
|
||||
|
||||
FL KCBJZLPG, Z PEFJZSPG UQP MFDAU CPXBCGL ZS GPUFZA, FSG UQPN GB UPAA F LUBCN, UQBDHQ Z FJ SBU LDCP VQFU ZU JPFSL. UQPCP ZL F KFUUPCS ZS UQP SDJOPCL UQFU ZL MPCN LDHHPLUZMP FSG ZY NBD XFS PEKPGZUP JN CPTDPLU UB LKPSG LBJP UZJP FABSP ZS UQP MFDAU UQPS Z QBKP UB OP FOAP UB ZSMPLUZHFUP UQFU YDCUQPC.
|
||||
|
||||
CP-PEFJZSZSH UQP MFDAU XFJPCF YBBUFHP UQFU NBD LPSU, Z VFL LDCKCZLPG UB LPP UQFU XDAKPKPC QFL SB FXUDFA YBBUFHP BY UQP ABOON BC MFDAU ZULPAY. NBDC LPXDCZUN UPFJ PEKAFZSPG UQFU UQZL ZL F KCZMFXN KBAZXN UB PSLDCP XAZPSU XBSYZGPSUZFAZUN. ZU FALB LPPJL UB OP UQP XFLP UQFU VQZAP XDLUBJPCL LZHS ZS FSG BDU BY UQP MFDAU, OFSR LUFYY FCP SBU CPTDZCPG UB GB LB. UQPN UBAG JP UQFU LUFYY GB SBU ZS HPSPCFA PSUPC UQP ZSSPC XQFJOPC, FSG UQFU SB-BSP LQBDAG PSUPC UQP ABOON DSFXXBJKFSZPG VQZAP UQP MFDAU ZL DSABXRPG. UQP LUFYY LFN UQFU UQZL KCBUBXBA ZL UFRPS MPCN LPCZBDLAN; ZU ZL F LFXRFOAP BYYPSLP UB PSUPC UQP ABOON FABSP. UQPCP ZL BSP PEXPKUZBS. ZS BCGPC UB PSLDCP UQP LPXDCZUN BY UQP XBJOZSFUZBS UQFU BKPSL UQP MFDAU ZULPAY, UQP XQZPY UPAAPC PSUPCL UQP ABOON FABSP ZS UQP JBCSZSH UB BKPS DK. UQP QPFG BY LPXDCZUN VFZUL BDULZGP, UQPS XBSGDXUL F LPFCXQ BY UQP UPAAPC VQPS UQPN APFMP UQP MFDAU UB PSLDCP UQFU SBUQZSH QFL OPPS CPJBMPG. UQP YBBUFHP LQBVL UQP KFU GBVS ZS KCBHCPLL UQFU GFN, LB Z UQZSR ZU ZL YFZC UB GPGDXP UQFU ZY UQP UPAAPC QFG CPJBMPG FSNUQZSH YCBJ UQP LFYP UQPS ZU VBDAG QFMP OPPS GZLXBMPCPG FU UQP UZJP. UQFU JPFSL UQFU ZY FSNUQZSH VFL UFRPS YCBJ UQP OBE, UQPS ZU QFG FACPFGN OPPS CPJBMPG VQPS UQP UPAAPC FSG UQP LPXDCZUN HDFCG FCCZMPG.
|
||||
|
||||
CPHFCGZSH UQP KFKPC AZSZSH ZS UQP GPKBLZU OBE AZG: Z FLRPG UQP OFSR LUFYY FOBDU ZU FSG UQP XQZPY UPAAPC, VQB ZL F JFSGFCZS LKPFRPC, CPXBHSZLPG UQP XQFCFXUPCL FL UQP GZHZUL WPCB FSG BSP. LQP LDHHPLUPG UQFU UQP UQCPP AZSPL XBDAG GPSBUP UQP SDJOPCL YZMP, YBDC, UQCPP ZS OZSFCN, UQBDHQ BUQPC CPFGZSHL FCP KBLLZOAP. ZY UQPN VPCP VCZUUPS XAFLLZXFAAN, YBC PEFJKAP UB OP CPFG MPCUZXFAAN CZHQU UB APYU, UQPS UQPN XBDAG GPSBUP LZE, BSP, YZMP. Z VBSGPCPG ZY UQZL CPYPCCPG UB UQP OBE SDJOPC, FL UQPCP FCP LPMPS QDSGCPG FSG LZEUN-UQCPP OBEPL ZS UQP MFDAU, ODU UQP OBE ZULPAY VFL FKKFCPSUAN UFRPS YCBJ XFLLPUUP UVPSUN-UQCPP, LB DSAPLL ZU QFL OPPS KDU OFXR ZS UQP VCBSH KAFXP LBJP UZJP UQPS Z GBS’U UQZSR UQFU XFS OP ZU. KPCQFKL LBJPBSP FU UQP OFSR JZHQU QFMP FS ZGPF. APU JP RSBV VQPS NBD QFMP FCCFSHPG UQP MFDAU FXXPLL YBC JP.
|
||||
|
||||
NBDCL LZSXPCPAN,
|
||||
|
||||
IFGP XZYCFC"""
|
||||
|
||||
[<Literal>]
|
||||
let challenge3A =
|
||||
"RWLQM QAUIS QVOBP QADMZ GMIAG NWZUM PMZZM KMVBK IAMVW BMAEM ZMTMN BWVIV MVKZG XBMLC AJSMG IBBIK PMLBW PMZSM GKPIQ VQPIL BISMV BPMAC QBMWX XWAQB MIVLZ MDMZA MLBPM AXGPW TMQVU GLWWZ AWQKW CTLEI BKPPM ZUWDM UMVBA QBPWC OPBQP ILJMM VKIZM NCTJC BQAEM IZBPI BAPMO TIVKM LWDMZ IBUMI AAPMT WKSML BPMLW WZBWP MZZWW UBPMV APMEI TSMLI EIGLW EVBPM KWZZQ LWZTM IDQVO BPMSM GAQVB PMTWK SQEWV LMZML QNQAP WCTLK ITTWC BBWPM ZJCBX MZPIX AAPME IAKPM KSQVO BPIBQ EIAVW BBPMZ MJMNW ZMTMI DQVOB PMSMG AZIBP MZBPI VBZGQ VOBWU ISMAC ZMQEI ACVBQ TQKIV JMKMZ BIQVB PIBAP MQAZM IKPQV OWCBQ EQTTP IDMBW JMLQA KZMMB BPMMV KZGXB QWVWV BPMCA JQAMI AGBWJ ZMISC AQVOI AQUXT MSMGE WZLAC JABQB CBQWV QBKWV BIQVA RCABW VMNQT MEQBP VWBMA WVPMZ QVDMA BQOIB QWVIV LAPMP IAKPI VVMTT MLPMZ QVVMZ APMZT WKSMT QUQVI BQVOB PMQUX WAAQJ TMBWI ZZQDM IBBPM WVTGT WOQKI TKWVK TCAQW VQVAP WZBAW UMWVM PIAIA MKZMB IVLAW UMWVM MTAMB PMKPQ MNBMT TMZEI VBABW SVWEE PIBQB QABPM GBPQV SRWLQ MKIVI AAQAB IVLUI GJMRW LQMQA BZGQV OBWBM TTUMI JWCBQ BQLWV BSVWE QNBPI BQAJM KICAM APMBP QVSAA PMVMM LAUGP MTXQI UXZMB BGACZ MAPML WMAVB WZQNA PMBPQ VSAQV MMLBW SVWEI JWCBQ BJCBC VBQTE MKIVN QVLIE IGBWZ MMABI JTQAP BZCAB QBQAO WQVOB WJMLQ NNQKC TBBWN QVLWC BEPQK P"
|
||||
|
||||
[<Literal>]
|
||||
let challenge3B =
|
||||
"""ZBGOF BZ GQO RZIOFGRPWGRBZ
|
||||
GQO TQRON GOXXOE OZGOEOS GQO IWHXG WTTBYCWZROS AL GQO QOWS BN FOTHERGL GQO ZRPQG AONBEO GQO RZTRSOZG GB TQOTV GQWG GQO SOCBFRG ABKOF JOEO FOTHEO WZS GB XBTV GQO IWHXG SBBE. WXX JWF RZ BESOE WG GQWG FGWPO.
|
||||
|
||||
GQO FOTHERGL NBBGWPO FQBJF GQWG ZB-BZO WZS ZBGQRZP XONG GQO IWHXG BIOEZRPQG. GQO TWYOEWF JOEO YBZRGBEOS XRIO NEBY W EOYBGO XBTWGRBZ, WZS R QWIO EOIROJOS GQO NBBGWPO YLFOXN.
|
||||
|
||||
WNGOE GQO GOXXOE XONG GQO IWHXG GB EWRFO GQO WXWEY, FQO WZS GQO FOTHERGL PHWES JOEO BZ TWYOEW HZGRX WSSRGRBZWX FOTHERGL WEERIOS WZS ZORGQOE BN GQOY QWS WZLGQRZP RZ GQORE CBFFOFFRBZ GQWG GQOL TBHXS ZBG WTTBHZG NBE.
|
||||
|
||||
GQO SOCBFRG ABKOF WEO WXX OYCGL, OKTOCG GQWG GQOL OWTQ TBZGWRZ W CWCOE XRZRZP RZ GQO XRS YWEVOS JRGQ ZRZO TQRZOFO TQWEWTGOEF EOCEOFOZGRZP GQO SRPRGF BZO WZS MOEB, FBYO JRGQ GQO PERS RZFRSO WZ BHGXRZO WZS FBYO JRGQBHG. GQO YWEVRZPF WEO HZRDHO GB OWTQ ABK.
|
||||
|
||||
TBZTXHFRBZ: GQO AWZV IWHXG JWF FOTHEO HZGRX BCOZOS RZ GQO YBEZRZP WZS ZBGQRZP JWF EOYBIOS RZ GQWG COERBS, FB JO TWZ EHXO BHG GQONG WF W YBGRIO NBE GQO AEOWV RZ. GQO BZXL COEFBZ JQB TBHXS QWIO SRFGHEAOS GQO IWHXG TBZGOZGF JWF GQO TQRON GOXXOE, AHG FQO ZBG BZXL NWRXOS GB TBZTOWX GQO SRFGHEAWZTO, FQO WXFB ZBGRNROS FOTHERGL WABHG RG. TXOWEXL, FQO JWZGOS WZ RZIOFGRPWGRBZ, AHG SRS ZBG JWZG GQO CBXRTO RZIBXIOS. R JWF AEBHPQG RZ WG PEOWG OKCOZFO OIOZ GQBHPQ THXCOCOE WXEOWSL OYCXBLF RGF BJZ FOTHERGL WZS RZIOFGRPWGRBZ GOWY JQRTQ QWF YWZL BN GQO FWYO FVRXXF WF R SB. GQOEO RF COEQWCF UHFG BZO GQRZP R TWZ SB AOGGOE GQWZ GQOY WZS GQWG RF GB AEOWV TBSOF WZS TRCQOEF. YWLAO GQWG RF JQL R WY QOEO. R AOXROIO GQWG GQO TQRON GOXXOE SOXRAOEWGOXL FGWPOS GQO AEOWV RZ GB QBBV YO, FB R TBHXS SRFTBIOE WZS AEOWV W TBSO QRSSOZ RZ GQO IWHXG. JQWG R SBZ’G LOG VZBJ RF, JQL?
|
||||
|
||||
R SBZ’G GEHFG GQO TQRON GOXXOE, GQBHPQ R SBZ’G VZBJ JQWG FQO RF HC GB, WZS R WY ZBG FHEO GQWG R TWZ GEHFG XLZZ NEWZV, AHG WFFHYRZP GQWG R WY ERPQG GQOL ZOOS YO YBEO GQWZ R ZOOS GQOY, FB R FQBHXS AO FWNO NBE ZBJ JQRXO R NBTHF BZ GQO THXCOCOE TBSO."""
|
13
CipherSuite.Test/String.fs
Normal file
13
CipherSuite.Test/String.fs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace CipherSuite.Test
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module String =
|
||||
|
||||
let stripNonAlpha (s : string) =
|
||||
s.ToCharArray ()
|
||||
|> Array.choose (fun c ->
|
||||
let c = System.Char.ToUpper c
|
||||
let shifted = int c - 65
|
||||
if shifted >= 0 && shifted < 26 then Some c else None
|
||||
)
|
||||
|> System.String
|
48
CipherSuite.Test/TestAffine.fs
Normal file
48
CipherSuite.Test/TestAffine.fs
Normal file
@@ -0,0 +1,48 @@
|
||||
namespace CipherSuite.Test
|
||||
|
||||
open NUnit.Framework
|
||||
open CipherSuite
|
||||
open FsUnitTyped
|
||||
|
||||
[<TestFixture>]
|
||||
module TestAffine =
|
||||
|
||||
[<Test>]
|
||||
let ``Examples, Challenge 1`` () =
|
||||
let key, plain, fitness = Affine.crack Examples.challenge1A
|
||||
|
||||
plain.StartsWith "I WAS HOPING I WOULD FIND YOU HERE" |> shouldEqual true
|
||||
|
||||
// Note: this is the inverse of the correct key
|
||||
key |> shouldEqual (1, 19)
|
||||
|
||||
let key, plain, fitness = Affine.crack Examples.challenge1B
|
||||
|
||||
plain.StartsWith "DEAR MS FRANK," |> shouldEqual true
|
||||
|
||||
key |> shouldEqual (1, 7)
|
||||
|
||||
[<Test>]
|
||||
let ``Examples, Challenge 2`` () =
|
||||
let key, plain, fitness = Affine.crack Examples.challenge2A
|
||||
|
||||
plain.StartsWith "I MANAGED TO TRACE JADE/JODIE TO A SUITE" |> shouldEqual true
|
||||
|
||||
// Note: this is the inverse of the correct key
|
||||
key |> shouldEqual (21, 6)
|
||||
|
||||
let key, plain, fitness = Affine.crack Examples.challenge2B
|
||||
|
||||
plain.StartsWith "DEAR MS FRANK," |> shouldEqual true
|
||||
|
||||
key |> shouldEqual (3, 11)
|
||||
|
||||
[<Test>]
|
||||
let ``Examples, Challenge 3`` () =
|
||||
let key, plain, fitness = Affine.crack Examples.challenge3A
|
||||
|
||||
plain.StartsWith "JODIE ISMAK INGTH ISVER YEASY FORME HERRE CENTC"
|
||||
|> shouldEqual true
|
||||
|
||||
// Note: this is the inverse of the correct key
|
||||
key |> shouldEqual (1, 18)
|
23
CipherSuite.Test/TestCaesar.fs
Normal file
23
CipherSuite.Test/TestCaesar.fs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace CipherSuite.Test
|
||||
|
||||
open NUnit.Framework
|
||||
open CipherSuite
|
||||
open FsUnitTyped
|
||||
|
||||
[<TestFixture>]
|
||||
module TestCaesar =
|
||||
|
||||
[<Test>]
|
||||
let ``Examples, Challenge 1`` () =
|
||||
let key, plain, fitness = Caesar.crack Examples.challenge1A
|
||||
|
||||
plain.StartsWith "I WAS HOPING I WOULD FIND YOU HERE" |> shouldEqual true
|
||||
|
||||
printfn "%f" fitness
|
||||
key |> shouldEqual 6
|
||||
|
||||
let key, plain, fitness = Caesar.crack Examples.challenge1B
|
||||
|
||||
plain.StartsWith "DEAR MS FRANK," |> shouldEqual true
|
||||
|
||||
key |> shouldEqual 18
|
17
CipherSuite.Test/TestMonoalphabetic.fs
Normal file
17
CipherSuite.Test/TestMonoalphabetic.fs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace CipherSuite.Test
|
||||
|
||||
open CipherSuite
|
||||
open NUnit.Framework
|
||||
open FsUnitTyped
|
||||
|
||||
[<TestFixture>]
|
||||
module TestMonoalphabetic =
|
||||
|
||||
[<Test>]
|
||||
let ``Challenge 1A`` () =
|
||||
let rand = System.Random 10
|
||||
|
||||
let key, _plain, _fitness =
|
||||
Monoalphabetic.crack rand 20000 (String.stripNonAlpha Examples.challenge1A)
|
||||
|
||||
key |> shouldEqual [| yield! [| 19..25 |] ; yield! [| 0..18 |] |]
|
22
CipherSuite.sln
Normal file
22
CipherSuite.sln
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "CipherSuite", "CipherSuite\CipherSuite.fsproj", "{2D7FFCCE-91B8-4EA0-9FA1-52D95AB88C2B}"
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "CipherSuite.Test", "CipherSuite.Test\CipherSuite.Test.fsproj", "{42EBED52-DFE2-4DAC-BE31-87DCA6EC69BD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{2D7FFCCE-91B8-4EA0-9FA1-52D95AB88C2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2D7FFCCE-91B8-4EA0-9FA1-52D95AB88C2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2D7FFCCE-91B8-4EA0-9FA1-52D95AB88C2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2D7FFCCE-91B8-4EA0-9FA1-52D95AB88C2B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{42EBED52-DFE2-4DAC-BE31-87DCA6EC69BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{42EBED52-DFE2-4DAC-BE31-87DCA6EC69BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{42EBED52-DFE2-4DAC-BE31-87DCA6EC69BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{42EBED52-DFE2-4DAC-BE31-87DCA6EC69BD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
59
CipherSuite/Affine.fs
Normal file
59
CipherSuite/Affine.fs
Normal file
@@ -0,0 +1,59 @@
|
||||
namespace CipherSuite
|
||||
|
||||
#if DEBUG
|
||||
#else
|
||||
#nowarn "9"
|
||||
#endif
|
||||
|
||||
open System.Text
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module Affine =
|
||||
|
||||
let private hcf (i : int) (j : int) =
|
||||
let rec go (bigger : int) (smaller : int) =
|
||||
if smaller = 0 then
|
||||
bigger
|
||||
else
|
||||
go smaller (bigger % smaller)
|
||||
|
||||
if i < 0 || j < 0 then
|
||||
failwithf "HCF only implemented for positive numbers, got %i %i" i j
|
||||
|
||||
go (max i j) (min i j)
|
||||
|
||||
/// multiplier must be coprime to 26.
|
||||
let encrypt (multiplier : int) (add : int) (s : string) : string =
|
||||
if hcf multiplier 26 <> 1 then
|
||||
failwithf "multiplier must be coprime to 26, got %i" multiplier
|
||||
|
||||
let sb = StringBuilder ()
|
||||
|
||||
for c in s do
|
||||
if 'A' <= c && c <= 'Z' then
|
||||
sb.Append (((int c - int 'A') * multiplier + add) % 26 + int 'A' |> char)
|
||||
elif 'a' <= c && c <= 'z' then
|
||||
sb.Append (((int c - int 'a') * multiplier + add) % 26 + int 'a' |> char)
|
||||
else
|
||||
sb.Append c
|
||||
|> ignore
|
||||
|
||||
sb.ToString ()
|
||||
|
||||
/// Returns the inverse of the correct key, because I'm lazy.
|
||||
let crack (s : string) =
|
||||
#if DEBUG
|
||||
let fitness = Fitness.fromEmbedded ()
|
||||
#else
|
||||
let arr = Fitness.allocate ()
|
||||
use ptr = fixed arr
|
||||
let fitness = Fitness.fromEmbedded ptr
|
||||
#endif
|
||||
seq {
|
||||
for mul in 1..2..25 do
|
||||
if mul <> 13 then
|
||||
for add in 0..25 do
|
||||
let encrypt = encrypt mul add s
|
||||
yield (mul, add), encrypt, Fitness.get encrypt fitness
|
||||
}
|
||||
|> Seq.maxBy (fun (_, _, fitness) -> fitness)
|
135
CipherSuite/Arr4D.fs
Normal file
135
CipherSuite/Arr4D.fs
Normal file
@@ -0,0 +1,135 @@
|
||||
namespace CipherSuite
|
||||
|
||||
#if DEBUG
|
||||
#else
|
||||
#nowarn "9"
|
||||
#endif
|
||||
|
||||
open Microsoft.FSharp.NativeInterop
|
||||
|
||||
[<Struct>]
|
||||
#if DEBUG
|
||||
type Arr4D<'a> =
|
||||
{
|
||||
Elements : 'a array
|
||||
Width : int
|
||||
WidthTimesHeight : int
|
||||
WidthTimesHeightTimesDepth : int
|
||||
}
|
||||
|
||||
member this.Depth = this.Elements.Length / this.WidthTimesHeightTimesDepth
|
||||
#else
|
||||
type Arr4D<'a when 'a : unmanaged> =
|
||||
{
|
||||
Elements : nativeptr<'a>
|
||||
Length : int
|
||||
Width : int
|
||||
WidthTimesHeight : int
|
||||
WidthTimesHeightTimesDepth : int
|
||||
}
|
||||
|
||||
member this.Depth = this.Length / this.WidthTimesHeightTimesDepth
|
||||
#endif
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module Arr4D =
|
||||
|
||||
/// It's faster to iterate forward over the first argument, `x`, and then the
|
||||
/// second argument, `y`, and then the third argument, `z`.
|
||||
let inline get (arr : Arr4D<'a>) (x : int) (y : int) (z : int) (i : int) : 'a =
|
||||
#if DEBUG
|
||||
arr.Elements.[i * arr.WidthTimesHeightTimesDepth
|
||||
+ z * arr.WidthTimesHeight
|
||||
+ y * arr.Width
|
||||
+ x]
|
||||
#else
|
||||
NativePtr.get
|
||||
arr.Elements
|
||||
(i * arr.WidthTimesHeightTimesDepth
|
||||
+ z * arr.WidthTimesHeight
|
||||
+ y * arr.Width
|
||||
+ x)
|
||||
#endif
|
||||
|
||||
let inline set (arr : Arr4D<'a>) (x : int) (y : int) (z : int) (i : int) (newVal : 'a) : unit =
|
||||
#if DEBUG
|
||||
arr.Elements.[i * arr.WidthTimesHeightTimesDepth
|
||||
+ z * arr.WidthTimesHeight
|
||||
+ y * arr.Width
|
||||
+ x] <- newVal
|
||||
#else
|
||||
NativePtr.write
|
||||
(NativePtr.add
|
||||
arr.Elements
|
||||
(i * arr.WidthTimesHeightTimesDepth
|
||||
+ z * arr.WidthTimesHeight
|
||||
+ y * arr.Width
|
||||
+ x))
|
||||
newVal
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
/// In lieu of a meaningful name for the ana-kata axis, I am just going to call it katana.
|
||||
let create (width : int) (height : int) (depth : int) (katana : int) (value : 'a) : Arr4D<'a> =
|
||||
let arr = Array.create (width * height * depth * katana) value
|
||||
|
||||
{
|
||||
Width = width
|
||||
WidthTimesHeight = width * height
|
||||
WidthTimesHeightTimesDepth = width * height * depth
|
||||
Elements = arr
|
||||
}
|
||||
#else
|
||||
/// In lieu of a meaningful name for the ana-kata axis, I am just going to call it katana.
|
||||
/// The input array must be at least of size width * height * depth * katana.
|
||||
let create
|
||||
(arr : nativeptr<'a>)
|
||||
(width : int)
|
||||
(height : int)
|
||||
(depth : int)
|
||||
(katana : int)
|
||||
(value : 'a)
|
||||
: Arr4D<'a>
|
||||
=
|
||||
{
|
||||
Width = width
|
||||
Elements = arr
|
||||
Length = width * height * depth * katana
|
||||
WidthTimesHeight = width * height
|
||||
WidthTimesHeightTimesDepth = width * height * depth
|
||||
}
|
||||
#endif
|
||||
|
||||
[<RequiresExplicitTypeArguments>]
|
||||
#if DEBUG
|
||||
let zeroCreate<'a when 'a : unmanaged> (width : int) (height : int) (depth : int) (katana : int) : Arr4D<'a> =
|
||||
{
|
||||
Elements = Array.zeroCreate (width * height * depth * katana)
|
||||
Width = width
|
||||
WidthTimesHeight = width * height
|
||||
WidthTimesHeightTimesDepth = width * height * depth
|
||||
}
|
||||
#else
|
||||
let zeroCreate<'a when 'a : unmanaged>
|
||||
(elts : nativeptr<'a>)
|
||||
(width : int)
|
||||
(height : int)
|
||||
(depth : int)
|
||||
(katana : int)
|
||||
: Arr4D<'a>
|
||||
=
|
||||
{
|
||||
Elements = elts
|
||||
Width = width
|
||||
WidthTimesHeight = width * height
|
||||
WidthTimesHeightTimesDepth = width * height * depth
|
||||
Length = width * height * depth * katana
|
||||
}
|
||||
#endif
|
||||
|
||||
let inline clear (a : Arr4D<'a>) : unit =
|
||||
#if DEBUG
|
||||
System.Array.Clear a.Elements
|
||||
#else
|
||||
NativePtr.initBlock a.Elements 0uy (uint32 sizeof<'a> * uint32 a.Length)
|
||||
#endif
|
22
CipherSuite/Assembly.fs
Normal file
22
CipherSuite/Assembly.fs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace CipherSuite
|
||||
|
||||
open System.IO
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal Assembly =
|
||||
let loadResource (name : string) =
|
||||
let assembly = System.Reflection.Assembly.GetExecutingAssembly ()
|
||||
|
||||
if not (assembly.GetManifestResourceNames () |> Array.contains name) then
|
||||
assembly.GetManifestResourceNames ()
|
||||
|> String.concat ", "
|
||||
|> failwithf "bad name %s, had: %s" name
|
||||
|
||||
seq {
|
||||
use sr = new StreamReader (assembly.GetManifestResourceStream name)
|
||||
let mutable line = sr.ReadLine ()
|
||||
|
||||
while not (obj.ReferenceEquals (null, line)) do
|
||||
yield line
|
||||
line <- sr.ReadLine ()
|
||||
}
|
38
CipherSuite/Caesar.fs
Normal file
38
CipherSuite/Caesar.fs
Normal file
@@ -0,0 +1,38 @@
|
||||
namespace CipherSuite
|
||||
|
||||
#if DEBUG
|
||||
#else
|
||||
#nowarn "9"
|
||||
#endif
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module Caesar =
|
||||
|
||||
let shift (s : string) (i : int) : string =
|
||||
Array.init
|
||||
s.Length
|
||||
(fun index ->
|
||||
let c = s.[index]
|
||||
|
||||
if 'A' <= c && c <= 'Z' then
|
||||
char ((int c - int 'A' + i) % 26 + int 'A')
|
||||
elif 'a' <= c && c <= 'z' then
|
||||
char ((int c - int 'a' + i) % 26 + int 'a')
|
||||
else
|
||||
c
|
||||
)
|
||||
|> System.String
|
||||
|
||||
let crack (s : string) =
|
||||
#if DEBUG
|
||||
let fitness = Fitness.fromEmbedded ()
|
||||
#else
|
||||
let arr = Fitness.allocate ()
|
||||
use ptr = fixed arr
|
||||
let fitness = Fitness.fromEmbedded ptr
|
||||
#endif
|
||||
|
||||
seq { 0..25 }
|
||||
|> Seq.map (fun i -> 25 - i, shift s i)
|
||||
|> Seq.map (fun (shift, text) -> (shift, text, Fitness.get text fitness))
|
||||
|> Seq.maxBy (fun (_, _, fitness) -> fitness)
|
19
CipherSuite/CipherSuite.fsproj
Normal file
19
CipherSuite/CipherSuite.fsproj
Normal file
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Arr4D.fs" />
|
||||
<Compile Include="Assembly.fs" />
|
||||
<Compile Include="FitnessAnalyser.fs" />
|
||||
<Compile Include="Caesar.fs" />
|
||||
<Compile Include="Affine.fs" />
|
||||
<Compile Include="Monoalphabetic.fs" />
|
||||
<EmbeddedResource Include="tetragraphs.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
83
CipherSuite/FitnessAnalyser.fs
Normal file
83
CipherSuite/FitnessAnalyser.fs
Normal file
@@ -0,0 +1,83 @@
|
||||
namespace CipherSuite
|
||||
|
||||
open System
|
||||
|
||||
type Fitness =
|
||||
private
|
||||
{
|
||||
Quadruplets : Arr4D<int>
|
||||
Total : int
|
||||
}
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module Fitness =
|
||||
|
||||
let inline private toIndex (c : char) : int = int (System.Char.ToUpper c) - 65
|
||||
|
||||
#if DEBUG
|
||||
let fromEmbedded () : Fitness =
|
||||
let frequencies = Arr4D.zeroCreate<_> 26 26 26 26
|
||||
#else
|
||||
|
||||
let allocate () =
|
||||
Array.zeroCreate<int> (26 * 26 * 26 * 26)
|
||||
|
||||
/// Pass in a pointer to an array of length 26*26*26*26, e.g. a pointer to
|
||||
/// the output of `allocate`.
|
||||
let fromEmbedded (arr : nativeptr<int>) : Fitness =
|
||||
let frequencies = Arr4D.zeroCreate<_> arr 26 26 26 26
|
||||
#endif
|
||||
let tetragraphs = Assembly.loadResource "CipherSuite.tetragraphs.txt"
|
||||
|
||||
let mutable total = 0
|
||||
|
||||
for line in tetragraphs do
|
||||
if line.[0] <> '#' then
|
||||
let line = line.AsSpan ()
|
||||
let i = Int32.Parse (line.Slice (line.IndexOf (' ') + 1))
|
||||
total <- total + i
|
||||
let w = toIndex line.[0]
|
||||
let x = toIndex line.[1]
|
||||
let y = toIndex line.[2]
|
||||
let z = toIndex line.[3]
|
||||
|
||||
if w < 0 || x < 0 || y < 0 || z < 0 then
|
||||
failwith "negative"
|
||||
|
||||
if w > 25 || x > 25 || y > 25 || z > 25 then
|
||||
failwith "too big"
|
||||
|
||||
Arr4D.set frequencies w x y z i
|
||||
|
||||
{
|
||||
Quadruplets = frequencies
|
||||
Total = total
|
||||
}
|
||||
|
||||
/// Assumes the input is characters 0..25, where "a" is 0.
|
||||
/// This fitness can meaningfully be compared across strings
|
||||
/// with different lengths.
|
||||
let get' (s : int[]) (f : Fitness) : float =
|
||||
let mutable score = 0
|
||||
|
||||
for j = 0 to s.Length - 4 do
|
||||
let first = s.[j]
|
||||
let second = s.[j + 1]
|
||||
let third = s.[j + 2]
|
||||
let fourth = s.[j + 3]
|
||||
|
||||
score <- score + Arr4D.get f.Quadruplets first second third fourth
|
||||
|
||||
float score / float s.Length
|
||||
|
||||
let get (s : string) (f : Fitness) : float =
|
||||
let s =
|
||||
s.ToUpper().ToCharArray ()
|
||||
|> Array.choose (fun c ->
|
||||
if 'A' <= c && c <= 'Z' then
|
||||
Some (int c - int 'A')
|
||||
else
|
||||
None
|
||||
)
|
||||
|
||||
get' s f
|
118
CipherSuite/Monoalphabetic.fs
Normal file
118
CipherSuite/Monoalphabetic.fs
Normal file
@@ -0,0 +1,118 @@
|
||||
namespace CipherSuite
|
||||
|
||||
#if DEBUG
|
||||
#else
|
||||
#nowarn "9"
|
||||
#endif
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module Monoalphabetic =
|
||||
|
||||
/// The hill climber is allowed to accept a worse solution sometimes
|
||||
/// (in the name of escaping local optima). This is a table of probabilities
|
||||
/// for how much worse the solution is allowed to be; for example, there is a
|
||||
/// 5 in 20 chance that we don't accept any worse solution, and a 2 in 20 chance
|
||||
/// we accept a solution that is 8-or-more worse.
|
||||
/// I have completely lost the source of these numbers, and it appears that
|
||||
/// by sheer coincidence the scale I chose for the built-in fitness function
|
||||
/// happens to be very compatible with these perturbations.
|
||||
let private perturbations =
|
||||
[|
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
2
|
||||
2
|
||||
2
|
||||
3
|
||||
4
|
||||
4
|
||||
5
|
||||
6
|
||||
8
|
||||
15
|
||||
|]
|
||||
|> Array.map float
|
||||
|
||||
let private decrypt (key : int[]) (ciphertext : int[]) (output : int[]) : unit =
|
||||
for i = 0 to ciphertext.Length - 1 do
|
||||
output.[i] <- key.[ciphertext.[i]]
|
||||
|
||||
let inline private swap (arr : int[]) (p1 : int) (p2 : int) : unit =
|
||||
let temp = arr.[p1]
|
||||
arr.[p1] <- arr.[p2]
|
||||
arr.[p2] <- temp
|
||||
|
||||
let rec private backToString (text : int[]) : string =
|
||||
text |> Array.map ((+) (int 'a') >> char) |> System.String
|
||||
|
||||
// I *think* this may originally be an algorithm described in
|
||||
// http://web.archive.org/web/20110210123730/http://web.mac.com/mikejcowan/Ciphers/Churn_Algorithm.html
|
||||
// But it was over a decade ago and I've simply forgotten the source.
|
||||
let crack (rand : System.Random) (keysLimit : int) (ciphertext : string) : int[] * string * float =
|
||||
let ciphertext = ciphertext.ToUpperInvariant ()
|
||||
#if DEBUG
|
||||
let fitness = Fitness.fromEmbedded ()
|
||||
#else
|
||||
let arr = Fitness.allocate ()
|
||||
use ptr = fixed arr
|
||||
let fitness = Fitness.fromEmbedded ptr
|
||||
#endif
|
||||
let plaintext =
|
||||
Array.init
|
||||
ciphertext.Length
|
||||
(fun i ->
|
||||
let output = int ciphertext.[i] - int 'A'
|
||||
|
||||
if output < 0 || output > 25 then
|
||||
failwith "non-alphabetic character"
|
||||
|
||||
output
|
||||
)
|
||||
|
||||
let ciphertext = Array.copy plaintext
|
||||
let currentKey = [| 0..25 |]
|
||||
let bestKey = Array.copy currentKey
|
||||
decrypt currentKey ciphertext plaintext
|
||||
let mutable currentFitness = Fitness.get' plaintext fitness
|
||||
let mutable bestFitness = currentFitness
|
||||
let mutable keyCount = 0
|
||||
|
||||
while keyCount < keysLimit do
|
||||
let swap1 = rand.Next (0, 26)
|
||||
let swap2 = rand.Next (0, 25)
|
||||
let swap2 = if swap2 < swap1 then swap2 else swap2 + 1
|
||||
|
||||
swap currentKey swap1 swap2
|
||||
|
||||
// We could do better here, because the plaintext changes
|
||||
// only in well-defined ways from loop to loop.
|
||||
// I'm lazy.
|
||||
decrypt currentKey ciphertext plaintext
|
||||
|
||||
let newFitness = Fitness.get' plaintext fitness
|
||||
|
||||
if newFitness > bestFitness then
|
||||
bestFitness <- newFitness
|
||||
currentFitness <- newFitness
|
||||
Array.blit currentKey 0 bestKey 0 currentKey.Length
|
||||
elif newFitness > currentFitness - perturbations.[rand.Next (0, perturbations.Length)] then
|
||||
// This guess wasn't the best we've had, but it's good enough when we
|
||||
// add in a bit of jitter to get us out of local optima.
|
||||
currentFitness <- newFitness
|
||||
else
|
||||
// Revert this guess, it wasn't sufficiently high fitness
|
||||
swap currentKey swap1 swap2
|
||||
|
||||
keyCount <- keyCount + 1
|
||||
|
||||
decrypt bestKey ciphertext plaintext
|
||||
let plaintext = backToString plaintext
|
||||
bestKey, plaintext, bestFitness
|
70333
CipherSuite/tetragraphs.txt
Normal file
70333
CipherSuite/tetragraphs.txt
Normal file
File diff suppressed because it is too large
Load Diff
14
Directory.Build.props
Normal file
14
Directory.Build.props
Normal file
@@ -0,0 +1,14 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<DebugType Condition=" '$(DebugType)' == '' ">embedded</DebugType>
|
||||
<Deterministic>true</Deterministic>
|
||||
<NetCoreTargetingPackRoot>[UNDEFINED]</NetCoreTargetingPackRoot>
|
||||
<DisableImplicitLibraryPacksFolder>true</DisableImplicitLibraryPacksFolder>
|
||||
<DisableImplicitNuGetFallbackFolder>true</DisableImplicitNuGetFallbackFolder>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Nerdbank.GitVersioning" Version="3.5.119" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
|
||||
<SourceLinkGitHubHost Include="github.com" ContentUrl="https://raw.githubusercontent.com" />
|
||||
</ItemGroup>
|
||||
</Project>
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Patrick Stevens
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
9
README.md
Normal file
9
README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# dotnet-classical-ciphers
|
||||
|
||||
This is a partial .NET port of some *ancient* Pascal code I wrote with friends at school, for the primary purpose of solving the [National Cipher Challenge](https://www.cipherchallenge.org) challenges.
|
||||
|
||||
## Building from source
|
||||
|
||||
Just clone and `dotnet build`.
|
||||
|
||||
To upgrade the NuGet dependencies in the flake, run `nix build .#fetchDeps` and copy the resulting file into `nix/deps.nix`.
|
42
flake.lock
generated
Normal file
42
flake.lock
generated
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1667395993,
|
||||
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1671548329,
|
||||
"narHash": "sha256-OrC6R6zihRjFqdKFF3/vD3bkz44poONSII8ncre1Wh0=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ba6ba2b90096dc49f448aa4d4d783b5081b1cc87",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
90
flake.nix
Normal file
90
flake.nix
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
description = "Transcription of some classical cipher solvers from Pascal";
|
||||
|
||||
inputs = {
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
nixpkgs.url = "nixpkgs/nixpkgs-unstable";
|
||||
};
|
||||
|
||||
outputs = {
|
||||
self,
|
||||
nixpkgs,
|
||||
flake-utils,
|
||||
...
|
||||
}:
|
||||
flake-utils.lib.eachDefaultSystem (system: let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
projectFile = "./CipherSuite/CipherSuite.fsproj";
|
||||
testProjectFile = "./CipherSuite.Test/CipherSuite.Test.fsproj";
|
||||
pname = "dotnet-cipher-suite";
|
||||
dotnet-sdk = pkgs.dotnet-sdk_7;
|
||||
dotnet-runtime = pkgs.dotnetCorePackages.runtime_7_0;
|
||||
version = "0.1";
|
||||
dotnetTool = toolName: toolVersion: sha256:
|
||||
pkgs.stdenvNoCC.mkDerivation rec {
|
||||
name = toolName;
|
||||
version = toolVersion;
|
||||
nativeBuildInputs = [pkgs.makeWrapper];
|
||||
src = pkgs.fetchNuGet {
|
||||
pname = name;
|
||||
version = version;
|
||||
sha256 = sha256;
|
||||
installPhase = ''mkdir -p $out/bin && cp -r tools/net6.0/any/* $out/bin'';
|
||||
};
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p "$out/lib"
|
||||
cp -r ./bin/* "$out/lib"
|
||||
makeWrapper "${dotnet-runtime}/bin/dotnet" "$out/bin/${name}" --add-flags "$out/lib/${name}.dll"
|
||||
runHook postInstall
|
||||
'';
|
||||
};
|
||||
in {
|
||||
packages = {
|
||||
fantomas = dotnetTool "fantomas" "5.2.0-alpha-008" "sha256-1egphbWXTjs2I5aFaWibFDKgu3llP1o32o1X5vab6v4=";
|
||||
fetchDeps = let
|
||||
flags = [];
|
||||
runtimeIds = ["win-x64"] ++ map (system: pkgs.dotnetCorePackages.systemToDotnetRid system) dotnet-sdk.meta.platforms;
|
||||
in
|
||||
pkgs.writeShellScriptBin "fetch-${pname}-deps" (builtins.readFile (pkgs.substituteAll {
|
||||
src = ./nix/fetchDeps.sh;
|
||||
pname = pname;
|
||||
binPath = pkgs.lib.makeBinPath [pkgs.coreutils dotnet-sdk (pkgs.nuget-to-nix.override {inherit dotnet-sdk;})];
|
||||
projectFiles = toString (pkgs.lib.toList projectFile);
|
||||
testProjectFiles = toString (pkgs.lib.toList testProjectFile);
|
||||
rids = pkgs.lib.concatStringsSep "\" \"" runtimeIds;
|
||||
packages = dotnet-sdk.packages;
|
||||
storeSrc = pkgs.srcOnly {
|
||||
src = ./.;
|
||||
pname = pname;
|
||||
version = version;
|
||||
};
|
||||
}));
|
||||
default = pkgs.buildDotnetModule {
|
||||
pname = pname;
|
||||
name = "cipher-suite";
|
||||
version = version;
|
||||
src = ./.;
|
||||
projectFile = projectFile;
|
||||
nugetDeps = ./nix/deps.nix;
|
||||
doCheck = true;
|
||||
dotnet-sdk = dotnet-sdk;
|
||||
dotnet-runtime = dotnet-runtime;
|
||||
};
|
||||
};
|
||||
devShell = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
(with dotnetCorePackages;
|
||||
combinePackages [
|
||||
dotnet-sdk_7
|
||||
dotnetPackages.Nuget
|
||||
])
|
||||
];
|
||||
packages = [
|
||||
pkgs.alejandra
|
||||
pkgs.nodePackages.markdown-link-check
|
||||
pkgs.shellcheck
|
||||
];
|
||||
};
|
||||
});
|
||||
}
|
6
hooks/pre-push
Normal file
6
hooks/pre-push
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
if ! dotnet tool run fantomas --check -r . ; then
|
||||
echo "Formatting incomplete. Consider running 'dotnet tool run fantomas -r .'"
|
||||
exit 1
|
||||
fi
|
99
nix/deps.nix
Normal file
99
nix/deps.nix
Normal file
@@ -0,0 +1,99 @@
|
||||
# This file was automatically generated by passthru.fetch-deps.
|
||||
# Please don't edit it manually, your changes might get overwritten!
|
||||
{fetchNuGet}: [
|
||||
(fetchNuGet {
|
||||
pname = "coverlet.collector";
|
||||
version = "3.2.0";
|
||||
sha256 = "1qxpv8v10p5wn162lzdm193gdl6c5f81zadj8h889dprlnj3g8yr";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "FSharp.Core";
|
||||
version = "7.0.0";
|
||||
sha256 = "1pgk3qk9p1s53wvja17744x4bf7zs3a3wf0dmxi66w1w06z7i85x";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "FsUnit";
|
||||
version = "5.2.0";
|
||||
sha256 = "0l4n453slnynp8x372618yx6gjwywfai1dyl4m5iyw87d0iam7q3";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.Build.Tasks.Git";
|
||||
version = "1.1.1";
|
||||
sha256 = "1bb5p4zlnfn88skkvymxfsn0jybqncl4356hwnic9jxdq2d4fz1w";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.CodeCoverage";
|
||||
version = "17.4.1";
|
||||
sha256 = "0bf68gq6mc6kzri4zi8ydc0xrazqwqg38bhbpjpj90zmqc28kari";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NET.Test.Sdk";
|
||||
version = "17.4.1";
|
||||
sha256 = "02p1j9fncd4fb2hyp51kw49d0dz30vvazhzk24c9f5ccc00ijpra";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.Platforms";
|
||||
version = "1.1.0";
|
||||
sha256 = "08vh1r12g6ykjygq5d3vq09zylgb84l63k49jc4v8faw9g93iqqm";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.SourceLink.Common";
|
||||
version = "1.1.1";
|
||||
sha256 = "0xkdqs7az2cprar7jzjlgjpd64l6f8ixcmwmpkdm03fyb4s5m0bg";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.SourceLink.GitHub";
|
||||
version = "1.1.1";
|
||||
sha256 = "099y35f2npvva3jk1zp8hn0vb9pwm2l0ivjasdly6y2idv53s5yy";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.TestPlatform.ObjectModel";
|
||||
version = "17.4.1";
|
||||
sha256 = "0s68wf9yphm4hni9p6kwfk0mjld85f4hkrs93qbk5lzf6vv3kba1";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.TestPlatform.TestHost";
|
||||
version = "17.4.1";
|
||||
sha256 = "1n9ilq8n5rhyxcri06njkxb0h2818dbmzddwd2rrvav91647m2s4";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Nerdbank.GitVersioning";
|
||||
version = "3.5.119";
|
||||
sha256 = "0g7a812lfa5y140pinpy5q3nl3xcarydflpxzzcyxxk4hjjlawy0";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NETStandard.Library";
|
||||
version = "2.0.0";
|
||||
sha256 = "1bc4ba8ahgk15m8k4nd7x406nhi0kwqzbgjk2dmw52ss553xz7iy";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Newtonsoft.Json";
|
||||
version = "13.0.1";
|
||||
sha256 = "0fijg0w6iwap8gvzyjnndds0q4b8anwxxvik7y8vgq97dram4srb";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NuGet.Frameworks";
|
||||
version = "5.11.0";
|
||||
sha256 = "0wv26gq39hfqw9md32amr5771s73f5zn1z9vs4y77cgynxr73s4z";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NUnit";
|
||||
version = "3.13.3";
|
||||
sha256 = "0wdzfkygqnr73s6lpxg5b1pwaqz9f414fxpvpdmf72bvh4jaqzv6";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NUnit.Analyzers";
|
||||
version = "3.5.0";
|
||||
sha256 = "1dssqrzbqpx6xf517i4vya4m75pa0d52aach16n2im8vjp12i1j2";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NUnit3TestAdapter";
|
||||
version = "4.3.1";
|
||||
sha256 = "1j80cfrg0fflgw7wxi76mxj1wllwzcg4ck957knmjpghw5cw7lvv";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "System.Reflection.Metadata";
|
||||
version = "1.6.0";
|
||||
sha256 = "1wdbavrrkajy7qbdblpbpbalbdl48q3h34cchz24gvdgyrlf15r4";
|
||||
})
|
||||
]
|
73
nix/fetchDeps.sh
Normal file
73
nix/fetchDeps.sh
Normal file
@@ -0,0 +1,73 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This file was adapted from
|
||||
# https://github.com/NixOS/nixpkgs/blob/b981d811453ab84fb3ea593a9b33b960f1ab9147/pkgs/build-support/dotnet/build-dotnet-module/default.nix#L173
|
||||
set -euo pipefail
|
||||
export PATH="@binPath@"
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--keep-sources|-k)
|
||||
keepSources=1
|
||||
shift
|
||||
;;
|
||||
--help|-h)
|
||||
echo "usage: $0 [--keep-sources] [--help] <output path>"
|
||||
echo " <output path> The path to write the lockfile to. A temporary file is used if this is not set"
|
||||
echo " --keep-sources Don't remove temporary directories upon exit, useful for debugging"
|
||||
echo " --help Show this help message"
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
done
|
||||
tmp=$(mktemp -td "@pname@-tmp-XXXXXX")
|
||||
export tmp
|
||||
HOME=$tmp/home
|
||||
exitTrap() {
|
||||
test -n "${ranTrap-}" && return
|
||||
ranTrap=1
|
||||
if test -n "${keepSources-}"; then
|
||||
echo -e "Path to the source: $tmp/src\nPath to the fake home: $tmp/home"
|
||||
else
|
||||
rm -rf "$tmp"
|
||||
fi
|
||||
# Since mktemp is used this will be empty if the script didnt succesfully complete
|
||||
if ! test -s "$depsFile"; then
|
||||
rm -rf "$depsFile"
|
||||
fi
|
||||
}
|
||||
trap exitTrap EXIT INT TERM
|
||||
dotnetRestore() {
|
||||
local -r project="${1-}"
|
||||
local -r rid="$2"
|
||||
dotnet restore "${project-}" \
|
||||
-p:ContinuousIntegrationBuild=true \
|
||||
-p:Deterministic=true \
|
||||
--packages "$tmp/nuget_pkgs" \
|
||||
--runtime "$rid" \
|
||||
--no-cache \
|
||||
--force
|
||||
}
|
||||
declare -a projectFiles=( @projectFiles@ )
|
||||
declare -a testProjectFiles=( @testProjectFiles@ )
|
||||
export DOTNET_NOLOGO=1
|
||||
export DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
depsFile=$(realpath "${1:-$(mktemp -t "@pname@-deps-XXXXXX.nix")}")
|
||||
mkdir -p "$tmp/nuget_pkgs"
|
||||
storeSrc="@storeSrc@"
|
||||
src="$tmp/src"
|
||||
cp -rT "$storeSrc" "$src"
|
||||
chmod -R +w "$src"
|
||||
cd "$src"
|
||||
echo "Restoring project..."
|
||||
rids=("@rids@")
|
||||
for rid in "${rids[@]}"; do
|
||||
(( ${#projectFiles[@]} == 0 )) && dotnetRestore "" "$rid"
|
||||
for project in "${projectFiles[@]-}" "${testProjectFiles[@]-}"; do
|
||||
dotnetRestore "$project" "$rid"
|
||||
done
|
||||
done
|
||||
echo "Successfully restored project"
|
||||
echo "Writing lockfile..."
|
||||
echo -e "# This file was automatically generated by passthru.fetch-deps.\n# Please don't edit it manually, your changes might get overwritten!\n" > "$depsFile"
|
||||
nuget-to-nix "$tmp/nuget_pkgs" "@packages@" >> "$depsFile"
|
||||
echo "Successfully wrote lockfile to $depsFile"
|
Reference in New Issue
Block a user