1/// This package is based on the Go implementation found here:
2/// https://cs.opensource.google/go/go/+/refs/tags/go1.23.0:src/crypto/hmac/hmac.go
3/// which has the copyright notice:
4/// Copyright 2009 The Go Authors. All rights reserved.
5/// Use of this source code is governed by a BSD-style
6/// license that can be found in the LICENSE file.
7
8///|
9/// `gen_hmac` generates a base64-encoded String representing
10/// the SHA256 signature of the provided `body` using the provided
11/// `client_secret` key.
12pub fn 
(body : Bytes, client_secret : Bytes) -> String

gen_hmac generates a base64-encoded String representing the SHA256 signature of the provided body using the provided client_secret key.

gen_hmac
(
Bytes
body
:
Bytes
Bytes
,
Bytes
client_secret
:
Bytes
Bytes
) ->
String
String
{
13 let
HMAC
h
=
struct HMAC {
  opad: FixedArray[Byte]
  ipad: FixedArray[Byte]
  outer: Digest
  inner: Digest
}
HMAC
::
(key : Bytes) -> HMAC
new
(
Bytes
client_secret
)
14 for
Byte
b
in
Bytes
body
{
15
HMAC
h
.
Digest
inner
.
(self : Digest, b : Byte) -> Unit

write writes a byte to the digest.

write
(
Byte
b
)
16 } 17 let
FixedArray[Byte]
buf
=
HMAC
h
.
(self : HMAC) -> FixedArray[Byte]
sum
()
18
(src : FixedArray[Byte], no_padding~ : Bool = ..) -> String

url_encode2str base64-encodes the provided bytes using URL encoding and returns a String. Setting no_padding=true is used for raw encoding.

Note that standard encoding uses + and / characters whereas URL encoding uses - and _.

Examples:

let b : Bytes = "+/ Hello, δΈ–η•Œ! 🌍"
inspect!(url_encode2str(b.to_fixedarray()), content="Ky8gSGVsbG8sIOS4lueVjCEg8J-MjQ==")
inspect!(url_encode2str(b.to_fixedarray(), no_padding=true), content="Ky8gSGVsbG8sIOS4lueVjCEg8J-MjQ")
@base64.url_encode2str
(
FixedArray[Byte]
buf
)
19} 20 21///| 22priv struct HMAC { 23
FixedArray[Byte]
opad
:
type FixedArray[A]
FixedArray
[
Byte
Byte
]
24
FixedArray[Byte]
ipad
:
type FixedArray[A]
FixedArray
[
Byte
Byte
]
25
Digest
outer
:
struct Digest {
  h: FixedArray[UInt]
  x: FixedArray[Byte]
  mut nx: Int
  mut len: UInt64
  name: String
}

Digest represents the partial evaluation of a checksum.

Digest
26
Digest
inner
:
struct Digest {
  h: FixedArray[UInt]
  x: FixedArray[Byte]
  mut nx: Int
  mut len: UInt64
  name: String
}

Digest represents the partial evaluation of a checksum.

