mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
Compare commits
5 commits
919c68e6f9
...
c2e2aac0c9
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c2e2aac0c9 | ||
![]() |
97145ca3a8 | ||
![]() |
b653d65676 | ||
![]() |
a10c59704b | ||
![]() |
f16452d3a6 |
17 changed files with 538 additions and 147 deletions
|
@ -91,7 +91,7 @@ fn get_all_commands() []Command {
|
||||||
rmfile: 'examples/hello_world'
|
rmfile: 'examples/hello_world'
|
||||||
}
|
}
|
||||||
res << Command{
|
res << Command{
|
||||||
line: '${vexe} -W -Wimpure-v run examples/hello_world.v'
|
line: '${vexe} -W -Wimpure-v examples/hello_world.v'
|
||||||
okmsg: 'V can compile hello world with the stricter `-W -Wimpure-v` mode .'
|
okmsg: 'V can compile hello world with the stricter `-W -Wimpure-v` mode .'
|
||||||
rmfile: 'examples/hello_world'
|
rmfile: 'examples/hello_world'
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,6 +131,11 @@ pub fn (mut b Builder) middle_stages() ! {
|
||||||
|
|
||||||
b.checker.check_files(b.parsed_files)
|
b.checker.check_files(b.parsed_files)
|
||||||
util.timing_measure('CHECK')
|
util.timing_measure('CHECK')
|
||||||
|
$if trace_type_symbols_after_checker ? {
|
||||||
|
for t, s in b.table.type_symbols {
|
||||||
|
println('> t: ${t:10} | s.mod: ${s.mod:-40} | s.name: ${'${s.name#[..30]}':-30} | s.is_builtin: ${s.is_builtin:6} | s.is_pub: ${s.is_pub}')
|
||||||
|
}
|
||||||
|
}
|
||||||
if b.pref.dump_defines != '' {
|
if b.pref.dump_defines != '' {
|
||||||
b.dump_defines()
|
b.dump_defines()
|
||||||
}
|
}
|
||||||
|
|
16
vlib/v/gen/c/testdata/autofree_toml.vv
vendored
16
vlib/v/gen/c/testdata/autofree_toml.vv
vendored
|
@ -2,14 +2,8 @@
|
||||||
import toml
|
import toml
|
||||||
import os
|
import os
|
||||||
|
|
||||||
fn main() {
|
config_fname := os.join_path(os.vtmp_dir(), 'config.toml')
|
||||||
config_fname := 'config.toml'
|
tab_title := 'test tab title'
|
||||||
tab_title := 'test tab title'
|
os.write_file(config_fname, 'tab_title = "${tab_title}"')!
|
||||||
if !os.exists(config_fname) {
|
doc := toml.parse_file(config_fname)!
|
||||||
mut f := os.create(config_fname) or { panic(err) }
|
assert doc.value('tab_title').string() == tab_title
|
||||||
f.writeln('tab_title = "${tab_title}"') or { panic(err) }
|
|
||||||
f.close()
|
|
||||||
}
|
|
||||||
doc := toml.parse_file(config_fname) or { panic(err) }
|
|
||||||
assert doc.value('tab_title').string() == tab_title
|
|
||||||
}
|
|
||||||
|
|
|
@ -953,7 +953,7 @@ fn (mut c Amd64) lea_var_to_reg(r Register, var_offset i32) {
|
||||||
|
|
||||||
is_far_var := var_offset > 0x80 || var_offset < -0x7f
|
is_far_var := var_offset > 0x80 || var_offset < -0x7f
|
||||||
match reg {
|
match reg {
|
||||||
.rax, .rbx, .rsi, .rdi {
|
.rax, .rbx, .rsi, .rdi, .rdx, .rcx {
|
||||||
c.g.write8(0x48)
|
c.g.write8(0x48)
|
||||||
}
|
}
|
||||||
else {}
|
else {}
|
||||||
|
@ -2753,6 +2753,7 @@ fn (mut c Amd64) gen_type_promotion(from ast.Type, to ast.Type, option Amd64Regi
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Amd64) return_stmt(node ast.Return) {
|
fn (mut c Amd64) return_stmt(node ast.Return) {
|
||||||
|
c.g.println('; return statement {')
|
||||||
mut s := '?' //${node.exprs[0].val.str()}'
|
mut s := '?' //${node.exprs[0].val.str()}'
|
||||||
if node.exprs.len == 1 {
|
if node.exprs.len == 1 {
|
||||||
match node.exprs[0] {
|
match node.exprs[0] {
|
||||||
|
@ -2812,6 +2813,8 @@ fn (mut c Amd64) return_stmt(node ast.Return) {
|
||||||
c.add(Amd64Register.rax, size % 8)
|
c.add(Amd64Register.rax, size % 8)
|
||||||
c.add(Amd64Register.rdx, size % 8)
|
c.add(Amd64Register.rdx, size % 8)
|
||||||
c.mov_deref(Amd64Register.rcx, Amd64Register.rax, ast.i64_type_idx)
|
c.mov_deref(Amd64Register.rcx, Amd64Register.rax, ast.i64_type_idx)
|
||||||
|
// TODO: check if it does not write too far as the size of
|
||||||
|
// the remaining data is not 64bits
|
||||||
c.mov_store(.rdx, .rcx, ._64)
|
c.mov_store(.rdx, .rcx, ._64)
|
||||||
}
|
}
|
||||||
c.mov_var_to_reg(c.main_reg(), LocalVar{
|
c.mov_var_to_reg(c.main_reg(), LocalVar{
|
||||||
|
@ -2841,7 +2844,14 @@ fn (mut c Amd64) return_stmt(node ast.Return) {
|
||||||
offset := c.g.structs[typ.idx()].offsets[i]
|
offset := c.g.structs[typ.idx()].offsets[i]
|
||||||
c.g.expr(expr)
|
c.g.expr(expr)
|
||||||
// TODO: expr not on rax
|
// TODO: expr not on rax
|
||||||
c.mov_reg_to_var(var, Amd64Register.rax, offset: offset, typ: ts.mr_info().types[i])
|
e_typ := ts.mr_info().types[i]
|
||||||
|
e_ts := c.g.table.sym(e_typ)
|
||||||
|
if e_ts.info is ast.Struct {
|
||||||
|
c.lea_var_to_reg(Amd64Register.rdx, var.offset - offset)
|
||||||
|
c.move_struct(.rdx, .rax, c.g.get_type_size(e_typ))
|
||||||
|
} else {
|
||||||
|
c.mov_reg_to_var(var, Amd64Register.rax, offset: offset, typ: ts.mr_info().types[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// store the multi return struct value
|
// store the multi return struct value
|
||||||
c.lea_var_to_reg(Amd64Register.rax, var.offset)
|
c.lea_var_to_reg(Amd64Register.rax, var.offset)
|
||||||
|
@ -2897,6 +2907,7 @@ fn (mut c Amd64) return_stmt(node ast.Return) {
|
||||||
pos: pos
|
pos: pos
|
||||||
}
|
}
|
||||||
c.g.println('; jump to label ${label}')
|
c.g.println('; jump to label ${label}')
|
||||||
|
c.g.println('; return statement }')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Amd64) multi_assign_stmt(node ast.AssignStmt) {
|
fn (mut c Amd64) multi_assign_stmt(node ast.AssignStmt) {
|
||||||
|
@ -2926,7 +2937,7 @@ fn (mut c Amd64) multi_assign_stmt(node ast.AssignStmt) {
|
||||||
} else {
|
} else {
|
||||||
c.g.expr(node.right[0])
|
c.g.expr(node.right[0])
|
||||||
}
|
}
|
||||||
c.mov_reg(Amd64Register.rdx, Amd64Register.rax)
|
c.mov_reg(Amd64Register.rdx, Amd64Register.rax) // value of right expr(s)
|
||||||
|
|
||||||
mut current_offset := i32(0)
|
mut current_offset := i32(0)
|
||||||
for i, offset in multi_return.offsets {
|
for i, offset in multi_return.offsets {
|
||||||
|
@ -2943,7 +2954,7 @@ fn (mut c Amd64) multi_assign_stmt(node ast.AssignStmt) {
|
||||||
c.add(Amd64Register.rdx, offset - current_offset)
|
c.add(Amd64Register.rdx, offset - current_offset)
|
||||||
current_offset = offset
|
current_offset = offset
|
||||||
}
|
}
|
||||||
c.g.gen_left_value(node.left[i])
|
c.g.gen_left_value(node.left[i]) // in rax
|
||||||
left_type := node.left_types[i]
|
left_type := node.left_types[i]
|
||||||
right_type := node.right_types[i]
|
right_type := node.right_types[i]
|
||||||
if c.g.is_register_type(right_type) {
|
if c.g.is_register_type(right_type) {
|
||||||
|
@ -3001,11 +3012,36 @@ fn (mut c Amd64) multi_assign_stmt(node ast.AssignStmt) {
|
||||||
c.g.println('movsd [rax], xmm0')
|
c.g.println('movsd [rax], xmm0')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.g.n_error('${@LOCATION} multi return for struct is not supported yet')
|
c.move_struct(.rax, .rdx, c.g.get_type_size(left_type))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Moves a struct of size `_size` (in bytes) from the address stored in input to the address stored in output
|
||||||
|
fn (mut c Amd64) move_struct(output Amd64Register, input Amd64Register, _size i32) {
|
||||||
|
mut size := _size
|
||||||
|
for size != 0 {
|
||||||
|
c.mov_deref(Amd64Register.rcx, input, ast.i64_type_idx)
|
||||||
|
// mov_store can only move powers of 2 bytes at once
|
||||||
|
// the remainder will then get handled the next iteration for simplicity
|
||||||
|
data_size := i32(match true {
|
||||||
|
size < 2 { 1 }
|
||||||
|
size < 4 { 2 }
|
||||||
|
size < 8 { 4 }
|
||||||
|
else { 8 }
|
||||||
|
})
|
||||||
|
c.mov_store(output, .rcx, match data_size {
|
||||||
|
1 { ._8 }
|
||||||
|
2 { ._16 }
|
||||||
|
4 { ._32 }
|
||||||
|
else { ._64 }
|
||||||
|
})
|
||||||
|
size -= data_size
|
||||||
|
c.add(output, data_size)
|
||||||
|
c.add(input, data_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut c Amd64) assign_stmt(node ast.AssignStmt) {
|
fn (mut c Amd64) assign_stmt(node ast.AssignStmt) {
|
||||||
// `a, b := foo()`
|
// `a, b := foo()`
|
||||||
// `a, b := if cond { 1, 2 } else { 3, 4 }`
|
// `a, b := if cond { 1, 2 } else { 3, 4 }`
|
||||||
|
|
|
@ -61,7 +61,44 @@ fn cross_assign_of_struct_test() { // from cross_assign_test.v
|
||||||
assert x.b == 1
|
assert x.b == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MyStruct {
|
||||||
|
a int
|
||||||
|
b u64
|
||||||
|
c u16
|
||||||
|
d u8
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyStruct2 {
|
||||||
|
a u8
|
||||||
|
b u8
|
||||||
|
c u8
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_multi_return() (int, MyStruct) {
|
||||||
|
return 3, MyStruct{4, 5, 6, 7}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_multi_return2() (int, MyStruct2) {
|
||||||
|
return 3, MyStruct2{4, 5, 6}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_multi_return_test() {
|
||||||
|
a, b := struct_multi_return()
|
||||||
|
assert a == 3
|
||||||
|
assert b.a == 4
|
||||||
|
assert b.b == 5
|
||||||
|
assert b.c == 6
|
||||||
|
assert b.d == 7
|
||||||
|
|
||||||
|
c, d := struct_multi_return2()
|
||||||
|
assert c == 3
|
||||||
|
assert d.a == 4
|
||||||
|
assert d.b == 5
|
||||||
|
assert d.c == 6
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
fn_multi_return_test()
|
fn_multi_return_test()
|
||||||
cross_assign_of_struct_test()
|
cross_assign_of_struct_test()
|
||||||
|
struct_multi_return_test()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
# ascon
|
# ascon
|
||||||
|
|
||||||
`ascon` is a implementation of Ascon-Based Cryptography module implemented in pure V language.
|
`ascon` is an implementation of Ascon-Based Cryptography module implemented in pure V language.
|
||||||
This module was mostly based on NIST Special Publication of 800 NIST SP 800-232 document.
|
This module was mostly based on NIST Special Publication of 800 NIST SP 800-232 document.
|
||||||
Its describes an Ascon-Based Lightweight Cryptography Standards for Constrained Devices
|
Its describes an Ascon-Based Lightweight Cryptography Standards for Constrained Devices
|
||||||
thats provides Authenticated Encryption, Hash, and Extendable Output Functions.
|
thats provides Authenticated Encryption, Hash, and Extendable Output Functions.
|
||||||
See the [NIST.SP.800-232 Standard](https://doi.org/10.6028/NIST.SP.800-232) for more detail.
|
See the [NIST.SP.800-232 Standard](https://doi.org/10.6028/NIST.SP.800-232) for more detail.
|
||||||
|
|
||||||
This module does not fully implements all the features availables on the document.
|
This module mostly implements all the features availables on the document.
|
||||||
Its currently implements:
|
It currently implements:
|
||||||
- `Ascon-Hash256`, Ascon-based hashing implementation that produces 256-bits output.
|
- `Ascon-Hash256`, Ascon-based hashing implementation that produces 256-bits output.
|
||||||
- `Ascon-XOF128`, Ascon-based eXtendible Output Function (XOF) where the output size of
|
- `Ascon-XOF128`, Ascon-based eXtendable Output Function (XOF) where the output size of
|
||||||
the hash of the message can be selected by the user.
|
the hash of the message can be selected by the user.
|
||||||
- `Ascon-CXOF128`, a customized XOF that allows users to specify a customization
|
- `Ascon-CXOF128`, a customized XOF that allows users to specify a customization
|
||||||
string and choose the output size of the message hash.
|
string and choose the output size of the message hash.
|
||||||
|
- `Ascon-AEAD128`, an Authenticated Encryption with Additional Data (AEAD) Scheme based
|
||||||
|
on Ascon-family crypto.
|
||||||
|
|
|
@ -181,7 +181,7 @@ pub fn (mut c Aead128) encrypt(msg []u8, nonce []u8, ad []u8) ![]u8 {
|
||||||
c.State.e4 = n1
|
c.State.e4 = n1
|
||||||
|
|
||||||
// Update state by permutation
|
// Update state by permutation
|
||||||
ascon_pnr(mut c.State, 12)
|
ascon_pnr(mut c.State, ascon_prnd_12)
|
||||||
// XOR-ing with the cipher's key
|
// XOR-ing with the cipher's key
|
||||||
c.State.e3 ^= c.key[0]
|
c.State.e3 ^= c.key[0]
|
||||||
c.State.e4 ^= c.key[1]
|
c.State.e4 ^= c.key[1]
|
||||||
|
@ -229,7 +229,7 @@ pub fn (mut c Aead128) decrypt(ciphertext []u8, nonce []u8, ad []u8) ![]u8 {
|
||||||
c.State.e4 = n1
|
c.State.e4 = n1
|
||||||
|
|
||||||
// scrambled with permutation routine
|
// scrambled with permutation routine
|
||||||
ascon_pnr(mut c.State, 12)
|
ascon_pnr(mut c.State, ascon_prnd_12)
|
||||||
// xor-ing with the cipher's key
|
// xor-ing with the cipher's key
|
||||||
c.State.e3 ^= c.key[0]
|
c.State.e3 ^= c.key[0]
|
||||||
c.State.e4 ^= c.key[1]
|
c.State.e4 ^= c.key[1]
|
||||||
|
@ -288,7 +288,7 @@ fn aead128_init(mut s State, key []u8, nonce []u8) (u64, u64) {
|
||||||
s.e4 = n1
|
s.e4 = n1
|
||||||
|
|
||||||
// updates State using the permutation 𝐴𝑠𝑐𝑜𝑛-𝑝[12], S ← 𝐴𝑠𝑐𝑜𝑛-𝑝[12](S)
|
// updates State using the permutation 𝐴𝑠𝑐𝑜𝑛-𝑝[12], S ← 𝐴𝑠𝑐𝑜𝑛-𝑝[12](S)
|
||||||
ascon_pnr(mut s, 12)
|
ascon_pnr(mut s, ascon_prnd_12)
|
||||||
|
|
||||||
// Then XORing the secret key 𝐾 into the last 128 bits of internal state:
|
// Then XORing the secret key 𝐾 into the last 128 bits of internal state:
|
||||||
// S ← S ⊕ (0¹⁹² ∥ 𝐾).
|
// S ← S ⊕ (0¹⁹² ∥ 𝐾).
|
||||||
|
@ -312,7 +312,7 @@ fn aead128_process_ad(mut s State, ad []u8) {
|
||||||
s.e1 ^= binary.little_endian_u64(block[8..16])
|
s.e1 ^= binary.little_endian_u64(block[8..16])
|
||||||
|
|
||||||
// Apply permutation 𝐴𝑠𝑐𝑜𝑛-𝑝[8] to the state
|
// Apply permutation 𝐴𝑠𝑐𝑜𝑛-𝑝[8] to the state
|
||||||
ascon_pnr(mut s, 8)
|
ascon_pnr(mut s, ascon_prnd_8)
|
||||||
// Updates index
|
// Updates index
|
||||||
ad_length -= aead128_block_size
|
ad_length -= aead128_block_size
|
||||||
ad_idx += aead128_block_size
|
ad_idx += aead128_block_size
|
||||||
|
@ -339,7 +339,7 @@ fn aead128_process_ad(mut s State, ad []u8) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Apply permutation 𝐴𝑠𝑐𝑜𝑛-𝑝[8] to the state
|
// Apply permutation 𝐴𝑠𝑐𝑜𝑛-𝑝[8] to the state
|
||||||
ascon_pnr(mut s, 8)
|
ascon_pnr(mut s, ascon_prnd_8)
|
||||||
}
|
}
|
||||||
// The final step of processing associated data is to update the state
|
// The final step of processing associated data is to update the state
|
||||||
// with a constant that provides domain separation.
|
// with a constant that provides domain separation.
|
||||||
|
@ -361,7 +361,7 @@ fn aead128_process_msg(mut out []u8, mut s State, msg []u8) int {
|
||||||
binary.little_endian_put_u64(mut out[pos..pos + 8], s.e0)
|
binary.little_endian_put_u64(mut out[pos..pos + 8], s.e0)
|
||||||
binary.little_endian_put_u64(mut out[pos + 8..], s.e1)
|
binary.little_endian_put_u64(mut out[pos + 8..], s.e1)
|
||||||
// apply permutation
|
// apply permutation
|
||||||
ascon_pnr(mut s, 8)
|
ascon_pnr(mut s, ascon_prnd_8)
|
||||||
|
|
||||||
// updates index
|
// updates index
|
||||||
mlen -= aead128_block_size
|
mlen -= aead128_block_size
|
||||||
|
@ -413,7 +413,7 @@ fn aead128_partial_dec(mut out []u8, mut s State, cmsg []u8) {
|
||||||
s.e0 = c0
|
s.e0 = c0
|
||||||
s.e1 = c1
|
s.e1 = c1
|
||||||
|
|
||||||
ascon_pnr(mut s, 8)
|
ascon_pnr(mut s, ascon_prnd_8)
|
||||||
// updates index
|
// updates index
|
||||||
pos += aead128_block_size
|
pos += aead128_block_size
|
||||||
cmsg_len -= aead128_block_size
|
cmsg_len -= aead128_block_size
|
||||||
|
@ -448,7 +448,7 @@ fn aead128_finalize(mut s State, k0 u64, k1 u64) {
|
||||||
s.e2 ^= k0
|
s.e2 ^= k0
|
||||||
s.e3 ^= k1
|
s.e3 ^= k1
|
||||||
// then updated using the permutation 𝐴𝑠𝑐𝑜𝑛-𝑝[12]
|
// then updated using the permutation 𝐴𝑠𝑐𝑜𝑛-𝑝[12]
|
||||||
ascon_pnr(mut s, 12)
|
ascon_pnr(mut s, ascon_prnd_12)
|
||||||
|
|
||||||
// Finally, the tag 𝑇 is generated by XORing the key with the last 128 bits of the state:
|
// Finally, the tag 𝑇 is generated by XORing the key with the last 128 bits of the state:
|
||||||
// 𝑇 ← 𝑆[192∶319] ⊕ 𝐾.
|
// 𝑇 ← 𝑆[192∶319] ⊕ 𝐾.
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
//
|
//
|
||||||
|
module ascon
|
||||||
|
|
||||||
import encoding.hex
|
import encoding.hex
|
||||||
import x.crypto.ascon
|
|
||||||
|
|
||||||
// This test materials was taken and adapted into v from references implementation of Ascon-aead128
|
// This test materials was taken and adapted into v from references implementation of Ascon-aead128
|
||||||
// especially for the known answer test data, but, its not all fully-taken, just randomly choosen item.
|
// especially for the known answer test data, but, its not all fully-taken, just randomly choosen item.
|
||||||
|
@ -26,14 +27,14 @@ fn test_ascon_aead128_enc_dec() ! {
|
||||||
ad := hex.decode(item.ad)!
|
ad := hex.decode(item.ad)!
|
||||||
ct := hex.decode(item.ct)!
|
ct := hex.decode(item.ct)!
|
||||||
|
|
||||||
out := ascon.encrypt(key, nonce, ad, pt)!
|
out := encrypt(key, nonce, ad, pt)!
|
||||||
assert out == ct
|
assert out == ct
|
||||||
|
|
||||||
msg := ascon.decrypt(key, nonce, ad, ct)!
|
msg := decrypt(key, nonce, ad, ct)!
|
||||||
assert msg == pt
|
assert msg == pt
|
||||||
|
|
||||||
// Work with object-based Cipher
|
// Work with object-based Cipher
|
||||||
mut c := ascon.new_aead128(key)!
|
mut c := new_aead128(key)!
|
||||||
// Lets encrypt the message
|
// Lets encrypt the message
|
||||||
exp_ct := c.encrypt(msg, nonce, ad)!
|
exp_ct := c.encrypt(msg, nonce, ad)!
|
||||||
assert exp_ct == ct
|
assert exp_ct == ct
|
||||||
|
|
|
@ -10,6 +10,10 @@ module ascon
|
||||||
// constants for up to 16 rounds to accommodate potential functionality extensions in the future.
|
// constants for up to 16 rounds to accommodate potential functionality extensions in the future.
|
||||||
const max_nr_perm = 16
|
const max_nr_perm = 16
|
||||||
|
|
||||||
|
// The number how many round(s) for the Ascon permutation routine called.
|
||||||
|
const ascon_prnd_8 = 8
|
||||||
|
const ascon_prnd_12 = 12
|
||||||
|
|
||||||
// The constants to derive round constants of the Ascon permutations
|
// The constants to derive round constants of the Ascon permutations
|
||||||
// See Table 5. of NIST SP 800-232 docs
|
// See Table 5. of NIST SP 800-232 docs
|
||||||
//
|
//
|
||||||
|
@ -26,72 +30,74 @@ const max_nr_perm = 16
|
||||||
const rnc = [u8(0x3c), 0x2d, 0x1e, 0x0f, 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, 0x78,
|
const rnc = [u8(0x3c), 0x2d, 0x1e, 0x0f, 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, 0x78,
|
||||||
0x69, 0x5a, 0x4b]
|
0x69, 0x5a, 0x4b]
|
||||||
|
|
||||||
// ascon_pnr is ascon permutation routine with specified numbers of round nr, where 1 ≤ nr ≤ 16
|
// ascon_pnr is the core of Ascon family permutation routine with specified numbers of round nr, where 1 ≤ nr ≤ 16
|
||||||
|
// Its consist of iterations of the round function that is defined as the composition of three steps, ie:
|
||||||
|
// 1. the constant-addition layer (see Sec. 3.2),
|
||||||
|
// 2. the substitution layer (see Sec.3.3), and,
|
||||||
|
// 3. the linear diffusion layer (Sec 3.4)
|
||||||
@[direct_array_access]
|
@[direct_array_access]
|
||||||
fn ascon_pnr(mut s State, nr int) {
|
fn ascon_pnr(mut s State, nr int) {
|
||||||
// We dont allow nr == 0
|
// We dont allow nr == 0
|
||||||
if nr < 1 || nr > 16 {
|
if nr < 1 || nr > 16 {
|
||||||
panic('Invalid round number')
|
panic('Invalid round number')
|
||||||
}
|
}
|
||||||
|
// Ascon permutation routine
|
||||||
for i := max_nr_perm - nr; i < max_nr_perm; i++ {
|
for i := max_nr_perm - nr; i < max_nr_perm; i++ {
|
||||||
ascon_perm(mut s, rnc[i])
|
// 3.2 Constant-Addition Layer step
|
||||||
|
//
|
||||||
|
// The constant-addition layer adds a 64-bit round constant 𝑐𝑖
|
||||||
|
// to 𝑆₂ in round 𝑖, for 𝑖 ≥ 0, ie, this is equivalent to applying
|
||||||
|
// the constant to only the least significant eight bits of 𝑆₂
|
||||||
|
s.e2 ^= rnc[i]
|
||||||
|
|
||||||
|
// 3.3. Substitution Layer
|
||||||
|
// The substitution layer updates the state S with 64 parallel applications of the 5-bit
|
||||||
|
// substitution box SBOX
|
||||||
|
s.e0 ^= s.e4
|
||||||
|
s.e4 ^= s.e3
|
||||||
|
s.e2 ^= s.e1
|
||||||
|
|
||||||
|
t0 := s.e4 ^ (~s.e0 & s.e1)
|
||||||
|
t1 := s.e0 ^ (~s.e1 & s.e2)
|
||||||
|
t2 := s.e1 ^ (~s.e2 & s.e3)
|
||||||
|
t3 := s.e2 ^ (~s.e3 & s.e4)
|
||||||
|
t4 := s.e3 ^ (~s.e4 & s.e0)
|
||||||
|
|
||||||
|
s.e0 = t1
|
||||||
|
s.e1 = t2
|
||||||
|
s.e2 = t3
|
||||||
|
s.e3 = t4
|
||||||
|
s.e4 = t0
|
||||||
|
|
||||||
|
s.e1 ^= s.e0
|
||||||
|
s.e0 ^= s.e4
|
||||||
|
s.e3 ^= s.e2
|
||||||
|
s.e2 = ~(s.e2)
|
||||||
|
|
||||||
|
// 3.4. Linear Diffusion Layer
|
||||||
|
//
|
||||||
|
// The linear diffusion layer provides diffusion within each 64-bit word S,
|
||||||
|
// defined as :
|
||||||
|
// Σ0(𝑆0) = 𝑆0 ⊕ (𝑆0 ⋙ 19) ⊕ (𝑆0 ⋙ 28)
|
||||||
|
// Σ1(𝑆1) = 𝑆1 ⊕ (𝑆1 ⋙ 61) ⊕ (𝑆1 ⋙ 39)
|
||||||
|
// Σ2(𝑆2) = 𝑆2 ⊕ (𝑆2 ⋙ 1) ⊕ (𝑆2 ⋙ 6)
|
||||||
|
// Σ3(𝑆3) = 𝑆3 ⊕ (𝑆3 ⋙ 10) ⊕ (𝑆3 ⋙ 17)
|
||||||
|
// Σ4(𝑆4) = 𝑆4 ⊕ (𝑆4 ⋙ 7) ⊕ (𝑆4 ⋙ 41)
|
||||||
|
//
|
||||||
|
// This diffusion layer, especially on the bits right rotation part is a most widely called
|
||||||
|
// for Ascon permutation routine. So, even bits rotation almost efficient on most platform,
|
||||||
|
// to reduce overhead on function call, we work on the raw bits right rotation here.
|
||||||
|
// Bits right rotation, basically can be defined as:
|
||||||
|
// ror = (x >> n) | x << (64 - n) for some u64 x
|
||||||
|
//
|
||||||
|
s.e0 ^= (s.e0 >> 19 | (s.e0 << (64 - 19))) ^ (s.e0 >> 28 | (s.e0 << (64 - 28)))
|
||||||
|
s.e1 ^= (s.e1 >> 61 | (s.e1 << (64 - 61))) ^ (s.e1 >> 39 | (s.e1 << (64 - 39)))
|
||||||
|
s.e2 ^= (s.e2 >> 1 | (s.e2 << (64 - 1))) ^ (s.e2 >> 6 | (s.e2 << (64 - 6))) //
|
||||||
|
s.e3 ^= (s.e3 >> 10 | (s.e3 << (64 - 10))) ^ (s.e3 >> 17 | (s.e3 << (64 - 17)))
|
||||||
|
s.e4 ^= (s.e4 >> 7 | (s.e4 << (64 - 7))) ^ (s.e4 >> 41 | (s.e4 << (64 - 41)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ascon_perm was the main permutations routine in Ascon-family crypto. Its consist of
|
|
||||||
// iterations of the round function that is defined as the composition of three steps, ie:
|
|
||||||
// 1. the constant-addition layer (see Sec. 3.2),
|
|
||||||
// 2. the substitution layer (see Sec.3.3), and,
|
|
||||||
// 3. the linear diffusion layer
|
|
||||||
fn ascon_perm(mut s State, c u8) {
|
|
||||||
// 3.2 Constant-Addition Layer step
|
|
||||||
//
|
|
||||||
// The constant-addition layer adds a 64-bit round constant 𝑐𝑖
|
|
||||||
// to 𝑆₂ in round 𝑖, for 𝑖 ≥ 0, ie, this is equivalent to applying
|
|
||||||
// the constant to only the least significant eight bits of 𝑆₂
|
|
||||||
s.e2 ^= c
|
|
||||||
|
|
||||||
// 3.3. Substitution Layer
|
|
||||||
// The substitution layer updates the state S with 64 parallel applications of the 5-bit
|
|
||||||
// substitution box SBOX
|
|
||||||
s.e0 ^= s.e4
|
|
||||||
s.e4 ^= s.e3
|
|
||||||
s.e2 ^= s.e1
|
|
||||||
|
|
||||||
t0 := s.e4 ^ (~s.e0 & s.e1)
|
|
||||||
t1 := s.e0 ^ (~s.e1 & s.e2)
|
|
||||||
t2 := s.e1 ^ (~s.e2 & s.e3)
|
|
||||||
t3 := s.e2 ^ (~s.e3 & s.e4)
|
|
||||||
t4 := s.e3 ^ (~s.e4 & s.e0)
|
|
||||||
|
|
||||||
s.e0 = t1
|
|
||||||
s.e1 = t2
|
|
||||||
s.e2 = t3
|
|
||||||
s.e3 = t4
|
|
||||||
s.e4 = t0
|
|
||||||
|
|
||||||
s.e1 ^= s.e0
|
|
||||||
s.e0 ^= s.e4
|
|
||||||
s.e3 ^= s.e2
|
|
||||||
s.e2 = ~(s.e2)
|
|
||||||
|
|
||||||
// 3.4. Linear Diffusion Layer
|
|
||||||
//
|
|
||||||
// The linear diffusion layer provides diffusion within each 64-bit word S,
|
|
||||||
// defined as :
|
|
||||||
// Σ0(𝑆0) = 𝑆0 ⊕ (𝑆0 ⋙ 19) ⊕ (𝑆0 ⋙ 28)
|
|
||||||
// Σ1(𝑆1) = 𝑆1 ⊕ (𝑆1 ⋙ 61) ⊕ (𝑆1 ⋙ 39)
|
|
||||||
// Σ2(𝑆2) = 𝑆2 ⊕ (𝑆2 ⋙ 1) ⊕ (𝑆2 ⋙ 6)
|
|
||||||
// Σ3(𝑆3) = 𝑆3 ⊕ (𝑆3 ⋙ 10) ⊕ (𝑆3 ⋙ 17)
|
|
||||||
// Σ4(𝑆4) = 𝑆4 ⊕ (𝑆4 ⋙ 7) ⊕ (𝑆4 ⋙ 41)
|
|
||||||
|
|
||||||
s.e0 ^= ascon_rotate_right(s.e0, 19) ^ ascon_rotate_right(s.e0, 28)
|
|
||||||
s.e1 ^= ascon_rotate_right(s.e1, 61) ^ ascon_rotate_right(s.e1, 39)
|
|
||||||
s.e2 ^= ascon_rotate_right(s.e2, 1) ^ ascon_rotate_right(s.e2, 6)
|
|
||||||
s.e3 ^= ascon_rotate_right(s.e3, 10) ^ ascon_rotate_right(s.e3, 17)
|
|
||||||
s.e4 ^= ascon_rotate_right(s.e4, 7) ^ ascon_rotate_right(s.e4, 41)
|
|
||||||
}
|
|
||||||
|
|
||||||
// State is structure represents Ascon state. Its operates on the 320-bit opaque,
|
// State is structure represents Ascon state. Its operates on the 320-bit opaque,
|
||||||
// which is represented as five of 64-bit words.
|
// which is represented as five of 64-bit words.
|
||||||
@[noinit]
|
@[noinit]
|
||||||
|
|
|
@ -5,23 +5,6 @@
|
||||||
module ascon
|
module ascon
|
||||||
|
|
||||||
// This test mostly taken from https://docs.rs/ascon/latest/src/ascon/lib.rs.html
|
// This test mostly taken from https://docs.rs/ascon/latest/src/ascon/lib.rs.html
|
||||||
fn test_ascon_round_one() {
|
|
||||||
mut s := State{
|
|
||||||
e0: u64(0x0123456789abcdef)
|
|
||||||
e1: 0x23456789abcdef01
|
|
||||||
e2: 0x456789abcdef0123
|
|
||||||
e3: 0x6789abcdef012345
|
|
||||||
e4: 0x89abcde01234567f
|
|
||||||
}
|
|
||||||
ascon_perm(mut s, 0x1f)
|
|
||||||
|
|
||||||
assert s.e0 == u64(0x3c1748c9be2892ce)
|
|
||||||
assert s.e1 == u64(0x5eafb305cd26164f)
|
|
||||||
assert s.e2 == u64(0xf9470254bb3a4213)
|
|
||||||
assert s.e3 == u64(0xf0428daf0c5d3948)
|
|
||||||
assert s.e4 == u64(0x281375af0b294899)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_ascon_round_p6() {
|
fn test_ascon_round_p6() {
|
||||||
mut s := State{
|
mut s := State{
|
||||||
e0: u64(0x0123456789abcdef)
|
e0: u64(0x0123456789abcdef)
|
||||||
|
|
75
vlib/x/crypto/ascon/bench/aead.v
Normal file
75
vlib/x/crypto/ascon/bench/aead.v
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
// This benchmark is for Ascon-AEAD128 in `x.crypto.ascon` compared to
|
||||||
|
// already stocked `x.crypto.cacha20poly1305 for AEAD functionalities.
|
||||||
|
//
|
||||||
|
// Here is output in my tests, first item was `x.crypto.ascon` and the later
|
||||||
|
// for `x.crypto.chacha20poly1305` on encryption or decryption part.
|
||||||
|
//
|
||||||
|
// Encryption..
|
||||||
|
// -----------
|
||||||
|
// Iterations: 10000 Total Duration: 26.008ms ns/op: 2600 B/op: 16 allocs/op: 17
|
||||||
|
// Iterations: 10000 Total Duration: 158.865ms ns/op: 15886 B/op: 16 allocs/op: 16
|
||||||
|
//
|
||||||
|
// Decryption..
|
||||||
|
// -----------
|
||||||
|
// Iterations: 10000 Total Duration: 29.091ms ns/op: 2909 B/op: 6 allocs/op: 8
|
||||||
|
// Iterations: 10000 Total Duration: 158.373ms ns/op: 15837 B/op: 8 allocs/op: 12
|
||||||
|
//
|
||||||
|
import encoding.hex
|
||||||
|
import x.benchmark
|
||||||
|
import x.crypto.ascon
|
||||||
|
import x.crypto.chacha20poly1305
|
||||||
|
|
||||||
|
// randomly generated key and nonce, 16-bytes of ascon key and 32-bytes of chacha20poly1305 key.
|
||||||
|
const key_ascon = hex.decode('7857bfb462c654d1d1b02971be021235')!
|
||||||
|
const key_cpoly = hex.decode('9d9603f4fc460e273b80795ea50eab5873c04f589226c7d591b5336feb32fcba')!
|
||||||
|
|
||||||
|
// 16-bytes ascon-nonce
|
||||||
|
const ascon_nonce = hex.decode('8b521028fb54591472d8d8ee14430835')!
|
||||||
|
|
||||||
|
// 12-bytes chacha20poly1305 nonce
|
||||||
|
const cpoly_nonce = hex.decode('9a3c83e4236ea9a2c4e482da')!
|
||||||
|
|
||||||
|
const ad = 'Ascon-AEAD128 additional data'.bytes()
|
||||||
|
const msg = 'Ascon-AEAD128 benchmarking message'.bytes()
|
||||||
|
|
||||||
|
// expected ciphertext for aead128 := 4b21a18cbca65b11aaf73dc74241c89bfcec96a4c8973ae696a938e0a591e846c4eb7b2906664f2318c0fd6ec1c56424aa9b
|
||||||
|
const ciphertext_aead128 = hex.decode('4b21a18cbca65b11aaf73dc74241c89bfcec96a4c8973ae696a938e0a591e846c4eb7b2906664f2318c0fd6ec1c56424aa9b')!
|
||||||
|
|
||||||
|
fn bench_ascon_aead128_encrypt() ! {
|
||||||
|
_ := ascon.encrypt(key_ascon, ascon_nonce, ad, msg)!
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench_ascon_aead128_decrypt() ! {
|
||||||
|
_ := ascon.decrypt(key_ascon, ascon_nonce, ad, ciphertext_aead128)!
|
||||||
|
}
|
||||||
|
|
||||||
|
// expected ciphertext for chacha20poly1305
|
||||||
|
const ciphertext_chachapoly1305 = hex.decode('67dea3c65f0f326bcf587f024140a85d9535790d9b16129210a2289eda43bb9b62746450026fc1baf466bcb8a181843cd424')!
|
||||||
|
|
||||||
|
fn bench_chacha20poly1305_encrypt() ! {
|
||||||
|
_ := chacha20poly1305.encrypt(msg, key_cpoly, cpoly_nonce, ad)!
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench_chacha20poly1305_decrypt() ! {
|
||||||
|
_ := chacha20poly1305.decrypt(ciphertext_chachapoly1305, key_cpoly, cpoly_nonce, ad)!
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
cf := benchmark.BenchmarkDefaults{
|
||||||
|
n: 10000
|
||||||
|
}
|
||||||
|
println('Encryption..')
|
||||||
|
println('-----------')
|
||||||
|
mut b0 := benchmark.setup(bench_ascon_aead128_encrypt, cf)!
|
||||||
|
b0.run()
|
||||||
|
mut b1 := benchmark.setup(bench_chacha20poly1305_encrypt, cf)!
|
||||||
|
b1.run()
|
||||||
|
|
||||||
|
println('')
|
||||||
|
println('Decryption..')
|
||||||
|
println('-----------')
|
||||||
|
mut b2 := benchmark.setup(bench_ascon_aead128_decrypt, cf)!
|
||||||
|
b2.run()
|
||||||
|
mut b3 := benchmark.setup(bench_chacha20poly1305_decrypt, cf)!
|
||||||
|
b3.run()
|
||||||
|
}
|
197
vlib/x/crypto/ascon/bench/hashxof.v
Normal file
197
vlib/x/crypto/ascon/bench/hashxof.v
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
// Ascon-Hash256 (and Ascon-XOF128) benchmark compared to builtin
|
||||||
|
// crypto.sha256 (for sum256) and sha3.shake256 (for xof outputing 256-bits)
|
||||||
|
//
|
||||||
|
// This benchmark code was adapted from argon2 benchmark by @fleximus, the creator argon2 module.
|
||||||
|
// Credit tributed to @fleximus
|
||||||
|
// See https://gist.github.com/fleximus/db5b867a9a37da46340db61bdac6e696
|
||||||
|
//
|
||||||
|
// Output
|
||||||
|
// ======
|
||||||
|
// Sum and Xof 256-bits output performance comparison
|
||||||
|
// ============================================================
|
||||||
|
// Iterations per test: 10000
|
||||||
|
// --------------------------------------------------------------------------------------------------
|
||||||
|
// Data Size | Ascon256 | Sha256 | Ratio 256 || AsconXof128 | Shake256 | Ratio (Xof) |
|
||||||
|
// --------------------------------------------------------------------------------------------------
|
||||||
|
// 4 B | 24.00ms | 33.00ms | 0.73x || 24.00ms | 208.00ms | 0.12x |
|
||||||
|
// 6 B | 23.00ms | 53.00ms | 0.45x || 25.00ms | 287.00ms | 0.08x |
|
||||||
|
// 8 B | 35.00ms | 37.00ms | 0.95x || 26.00ms | 202.00ms | 0.18x |
|
||||||
|
// 16 B | 30.00ms | 37.00ms | 0.83x || 30.00ms | 205.00ms | 0.15x |
|
||||||
|
// 64 B | 55.00ms | 61.00ms | 0.89x || 53.00ms | 241.00ms | 0.23x |
|
||||||
|
// 75 B | 61.00ms | 57.00ms | 1.07x || 58.00ms | 182.00ms | 0.34x |
|
||||||
|
// 256 B | 154.00ms | 123.00ms | 1.25x || 144.00ms | 398.00ms | 0.39x |
|
||||||
|
// 512 B | 273.00ms | 216.00ms | 1.26x || 265.00ms | 779.00ms | 0.35x |
|
||||||
|
// 1025 B | 610.00ms | 401.00ms | 1.52x || 509.00ms | 1.37s | 0.45x |
|
||||||
|
// --------------------------------------------------------------------------------------------------
|
||||||
|
// Total | 1.27s | 1.02s | 1.24x || 1.14s | 3.87s | 0.294x|
|
||||||
|
// --------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Per-operation averages:
|
||||||
|
// Ascon256: 14108 ns per hash
|
||||||
|
// Sha256: 11360 ns per hash
|
||||||
|
// AsconXof128: 12648 ns per hash
|
||||||
|
// Shake256: 43036 ns per hash
|
||||||
|
//
|
||||||
|
module main
|
||||||
|
|
||||||
|
import time
|
||||||
|
import crypto.sha3
|
||||||
|
import crypto.sha256
|
||||||
|
import x.crypto.ascon
|
||||||
|
|
||||||
|
const benchmark_iterations = 10000
|
||||||
|
|
||||||
|
// We include more small size because, Ascon-Hash256 working with more smaller block size.
|
||||||
|
const test_data_sizes = [
|
||||||
|
4, // below Ascon-Hash256 block size
|
||||||
|
6, // Still below Ascon-Hash256 block size
|
||||||
|
8, // align with Ascon-Hash256 block size
|
||||||
|
16, // Small data
|
||||||
|
64, // Medium data
|
||||||
|
75, // above 64-bytes block
|
||||||
|
256, // Large data
|
||||||
|
512,
|
||||||
|
1025,
|
||||||
|
]
|
||||||
|
|
||||||
|
fn generate_test_data(size int) []u8 {
|
||||||
|
mut data := []u8{len: size}
|
||||||
|
for i in 0 .. size {
|
||||||
|
data[i] = u8(i % 256)
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn benchmark_ascon_sha256(data []u8, iterations int) time.Duration {
|
||||||
|
start := time.now()
|
||||||
|
for _ in 0 .. iterations {
|
||||||
|
_ := ascon.sum256(data)
|
||||||
|
}
|
||||||
|
return time.since(start)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn benchmark_sha256_sum256(data []u8, iterations int) time.Duration {
|
||||||
|
start := time.now()
|
||||||
|
for _ in 0 .. iterations {
|
||||||
|
_ := sha256.sum256(data)
|
||||||
|
}
|
||||||
|
return time.since(start)
|
||||||
|
}
|
||||||
|
|
||||||
|
// for eXtendable output functions (XOF)
|
||||||
|
fn benchmark_ascon_xof128_32(data []u8, iterations int) time.Duration {
|
||||||
|
start := time.now()
|
||||||
|
for _ in 0 .. iterations {
|
||||||
|
_ := ascon.xof128(data, 32) or { panic(err) }
|
||||||
|
}
|
||||||
|
return time.since(start)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn benchmark_sha3_shake256(data []u8, iterations int) time.Duration {
|
||||||
|
start := time.now()
|
||||||
|
for _ in 0 .. iterations {
|
||||||
|
_ := sha3.shake256(data, 32)
|
||||||
|
}
|
||||||
|
return time.since(start)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_duration(d time.Duration) string {
|
||||||
|
if d.microseconds() < 1000 {
|
||||||
|
return '${d.microseconds():6}μs'
|
||||||
|
} else if d.milliseconds() < 1000 {
|
||||||
|
return '${f64(d.milliseconds()):6.2f}ms'
|
||||||
|
} else {
|
||||||
|
return '${f64(d.seconds()):6.2f}s'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const data_title = 'Data Size'
|
||||||
|
const ascon_sum256_title = 'Ascon256'
|
||||||
|
const sha256_title = 'Sha256'
|
||||||
|
const ascon_xof128_title = 'AsconXof128'
|
||||||
|
const sha3_shake256_title = 'Shake256'
|
||||||
|
const ratio_ascon256_w_sha256 = 'Ratio 256'
|
||||||
|
const ratio_asconxof128_w_shake256 = 'Ratio (Xof)'
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println('')
|
||||||
|
println('Sum and Xof 256-bits output performance comparison')
|
||||||
|
println('============================================================')
|
||||||
|
println('Iterations per test: ${benchmark_iterations}')
|
||||||
|
|
||||||
|
println('${'-'.repeat(98)}')
|
||||||
|
println('${data_title:12} | ${ascon_sum256_title:10} | ${sha256_title:10} | ${ratio_ascon256_w_sha256:12} || ${ascon_xof128_title:10} | ${sha3_shake256_title:10} | ${ratio_asconxof128_w_shake256:12} |')
|
||||||
|
println('${'-'.repeat(98)}')
|
||||||
|
|
||||||
|
mut total_ascon256 := time.Duration(0)
|
||||||
|
mut total_sha256 := time.Duration(0)
|
||||||
|
mut total_shake256 := time.Duration(0)
|
||||||
|
mut total_asconxof128 := time.Duration(0)
|
||||||
|
|
||||||
|
for size in test_data_sizes {
|
||||||
|
test_data := generate_test_data(size)
|
||||||
|
|
||||||
|
// Warm up
|
||||||
|
_ := ascon.sum256(test_data)
|
||||||
|
_ := sha256.sum256(test_data)
|
||||||
|
|
||||||
|
_ := ascon.xof128(test_data, 32)!
|
||||||
|
_ := sha3.shake256(test_data, 32)
|
||||||
|
|
||||||
|
// Benchmark Ascon-HASH256
|
||||||
|
ascon256_time := benchmark_ascon_sha256(test_data, benchmark_iterations)
|
||||||
|
|
||||||
|
// Benchmark Sha256 implementation
|
||||||
|
sha256_time := benchmark_sha256_sum256(test_data, benchmark_iterations)
|
||||||
|
|
||||||
|
// Benchmark Sha3 shake256 implementation
|
||||||
|
shake256_time := benchmark_sha3_shake256(test_data, benchmark_iterations)
|
||||||
|
|
||||||
|
// Benchmark AsconXof128 256-bits output
|
||||||
|
asconxof128_time := benchmark_ascon_xof128_32(test_data, benchmark_iterations)
|
||||||
|
|
||||||
|
// Calculate ratio ascon256 / sha256
|
||||||
|
ratio_ascon256_sha256 := f64(ascon256_time.nanoseconds()) / f64(sha256_time.nanoseconds())
|
||||||
|
|
||||||
|
// Calculate ratio asconxof128 / shake256
|
||||||
|
ratio_asconxof128_shake256 := f64(asconxof128_time.nanoseconds()) / f64(shake256_time.nanoseconds())
|
||||||
|
|
||||||
|
ascon256_str := format_duration(ascon256_time)
|
||||||
|
sha256_str := format_duration(sha256_time)
|
||||||
|
asconxof128_str := format_duration(asconxof128_time)
|
||||||
|
shake256_str := format_duration(shake256_time)
|
||||||
|
|
||||||
|
ratio_ascon256_sha256_str := '${ratio_ascon256_sha256:6.2f}x'
|
||||||
|
ratio_asconxof128_shake256_str := '${ratio_asconxof128_shake256:6.2f}x'
|
||||||
|
|
||||||
|
println('${size:10} B | ${ascon256_str:10} | ${sha256_str:10} | ${ratio_ascon256_sha256_str:12} || ${asconxof128_str:11} | ${shake256_str:10} | ${ratio_asconxof128_shake256_str:12} |')
|
||||||
|
|
||||||
|
total_ascon256 += ascon256_time
|
||||||
|
total_sha256 += sha256_time
|
||||||
|
|
||||||
|
total_asconxof128 += asconxof128_time
|
||||||
|
total_shake256 += shake256_time
|
||||||
|
}
|
||||||
|
|
||||||
|
println('${'-'.repeat(98)}')
|
||||||
|
|
||||||
|
// Overall performance comparison
|
||||||
|
overall_ascon256_w_sha256_ratio := f64(total_ascon256.nanoseconds()) / f64(total_sha256.nanoseconds())
|
||||||
|
overall_asconxof128_w_shake256_ratio := f64(total_asconxof128.nanoseconds()) / f64(total_shake256.nanoseconds())
|
||||||
|
total_title := 'Total'
|
||||||
|
println('${total_title:12} | ${format_duration(total_ascon256):10} | ${format_duration(total_sha256):10} | ${overall_ascon256_w_sha256_ratio:11.2f}x || ${format_duration(total_asconxof128):11} | ${format_duration(total_shake256):10} | ${overall_asconxof128_w_shake256_ratio:12.2f}x|')
|
||||||
|
println('${'-'.repeat(98)}')
|
||||||
|
|
||||||
|
println('')
|
||||||
|
println('Per-operation averages:')
|
||||||
|
avg_ascon256 := total_ascon256.nanoseconds() / (benchmark_iterations * test_data_sizes.len)
|
||||||
|
avg_sha256 := total_sha256.nanoseconds() / (benchmark_iterations * test_data_sizes.len)
|
||||||
|
avg_shake256 := total_shake256.nanoseconds() / (benchmark_iterations * test_data_sizes.len)
|
||||||
|
avg_asconxof128 := total_asconxof128.nanoseconds() / (benchmark_iterations * test_data_sizes.len)
|
||||||
|
|
||||||
|
println(' Ascon256:\t ${avg_ascon256:8} ns per hash')
|
||||||
|
println(' Sha256:\t ${avg_sha256:8} ns per hash')
|
||||||
|
println(' AsconXof128:\t ${avg_asconxof128:8} ns per hash')
|
||||||
|
println(' Shake256:\t ${avg_shake256:8} ns per hash')
|
||||||
|
println('')
|
||||||
|
}
|
36
vlib/x/crypto/ascon/bench/sum.v
Normal file
36
vlib/x/crypto/ascon/bench/sum.v
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import time
|
||||||
|
import x.crypto.ascon
|
||||||
|
|
||||||
|
// Before:
|
||||||
|
// Benchmarking ascon.sum256 ...
|
||||||
|
// Average ascon.sum256 time: 8 µs
|
||||||
|
// Benchmarking ascon.sum256 ...
|
||||||
|
// Average ascon.sum256 time: 6 µs
|
||||||
|
|
||||||
|
// For xof128 (32 bytes)
|
||||||
|
// Benchmarking ascon.xof128 ...
|
||||||
|
// Average ascon.xof128 time: 7 µs
|
||||||
|
// Benchmarking ascon.xof128 ...
|
||||||
|
// Average ascon.xof128 time: 6 µs
|
||||||
|
|
||||||
|
// For cxof128 32 bytes
|
||||||
|
// Benchmarking ascon.cxof128 ...
|
||||||
|
// Average ascon.cxof128 time: 9 µs
|
||||||
|
// Benchmarking ascon.sum256 ...
|
||||||
|
// Average ascon.cxof128 time: 7 µs
|
||||||
|
//
|
||||||
|
fn main() {
|
||||||
|
iterations := 1000
|
||||||
|
msg := [u8(0xff)].repeat(100)
|
||||||
|
|
||||||
|
println('Benchmarking ascon.sum256 ...')
|
||||||
|
mut total_sum_time := i64(0)
|
||||||
|
for _ in 0 .. iterations {
|
||||||
|
sw := time.new_stopwatch()
|
||||||
|
_ := ascon.sum256(msg)
|
||||||
|
elapsed := sw.elapsed().microseconds()
|
||||||
|
total_sum_time += elapsed
|
||||||
|
}
|
||||||
|
avg_sum_time := total_sum_time / iterations
|
||||||
|
println('Average ascon.sum256 time: ${avg_sum_time} µs')
|
||||||
|
}
|
|
@ -33,7 +33,7 @@ fn (mut d Digest) finish() {
|
||||||
d.State.e0 ^= load_bytes(d.buf[..d.length], d.length)
|
d.State.e0 ^= load_bytes(d.buf[..d.length], d.length)
|
||||||
|
|
||||||
// Permutation step was done in squeezing-phase
|
// Permutation step was done in squeezing-phase
|
||||||
// ascon_pnr(mut d.State, 12)
|
// ascon_pnr(mut d.State, ascon_prnd_12)
|
||||||
|
|
||||||
// zeroing Digest buffer
|
// zeroing Digest buffer
|
||||||
d.length = 0
|
d.length = 0
|
||||||
|
@ -70,7 +70,7 @@ fn (mut d Digest) absorb(msg_ []u8) int {
|
||||||
// If this d.buf length has reached block_size bytes, absorb it.
|
// If this d.buf length has reached block_size bytes, absorb it.
|
||||||
if d.length == block_size {
|
if d.length == block_size {
|
||||||
d.State.e0 ^= binary.little_endian_u64(d.buf)
|
d.State.e0 ^= binary.little_endian_u64(d.buf)
|
||||||
ascon_pnr(mut d.State, 12)
|
ascon_pnr(mut d.State, ascon_prnd_12)
|
||||||
// reset the internal buffer
|
// reset the internal buffer
|
||||||
d.length = 0
|
d.length = 0
|
||||||
d.buf.reset()
|
d.buf.reset()
|
||||||
|
@ -87,7 +87,7 @@ fn (mut d Digest) absorb(msg_ []u8) int {
|
||||||
for msg.len >= block_size {
|
for msg.len >= block_size {
|
||||||
d.State.e0 ^= binary.little_endian_u64(msg[0..block_size])
|
d.State.e0 ^= binary.little_endian_u64(msg[0..block_size])
|
||||||
msg = msg[block_size..]
|
msg = msg[block_size..]
|
||||||
ascon_pnr(mut d.State, 12)
|
ascon_pnr(mut d.State, ascon_prnd_12)
|
||||||
}
|
}
|
||||||
// If there are partial block, just stored into buffer.
|
// If there are partial block, just stored into buffer.
|
||||||
if msg.len > 0 {
|
if msg.len > 0 {
|
||||||
|
@ -113,14 +113,14 @@ fn (mut d Digest) squeeze(mut dst []u8) int {
|
||||||
}
|
}
|
||||||
// The squeezing phase begins after msg is absorbed with an
|
// The squeezing phase begins after msg is absorbed with an
|
||||||
// permutation 𝐴𝑠𝑐𝑜𝑛-𝑝[12] to the state:
|
// permutation 𝐴𝑠𝑐𝑜𝑛-𝑝[12] to the state:
|
||||||
ascon_pnr(mut d.State, 12)
|
ascon_pnr(mut d.State, ascon_prnd_12)
|
||||||
|
|
||||||
mut pos := 0
|
mut pos := 0
|
||||||
mut clen := dst.len
|
mut clen := dst.len
|
||||||
// process for full block size
|
// process for full block size
|
||||||
for clen >= block_size {
|
for clen >= block_size {
|
||||||
binary.little_endian_put_u64(mut dst[pos..pos + 8], d.State.e0)
|
binary.little_endian_put_u64(mut dst[pos..pos + 8], d.State.e0)
|
||||||
ascon_pnr(mut d.State, 12)
|
ascon_pnr(mut d.State, ascon_prnd_12)
|
||||||
pos += block_size
|
pos += block_size
|
||||||
clen -= block_size
|
clen -= block_size
|
||||||
}
|
}
|
||||||
|
@ -133,3 +133,39 @@ fn (mut d Digest) squeeze(mut dst []u8) int {
|
||||||
|
|
||||||
return pos
|
return pos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@[direct_array_access; inline]
|
||||||
|
fn ascon_generic_hash(mut s State, msg_ []u8, size int) []u8 {
|
||||||
|
// Assumed state was correctly initialized
|
||||||
|
// Absorbing the message
|
||||||
|
mut msg := msg_.clone()
|
||||||
|
for msg.len >= block_size {
|
||||||
|
s.e0 ^= binary.little_endian_u64(msg[0..block_size])
|
||||||
|
unsafe {
|
||||||
|
msg = msg[block_size..]
|
||||||
|
}
|
||||||
|
ascon_pnr(mut s, ascon_prnd_12)
|
||||||
|
}
|
||||||
|
// Absorb the last partial message block
|
||||||
|
s.e0 ^= load_bytes(msg, msg.len)
|
||||||
|
s.e0 ^= pad(msg.len)
|
||||||
|
|
||||||
|
// Squeezing phase
|
||||||
|
//
|
||||||
|
// The squeezing phase begins after msg is absorbed with an
|
||||||
|
// permutation 𝐴𝑠𝑐𝑜𝑛-𝑝[12] to the state:
|
||||||
|
ascon_pnr(mut s, ascon_prnd_12)
|
||||||
|
mut out := []u8{len: size}
|
||||||
|
mut pos := 0
|
||||||
|
mut clen := out.len
|
||||||
|
for clen >= block_size {
|
||||||
|
binary.little_endian_put_u64(mut out[pos..pos + 8], s.e0)
|
||||||
|
ascon_pnr(mut s, ascon_prnd_12)
|
||||||
|
pos += block_size
|
||||||
|
clen -= block_size
|
||||||
|
}
|
||||||
|
// final output, the resulting 256-bit digest is the concatenation of hash blocks
|
||||||
|
store_bytes(mut out[pos..], s.e0, clen)
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
|
@ -42,13 +42,13 @@ const hash256_initial_state = State{
|
||||||
}
|
}
|
||||||
|
|
||||||
// sum256 creates an Ascon-Hash256 checksum for bytes on msg and produces a 256-bit hash.
|
// sum256 creates an Ascon-Hash256 checksum for bytes on msg and produces a 256-bit hash.
|
||||||
pub fn sum256(msg []u8) []u8 {
|
pub fn sum256(msg_ []u8) []u8 {
|
||||||
mut h := new_hash256()
|
// This is single-shot function, so, no need to use Hash256 opaque that process
|
||||||
_ := h.write(msg) or { panic(err) }
|
// message in streaming way. To reduce this overhead, use raw processing instead.
|
||||||
h.Digest.finish()
|
//
|
||||||
mut dst := []u8{len: hash256_size}
|
// Initialize state
|
||||||
_ := h.Digest.squeeze(mut dst)
|
mut s := hash256_initial_state
|
||||||
return dst
|
return ascon_generic_hash(mut s, msg_, hash256_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash256 is an opaque provides an implementation of Ascon-Hash256 from NIST.SP.800-232 standard.
|
// Hash256 is an opaque provides an implementation of Ascon-Hash256 from NIST.SP.800-232 standard.
|
||||||
|
|
|
@ -5,15 +5,8 @@
|
||||||
// Utility helpers used across the module
|
// Utility helpers used across the module
|
||||||
module ascon
|
module ascon
|
||||||
|
|
||||||
import math.bits
|
|
||||||
import encoding.binary
|
import encoding.binary
|
||||||
|
|
||||||
// rotate_right_64 rotates x right by k bits
|
|
||||||
fn rotate_right_64(x u64, k int) u64 {
|
|
||||||
// call rotate_left_64(x, -k).
|
|
||||||
return bits.rotate_left_64(x, -k)
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear_bytes clears the bytes of x in n byte
|
// clear_bytes clears the bytes of x in n byte
|
||||||
@[inline]
|
@[inline]
|
||||||
fn clear_bytes(x u64, n int) u64 {
|
fn clear_bytes(x u64, n int) u64 {
|
||||||
|
@ -100,8 +93,3 @@ fn store_bytes(mut out []u8, x u64, n int) {
|
||||||
out[i] = get_byte(x, i)
|
out[i] = get_byte(x, i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@[inline]
|
|
||||||
fn ascon_rotate_right(x u64, n int) u64 {
|
|
||||||
return (x >> n) | x << (64 - n)
|
|
||||||
}
|
|
||||||
|
|
|
@ -30,13 +30,11 @@ const xof128_initial_state = State{
|
||||||
|
|
||||||
// xof128 creates an Ascon-XOF128 checksum of msg with specified desired size of output.
|
// xof128 creates an Ascon-XOF128 checksum of msg with specified desired size of output.
|
||||||
pub fn xof128(msg []u8, size int) ![]u8 {
|
pub fn xof128(msg []u8, size int) ![]u8 {
|
||||||
mut x := new_xof128(size)
|
if size > max_hash_size {
|
||||||
_ := x.write(msg)!
|
return error('xof128: invalid size')
|
||||||
x.Digest.finish()
|
}
|
||||||
mut out := []u8{len: size}
|
mut s := xof128_initial_state
|
||||||
_ := x.Digest.squeeze(mut out)
|
return ascon_generic_hash(mut s, msg, size)
|
||||||
x.reset()
|
|
||||||
return out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// xof128_64 creates a 64-bytes of Ascon-XOF128 checksum of msg.
|
// xof128_64 creates a 64-bytes of Ascon-XOF128 checksum of msg.
|
||||||
|
@ -170,13 +168,10 @@ const cxof128_initial_state = State{
|
||||||
|
|
||||||
// cxof128 creates an Ascon-CXOF128 checksum of msg with supplied size and custom string cs.
|
// cxof128 creates an Ascon-CXOF128 checksum of msg with supplied size and custom string cs.
|
||||||
pub fn cxof128(msg []u8, size int, cs []u8) ![]u8 {
|
pub fn cxof128(msg []u8, size int, cs []u8) ![]u8 {
|
||||||
mut cx := new_cxof128(size, cs)!
|
// Initialize CXof128 state with precomputed-value and absorb the customization string
|
||||||
_ := cx.write(msg)!
|
mut s := cxof128_initial_state
|
||||||
cx.Digest.finish()
|
cxof128_absorb_custom_string(mut s, cs)
|
||||||
mut out := []u8{len: size}
|
return ascon_generic_hash(mut s, msg, size)
|
||||||
_ := cx.Digest.squeeze(mut out)
|
|
||||||
cx.reset()
|
|
||||||
return out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// cxof128_64 creates a 64-bytes of Ascon-CXOF128 checksum of msg with supplied custom string in cs.
|
// cxof128_64 creates a 64-bytes of Ascon-CXOF128 checksum of msg with supplied custom string in cs.
|
||||||
|
@ -305,7 +300,7 @@ pub fn (mut x CXof128) free() {
|
||||||
fn cxof128_absorb_custom_string(mut s State, cs []u8) {
|
fn cxof128_absorb_custom_string(mut s State, cs []u8) {
|
||||||
// absorb Z0, the length of the customization string (in bits) encoded as a u64
|
// absorb Z0, the length of the customization string (in bits) encoded as a u64
|
||||||
s.e0 ^= u64(cs.len) << 3
|
s.e0 ^= u64(cs.len) << 3
|
||||||
ascon_pnr(mut s, 12)
|
ascon_pnr(mut s, ascon_prnd_12)
|
||||||
|
|
||||||
// absorb the customization string
|
// absorb the customization string
|
||||||
mut zlen := cs.len
|
mut zlen := cs.len
|
||||||
|
@ -313,7 +308,7 @@ fn cxof128_absorb_custom_string(mut s State, cs []u8) {
|
||||||
for zlen >= block_size {
|
for zlen >= block_size {
|
||||||
block := unsafe { cs[zidx..zidx + block_size] }
|
block := unsafe { cs[zidx..zidx + block_size] }
|
||||||
s.e0 ^= binary.little_endian_u64(block)
|
s.e0 ^= binary.little_endian_u64(block)
|
||||||
ascon_pnr(mut s, 12)
|
ascon_pnr(mut s, ascon_prnd_12)
|
||||||
|
|
||||||
// updates a index
|
// updates a index
|
||||||
zlen -= block_size
|
zlen -= block_size
|
||||||
|
@ -323,5 +318,5 @@ fn cxof128_absorb_custom_string(mut s State, cs []u8) {
|
||||||
last_block := unsafe { cs[zidx..] }
|
last_block := unsafe { cs[zidx..] }
|
||||||
s.e0 ^= load_bytes(last_block, last_block.len)
|
s.e0 ^= load_bytes(last_block, last_block.len)
|
||||||
s.e0 ^= pad(last_block.len)
|
s.e0 ^= pad(last_block.len)
|
||||||
ascon_pnr(mut s, 12)
|
ascon_pnr(mut s, ascon_prnd_12)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue