v2 / vlib / x / crypto / ascon / util.v
105 lines · 93 sloc · 2.62 KB · 56f20d1ff8ce8c1f68bb3cee1bb241e7e2f45bb3
Raw
1// Copyright ©2025 blackshirt.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4//
5// Utility helpers used across the module
6module ascon
7
8import encoding.binary
9
10// clear_bytes clears the bytes of x in n byte
11@[inline]
12fn clear_bytes(x u64, n int) u64 {
13 mut c := x
14 for i := 0; i < n; i++ {
15 c &= ~set_byte(0xff, i)
16 }
17 return c
18}
19
20// pad appends a one followed by one or more zeroes to data
21@[inline]
22fn pad(n int) u64 {
23 return u64(0x01) << (8 * n)
24}
25
26// assume input.len < 8
27fn u64_from_partial_bytes(input []u8) u64 {
28 mut tmp := []u8{len: 8}
29 ct_copy_first(mut tmp, input)
30 return binary.little_endian_u64(tmp)
31}
32
33// ct_copy_at copies of y into x start from at position in constant-time manner.
34fn ct_copy_at(mut x []u8, y []u8, at int) {
35 ct_copy_internal(1, mut x, y, at)
36}
37
38// ct_copy_first copies of y into first y.len of x in constant-time manner.
39fn ct_copy_first(mut x []u8, y []u8) {
40 ct_copy_internal(1, mut x, y, 0)
41}
42
43@[direct_array_access]
44fn ct_copy_internal(v int, mut x []u8, y []u8, at int) {
45 if at > x.len {
46 panic('at > x.len')
47 }
48 if i64(x.len) < i64(y.len) + i64(at) {
49 panic('invalid pos')
50 }
51 if x.len < y.len {
52 panic('length x < y')
53 }
54 xmask := u8(v - 1)
55 ymask := u8(~(v - 1))
56 for i := 0; i < y.len; i++ {
57 x[i + at] = x[i + at] & xmask | y[i] & ymask
58 }
59}
60
61// portable little-endian helper
62@[inline]
63fn u64le(x u64) u64 {
64 $if little_endian {
65 return x
66 }
67 // otherwise, change into little-endian format
68 return ((u64(0x00000000000000FF) & x) << 56) | ((u64(0x000000000000FF00) & x) << 40) | ((u64(0x0000000000FF0000) & x) << 24) | ((u64(0x00000000FF000000) & x) << 8) | ((u64(0x000000FF00000000) & x) >> 8) | ((u64(0x0000FF0000000000) & x) >> 24) | ((u64(0x00FF000000000000) & x) >> 40) | ((u64(0xFF00000000000000) & x) >> 56)
69}
70
71@[inline]
72fn get_byte(x u64, i int) u8 {
73 return u8(x >> (8 * i))
74}
75
76@[inline]
77fn set_byte(b u8, i int) u64 {
78 return u64(b) << (8 * i)
79}
80
81// load_bytes load partial bytes with length n, used internally.
82@[direct_array_access]
83fn load_bytes(bytes []u8, n int) u64 {
84 mut x := u64(0)
85 for i := 0; i < n; i++ {
86 // This is the same way to store bytes in little-endian way
87 // x |= u64(bytes[0]) << 8*0 // LSB at lowest index
88 // x |= u64(bytes[1]) << 8*1
89 // x |= u64(bytes[2]) << 8*2
90 // x |= u64(bytes[3]) << 8*3
91 // ...etc
92 // x |= u64(bytes[7]) << 8*7 // MSB at highest index
93 x |= u64(bytes[i]) << (8 * i)
94 }
95 // No need to cast with u64le, its alread le
96 return x
97}
98
99@[direct_array_access]
100fn store_bytes(mut out []u8, x u64, n int) {
101 for i := 0; i < n; i++ {
102 // use underlying get_byte directly
103 out[i] = u8(x >> (8 * i))
104 }
105}
106