DEV Community

Weerasak Chongnguluam
Weerasak Chongnguluam

Posted on

3 1

ทำ sha1-challenge ด้วย Haskell

ไปเจอเพื่อนร่วมงานเล่นโจทย์ https://github.com/mrchoke/sha1-challages เลยลองเล่นดูบ้างโดยเขียนด้วย Haskell

โจทย์มีอยู่ว่า

เริ่มต้นด้วยคำว่า "clubhouse"

นำไป sha1 ครั้งแรกจะได้ "1313994e55ed4bbe79d2b04e4529ee2f4ac288f5"

นำคำตอบไป sha1 ครั้งที่ 2 จะได้ "b42f871cff37138a6b8f53cf55a585d7d1445dfb"

นำคำตอบไป sha1 ครั้งที่ 3 จะได้ "5c7c81615ad8050363c911c7b5e5ed8661be80d6"

ทำไปเรื่อยๆ จนถึงครั้งที่ 5,555,555,555 จะได้ sha1 ลงท้ายด้วย "229a"

สำหรับ Haskell ผมใช้เครื่องมือในการเริ่มโปรเจ็คคือ stack ติดตั้งง่ายๆได้ทั้งบน macOS, Linux และ Windows จากนั้นก็เริ่มสร้างโปรเจ็คด้วยคำสั่ง

stack new sha1-challenges
Enter fullscreen mode Exit fullscreen mode

แล้ว cd sha1-challenges เข้าไปใน project

ผมจะใช้ library 3 ตัวคือ

    - cryptohash-sha1 เพื่อใช้ sha1 function
    - bytestring เพื่อใช้ type Data.ByteString
    - base16-bytestring เพื่อใช้ encode base16
Enter fullscreen mode Exit fullscreen mode

ผมก็แก้ไฟล์ package.yml ตรงส่วน dependencies ของ executables แบบนี้

executables:
  sha1-challenges-exe:
    main:                Main.hs
    source-dirs:         app
    ghc-options:
    - -threaded
    - -rtsopts
    - -O3
    - -with-rtsopts=-N
    dependencies:
    - sha1-challenges
    - cryptohash-sha1
    - bytestring
    - base16-bytestring
Enter fullscreen mode Exit fullscreen mode

ในส่วนของโค้ดที่แก้โจทย์นั้นเขียนในไฟล์ app/Main.hs เท่านี้เอง

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NumericUnderscores #-}

module Main where

import Data.ByteString.Base16
import Crypto.Hash.SHA1

loop 5_555_555_555 v = encode $ hash v
loop n v = loop (n+1) (encode $ hash v)

main :: IO ()
main = print $ loop 1 "clubhouse"
Enter fullscreen mode Exit fullscreen mode

ผมเปิดใช้ language extension 2 ตัวคือ OverloadedStrings เพื่อให้ใช้ string literal (ตรง double quote "clubhouse") แล้วให้มันแปลงเป็น ByteString ให้เอง และ NumericUnderscores เพื่อให้เขียนตัวเลขโดยใช้ unserscore คั่นได้แบบนี้ 5_555_555_555

จากนั้น import Data.ByteString.Base16 เพื่อให้ใช้ function encode เพื่อแปลงจาก ByteString ที่ได้เป็น base16 format และ import Crypto.Hash.SHA1 เพื่อใช้ function hash ในการ hash แบบ sha1

จากนั้นก็สร้างฟังก์ชัน loop เพื่อ recursive วนซ้ำจาก 1 ถึง 5_555_555_555 โดยแต่ละรอบก็เอาผลลัพธ์ที่ได้ไป hash ต่อๆไป

ใน main ก็แค่เรียก print $ loop 1 "clubhouse" เพื่อให้เริ่มที่ 1 ไปเรื่อยๆจนถึง 5_555_555_555 แล้วก็ปริ้นออกมา

วิธี build binary ก็ให้สั่ง

stack build --copy-bins --local-bin-path=$PWD
Enter fullscreen mode Exit fullscreen mode

แล้วก็รันโดยใช้ time จับเวลาแบบนี้

time ./sha1-challenges-exe
Enter fullscreen mode Exit fullscreen mode

จากที่ลองวันในเครื่องผมที่เป็น macbook pro รุ่นเก่า

MacBook Pro (Retina, 15-inch, Mid 2014)
Processor: 2.2 GHz Quad-Core Intel Core i7
Memory: 16 GB 1600 MHz DDR3
Enter fullscreen mode Exit fullscreen mode

ผลลัพธ์ได้ออกมาแบบนี้

time ./sha1-challenges-exe
"87803aa93893f0fc1262b78e879d7a7f7075229a"

real    30m44.986s
user    44m16.479s
sys     5m26.883s
Enter fullscreen mode Exit fullscreen mode

ลองเอาโค้ด Go จากใน repository https://github.com/mrchoke/sha1-challages/tree/main/golang/oat มารันดูเวลาที่ใช้ได้เท่านี้

time ./sha1
87803aa93893f0fc1262b78e879d7a7f7075229a
Time diff: 19m14.995697452s

real    19m14.953s
user    19m12.227s
sys 0m2.267s
Enter fullscreen mode Exit fullscreen mode

ซึ่งถ้าเทียบกันก็ถือว่าไม่แย่ไป ตัว library cryptohash-sha1 นั้นจริงๆในส่วนของ hash function เขียนด้วย C แล้วใช้วิธี FFI ในการให้โค้ดของ Haskell ไปเรียกใช้งาน C ได้ ส่วนของ Go นั้นเขียนด้วย Go บวกกับ Assembly ที่เจาะจงในแต่ละ CPU architecture ซึ่งช่วยให้ได้ความเร็วที่ดีใช้ได้เลย

ขอฝาก Buy Me a Coffee

สำหรับท่านใดที่อ่านแล้วชอบโพสต์ต่างๆของผมที่นี่ ต้องการสนับสนุนค่ากาแฟเล็กๆน้อยๆ สามารถสนับสนุนผมได้ผ่านทาง Buy Me a Coffee คลิ๊กที่รูปด้านล่างนี้ได้เลยครับ

Buy Me A Coffee

ส่วนท่านใดไม่สะดวกใช้บัตรเครดิต หรือ Paypal สามารถสนับสนุนผมได้ผ่านทาง PromptPay โดยดู QR Code ได้จากโพสต์ที่พินเอาไว้ได้ที่ Page DevDose ครับ https://web.facebook.com/devdoseth

ขอบคุณครับ 🙏

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay