diff --git a/content/about/_index.md b/content/about/_index.md index 087da6f..e694e93 100644 --- a/content/about/_index.md +++ b/content/about/_index.md @@ -8,7 +8,7 @@ Hi, I'm Yifei (逸飞)! This is my personal website where I maintain a very cool blog and share various photos I've taken on my camera (FujiFilm X100) and on my smartphone (Samsung Galaxy S9). -This website doesn't use any JavaScript or cookies, just some plain HTML and CSS built with Hugo, hosted on GitHub Pages. The website theme was designed and coded by myself ! :D ! +This website doesn't use any cookies, and for the most part doesn't use any JavaScript. Pages that do contain scripting will indicate so at the top of the page. This website is built with Hugo, and is hosted on GitHub Pages. The website theme was designed and coded by myself ! :D ! ## life diff --git a/content/gallery/hypnosis.md b/content/gallery/hypnosis.md index 08129c8..bcd3f38 100644 --- a/content/gallery/hypnosis.md +++ b/content/gallery/hypnosis.md @@ -6,4 +6,6 @@ location: "University of Waterloo, SCH to Arts Tunnel" imageUrl: "https://live.staticflickr.com/65535/53713021703_83ddf8ec50_o.jpg" width: 2870 height: 4310 ---- \ No newline at end of file +--- + +One time during university, my friend and I 1v1'ed each other here in a fierce battle of the [penis game](https://www.urbandictionary.com/define.php?term=the+penis+game). \ No newline at end of file diff --git a/content/gallery/solar-eclipse.md b/content/gallery/solar-eclipse.md index 1bbb76f..6eba42f 100644 --- a/content/gallery/solar-eclipse.md +++ b/content/gallery/solar-eclipse.md @@ -8,7 +8,7 @@ width: 4310 height: 2870 --- -First in my life experiencing a total solar eclipse, and holy shit that was magical. Unfortunately I didn't have a zoom lens so this photo hopefully captures more accurately what the real experience is like seeing the sun through eclipse glasses. +First time in my life experiencing a total solar eclipse, and holy shit was that magical. Unfortunately I didn't have a zoom lens so this photo hopefully captures more accurately what the real experience is like seeing the sun through eclipse glasses. A few weeks before the eclipse, I suggested to one of my good friends that we organize a small trip to see the total solar eclipse. That small group ended up becoming 10 or so people, and we struggled for a while coming to a decision on where to go. Initially we were thinking of going to Niagara Falls. It was right under the path of totality, and there were a lot of fun things to do in the area while we waited. Buuuuut eventually we all came to realize that the other six million people living in the GTA were all going to go there as well, so we figured we'd go somewhere else with hopefully fewer people. Spoiler alert: Niagara Falls ended up being completely clouded out for the entire eclipse ! :D ! diff --git a/content/posts/hashing.md b/content/posts/hashing.md new file mode 100644 index 0000000..33385da --- /dev/null +++ b/content/posts/hashing.md @@ -0,0 +1,46 @@ +--- +title: "SHA-256" +date: 2025-03-05 +draft: false +scripts: ["hash.js"] +stylesheets: ["hash"] +--- + +*The data visualizations in this post may be more legible on a light colour-scheme.* + +I had this sudden idea to visualize each and every single bit of a SHA-256 hash in a heatmap-style visual, not really sure where the inspiration came from. + +We generally know that SHA-256 is pretty secure (for now), but aside from just trusting that it works, I've never really stopped to understand nor proven to myself that it truly is secure. + +Now I'm not really a mathematician, but I _do_ have some rapidly decaying leftover memories from [ECE 307 - Probability Theory and Statistics 2](https://ucalendar.uwaterloo.ca/2324/COURSE/course-ECE.html#ECE307), so let's run some un-scientific tests to see if we can find any predictable patterns in how SHA-256 hashes are computed. + +One of the craziest things to me is that this algorithm is supposed to be able to generate two virtually indistinguishable hashes from two nearly-identical strings. You'd think that the difference between `0x61` ('a') and `0x63` ('c') is pretty minute right? Bit-wise, they differ by 1 bit-flip in the 2nd least significant bit. + +``` +'a' -> 0x61 -> 01100001 +'c' -> 0x63 -> 01100011 +``` + +Below, I've displayed two heatmaps for the SHA-256 hashes of both 'a' and 'c'. Each column of the heatmap corresponds to one byte of the 32 byte long hash, and each cell corresponds to one of the eight bits in that byte. The left-most column displays the most significant byte, and the top of each column represents the most significant bit. + +{{< hash id="hash-a" caption="SHA-256 hash of UTF-8 string 'a'" >}} +
+{{< hash id="hash-c" caption="SHA-256 hash of UTF-8 string 'c'" >}} + +It's pretty hard to compare these two visualizations at a glance, so let's overlay them on top of each other. + +{{< hash id="hash-a-c" caption="SHA-256 hashes of UTF-8 string 'a' & 'c' overlaid on top of each other" >}} + +I don't know about you, but I don't really see any obvious patterns going on here. The + +# Playground + +Before we begin, here's a little interactive sandbox to compute the SHA-256 hash of any text. + +{{< hash id="table" >}} + + +
+ + +Now that that's out of the way, let's begin with test #1. \ No newline at end of file diff --git a/content/posts/sdvx-controller.md b/content/posts/sdvx-controller.md new file mode 100644 index 0000000..0a3488b --- /dev/null +++ b/content/posts/sdvx-controller.md @@ -0,0 +1,20 @@ +--- +title: "Sound Voltex Controller: Embedded Systems Project (Ongoing)" +date: 2024-07-05 +draft: true +--- + +## Intro + +I've decided to start making my own personal [Sound Voltex](https://remywiki.com/What_is_SOUND_VOLTEX) rhythm game controller. It'll be a project that involves electronics, maybe some PCB design, embedded programming, and 3D design. + +## Why + +While I was co-oping in Tokyo, I found myself visiting rhythm game arcades a lot. A few games that I really stuck with were *Chunithm*, *Dance Dance Revolution*, and *Sound Voltex*. + +## Parts + +I haven't yet picked out specific parts. I'll need: + +- 2 rotary encoders (100-200 PPR minimum) +- 7 buttons (probably mechanical key switches) diff --git a/hugo.yaml b/hugo.yaml index 74b10ad..2bf550e 100644 --- a/hugo.yaml +++ b/hugo.yaml @@ -48,4 +48,9 @@ menus: weight: 20 - name: github url: "https://github.com/yfxu" - weight: 30 \ No newline at end of file + weight: 30 +markup: + goldmark: + renderer: + unsafe: true +enableGitInfo: true \ No newline at end of file diff --git a/themes/ennui/assets/js/hash.js b/themes/ennui/assets/js/hash.js new file mode 100644 index 0000000..7f3b4e3 --- /dev/null +++ b/themes/ennui/assets/js/hash.js @@ -0,0 +1,118 @@ +const textEncoder = new TextEncoder(); +const table = document.getElementById("table"); +const rows = table.getElementsByTagName("tr"); +const hashRow = document.getElementById("hash").children[0].children[0].children; + +async function update(text) { + const hash = await crypto.subtle + .digest("SHA-256", textEncoder.encode(text)) + .then((hashBuffer) => { + const hashArray = Array.from(new Uint8Array(hashBuffer)); + return hashArray; + }); + var i = 0; + hash.forEach((byte) => { + for (var j = 0; j < 8; j++) { + var bitwiseAnd = byte & Math.pow(2, j); + if (bitwiseAnd > 0) { + rows[7 - j].children[i].children[0].className = "set"; + } else { + rows[7 - j].children[i].children[0].className = ""; + } + } + i++; + }); + + for (var i = 0; i < 32; i++) { + var byteString = hash[i].toString(16).padStart(2, "0"); + hashRow[i].children[0].innerHTML = byteString; + } +} + +async function draw(id, texts) { + const staticTable = document.getElementById(id); + const staticRows = staticTable.getElementsByTagName("tr"); + + const hashes = texts.map(async (text) => { + return await crypto.subtle + .digest("SHA-256", textEncoder.encode(text)) + .then((hashBuffer) => { + const hashArray = Array.from(new Uint8Array(hashBuffer)); + return hashArray; + }) + }); + + var opacityValues = [ + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + ], + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + ], + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + ], + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + ], + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + ], + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + ], + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + ], + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + ], + ]; + + Promise.all(hashes).then((values) => { + values.forEach((hash) => { + var i = 0; + hash.forEach((byte) => { + for (var j = 0; j < 8; j++) { + var bitwiseAnd = byte & Math.pow(2, j); + if (bitwiseAnd > 0) { + staticRows[7 - j].children[i].children[0].className = "set"; + opacityValues[7 - j][i] += 1 / texts.length; + } + } + i++; + }); + }); + + for (var i = 0; i < 8; i++) { + for (var j = 0; j < 32; j++) { + staticRows[i].children[j].children[0].style.opacity = + opacityValues[i][j]; + } + } + }); +} + +document.addEventListener( + "DOMContentLoaded", + function () { + update(""); + draw("hash-a", ["a"]); + draw("hash-c", ["c"]); + draw("hash-a-c", ["a", "c"]); + }, + false +); + +window.textEncoder = textEncoder; +window.rows = rows; +window.update = update; +window.hashRow = hashRow; \ No newline at end of file diff --git a/themes/ennui/assets/scss/_variables.scss b/themes/ennui/assets/scss/_variables.scss index b18a0b1..e41c577 100644 --- a/themes/ennui/assets/scss/_variables.scss +++ b/themes/ennui/assets/scss/_variables.scss @@ -1,17 +1,21 @@ :root { - --color-background: #ffffff; + --color-background: #f0f2f8; + --color-background-secondary: #e9e9e9; + --color-background-tertiary: #ffffff; --color-text-primary: #3b393d; - --color-text-secondary: #a6a9ad; - --color-accent: #45b694; + --color-text-secondary: #929497; + --color-accent: #3d37ec; --max-width: 600px; --mobile-width: 450px; } @media (prefers-color-scheme: dark) { :root { - --color-background: #2B2A33; + --color-background: #2b2a33; + --color-background-secondary: #323238; + --color-background-tertiary: #26242b; --color-text-primary: #ede3dd; --color-text-secondary: #747a7a; - --color-accent: #03CEA4; + --color-accent: #5a5ae7; } } diff --git a/themes/ennui/assets/scss/hash.scss b/themes/ennui/assets/scss/hash.scss new file mode 100644 index 0000000..2998b70 --- /dev/null +++ b/themes/ennui/assets/scss/hash.scss @@ -0,0 +1,58 @@ +table.hash-grid { + width: calc(100% + 4px); + border-collapse: separate; + border-spacing: 2px; + margin: 0 -2px; + + td { + padding: 0; + background-color: var(--color-background-secondary); + + div { + font-family: monospace; + font-size: 0.625rem; + text-align: center; + aspect-ratio: 1; + padding: 0; + margin: 0; + + &.set { + background-color: var(--color-accent); + } + } + } + + caption { + caption-side: bottom; + font-size: 0.75rem; + font-style: italic; + } +} + + +table#hash td { + line-height: 1rem; + height: auto; + background-color: var(--color-background-tertiary); +} + +div.centre { + display: flex; + justify-content: center; +} + +input#input { + width: 100%; + height: 1.5rem; + text-align: center; + outline: none; + border: none; + margin: auto; + background-color: var(--color-background-secondary); + color: var(--color-text-primary); + padding: 0; +} + +input#input:focus { + outline: none; +} \ No newline at end of file diff --git a/themes/ennui/assets/scss/main.scss b/themes/ennui/assets/scss/main.scss index 2dedd5e..cbacc3e 100644 --- a/themes/ennui/assets/scss/main.scss +++ b/themes/ennui/assets/scss/main.scss @@ -33,10 +33,18 @@ body { min-height: 100vh; } +div.section { + width: 100%; + + &.highlight { + background-color: var(--color-background-tertiary); + } +} + div.name-header { text-transform: lowercase; margin: 1rem auto; - text-align: center; + // text-align: center; h1 { margin: 0 } h4 { @@ -76,9 +84,12 @@ div.gallery { nav.main-nav { @include flex-row(); justify-content: space-evenly; - padding-bottom: 1rem; column-gap: 1rem; - width: 100% + width: 100%; + + a { + font-weight: bold; + } } footer { @@ -91,6 +102,10 @@ footer { } } +div#git-hash { + font-family: monospace; +} + blockquote { border-left: 4px solid var(--color-accent); margin-left: 0; @@ -148,13 +163,15 @@ div.image-info, div.post-info { } } - p.image-time, p.post-time { + td.image-time, td.post-time { margin: 0; font-size: 0.75rem; font-weight: bold; - svg { + > svg { margin-right: 0.25em; + width: 1rem; + fill: var(--color-text-secondary); } } } @@ -240,4 +257,8 @@ div.home-container { column-gap: 1rem; } } +} + +.secondary-font { + font-family: monospace; } \ No newline at end of file diff --git a/themes/ennui/layouts/_default/baseof.html b/themes/ennui/layouts/_default/baseof.html index 4e147b2..74d72bb 100644 --- a/themes/ennui/layouts/_default/baseof.html +++ b/themes/ennui/layouts/_default/baseof.html @@ -2,17 +2,22 @@ {{- partial "head.html" . -}} -
-

{{ .Site.Params.Author.StylizedName }}

-

- {{ .Site.Params.Author.FirstName }} - {{ .Site.Params.Author.LastName }}. -

+
+
+

{{ .Site.Params.Author.StylizedName }}

+

+ {{ .Site.Params.Author.FirstName }} + {{ .Site.Params.Author.LastName }}. +

+
+ {{- partial "navbar.html" . -}} +
+
+ {{- block "main" . }} + {{- end }} +
+
+ {{- partial "footer.html" . -}}
- {{- partial "navbar.html" . -}} -
- {{- block "main" . }} - {{- end }} - {{- partial "footer.html" . -}} \ No newline at end of file diff --git a/themes/ennui/layouts/gallery/single.html b/themes/ennui/layouts/gallery/single.html index bb4f87c..5b206e0 100644 --- a/themes/ennui/layouts/gallery/single.html +++ b/themes/ennui/layouts/gallery/single.html @@ -1,10 +1,13 @@ {{- define "main" -}}
- +
+ + +

{{ .Title }}

-

{{ partial "svg.html" "location" }}{{ .Params.Location }}

-

{{ partial "svg.html" "calendar" }} {{ partial "long-date-time.html" .Params.Date }}

+

{{ partial "svg.html" "location" }} {{ .Params.Location }}

+

{{ partial "svg.html" "calendar" }} {{ partial "long-date-time.html" .Params.Date }}

{{ range sort .Params.Tags }} diff --git a/themes/ennui/layouts/index.html b/themes/ennui/layouts/index.html index 3b1e850..33a9738 100644 --- a/themes/ennui/layouts/index.html +++ b/themes/ennui/layouts/index.html @@ -6,7 +6,7 @@

{{ site.Params.Author.StylizedName }}

-

{{ site.Params.Author.FirstName}} {{ site.Params.Author.LastName}} .

+

{{ site.Params.Author.FirstName}} {{ site.Params.Author.LastName}}.

{{- range site.Params.HomePageSocials }} diff --git a/themes/ennui/layouts/partials/footer.html b/themes/ennui/layouts/partials/footer.html index d0ab7b2..c7a7ab2 100644 --- a/themes/ennui/layouts/partials/footer.html +++ b/themes/ennui/layouts/partials/footer.html @@ -1,6 +1,22 @@ -
+
{{- range site.Menus.footer }} {{ .Name }} {{- end }} -
\ No newline at end of file + {{ range .Params.scripts }} + {{ $js := resources.Get (printf "/js/%s" .) | js.Build . }} + + {{ end }} + {{ range .Params.stylesheets }} + {{ $options := dict + "targetPath" (printf "css/%s.css" .) + "transpiler" "dartsass" + }} + {{ $style := resources.Get (printf "/scss/%s.scss" .) | toCSS $options }} + + {{ end }} + +{{ $gitRev := trim (getenv "HUGO_GIT_REV") " " }} +{{ $gitRevShort := getenv "HUGO_GIT_REV_SHORT" }} + +
\ No newline at end of file diff --git a/themes/ennui/layouts/partials/navbar.html b/themes/ennui/layouts/partials/navbar.html index fa50fa4..8729d5c 100644 --- a/themes/ennui/layouts/partials/navbar.html +++ b/themes/ennui/layouts/partials/navbar.html @@ -3,3 +3,4 @@ {{ .Name }} {{- end }} +
diff --git a/themes/ennui/layouts/partials/posts-list.html b/themes/ennui/layouts/partials/posts-list.html index 9fcbbc6..2c91028 100644 --- a/themes/ennui/layouts/partials/posts-list.html +++ b/themes/ennui/layouts/partials/posts-list.html @@ -5,7 +5,7 @@ {{- range first $pages .Pages -}}
  • {{ .Title }} -
  • diff --git a/themes/ennui/layouts/partials/short-date-time.html b/themes/ennui/layouts/partials/short-date-time.html index 52dd6d3..7da9831 100644 --- a/themes/ennui/layouts/partials/short-date-time.html +++ b/themes/ennui/layouts/partials/short-date-time.html @@ -1,4 +1,4 @@ - {{ .Format "Mon, 2006 Jan 02" }} + {{ .Format "2006 Jan 02" }} \ No newline at end of file diff --git a/themes/ennui/layouts/posts/single.html b/themes/ennui/layouts/posts/single.html index 02f50e1..a3827c7 100644 --- a/themes/ennui/layouts/posts/single.html +++ b/themes/ennui/layouts/posts/single.html @@ -2,8 +2,19 @@
    - {{ .Content }} + {{ .Content | safeHTML }}
    {{- end -}} \ No newline at end of file diff --git a/themes/ennui/layouts/shortcodes/hash.html b/themes/ennui/layouts/shortcodes/hash.html new file mode 100644 index 0000000..4ed39b5 --- /dev/null +++ b/themes/ennui/layouts/shortcodes/hash.html @@ -0,0 +1,14 @@ +{{ $id := .Get "id" }} + + {{ with .Get "caption" }} + + {{ end }} + + + + + + + + +
    {{ . }}
    \ No newline at end of file diff --git a/themes/ennui/static/svg/code.svg b/themes/ennui/static/svg/code.svg new file mode 100644 index 0000000..7c4b685 --- /dev/null +++ b/themes/ennui/static/svg/code.svg @@ -0,0 +1 @@ + \ No newline at end of file