-
Notifications
You must be signed in to change notification settings - Fork 274
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
Cryptographic primitives for hashing and HMAC #1712
Changes from 20 commits
8e1cb81
87b83a3
c9e45f0
9c9b623
2f2ec70
27173e5
91220df
238dfbe
25a2e43
f17fafb
af9190e
1e39533
1447b0a
b2882fe
2e5833d
65acd45
9ed2a46
9244f14
6fc235c
9f23277
ee9a547
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,15 +28,19 @@ import Unison.Symbol | |
import Unison.Runtime.Stack (Closure) | ||
import Unison.Runtime.Foreign.Function | ||
import Unison.Runtime.IOSource | ||
import Unison.Runtime.Foreign (HashAlgorithm(..)) | ||
|
||
import qualified Unison.Type as Ty | ||
import qualified Unison.Builtin as Ty (builtinTypes) | ||
import qualified Unison.Builtin.Decls as Ty | ||
import qualified Crypto.Hash as Hash | ||
import qualified Crypto.MAC.HMAC as HMAC | ||
|
||
import Unison.Util.EnumContainers as EC | ||
|
||
import Data.Word (Word64) | ||
import Data.Text as Text (Text, unpack) | ||
import qualified Data.ByteArray as BA | ||
|
||
import Data.Set (Set, insert) | ||
|
||
|
@@ -1104,6 +1108,50 @@ mvar'try'read instr | |
where | ||
[mv,t,r] = freshes 3 | ||
|
||
-- Pure ForeignOp taking two boxed values | ||
pfopbb :: ForeignOp | ||
pfopbb instr | ||
= ([BX,BX],) | ||
. TAbss [b1,b2] | ||
$ TFOp instr [b1,b2] | ||
where | ||
[b1,b2] = freshes 2 | ||
|
||
pfopbbb :: ForeignOp | ||
pfopbbb instr | ||
= ([BX,BX,BX],) | ||
. TAbss [b1,b2,b3] | ||
$ TFOp instr [b1,b2,b3] | ||
where | ||
[b1,b2,b3] = freshes 3 | ||
|
||
-- Pure ForeignOp taking no values | ||
pfop0 :: ForeignOp | ||
pfop0 instr = ([],) $ TFOp instr [] | ||
|
||
-- Pure ForeignOp taking 1 boxed value and returning 1 boxed value | ||
pfopb :: ForeignOp | ||
pfopb instr | ||
= ([BX],) | ||
. TAbss [b] | ||
$ TFOp instr [b] | ||
where | ||
[b] = freshes 1 | ||
|
||
-- Pure ForeignOp taking 1 boxed value and returning 1 Either, both sides boxed | ||
pfopb_ebb :: ForeignOp | ||
pfopb_ebb instr | ||
= ([BX],) | ||
. TAbss [b] | ||
. TLet e UN (AFOp instr [b]) | ||
. TMatch e . MatchSum | ||
$ mapFromList | ||
[ (0, ([BX], TAbs ev $ TCon eitherReference 0 [ev])) | ||
, (1, ([BX], TAbs ev $ TCon eitherReference 1 [ev])) | ||
] | ||
where | ||
[e,b,ev] = freshes 3 | ||
|
||
builtinLookup :: Var v => Map.Map Reference (SuperNormal v) | ||
builtinLookup | ||
= Map.fromList | ||
|
@@ -1354,10 +1402,10 @@ declareForeigns = do | |
declareForeign "IO.socketAccept" socket'accept | ||
. mkForeignIOE $ void . SYS.accept | ||
declareForeign "IO.socketSend" socket'send | ||
. mkForeignIOE $ \(sk,bs) -> SYS.send sk (Bytes.toByteString bs) | ||
. mkForeignIOE $ \(sk,bs) -> SYS.send sk (Bytes.toArray bs) | ||
declareForeign "IO.socketReceive" socket'receive | ||
. mkForeignIOE $ \(hs,n) -> | ||
fmap Bytes.fromByteString <$> SYS.recv hs n | ||
fmap Bytes.fromArray <$> SYS.recv hs n | ||
declareForeign "IO.kill" kill'thread $ mkForeignIOE killThread | ||
declareForeign "IO.delay" delay'thread $ mkForeignIOE threadDelay | ||
declareForeign "IO.stdHandle" standard'handle | ||
|
@@ -1388,6 +1436,46 @@ declareForeigns = do | |
declareForeign "MVar.tryRead" mvar'try'read | ||
. mkForeign $ \(mv :: MVar Closure) -> tryReadMVar mv | ||
|
||
-- Hashing functions | ||
let declareHashAlgorithm :: forall v alg . Var v => Hash.HashAlgorithm alg => Text -> alg -> FDecl v () | ||
declareHashAlgorithm txt alg = do | ||
let algoRef = Builtin ("crypto.HashAlgorithm." <> txt) | ||
declareForeign ("crypto.HashAlgorithm." <> txt) pfop0 . mkForeign $ \() -> | ||
pure (HashAlgorithm algoRef alg) | ||
|
||
declareHashAlgorithm "Sha3_512" Hash.SHA3_512 | ||
declareHashAlgorithm "Sha3_256" Hash.SHA3_256 | ||
declareHashAlgorithm "Sha2_512" Hash.SHA512 | ||
declareHashAlgorithm "Sha2_256" Hash.SHA256 | ||
declareHashAlgorithm "Blake2b_512" Hash.Blake2b_512 | ||
declareHashAlgorithm "Blake2b_256" Hash.Blake2b_256 | ||
declareHashAlgorithm "Blake2s_256" Hash.Blake2s_256 | ||
|
||
-- declareForeign ("crypto.hash") pfopbb . mkForeign $ \(HashAlgorithm _ref _alg, _a :: Closure) -> | ||
-- pure $ Bytes.empty -- todo : implement me | ||
|
||
declareForeign "crypto.hashBytes" pfopbb . mkForeign $ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Notice am using the |
||
\(HashAlgorithm _ alg, b :: Bytes.Bytes) -> | ||
let ctx = Hash.hashInitWith alg | ||
in pure . Bytes.fromArray . Hash.hashFinalize $ Hash.hashUpdates ctx (Bytes.chunks b) | ||
|
||
declareForeign "crypto.hmacBytes" pfopbbb | ||
. mkForeign $ \(HashAlgorithm _ alg, key :: Bytes.Bytes, msg :: Bytes.Bytes) -> | ||
let out = u alg $ HMAC.hmac (Bytes.toArray @BA.Bytes key) (Bytes.toArray @BA.Bytes msg) | ||
u :: a -> HMAC.HMAC a -> HMAC.HMAC a | ||
u _ h = h -- to help typechecker along | ||
in pure $ Bytes.fromArray out | ||
|
||
declareForeign "Bytes.toBase16" pfopb . mkForeign $ pure . Bytes.toBase16 | ||
declareForeign "Bytes.toBase32" pfopb . mkForeign $ pure . Bytes.toBase32 | ||
declareForeign "Bytes.toBase64" pfopb . mkForeign $ pure . Bytes.toBase64 | ||
declareForeign "Bytes.toBase64UrlUnpadded" pfopb . mkForeign $ pure . Bytes.toBase64UrlUnpadded | ||
|
||
declareForeign "Bytes.fromBase16" pfopb_ebb . mkForeign $ pure . Bytes.fromBase16 | ||
declareForeign "Bytes.fromBase32" pfopb_ebb . mkForeign $ pure . Bytes.fromBase32 | ||
declareForeign "Bytes.fromBase64" pfopb_ebb . mkForeign $ pure . Bytes.fromBase64 | ||
declareForeign "Bytes.fromBase64UrlUnpadded" pfopb . mkForeign $ pure . Bytes.fromBase64UrlUnpadded | ||
|
||
hostPreference :: Maybe Text -> SYS.HostPreference | ||
hostPreference Nothing = SYS.HostAny | ||
hostPreference (Just host) = SYS.Host $ Text.unpack host | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
{-# language DataKinds #-} | ||
{-# language ViewPatterns #-} | ||
{-# language RecordWildCards #-} | ||
{-# language UndecidableInstances #-} | ||
|
||
module Unison.Runtime.Foreign.Function | ||
( ForeignFunc(..) | ||
|
@@ -295,6 +296,10 @@ instance ForeignConvention (MVar Closure) where | |
readForeign = readForeignAs (unwrapForeign . marshalToForeign) | ||
writeForeign = writeForeignAs (Foreign . Wrap mvarRef) | ||
|
||
instance {-# overlappable #-} BuiltinForeign b => ForeignConvention b where | ||
readForeign = readForeignBuiltin | ||
writeForeign = writeForeignBuiltin | ||
Comment on lines
+299
to
+301
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This saves you from needing to provide a |
||
|
||
instance {-# overlappable #-} BuiltinForeign b => ForeignConvention [b] | ||
where | ||
readForeign us (i:bs) _ bstk | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added these common cases and am recycling them in a few places for various builtins.