File: shake.ha

package info (click to toggle)
hare 0.26.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,352 kB
  • sloc: asm: 1,374; makefile: 123; sh: 117; lisp: 101
file content (103 lines) | stat: -rw-r--r-- 2,865 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>
// (c) 2023 Nicholas Rodrigues Lordello <n@lordello.net>

use bytes;
use io;

// The rate or block size, in bytes, of a SHAKE128 XOF.
export def SHAKE_BLOCKSZ128: size = 168;

// The rate or block size, in bytes, of a SHAKE256 XOF.
export def SHAKE_BLOCKSZ256: size = 136;

// The domain separation byte **including** the first bit of padding for the
// SHAKE family of XOFs as specified in Appendix B.2 of FIPS 202.
def SHAKE_DS: u8 = 0x1f;

// Creates an [[io::stream]] that acts as a SHAKE128 eXtendable-Output Function
// (XOF). XOFs produce an output of unlimited size given some input data.
//
//	let shake = sha3::shake128();
//	// Absorb some input:
//	io::write(&shake, strings::toutf8("hello "))!;
//	io::write(&shake, strings::toutf8("hare!"))!;
//
//	// Copying the XOF copies its state:
//	let dup = shake;
//
//	// Squeeze some output:
//	let buf: []u8 = alloc([0...], 1337);
//	io::read(&shake, buf[..42])!;
//	io::read(&shake, buf[42..])!;
//
//	// Absorbing (i.e. writing) more input is an error:
//	assert(io::write(&shake, []) is errors::unsupported);
//
// All calls to [[io::write]] while absorbing and to [[io::read]] always
// write/read the full specified buffer and never fail. If this stream is used
// to write sensitive information, the caller should call [[io::close]] to erase
// sensitive data from memory after use; if not, the use of [[io::close]] is
// optional.
export fn shake128() xof = shake_init(SHAKE_BLOCKSZ128);

// Creates an [[io::stream]] that acts as a SHAKE256 eXtendable-Output Function
// (XOF). See [[shake128]] for more information.
export fn shake256() xof = shake_init(SHAKE_BLOCKSZ256);

export type xof = struct {
	stream: io::stream,
	e: sponge,
};

fn shake_init(rate: size) xof = {
	return xof {
		stream = &shake_absorb_vtable,
		e = sponge {
			rate = rate,
			ds = SHAKE_DS,
			s = [0...],
			pos = 0,
		},
	};
};

const shake_absorb_vtable: io::vtable = io::vtable {
	reader = &shake_first_read,
	writer = &shake_write,
	closer = &shake_close,
	...
};

const shake_squeeze_vtable: io::vtable = io::vtable {
	reader = &shake_read,
	closer = &shake_close,
	...
};

fn shake_first_read(st: *io::stream, buf: []u8) (size | io::EOF | io::error) = {
	let f = st: *xof;
	// once a sponge starts being squeezed, it cannot absorb new data anymore.
	f.stream = &shake_squeeze_vtable;
	pad(&f.e);
	squeeze(&f.e, buf);
	return len(buf);
};

fn shake_read(st: *io::stream, buf: []u8) (size | io::EOF | io::error) = {
	let f = st: *xof;
	squeeze(&f.e, buf);
	return len(buf);
};

fn shake_write(st: *io::stream, buf: const []u8) (size | io::error) = {
	let f = st: *xof;
	absorb(&f.e, buf);
	return len(buf);
};

fn shake_close(st: *io::stream) (void | io::error) = {
	let f = st: *xof;
	f.stream = &shake_absorb_vtable;
	reset(&f.e);
};