Digest
27} 28 29///| 30fn
struct HMAC {
  opad: FixedArray[Byte]
  ipad: FixedArray[Byte]
  outer: Digest
  inner: Digest
}
HMAC
::
(key : Bytes) -> HMAC
new
(
Bytes
key
:
Bytes
Bytes
) ->
struct HMAC {
  opad: FixedArray[Byte]
  ipad: FixedArray[Byte]
  outer: Digest
  inner: Digest
}
HMAC
{
31 let
HMAC
hm
= {
32
FixedArray[Byte]
opad
:
type FixedArray[A]
FixedArray
::
(len : Int, init : Byte) -> FixedArray[Byte]

Creates a new fixed-size array with the specified length, initializing all elements with the given value.

Parameters:

  • length : The length of the array to create. Must be non-negative.
  • initial_value : The value used to initialize all elements in the array.

Returns a new fixed-size array of type FixedArray[T] with length elements, where each element is initialized to initial_value.

Throws a panic if length is negative.

Example:

test "FixedArray::make" {
  let arr = FixedArray::make(3, 42)
  inspect(arr[0], content="42")
  inspect(arr.length(), content="3")
}

test "panic FixedArray::make/negative_length" {
  ignore(FixedArray::make(-1, 0))
}

WARNING: A common pitfall is creating with the same initial value, for example:

test {
  let two_dimension_array = FixedArray::make(10, FixedArray::make(10, 0))
  two_dimension_array[0][5] = 10
  assert_eq(two_dimension_array[5][5], 10)
}

This is because all the cells reference to the same object (the FixedArray[Int] in this case). One should use makei() instead which creates an object for each index.

make
(
Int
block_size
, b'\x00'),
33
FixedArray[Byte]
ipad
:
type FixedArray[A]
FixedArray
::
(len : Int, init : Byte) -> FixedArray[Byte]

Creates a new fixed-size array with the specified length, initializing all elements with the given value.

Parameters:

  • length : The length of the array to create. Must be non-negative.
  • initial_value : The value used to initialize all elements in the array.

Returns a new fixed-size array of type FixedArray[T] with length elements, where each element is initialized to initial_value.

Throws a panic if length is negative.

Example:

test "FixedArray::make" {
  let arr = FixedArray::make(3, 42)
  inspect(arr[0], content="42")
  inspect(arr.length(), content="3")
}

test "panic FixedArray::make/negative_length" {
  ignore(FixedArray::make(-1, 0))
}

WARNING: A common pitfall is creating with the same initial value, for example:

test {
  let two_dimension_array = FixedArray::make(10, FixedArray::make(10, 0))
  two_dimension_array[0][5] = 10
  assert_eq(two_dimension_array[5][5], 10)
}

This is because all the cells reference to the same object (the FixedArray[Int] in this case). One should use makei() instead which creates an object for each index.

make
(
Int
block_size
, b'\x00'),
34
Digest
outer
:
struct Digest {
  h: FixedArray[UInt]
  x: FixedArray[Byte]
  mut nx: Int
  mut len: UInt64
  name: String
}

Digest represents the partial evaluation of a checksum.

Digest
::
() -> Digest

Digest::new returns a new, reset Digest, ready to sum.

new
(),
35
Digest
inner
:
struct Digest {
  h: FixedArray[UInt]
  x: FixedArray[Byte]
  mut nx: Int
  mut len: UInt64
  name: String
}

Digest represents the partial evaluation of a checksum.

Digest
::
() -> Digest

Digest::new returns a new, reset Digest, ready to sum.

new
(),
36 } 37 // If key is too big, hash it. 38 let mut
FixedArray[Byte]
key
=
type FixedArray[A]
FixedArray
::
(iter : Iter[Byte]) -> FixedArray[Byte]

Creates a new fixed array from an iterator.

Parameters:

  • iterator : An iterator of type Iter[T] from which elements will be collected into a fixed array.

Returns a new fixed array containing all elements from the iterator.

Example:

test "FixedArray::from_iter" {
  let arr = [1, 2, 3]
  let fixed_arr = FixedArray::from_iter(arr.iter())
  inspect(fixed_arr, content="[1, 2, 3]")
}
from_iter
(
Bytes
key
.
(self : Bytes) -> Iter[Byte]

Creates an iterator over the bytes in the sequence.

Parameters:

  • bytes : A byte sequence to iterate over.

Returns an iterator that yields each byte in the sequence in order.

Example:

test "Bytes::iter" {
  let bytes = Bytes::from_array([b'h', b'i'])
  let mut sum = 0
  bytes.iter().each(fn(b) { sum = sum + b.to_int() })
  inspect(sum, content="209") // ASCII values: 'h'(104) + 'i'(105) = 209
}
iter
())
39 if
FixedArray[Byte]
key
.
(self : FixedArray[Byte]) -> Int

Returns the number of elements in a fixed-size array.

Parameters:

  • array : The fixed-size array whose length is to be determined.

Returns an integer representing the number of elements in the array.

Example:

test "FixedArray::length" {
  let arr = FixedArray::make(3, 42)
  inspect(arr.length(), content="3")
}
length
()
(self_ : Int, other : Int) -> Bool
>
Int
block_size
{
40 for
Byte
b
in
FixedArray[Byte]
key
{
41
HMAC
hm
.
Digest
outer
.
(self : Digest, b : Byte) -> Unit

write writes a byte to the digest.

write
(
Byte
b
)
42 } 43
FixedArray[Byte]
key
=
HMAC
hm
.
Digest
outer
.
(self : Digest) -> FixedArray[Byte]

sum returns the final sha256sum as a FixedArray[Byte].

sum
()
44 } 45 // copy 46 for
Int
index
,
Byte
b
in
FixedArray[Byte]
key
{
47
HMAC
hm
.
FixedArray[Byte]
ipad
(FixedArray[Byte], Int, Byte) -> Unit

Sets a value at the specified index in a fixed-size array. The original value at that index is overwritten.

Parameters:

  • array : The fixed-size array to modify.
  • index : The position in the array where the value will be set.
  • value : The new value to assign at the specified index.

Throws a runtime error if the index is out of bounds (less than 0 or greater than or equal to the length of the array).

Example:

test "FixedArray::op_set" {
  let arr = [1, 2, 3]
  arr[1] = 42
  inspect(arr, content="[1, 42, 3]")
}

test "panic FixedArray::op_set/out_of_bounds" {
  let arr = [1, 2, 3]
  arr[3] = 42 // Index out of bounds
}
[
index] =
Byte
b
48
HMAC
hm
.
FixedArray[Byte]
opad
(FixedArray[Byte], Int, Byte) -> Unit

Sets a value at the specified index in a fixed-size array. The original value at that index is overwritten.

Parameters:

  • array : The fixed-size array to modify.
  • index : The position in the array where the value will be set.
  • value : The new value to assign at the specified index.

Throws a runtime error if the index is out of bounds (less than 0 or greater than or equal to the length of the array).

Example:

test "FixedArray::op_set" {
  let arr = [1, 2, 3]
  arr[1] = 42
  inspect(arr, content="[1, 42, 3]")
}

test "panic FixedArray::op_set/out_of_bounds" {
  let arr = [1, 2, 3]
  arr[3] = 42 // Index out of bounds
}
[
index] =
Byte
b
49 } 50 for
Int
index
,
Byte
b
in
HMAC
hm
.
FixedArray[Byte]
ipad
{
51
HMAC
hm
.
FixedArray[Byte]
ipad
(FixedArray[Byte], Int, Byte) -> Unit

Sets a value at the specified index in a fixed-size array. The original value at that index is overwritten.

Parameters:

  • array : The fixed-size array to modify.
  • index : The position in the array where the value will be set.
  • value : The new value to assign at the specified index.

Throws a runtime error if the index is out of bounds (less than 0 or greater than or equal to the length of the array).

Example:

test "FixedArray::op_set" {
  let arr = [1, 2, 3]
  arr[1] = 42
  inspect(arr, content="[1, 42, 3]")
}

test "panic FixedArray::op_set/out_of_bounds" {
  let arr = [1, 2, 3]
  arr[3] = 42 // Index out of bounds
}
[
index] =
Byte
b
(self : Byte, that : Byte) -> Byte

Performs a bitwise XOR operation between two Byte values.

Parameters:

  • self : The first Byte value.
  • that : The second Byte value.

Returns the result of the bitwise XOR operation as a Byte.

^
b'\x36'
52
HMAC
hm
.
Digest
inner
.
(self : Digest, b : Byte) -> Unit

write writes a byte to the digest.

write
(
HMAC
hm
.
FixedArray[Byte]
ipad
(FixedArray[Byte], Int) -> Byte

Retrieves an element at the specified index from a fixed-size array. This function implements the array indexing operator [].

Parameters:

  • array : The fixed-size array to access.
  • index : The position in the array from which to retrieve the element.

Returns the element at the specified index.

Throws a runtime error if the index is out of bounds (negative or greater than or equal to the length of the array).

Example:

test "FixedArray::op_get" {
  let arr = FixedArray::make(3, 42)
  inspect(arr[1], content="42")
}

test "panic FixedArray::op_get/out_of_bounds" {
  let arr = FixedArray::make(3, 0)
  ignore(arr[3]) // Index out of bounds
}
[
index])
53 } 54 for
Int
index
,
Byte
b
in
HMAC
hm
.
FixedArray[Byte]
opad
{
55
HMAC
hm
.
FixedArray[Byte]
opad
(FixedArray[Byte], Int, Byte) -> Unit

Sets a value at the specified index in a fixed-size array. The original value at that index is overwritten.

Parameters:

  • array : The fixed-size array to modify.
  • index : The position in the array where the value will be set.
  • value : The new value to assign at the specified index.

Throws a runtime error if the index is out of bounds (less than 0 or greater than or equal to the length of the array).

Example:

test "FixedArray::op_set" {
  let arr = [1, 2, 3]
  arr[1] = 42
  inspect(arr, content="[1, 42, 3]")
}

test "panic FixedArray::op_set/out_of_bounds" {
  let arr = [1, 2, 3]
  arr[3] = 42 // Index out of bounds
}
[
index] =
Byte
b
(self : Byte, that : Byte) -> Byte

Performs a bitwise XOR operation between two Byte values.

Parameters:

  • self : The first Byte value.
  • that : The second Byte value.

Returns the result of the bitwise XOR operation as a Byte.

^
b'\x5c'
56 } 57
HMAC
hm
58} 59 60///| 61fn
struct HMAC {
  opad: FixedArray[Byte]
  ipad: FixedArray[Byte]
  outer: Digest
  inner: Digest
}
HMAC
::
(self : HMAC) -> FixedArray[Byte]
sum
(
HMAC
self
:
struct HMAC {
  opad: FixedArray[Byte]
  ipad: FixedArray[Byte]
  outer: Digest
  inner: Digest
}
HMAC
) ->
type FixedArray[A]
FixedArray
[
Byte
Byte
] {
62 let
FixedArray[Byte]
inner_sum
=
HMAC
self
.
Digest
inner
.
(self : Digest) -> FixedArray[Byte]

sum returns the final sha256sum as a FixedArray[Byte].

sum
()
63
HMAC
self
.
Digest
outer
.
(self : Digest) -> Unit

reset resets a digest for re-use.

reset
()
64 for
Byte
b
in
HMAC
self
.
FixedArray[Byte]
opad
{
65
HMAC
self
.
Digest
outer
.
(self : Digest, b : Byte) -> Unit

write writes a byte to the digest.

write
(
Byte
b
)
66 } 67 for
Byte
b
in
FixedArray[Byte]
inner_sum
{
68
HMAC
self
.
Digest
outer
.
(self : Digest, b : Byte) -> Unit

write writes a byte to the digest.

write
(
Byte
b
)
69 } 70
HMAC
self
.
Digest
outer
.
(self : Digest) -> FixedArray[Byte]

sum returns the final sha256sum as a FixedArray[Byte].

sum
()
71} 72