mirror of
https://github.com/odin-lang/Odin.git
synced 2026-07-17 13:11:07 +00:00
Merge branch 'master' into bill/rexcode
This commit is contained in:
@@ -60,13 +60,13 @@ Iterator :: struct($Value: typeid) {
|
||||
_called_next: bool,
|
||||
}
|
||||
|
||||
// init initializes a tree.
|
||||
// `init` initializes a tree.
|
||||
init :: proc {
|
||||
init_ordered,
|
||||
init_cmp,
|
||||
}
|
||||
|
||||
// init_cmp initializes a tree.
|
||||
// `init_cmp` initializes a tree.
|
||||
init_cmp :: proc(
|
||||
t: ^$T/Tree($Value),
|
||||
cmp_fn: proc(a, b: Value) -> Ordering,
|
||||
@@ -78,7 +78,7 @@ init_cmp :: proc(
|
||||
t._size = 0
|
||||
}
|
||||
|
||||
// init_ordered initializes a tree containing ordered items, with
|
||||
// `init_ordered` initializes a tree containing ordered items, with
|
||||
// a comparison function that results in an ascending order sort.
|
||||
init_ordered :: proc(
|
||||
t: ^$T/Tree($Value),
|
||||
@@ -87,7 +87,7 @@ init_ordered :: proc(
|
||||
init_cmp(t, slice.cmp_proc(Value), node_allocator)
|
||||
}
|
||||
|
||||
// destroy de-initializes a tree.
|
||||
// `destroy` de-initializes a tree.
|
||||
destroy :: proc(t: ^$T/Tree($Value), call_on_remove: bool = true) {
|
||||
iter := iterator(t, Direction.Forward)
|
||||
for _ in iterator_next(&iter) {
|
||||
@@ -95,24 +95,24 @@ destroy :: proc(t: ^$T/Tree($Value), call_on_remove: bool = true) {
|
||||
}
|
||||
}
|
||||
|
||||
// len returns the number of elements in the tree.
|
||||
// `len` returns the number of elements in the tree.
|
||||
len :: proc "contextless" (t: ^$T/Tree($Value)) -> int {
|
||||
return t._size
|
||||
}
|
||||
|
||||
// first returns the first node in the tree (in-order) or nil if and only if (⟺)
|
||||
// `first` returns the first node in the tree (in-order) or nil if and only if (⟺)
|
||||
// the tree is empty.
|
||||
first :: proc "contextless" (t: ^$T/Tree($Value)) -> ^Node(Value) {
|
||||
return tree_first_or_last_in_order(t, Direction.Backward)
|
||||
}
|
||||
|
||||
// last returns the last element in the tree (in-order) or nil if and only if (⟺)
|
||||
// `last` returns the last element in the tree (in-order) or nil if and only if (⟺)
|
||||
// the tree is empty.
|
||||
last :: proc "contextless" (t: ^$T/Tree($Value)) -> ^Node(Value) {
|
||||
return tree_first_or_last_in_order(t, Direction.Forward)
|
||||
}
|
||||
|
||||
// find finds the value in the tree, and returns the corresponding
|
||||
// `find` finds the value in the tree, and returns the corresponding
|
||||
// node or nil if and only if (⟺) the value is not present.
|
||||
find :: proc(t: ^$T/Tree($Value), value: Value) -> ^Node(Value) {
|
||||
cur := t._root
|
||||
@@ -130,7 +130,7 @@ find :: proc(t: ^$T/Tree($Value), value: Value) -> ^Node(Value) {
|
||||
return cur
|
||||
}
|
||||
|
||||
// find_or_insert attempts to insert the value into the tree, and returns
|
||||
// `find_or_insert` attempts to insert the value into the tree, and returns
|
||||
// the node, a boolean indicating if the value was inserted, and the
|
||||
// node allocator error if relevant. If the value is already
|
||||
// present, the existing node is returned un-altered.
|
||||
@@ -168,7 +168,7 @@ find_or_insert :: proc(
|
||||
return
|
||||
}
|
||||
|
||||
// remove removes a node or value from the tree, and returns true if and only if (⟺) the
|
||||
// `remove` removes a node or value from the tree, and returns true if and only if (⟺) the
|
||||
// removal was successful. While the node's value will be left intact,
|
||||
// the node itself will be freed via the tree's node allocator.
|
||||
remove :: proc {
|
||||
@@ -176,7 +176,7 @@ remove :: proc {
|
||||
remove_node,
|
||||
}
|
||||
|
||||
// remove_value removes a value from the tree, and returns true if and only if (⟺) the
|
||||
// `remove_value` removes a value from the tree, and returns true if and only if (⟺) the
|
||||
// removal was successful. While the node's value will be left intact,
|
||||
// the node itself will be freed via the tree's node allocator.
|
||||
remove_value :: proc(t: ^$T/Tree($Value), value: Value, call_on_remove: bool = true) -> bool {
|
||||
@@ -187,7 +187,7 @@ remove_value :: proc(t: ^$T/Tree($Value), value: Value, call_on_remove: bool = t
|
||||
return remove_node(t, n, call_on_remove)
|
||||
}
|
||||
|
||||
// remove_node removes a node from the tree, and returns true if and only if (⟺) the
|
||||
// `remove_node` removes a node from the tree, and returns true if and only if (⟺) the
|
||||
// removal was successful. While the node's value will be left intact,
|
||||
// the node itself will be freed via the tree's node allocator.
|
||||
remove_node :: proc(t: ^$T/Tree($Value), node: ^Node(Value), call_on_remove: bool = true) -> bool {
|
||||
@@ -249,7 +249,7 @@ remove_node :: proc(t: ^$T/Tree($Value), node: ^Node(Value), call_on_remove: boo
|
||||
return true
|
||||
}
|
||||
|
||||
// iterator returns a tree iterator in the specified direction.
|
||||
// `iterator` returns a tree iterator in the specified direction.
|
||||
iterator :: proc "contextless" (t: ^$T/Tree($Value), direction: Direction) -> Iterator(Value) {
|
||||
it: Iterator(Value)
|
||||
it._tree = transmute(^Tree(Value))t
|
||||
@@ -260,7 +260,7 @@ iterator :: proc "contextless" (t: ^$T/Tree($Value), direction: Direction) -> It
|
||||
return it
|
||||
}
|
||||
|
||||
// iterator_from_pos returns a tree iterator in the specified direction,
|
||||
// `iterator_from_pos` returns a tree iterator in the specified direction,
|
||||
// spanning the range [pos, last] (inclusive).
|
||||
iterator_from_pos :: proc "contextless" (
|
||||
t: ^$T/Tree($Value),
|
||||
@@ -280,14 +280,14 @@ iterator_from_pos :: proc "contextless" (
|
||||
return it
|
||||
}
|
||||
|
||||
// iterator_get returns the node currently pointed to by the iterator,
|
||||
// `iterator_get` returns the node currently pointed to by the iterator,
|
||||
// or nil if and only if (⟺) the node has been removed, the tree is empty, or the end
|
||||
// of the tree has been reached.
|
||||
iterator_get :: proc "contextless" (it: ^$I/Iterator($Value)) -> ^Node(Value) {
|
||||
return it._cur
|
||||
}
|
||||
|
||||
// iterator_remove removes the node currently pointed to by the iterator,
|
||||
// `iterator_remove` removes the node currently pointed to by the iterator,
|
||||
// and returns true if and only if (⟺) the removal was successful. Semantics are the
|
||||
// same as the Tree remove.
|
||||
iterator_remove :: proc(it: ^$I/Iterator($Value), call_on_remove: bool = true) -> bool {
|
||||
@@ -303,7 +303,7 @@ iterator_remove :: proc(it: ^$I/Iterator($Value), call_on_remove: bool = true) -
|
||||
return ok
|
||||
}
|
||||
|
||||
// iterator_next advances the iterator and returns the (node, true) or
|
||||
// `iterator_next` advances the iterator and returns the (node, true) or
|
||||
// or (nil, false) if and only if (⟺) the end of the tree has been reached.
|
||||
//
|
||||
// Note: The first call to iterator_next will return the first node instead
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package container_handle_map
|
||||
|
||||
import "base:runtime"
|
||||
import "base:builtin"
|
||||
import "base:intrinsics"
|
||||
@(require) import "core:container/xar"
|
||||
|
||||
@@ -139,4 +138,4 @@ dynamic_iterate :: proc "contextless" (it: ^$DHI/Dynamic_Handle_Map_Iterator($D/
|
||||
}
|
||||
it.index = 0
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,7 +406,7 @@ push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T, loc := #caller_location) -
|
||||
}
|
||||
|
||||
/*
|
||||
Consume `n` elements from the back of the queue.
|
||||
Consume `n` elements from the front of the queue.
|
||||
|
||||
This will raise a bounds checking error if the queue does not have enough elements.
|
||||
*/
|
||||
|
||||
@@ -63,13 +63,13 @@ Iterator :: struct($Key: typeid, $Value: typeid) {
|
||||
_called_next: bool,
|
||||
}
|
||||
|
||||
// init initializes a tree.
|
||||
// `init` initializes a tree.
|
||||
init :: proc {
|
||||
init_ordered,
|
||||
init_cmp,
|
||||
}
|
||||
|
||||
// init_cmp initializes a tree.
|
||||
// `init_cmp` initializes a tree.
|
||||
init_cmp :: proc(t: ^$T/Tree($Key, $Value), cmp_fn: proc(a, b: Key) -> Ordering, node_allocator := context.allocator) {
|
||||
t._root = nil
|
||||
t._node_allocator = node_allocator
|
||||
@@ -77,13 +77,13 @@ init_cmp :: proc(t: ^$T/Tree($Key, $Value), cmp_fn: proc(a, b: Key) -> Ordering,
|
||||
t._size = 0
|
||||
}
|
||||
|
||||
// init_ordered initializes a tree containing ordered keys, with
|
||||
// `init_ordered` initializes a tree containing ordered keys, with
|
||||
// a comparison function that results in an ascending order sort.
|
||||
init_ordered :: proc(t: ^$T/Tree($Key, $Value), node_allocator := context.allocator) where intrinsics.type_is_ordered(Key) {
|
||||
init_cmp(t, slice.cmp_proc(Key), node_allocator)
|
||||
}
|
||||
|
||||
// destroy de-initializes a tree.
|
||||
// `destroy` de-initializes a tree.
|
||||
destroy :: proc(t: ^$T/Tree($Key, $Value), call_on_remove: bool = true) {
|
||||
iter := iterator(t, .Forward)
|
||||
for _ in iterator_next(&iter) {
|
||||
@@ -95,19 +95,19 @@ len :: proc "contextless" (t: $T/Tree($Key, $Value)) -> (node_count: int) {
|
||||
return t._size
|
||||
}
|
||||
|
||||
// first returns the first node in the tree (in-order) or nil if and only if (⟺)
|
||||
// `first` returns the first node in the tree (in-order) or nil if and only if (⟺)
|
||||
// the tree is empty.
|
||||
first :: proc "contextless" (t: ^$T/Tree($Key, $Value)) -> ^Node(Key, Value) {
|
||||
return tree_first_or_last_in_order(t, Direction.Backward)
|
||||
}
|
||||
|
||||
// last returns the last element in the tree (in-order) or nil if and only if (⟺)
|
||||
// `last` returns the last element in the tree (in-order) or nil if and only if (⟺)
|
||||
// the tree is empty.
|
||||
last :: proc "contextless" (t: ^$T/Tree($Key, $Value)) -> ^Node(Key, Value) {
|
||||
return tree_first_or_last_in_order(t, Direction.Forward)
|
||||
}
|
||||
|
||||
// find finds the key in the tree, and returns the corresponding node, or nil if and only if (⟺) the value is not present.
|
||||
// `find` finds the key in the tree, and returns the corresponding node, or nil if and only if (⟺) the value is not present.
|
||||
find :: proc(t: $T/Tree($Key, $Value), key: Key) -> (node: ^Node(Key, Value)) {
|
||||
node = t._root
|
||||
for node != nil {
|
||||
@@ -120,7 +120,7 @@ find :: proc(t: $T/Tree($Key, $Value), key: Key) -> (node: ^Node(Key, Value)) {
|
||||
return node
|
||||
}
|
||||
|
||||
// find_value finds the key in the tree, and returns the corresponding value, or nil if and only if (⟺) the value is not present.
|
||||
// `find_value` finds the key in the tree, and returns the corresponding value, or nil if and only if (⟺) the value is not present.
|
||||
find_value :: proc(t: $T/Tree($Key, $Value), key: Key) -> (value: Value, ok: bool) #optional_ok {
|
||||
if n := find(t, key); n != nil {
|
||||
return n.value, true
|
||||
@@ -128,10 +128,36 @@ find_value :: proc(t: $T/Tree($Key, $Value), key: Key) -> (value: Value, ok: boo
|
||||
return
|
||||
}
|
||||
|
||||
// find_or_insert attempts to insert the key-value pair into the tree, and returns
|
||||
// `find_or_insert` attempts to insert the key-value pair into the tree, and returns
|
||||
// the node, a boolean indicating if a new node was inserted, and the
|
||||
// node allocator error if relevant. If the key is already present, the existing node is updated and returned.
|
||||
// node allocator error if relevant. If the key is already present, the existing node is returned un-altered.
|
||||
find_or_insert :: proc(t: ^$T/Tree($Key, $Value), key: Key, value: Value) -> (n: ^Node(Key, Value), inserted: bool, err: runtime.Allocator_Error) {
|
||||
n_ptr := &t._root
|
||||
for n_ptr^ != nil {
|
||||
n = n_ptr^
|
||||
switch t._cmp_fn(key, n.key) {
|
||||
case .Less:
|
||||
n_ptr = &n._left
|
||||
case .Greater:
|
||||
n_ptr = &n._right
|
||||
case .Equal:
|
||||
return
|
||||
}
|
||||
}
|
||||
_parent := n
|
||||
|
||||
n = new_clone(Node(Key, Value){key=key, value=value, _parent=_parent, _color=.Red}, t._node_allocator) or_return
|
||||
n_ptr^ = n
|
||||
insert_case1(t, n)
|
||||
t._size += 1
|
||||
return n, true, nil
|
||||
}
|
||||
|
||||
|
||||
// `upsert` attempts to insert the key-value pair into the tree, and returns
|
||||
// the node, a boolean indicating if a new node was inserted, and the
|
||||
// node allocator error if relevant. If the key is already present, the existing node's value is updated.
|
||||
upsert :: proc(t: ^$T/Tree($Key, $Value), key: Key, value: Value) -> (n: ^Node(Key, Value), inserted: bool, err: runtime.Allocator_Error) {
|
||||
n_ptr := &t._root
|
||||
for n_ptr^ != nil {
|
||||
n = n_ptr^
|
||||
@@ -154,7 +180,7 @@ find_or_insert :: proc(t: ^$T/Tree($Key, $Value), key: Key, value: Value) -> (n:
|
||||
return n, true, nil
|
||||
}
|
||||
|
||||
// remove removes a node or value from the tree, and returns true if and only if (⟺) the
|
||||
// `remove` removes a node or value from the tree, and returns true if and only if (⟺) the
|
||||
// removal was successful. While the node's value will be left intact,
|
||||
// the node itself will be freed via the tree's node allocator.
|
||||
remove :: proc {
|
||||
@@ -162,7 +188,7 @@ remove :: proc {
|
||||
remove_node,
|
||||
}
|
||||
|
||||
// remove_value removes a value from the tree, and returns true if and only if (⟺) the
|
||||
// `remove_value` removes a value from the tree, and returns true if and only if (⟺) the
|
||||
// removal was successful. While the node's key + value will be left intact,
|
||||
// the node itself will be freed via the tree's node allocator.
|
||||
remove_key :: proc(t: ^$T/Tree($Key, $Value), key: Key, call_on_remove := true) -> bool {
|
||||
@@ -173,7 +199,7 @@ remove_key :: proc(t: ^$T/Tree($Key, $Value), key: Key, call_on_remove := true)
|
||||
return remove_node(t, n, call_on_remove)
|
||||
}
|
||||
|
||||
// remove_node removes a node from the tree, and returns true if and only if (⟺) the
|
||||
// `remove_node` removes a node from the tree, and returns true if and only if (⟺) the
|
||||
// removal was successful. While the node's key + value will be left intact,
|
||||
// the node itself will be freed via the tree's node allocator.
|
||||
remove_node :: proc(t: ^$T/Tree($Key, $Value), node: ^$N/Node(Key, Value), call_on_remove := true) -> (found: bool) {
|
||||
@@ -207,7 +233,7 @@ remove_node :: proc(t: ^$T/Tree($Key, $Value), node: ^$N/Node(Key, Value), call_
|
||||
return true
|
||||
}
|
||||
|
||||
// iterator returns a tree iterator in the specified direction.
|
||||
// `iterator` returns a tree iterator in the specified direction.
|
||||
iterator :: proc "contextless" (t: ^$T/Tree($Key, $Value), direction: Direction) -> Iterator(Key, Value) {
|
||||
it: Iterator(Key, Value)
|
||||
it._tree = cast(^Tree(Key, Value))t
|
||||
@@ -218,7 +244,7 @@ iterator :: proc "contextless" (t: ^$T/Tree($Key, $Value), direction: Direction)
|
||||
return it
|
||||
}
|
||||
|
||||
// iterator_from_pos returns a tree iterator in the specified direction,
|
||||
// `iterator_from_pos` returns a tree iterator in the specified direction,
|
||||
// spanning the range [pos, last] (inclusive).
|
||||
iterator_from_pos :: proc "contextless" (t: ^$T/Tree($Key, $Value), pos: ^Node(Key, Value), direction: Direction) -> Iterator(Key, Value) {
|
||||
it: Iterator(Key, Value)
|
||||
@@ -234,14 +260,14 @@ iterator_from_pos :: proc "contextless" (t: ^$T/Tree($Key, $Value), pos: ^Node(K
|
||||
return it
|
||||
}
|
||||
|
||||
// iterator_get returns the node currently pointed to by the iterator,
|
||||
// `iterator_get` returns the node currently pointed to by the iterator,
|
||||
// or nil if and only if (⟺) the node has been removed, the tree is empty, or the end
|
||||
// of the tree has been reached.
|
||||
iterator_get :: proc "contextless" (it: ^$I/Iterator($Key, $Value)) -> ^Node(Key, Value) {
|
||||
return it._cur
|
||||
}
|
||||
|
||||
// iterator_remove removes the node currently pointed to by the iterator,
|
||||
// `iterator_remove` removes the node currently pointed to by the iterator,
|
||||
// and returns true if and only if (⟺) the removal was successful. Semantics are the
|
||||
// same as the Tree remove.
|
||||
iterator_remove :: proc(it: ^$I/Iterator($Key, $Value), call_on_remove: bool = true) -> bool {
|
||||
@@ -257,7 +283,7 @@ iterator_remove :: proc(it: ^$I/Iterator($Key, $Value), call_on_remove: bool = t
|
||||
return ok
|
||||
}
|
||||
|
||||
// iterator_next advances the iterator and returns the (node, true) or
|
||||
// `iterator_next` advances the iterator and returns the (node, true) or
|
||||
// or (nil, false) if and only if (⟺) the end of the tree has been reached.
|
||||
//
|
||||
// Note: The first call to iterator_next will return the first node instead
|
||||
|
||||
@@ -265,7 +265,7 @@ array_push_back_elem :: proc(x: ^$X/Array($T, $SHIFT), value: T, loc := #caller_
|
||||
|
||||
chunk_idx, elem_idx, chunk_cap := _meta_get(SHIFT, uint(x.len))
|
||||
if x.chunks[chunk_idx] == nil {
|
||||
x.chunks[chunk_idx] = make([^]T, chunk_cap, x.allocator) or_return
|
||||
x.chunks[chunk_idx] = make([^]T, chunk_cap, x.allocator, loc) or_return
|
||||
}
|
||||
x.chunks[chunk_idx][elem_idx] = value
|
||||
x.len += 1
|
||||
@@ -328,7 +328,7 @@ array_push_back_elem_and_get_ptr :: proc(x: ^$X/Array($T, $SHIFT), value: T, loc
|
||||
|
||||
chunk_idx, elem_idx, chunk_cap := _meta_get(SHIFT, uint(x.len))
|
||||
if x.chunks[chunk_idx] == nil {
|
||||
x.chunks[chunk_idx] = make([^]T, chunk_cap, x.allocator) or_return
|
||||
x.chunks[chunk_idx] = make([^]T, chunk_cap, x.allocator, loc) or_return
|
||||
}
|
||||
x.chunks[chunk_idx][elem_idx] = value
|
||||
x.len += 1
|
||||
|
||||
@@ -13,10 +13,11 @@ constant-time byte comparison.
|
||||
- The crypto packages are not thread-safe.
|
||||
- Best-effort is make to mitigate timing side-channels on reasonable
|
||||
architectures. Architectures that are known to be unreasonable include
|
||||
but are not limited to i386, i486, and WebAssembly.
|
||||
but are not limited to i386, i486, VIA Nano 2000, ARM7T/ARM9T/Cortex-M3,
|
||||
and WASM.
|
||||
- Implementations assume a 64-bit architecture (64-bit integer arithmetic
|
||||
is fast, and includes add-with-carry, sub-with-borrow, and full-result
|
||||
multiply).
|
||||
is fast, and includes contant-time add-with-carry, sub-with-borrow, and
|
||||
full-result multiply).
|
||||
- Hardware sidechannels are explicitly out of scope for this package.
|
||||
Notable examples include but are not limited to:
|
||||
- Power/RF side-channels etc.
|
||||
@@ -29,4 +30,4 @@ constant-time byte comparison.
|
||||
|
||||
## License
|
||||
|
||||
This library is made available under the zlib license.
|
||||
This library is made available under the zlib license.
|
||||
|
||||
904
core/crypto/_bigint/i31.odin
Normal file
904
core/crypto/_bigint/i31.odin
Normal file
@@ -0,0 +1,904 @@
|
||||
// Constant time Big Integers
|
||||
package _bigint
|
||||
|
||||
// Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “AS IS” AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import "base:intrinsics"
|
||||
import "core:crypto"
|
||||
import subtle "core:crypto/_subtle"
|
||||
import "core:slice"
|
||||
|
||||
// Integers 'i31'
|
||||
// --------------
|
||||
//
|
||||
// The 'i31' functions implement computations on big integers using
|
||||
// an internal representation as an array of 32-bit integers. For
|
||||
// an array `x`:
|
||||
// -- x[0] encodes the array length and the "announced bit length"
|
||||
// of the integer: namely, if the announced bit length is k,
|
||||
// then x[0] = ((k / 31) << 5) + (k % 31).
|
||||
// -- x[1], x[2]... contain the value in little-endian order, 31
|
||||
// bits per word (x[1] contains the least significant 31 bits).
|
||||
// The upper bit of each word is 0.
|
||||
//
|
||||
// Multiplications rely on the elementary 32x32->64 multiplication.
|
||||
//
|
||||
// The announced bit length specifies the number of bits that are
|
||||
// significant in the subsequent 32-bit words. Unused bits in the
|
||||
// last (most significant) word are set to 0; subsequent words are
|
||||
// uninitialized and need not exist at all.
|
||||
//
|
||||
// The execution time and memory access patterns of all computations
|
||||
// depend on the announced bit length, but not on the actual word
|
||||
// values. For modular integers, the announced bit length of any integer
|
||||
// modulo `n` is equal to the actual bit length of `n`; thus, computations
|
||||
// on modular integers are "constant-time" (only the modulus length may leak).
|
||||
|
||||
I31_MASK :: 0x7fff_ffff
|
||||
|
||||
// Compute the bit length of a 32-bit integer.
|
||||
// Returned value is between 0 and 32 (inclusive).
|
||||
@(require_results)
|
||||
_u32_bit_length :: proc "contextless" (x: u32) -> (length: u32) {
|
||||
x := x
|
||||
k := subtle.neq(x, 0)
|
||||
c := subtle.gt(x, 0xFFFF); x = subtle.csel(x, x >> 16, c); k += c << 4
|
||||
c = subtle.gt(x, 0x00FF); x = subtle.csel(x, x >> 8, c); k += c << 3
|
||||
c = subtle.gt(x, 0x000F); x = subtle.csel(x, x >> 4, c); k += c << 2
|
||||
c = subtle.gt(x, 0x0003); x = subtle.csel(x, x >> 2, c); k += c << 1
|
||||
k += subtle.gt(x, 0x0001)
|
||||
return k
|
||||
}
|
||||
|
||||
// Multiply two 31-bit integers, with a 62-bit result. This default
|
||||
// implementation assumes that the basic multiplication operator
|
||||
// yields constant-time code.
|
||||
//
|
||||
// The mul31_lo() returns only the low 31 bits of the product.
|
||||
//
|
||||
// Note/Odin:
|
||||
// The original BearSSL code provides alternative implemenetations
|
||||
// of these routines gated behind `BR_CT_MUL31`, however that macro
|
||||
// is only useful on Intel 80386/80486, VIA Nano 2000, and ARM7T/ARM9T.
|
||||
@(require_results)
|
||||
_mul31 :: #force_inline proc "contextless" (x, y: u32) -> (res: u64) {
|
||||
return u64(x) * u64(y)
|
||||
}
|
||||
|
||||
@(private="file", require_results)
|
||||
_mul31_lo :: #force_inline proc "contextless" (x, y: u32) -> (res: u32) {
|
||||
return (x * y) & I31_MASK
|
||||
}
|
||||
|
||||
// Wrapper for `div_rem`; the remainder is returned, and the quotient is
|
||||
// discarded.
|
||||
@(private, require_results)
|
||||
_rem_u32 :: #force_inline proc "contextless" (hi: u32, lo: u32, d: u32) -> (res: u32) {
|
||||
_, rem := div_rem_u32(hi, lo, d)
|
||||
return rem
|
||||
}
|
||||
|
||||
// Wrapper for `div_rem`; the quotient is returned, and the remainder is
|
||||
// discarded.
|
||||
@(private="file", require_results)
|
||||
_div_u32 :: #force_inline proc "contextless" (hi: u32, lo: u32, d: u32) -> (quo: u32) {
|
||||
q, _ := div_rem_u32(hi, lo, d)
|
||||
return q
|
||||
}
|
||||
|
||||
// Constant-time division. The dividend `hi:lo` is divided by the divisor `d`;
|
||||
// the quotient and remainder are returned.
|
||||
//
|
||||
// If `hi == d`, then the quotient does not fit on 32 bits; returned value is thus truncated.
|
||||
// If `hi > d`, returned values are indeterminate.
|
||||
@(require_results)
|
||||
div_rem_u32 :: proc "contextless" (hi: u32, lo: u32, d: u32) -> (quo: u32, rem: u32) {
|
||||
// TODO: optimize this
|
||||
hi := hi
|
||||
lo := lo
|
||||
ch := subtle.eq(hi, d)
|
||||
hi = subtle.csel(hi, 0, ch)
|
||||
for k := uint(31); k > 0; k -= 1 {
|
||||
j := 32 - k
|
||||
w := (hi << j) | (lo >> k)
|
||||
ctl := subtle.ge(w, d) | (hi >> k)
|
||||
hi2 := (w - d) >> j
|
||||
lo2 := lo - (d << k)
|
||||
hi = subtle.csel(hi, hi2, ctl)
|
||||
lo = subtle.csel(lo, lo2, ctl)
|
||||
quo |= ctl << k
|
||||
}
|
||||
cf := subtle.ge(lo, d) | hi
|
||||
quo |= cf
|
||||
rem = subtle.csel(lo, lo - d, cf)
|
||||
return
|
||||
}
|
||||
|
||||
// i31_rem computes x / y and returns the remainder.
|
||||
@(require_results)
|
||||
i31_rem :: proc "contextless" (x: []u32, y: u32) -> u32 {
|
||||
words := uint(x[0] + 31) >> 5
|
||||
x_ := x[1:]
|
||||
|
||||
r: u32
|
||||
for i := int(words-1); i >= 0; i -= 1 {
|
||||
r = _rem_u32(r, x_[i], y)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Test whether an integer `x` is zero.
|
||||
@(optimization_mode="none", require_results)
|
||||
i31_is_zero :: proc "contextless" (x: []u32) -> (res: u32) {
|
||||
z: u32
|
||||
|
||||
for u := (x[0] + 31) >> 5; u > 0; u -= 1 {
|
||||
z |= x[u]
|
||||
}
|
||||
return ~(z | -z) >> 31
|
||||
}
|
||||
|
||||
// Add `b` to `a` and return the `carry` (`0` or `1`). if `ctl` is `1`.
|
||||
// If `ctl` is `0`, `a` is left alone but the `carry` will still be computed.
|
||||
//
|
||||
// The slices `a` and `b` MUST have the same announced bit length (in subscript `0`)
|
||||
//
|
||||
// `a` and `b` MAY be the same array, but partial overlap is not allowed.
|
||||
@(require_results)
|
||||
i31_add :: proc "contextless" (a: []u32, b: []u32, ctl: u32) -> (carry: u32) {
|
||||
words := uint(a[0] + 63) >> 5
|
||||
for u in 1..<words {
|
||||
aw := a[u]
|
||||
bw := b[u]
|
||||
naw := aw + bw + carry
|
||||
carry = naw >> 31
|
||||
a[u] = subtle.csel(aw, naw & I31_MASK, ctl)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Subtract `b` from `a` and return the `carry` (`0` or `1`), if `ctl` is `1`.
|
||||
// If `ctl` is `0`, then `a` is unmodified, but the carry is still computed
|
||||
// and returned.
|
||||
//
|
||||
// The slices `a` and `b` MUST have the same announced bit length (in subscript `0`)
|
||||
//
|
||||
// `a` and `b` MAY be the same array, but partial overlap is not allowed.
|
||||
@(require_results)
|
||||
i31_sub :: proc "contextless" (a: []u32, b: []u32, ctl: u32) -> (carry: u32) {
|
||||
words := uint(a[0] + 63) >> 5
|
||||
for u in 1..<words {
|
||||
aw := a[u]
|
||||
bw := b[u]
|
||||
naw := aw - bw - carry
|
||||
carry = naw >> 31
|
||||
a[u] = subtle.csel(aw, naw & I31_MASK, ctl)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Compute the ENCODED actual bit length of an integer `x`.
|
||||
// The argument `x` should point to the first (least significant)
|
||||
// value word of the integer.
|
||||
//
|
||||
// The upper bit of each value word MUST be `0`.
|
||||
//
|
||||
// Returned value is `((k / 31) << 5) + (k % 31)` if the bit length is `k`.
|
||||
//
|
||||
// CT: value or length of `x` does not leak.
|
||||
@(require_results)
|
||||
i31_bit_length :: proc "contextless" (x: []u32) -> (res: u32) {
|
||||
tw, twk: u32
|
||||
|
||||
xlen := len(x)
|
||||
for xlen > 0 {
|
||||
xlen -= 1
|
||||
c := subtle.eq(tw, 0)
|
||||
w := x[xlen]
|
||||
|
||||
tw = subtle.csel(tw, w, c)
|
||||
twk = subtle.csel(twk, u32(xlen), c)
|
||||
}
|
||||
return (twk << 5) + _u32_bit_length(tw)
|
||||
}
|
||||
|
||||
// Decode an integer from its big-endian unsigned representation. The
|
||||
// "true" bit length of the integer is computed and set in the encoded
|
||||
// announced bit length (`x[0]`), but all words of `x` corresponding to
|
||||
// the full slice of source bytes.
|
||||
//
|
||||
// `x` needs to have a minimum length of: `1 + ((len(src) * 8) + 31) / 31`
|
||||
//
|
||||
// CT: value or length of `x` does not leak.
|
||||
i31_decode :: proc "contextless" (x: []u32, src: []byte) {
|
||||
u := len(src) - 1
|
||||
v := 1
|
||||
acc := u32(0)
|
||||
acc_len := uint(0)
|
||||
for u >= 0 {
|
||||
b := u32(src[u])
|
||||
acc |= b << acc_len
|
||||
acc_len += 8
|
||||
if acc_len >= 31 {
|
||||
x[v] = acc & I31_MASK
|
||||
acc_len -= 31
|
||||
acc = b >> (8 - acc_len)
|
||||
v += 1
|
||||
}
|
||||
u -= 1
|
||||
}
|
||||
if acc_len != 0 {
|
||||
x[v] = acc
|
||||
v += 1
|
||||
}
|
||||
x[0] = i31_bit_length(x[1:])
|
||||
}
|
||||
|
||||
// Decode an integer from its big-endian unsigned representation.
|
||||
// The integer MUST be lower than `m`; the (encoded) announced bit length
|
||||
// written in `x` will be equal to that of `m`. All bytes from the
|
||||
// `src` slice are read.
|
||||
//
|
||||
// Returned value is `1` if the decode value fits within the modulus, `0`
|
||||
// otherwise. In the latter case, the `x` buffer will be set to `0` (but
|
||||
// still with the announced bit length of `m`).
|
||||
//
|
||||
// CT: value or length of `x` does not leak. Memory access pattern depends
|
||||
// only `src`'s length and the announced bit length of `m`. Whether `x` fits or
|
||||
// not does not leak either.
|
||||
@(require_results)
|
||||
i31_decode_mod :: proc "contextless" (x: []u32, src: []byte, m: []u32) -> (res: u32) {
|
||||
// Two-pass algorithm: in the first pass, we determine whether the
|
||||
// value fits; in the second pass, we do the actual write.
|
||||
//
|
||||
// During the first pass, `res` contains the comparison result so far:
|
||||
// 0x00000000 value is equal to the modulus
|
||||
// 0x00000001 value is greater than the modulus
|
||||
// 0xFFFFFFFF value is lower than the modulus
|
||||
//
|
||||
// Since we iterate starting with the least significant bytes (at
|
||||
// the end of `src`), each new comparison overrides the previous
|
||||
// except when the comparison yields 0 (equal).
|
||||
//
|
||||
// During the second pass, `res` is either 0xFFFFFFFF (value fits) 0x00000000 (value does not fit).
|
||||
// We must iterate over all bytes of the source, _and_ possibly
|
||||
// some extra virtual bytes (with value 0) so as to cover the
|
||||
// complete modulus as well. We also add 4 such extra bytes beyond
|
||||
// the modulus length because it then guarantees that no accumulated
|
||||
// partial word remains to be processed.
|
||||
_len := uint(len(src))
|
||||
mlen := uint((m[0] + 31) >> 5)
|
||||
tlen := uint(mlen << 2)
|
||||
if tlen < _len {
|
||||
tlen = _len
|
||||
}
|
||||
tlen += 4
|
||||
|
||||
for pass in 0..<2 {
|
||||
v := uint(1)
|
||||
acc := u32(0)
|
||||
acc_len := u32(0)
|
||||
|
||||
for u in uint(0)..<tlen {
|
||||
b: u32 = ---
|
||||
|
||||
if u < _len {
|
||||
b = u32(src[_len - 1 - u])
|
||||
} else {
|
||||
b = 0
|
||||
}
|
||||
|
||||
acc |= (b << acc_len)
|
||||
acc_len += 8
|
||||
if acc_len >= 31 {
|
||||
xw := acc & I31_MASK
|
||||
acc_len -= 31
|
||||
|
||||
acc = b >> (8 - acc_len)
|
||||
if v <= mlen {
|
||||
if pass == 1 {
|
||||
x[v] = res & xw
|
||||
} else {
|
||||
cc := u32(subtle.cmp(xw, m[v]))
|
||||
res = subtle.csel(cc, res, subtle.eq(cc, 0))
|
||||
}
|
||||
} else {
|
||||
if pass == 0 {
|
||||
res = subtle.csel(1, res, subtle.eq(xw, 0))
|
||||
}
|
||||
}
|
||||
v += 1
|
||||
}
|
||||
}
|
||||
|
||||
// When we reach this point at the end of the first pass:
|
||||
// r is either 0, 1 or -1; we want to set r to 0 if it
|
||||
// is equal to 0 or 1, and leave it to -1 otherwise.
|
||||
//
|
||||
// When we reach this point at the end of the second pass:
|
||||
// r is either 0 or -1; we want to leave that value
|
||||
// untouched. This is a subcase of the previous.
|
||||
res >>= 1
|
||||
res |= (res << 1)
|
||||
}
|
||||
|
||||
x[0] = m[0]
|
||||
|
||||
return res & 1
|
||||
}
|
||||
|
||||
// Zeroize integer `x`. The announced bit length is set to the provided value,
|
||||
// and the corresponding words are set to 0. The ENCODED bit length is expected
|
||||
//here.
|
||||
i31_zero :: proc "contextless" (x: []u32, bit_len: u32) {
|
||||
x[0] = bit_len
|
||||
intrinsics.mem_zero(raw_data(x[1:]), ((bit_len + 31) >> 5) * size_of(u32))
|
||||
}
|
||||
|
||||
// Make a random integer of the provided size. The size is encoded.
|
||||
// The header word is untouched.
|
||||
i31_mkrand :: proc(x: []u32, esize: u32) {
|
||||
_len := (esize + 31) >> 5
|
||||
x_ := slice.reinterpret([]byte, x)
|
||||
crypto.rand_bytes(x_[4:4 + _len * size_of(u32)])
|
||||
for u in 1..<_len {
|
||||
x[u] &= I31_MASK
|
||||
}
|
||||
m := _len & 31
|
||||
if m == 0 {
|
||||
x[_len] &= I31_MASK
|
||||
} else {
|
||||
x[_len] &= I31_MASK >> (31 - m)
|
||||
}
|
||||
}
|
||||
|
||||
// Right-shift an integer. The shift amount must be lower than 31 bits.
|
||||
i31_rshift :: proc "contextless" (x: []u32, shift_amount: i32) {
|
||||
_len := uint(x[0] + 31) >> 5
|
||||
if _len == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
count := uint(shift_amount)
|
||||
|
||||
r := x[1] >> count
|
||||
for u in 2..= _len {
|
||||
w := u32(x[u])
|
||||
|
||||
x[u - 1] = ((w << (31 - count)) | r) & I31_MASK
|
||||
r = w >> count
|
||||
}
|
||||
x[_len] = r
|
||||
}
|
||||
|
||||
// Reduce integer `a` modulo `m`. The result is written to `x`,
|
||||
// and its announced bit length is set to be equal to that of `m`.
|
||||
//
|
||||
// `x` MUST be distinct from `a` and `m`.
|
||||
//
|
||||
// CT: only announced bit lengths leak, not values of `x`, `a` or `m`.
|
||||
i31_reduce :: proc "contextless" (x: []u32, a: []u32, m: []u32) {
|
||||
m_bitlen := m[0]
|
||||
mlen := uint(m_bitlen + 31) >> 5
|
||||
|
||||
x[0] = m_bitlen
|
||||
if m_bitlen == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// If the source is shorter, then simply copy all words from a[]
|
||||
// and zero out the upper words.
|
||||
a_bitlen := a[0]
|
||||
alen := uint(a_bitlen + 31) >> 5
|
||||
if a_bitlen < m_bitlen {
|
||||
copy(x[1:], a[1:][:alen])
|
||||
for u in alen..<mlen {
|
||||
x[u + 1] = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// The source length is at least equal to that of the modulus.
|
||||
// We must thus copy N-1 words, and input the remaining words one
|
||||
// by one.
|
||||
copy(x[1:], a[2 + (alen - mlen):][:mlen - 1])
|
||||
x[mlen] = 0
|
||||
for u := 1 + alen - mlen; u > 0; u -= 1 {
|
||||
i31_muladd_small(x, a[u], m)
|
||||
}
|
||||
}
|
||||
|
||||
// Decode an integer from its big-endian unsigned representation, and
|
||||
// reduce it modulo the provided modulus `m`. The announced bit length
|
||||
// of the result is set to be equal to that of the modulus.
|
||||
//
|
||||
// `x` MUST be distinct from `m`.
|
||||
i31_decode_reduce :: proc "contextless" (x: []u32, src: []byte, m: []u32) {
|
||||
// Get the encoded bit length.
|
||||
m_ebitlen := m[0]
|
||||
|
||||
// Special case for an invalid (null) modulus.
|
||||
if m_ebitlen == 0 {
|
||||
x[0] = 0
|
||||
return
|
||||
}
|
||||
|
||||
// Clear the destination.
|
||||
i31_zero(x, m_ebitlen)
|
||||
|
||||
// First decode directly as many bytes as possible.
|
||||
// This requires computing the actual bit length.
|
||||
m_rbitlen := m_ebitlen >> 5
|
||||
m_rbitlen = (m_ebitlen & 31) + (m_rbitlen << 5) - m_rbitlen
|
||||
|
||||
mblen := uint(m_rbitlen + 7) >> 3
|
||||
k := mblen - 1
|
||||
_len := uint(len(src))
|
||||
|
||||
if k >= _len {
|
||||
i31_decode(x, src)
|
||||
x[0] = m_ebitlen
|
||||
return
|
||||
}
|
||||
|
||||
i31_decode(x, src[:k])
|
||||
x[0] = m_ebitlen
|
||||
|
||||
// Input remaining bytes, using 31-bit words.
|
||||
acc := u32(0)
|
||||
acc_len := uint(0)
|
||||
|
||||
for {
|
||||
v := u32(src[k])
|
||||
|
||||
if acc_len >= 23 {
|
||||
acc_len -= 23
|
||||
acc <<= (8 - acc_len)
|
||||
acc |= v >> acc_len
|
||||
i31_muladd_small(x, acc, m)
|
||||
acc = v & (0xFF >> (8 - acc_len))
|
||||
} else {
|
||||
acc = (acc << 8) | v
|
||||
acc_len += 8
|
||||
}
|
||||
|
||||
if k += 1; k >= _len {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// We may have some bits accumulated. We then perform a shift to
|
||||
// be able to inject these bits as a full 31-bit word.
|
||||
if acc_len != 0 {
|
||||
acc = (acc | (x[1] << acc_len)) & I31_MASK
|
||||
i31_rshift(x, i32(31 - acc_len))
|
||||
i31_muladd_small(x, acc, m)
|
||||
}
|
||||
}
|
||||
|
||||
// Multiply `x` by 2^31 and then add integer `z`, modulo `m`.
|
||||
// This function assumes that `x` and `m` have the same announced bit
|
||||
// length, the announced bit length of `m` matches its true bit length.
|
||||
//
|
||||
// `x` and `m` MUST be distinct arrays.
|
||||
// `z` MUST fit in 31 bits (upper bit set to 0).
|
||||
//
|
||||
// CT: only the common announced bit length of `x` and `m` leaks, not
|
||||
// the values of `x`, `z` or `m`.
|
||||
i31_muladd_small :: proc "contextless" (x: []u32, z: u32, m: []u32) {
|
||||
// We can test on the modulus bit length since we accept to leak
|
||||
// that length.
|
||||
m_bitlen := m[0]
|
||||
if m_bitlen == 0 {
|
||||
return
|
||||
}
|
||||
hi: u32
|
||||
if m_bitlen <= 31 {
|
||||
hi = x[1] >> 1
|
||||
lo := (x[1] << 31) | z
|
||||
x[1] = _rem_u32(hi, lo, m[1])
|
||||
return
|
||||
}
|
||||
mlen := uint(m_bitlen + 31) >> 5
|
||||
mblr := uint(m_bitlen) & 31
|
||||
|
||||
// Principle: we estimate the quotient (x*2^31+z)/m by
|
||||
// doing a 64/32 division with the high words.
|
||||
//
|
||||
// Let:
|
||||
// w = 2^31
|
||||
// a = (w*a0 + a1) * w^N + a2
|
||||
// b = b0 * w^N + b2
|
||||
// such that:
|
||||
// 0 <= a0 < w
|
||||
// 0 <= a1 < w
|
||||
// 0 <= a2 < w^N
|
||||
// w/2 <= b0 < w
|
||||
// 0 <= b2 < w^N
|
||||
// a < w*b
|
||||
// I.e. the two top words of a are a0:a1, the top word of b is
|
||||
// b0, we ensured that b0 is "full" (high bit set), and a is
|
||||
// such that the quotient q = a/b fits on one word (0 <= q < w).
|
||||
//
|
||||
// If a = b*q + r (with 0 <= r < q), we can estimate q by
|
||||
// doing an Euclidean division on the top words:
|
||||
// a0*w+a1 = b0*u + v (with 0 <= v < b0)
|
||||
// Then the following holds:
|
||||
// 0 <= u <= w
|
||||
// u-2 <= q <= u
|
||||
hi = x[mlen]
|
||||
a0, a1, b0: u32
|
||||
if mblr == 0 {
|
||||
a0 = x[mlen]
|
||||
intrinsics.mem_copy(raw_data(x[2:]), raw_data(x[1:]), (mlen - 1) * size_of(u32))
|
||||
x[1] = z
|
||||
a1 = x[mlen]
|
||||
b0 = m[mlen]
|
||||
} else {
|
||||
a0 = ((x[mlen] << (31 - mblr)) | (x[mlen - 1] >> mblr)) & I31_MASK
|
||||
intrinsics.mem_copy(raw_data(x[2:]), raw_data(x[1:]), (mlen - 1) * size_of(u32))
|
||||
x[1] = z
|
||||
a1 = ((x[mlen] << (31 - mblr)) | (x[mlen - 1] >> mblr)) & I31_MASK
|
||||
b0 = ((m[mlen] << (31 - mblr)) | (m[mlen - 1] >> mblr)) & I31_MASK
|
||||
}
|
||||
|
||||
// We estimate a divisor q. If the quotient returned by div()
|
||||
// is g:
|
||||
// -- If a0 == b0 then g == 0; we want q = 0x7FFFFFFF.
|
||||
// -- Otherwise:
|
||||
// -- if g == 0 then we set q = 0;
|
||||
// -- otherwise, we set q = g - 1.
|
||||
// The properties described above then ensure that the true
|
||||
// quotient is q-1, q or q+1.
|
||||
//
|
||||
// Take care that a0, a1 and b0 are 31-bit words, not 32-bit. We
|
||||
// must adjust the parameters to br_div() accordingly.
|
||||
g := _div_u32(a0 >> 1, a1 | (a0 << 31), b0)
|
||||
q := subtle.csel(subtle.csel(g - 1, 0, subtle.eq(g, 0)), I31_MASK, subtle.eq(a0, b0))
|
||||
|
||||
// We subtract q*m from x (with the extra high word of value 'hi').
|
||||
// Since q may be off by 1 (in either direction), we may have to
|
||||
// add or subtract m afterwards.
|
||||
//
|
||||
// The 'tb' flag will be true (1) at the end of the loop if the
|
||||
// result is greater than or equal to the modulus (not counting
|
||||
// 'hi' or the carry).
|
||||
cc := u32(0)
|
||||
tb := u32(1)
|
||||
for u in 1..= mlen {
|
||||
mw := m[u]
|
||||
zl := _mul31(mw, q) + u64(cc)
|
||||
cc = u32(zl >> 31)
|
||||
zw := u32(zl) & I31_MASK
|
||||
xw := x[u]
|
||||
nxw := xw - zw
|
||||
cc += nxw >> 31
|
||||
nxw &= I31_MASK
|
||||
x[u] = nxw
|
||||
tb = subtle.csel(subtle.gt(nxw, mw), tb, subtle.eq(nxw, mw))
|
||||
}
|
||||
|
||||
// If we underestimated q, then either cc < hi (one extra bit
|
||||
// beyond the top array word), or cc == hi and tb is true (no
|
||||
// extra bit, but the result is not lower than the modulus). In
|
||||
// these cases we must subtract m once.
|
||||
//
|
||||
// Otherwise, we may have overestimated, which will show as
|
||||
// cc > hi (thus a negative result). Correction is adding m once.
|
||||
over := subtle.gt(cc, hi)
|
||||
under := ~over & (tb | subtle.lt(cc, hi))
|
||||
_ = i31_add(x, m, over)
|
||||
_ = i31_sub(x, m, under)
|
||||
}
|
||||
|
||||
// Encode an integer into its big-endian unsigned representation. The
|
||||
// output length in bytes is provided (parameter 'len'); if the length
|
||||
// is too short then the integer is appropriately truncated; if it is
|
||||
// too long then the extra bytes are set to 0.
|
||||
i31_encode :: proc "contextless" (dst: []byte, x: []u32) {
|
||||
xlen := uint(x[0] + 31) >> 5
|
||||
if xlen == 0 {
|
||||
intrinsics.mem_zero(raw_data(dst[:]), len(dst) * size_of(u32))
|
||||
return
|
||||
}
|
||||
_len := uint(len(dst))
|
||||
k := uint(1)
|
||||
acc := u32(0)
|
||||
acc_len := uint(0)
|
||||
for _len != 0 {
|
||||
w := (k <= xlen) ? x[k] : 0
|
||||
k += 1
|
||||
if (acc_len == 0) {
|
||||
acc = w
|
||||
acc_len = 31
|
||||
} else {
|
||||
z := acc | (w << acc_len)
|
||||
acc_len -= 1
|
||||
acc = w >> (31 - acc_len)
|
||||
if _len >= 4 {
|
||||
_len -= 4
|
||||
ptr := (^u32be)(raw_data(dst[_len:]))
|
||||
intrinsics.unaligned_store(ptr, u32be(z))
|
||||
} else {
|
||||
switch _len {
|
||||
case 3:
|
||||
dst[_len - 3] = byte(z >> 16)
|
||||
fallthrough
|
||||
case 2:
|
||||
dst[_len - 2] = byte(z >> 8)
|
||||
fallthrough
|
||||
case 1:
|
||||
dst[_len - 1] = byte(z)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute `-(1/x) % 2^31`. If `x` is even, then this function returns `0`.
|
||||
i31_ninv31 :: proc "contextless" (x: u32) -> (y: u32) {
|
||||
y = 2 - x
|
||||
y *= 2 - y * x
|
||||
y *= 2 - y * x
|
||||
y *= 2 - y * x
|
||||
y *= 2 - y * x
|
||||
return subtle.csel(0, -y, x & 1) & I31_MASK
|
||||
}
|
||||
|
||||
// Compute a modular Montgomery multiplication. `d` is filled with the
|
||||
// value of `x*y/R % m` (where `R` is the Montgomery factor).
|
||||
//
|
||||
// The array `d` MUST be distinct from `x`, `y` and `m`[].
|
||||
// `x` and `y` MUST be numerically lower than `m`.
|
||||
//
|
||||
// `x` and `y` MAY be the same array.
|
||||
//
|
||||
// The `m0i` parameter is equal to `-(1/m0) mod 2^31`, where `m0` is the least
|
||||
// significant value word of `m` (this works only if `m` is an odd integer).
|
||||
i31_montymul :: proc "contextless" (d: []u32, x: []u32, y: []u32, m: []u32, m0i: u32) {
|
||||
// Each outer loop iteration computes:
|
||||
// `d <- (d + xu*y + f*m) / 2^31`
|
||||
// We have `xu <= 2^31-1` and `f <= 2^31-1`.
|
||||
// Thus, if `d <= 2*m-1` on input, then:
|
||||
// `2*m-1 + 2*(2^31-1)*m <= (2^32)*m-1`
|
||||
// and the new `d` value is less than `2*m`.
|
||||
//
|
||||
// We represent `d` over 31-bit words, with an extra word `dh`,
|
||||
// which can thus be only 0 or 1.
|
||||
_len := uint((m[0] + 31) >> 5)
|
||||
len4 := _len & ~uint(3)
|
||||
i31_zero(d, m[0])
|
||||
dh := u32(0)
|
||||
for u in 0..<_len {
|
||||
// The carry for each operation fits on 32 bits:
|
||||
// `d[v+1] <= 2^31-1`
|
||||
// `xu*y[v+1] <= (2^31-1)*(2^31-1)`
|
||||
// `f*m[v+1] <= (2^31-1)*(2^31-1)`
|
||||
// `r <= 2^32-1`
|
||||
// `(2^31-1) + 2*(2^31-1)*(2^31-1) + (2^32-1) = 2^63 - 2^31`
|
||||
//
|
||||
// After division by `2^31`, the new `r` is then at most `2^32-1`
|
||||
//
|
||||
// Using a 32-bit carry has performance benefits on 32-bit
|
||||
// systems; however, on 64-bit architectures, we prefer to
|
||||
// keep the carry (r) in a 64-bit register, thus avoiding some
|
||||
// "clear high bits" operations.
|
||||
xu := x[u + 1]
|
||||
f := _mul31_lo((d[1] + _mul31_lo(xu, y[1])), m0i)
|
||||
|
||||
r := u64(0)
|
||||
v := uint(0)
|
||||
for ; v < len4; v += 4 {
|
||||
z := u64(d[v + 1]) + _mul31(xu, y[v + 1]) + _mul31(f, m[v + 1]) + r
|
||||
r = z >> 31
|
||||
d[v + 0] = u32(z) & I31_MASK
|
||||
z = u64(d[v + 2]) + _mul31(xu, y[v + 2]) + _mul31(f, m[v + 2]) + r
|
||||
r = z >> 31
|
||||
d[v + 1] = u32(z) & I31_MASK
|
||||
z = u64(d[v + 3]) + _mul31(xu, y[v + 3]) + _mul31(f, m[v + 3]) + r
|
||||
r = z >> 31
|
||||
d[v + 2] = u32(z) & I31_MASK
|
||||
z = u64(d[v + 4]) + _mul31(xu, y[v + 4]) + _mul31(f, m[v + 4]) + r
|
||||
r = z >> 31
|
||||
d[v + 3] = u32(z) & I31_MASK
|
||||
}
|
||||
for ; v < _len; v += 1 {
|
||||
z := u64(d[v + 1]) + _mul31(xu, y[v + 1]) + _mul31(f, m[v + 1]) + r
|
||||
r = z >> 31
|
||||
d[v] = u32(z) & I31_MASK
|
||||
}
|
||||
|
||||
// Since the new `dh` can only be `0` or `1`, the addition of
|
||||
// the old dh with the carry MUST fit on 32 bits, and
|
||||
// thus can be done into dh itself.
|
||||
dh += u32(r)
|
||||
d[_len] = dh & I31_MASK
|
||||
dh >>= 31
|
||||
}
|
||||
|
||||
// We must write back the bit length because it was overwritten in
|
||||
// the loop (not overwriting it would require a test in the loop,
|
||||
// which would yield bigger and slower code).
|
||||
d[0] = m[0]
|
||||
|
||||
// `d` may still be greater than `m` at that point; notably, the `dh`
|
||||
// word may be non-zero.
|
||||
_ = i31_sub(d, m, subtle.neq(dh, 0) | subtle.not(i31_sub(d, m, 0)))
|
||||
}
|
||||
|
||||
// Convert a modular integer to Montgomery representation.
|
||||
//
|
||||
// The integer `x` MUST be lower than `m`, but with the same announced bit length.
|
||||
i31_to_monty :: proc "contextless" (x: []u32, m: []u32) {
|
||||
// uint32_t k;
|
||||
for k := (m[0] + 31) >> 5; k > 0; k -= 1 {
|
||||
i31_muladd_small(x, 0, m)
|
||||
}
|
||||
}
|
||||
|
||||
// Convert a modular integer back from Montgomery representation.
|
||||
//
|
||||
// The integer `x` MUST be lower than `m`[], but with the same announced bit
|
||||
// length.
|
||||
//
|
||||
// The `m0i` parameter is equal to `-(1/m0) mod 2^32`, where `m0` is the least
|
||||
// significant value word of `m` (this works only if `m` is an odd integer).
|
||||
i31_from_monty :: proc "contextless" (x: []u32, m: []u32, m0i: u32) {
|
||||
_len := uint(m[0] + 31) >> 5
|
||||
for _ in 0..<_len {
|
||||
f := _mul31_lo(x[1], m0i)
|
||||
cc := u64(0)
|
||||
for v in 0..<_len {
|
||||
z := u64(x[v + 1]) + _mul31(f, m[v + 1]) + cc
|
||||
cc = z >> 31
|
||||
if v != 0 {
|
||||
x[v] = u32(z & I31_MASK)
|
||||
}
|
||||
}
|
||||
x[_len] = u32(cc)
|
||||
}
|
||||
|
||||
// We may have to do an extra subtraction, but only if the value in `x`
|
||||
// is indeed greater than or equal to that of `m`, which is why we must
|
||||
// do two calls:
|
||||
// - First call computes the carry
|
||||
// - Second call performs the subtraction only if the carry is 0).
|
||||
_ = i31_sub(x, m, subtle.not(i31_sub(x, m, 0)))
|
||||
}
|
||||
|
||||
// Compute a modular exponentiation.
|
||||
//
|
||||
// `x` MUST be an integer modulo `m` (same announced bit length, lower value).
|
||||
// `m` MUST be odd.
|
||||
//
|
||||
// The exponent `e` is in big-endian unsigned notation.
|
||||
//
|
||||
// The `m0i` parameter is equal to `-(1/m0) mod 2^31`, where `m0` is the least
|
||||
// significant value word of `m` (this works only if `m` is an odd integer).
|
||||
//
|
||||
// The `t1` and `t2` parameters must be temporary arrays, each large enough to
|
||||
// accommodate an integer with the same size as `m`.
|
||||
i31_modpow :: proc "contextless" (x: []u32, e: []byte, m: []u32, m0i: u32, t1: []u32, t2: []u32) {
|
||||
// `mlen` is the length of `m` expressed in `u32`'s (including the
|
||||
// "bit length" first field).
|
||||
mlen := uint((m[0] + 63) >> 5)
|
||||
elen := u32(len(e))
|
||||
|
||||
// Throughout the algorithm:
|
||||
// -- `t1` is in Montgomery representation; it contains x, x^2, x^4, x^8...
|
||||
// -- The result is accumulated, in normal representation, in the `x` array.
|
||||
// -- `t2` is used as destination buffer for each multiplication.
|
||||
//
|
||||
// Note that there is no need to call `i32_from_monty()`.
|
||||
copy(t1[:mlen], x[:mlen])
|
||||
i31_to_monty(t1, m)
|
||||
i31_zero(x, m[0])
|
||||
x[1] = 1
|
||||
for k := u32(0); k < (elen << 3); k += 1 {
|
||||
ctl := (e[elen - 1 - (k >> 3)] >> (k & 7)) & 1
|
||||
|
||||
i31_montymul(t2, x, t1, m, m0i)
|
||||
|
||||
for &d, i in x[:mlen] {
|
||||
d = subtle.csel(d, t2[i], ctl)
|
||||
}
|
||||
|
||||
i31_montymul(t2, t1, t1, m, m0i)
|
||||
copy(t1[:mlen], t2[:mlen])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Compute a modular exponentiation.
|
||||
//
|
||||
// `x` MUST be an integer modulo `m` (same announced bit length, lower value).
|
||||
// `m` MUST be odd.
|
||||
//
|
||||
// The exponent `e` is in big-endian unsigned notation.
|
||||
//
|
||||
// The `m0i` parameter is equal to `-(1/m0) mod 2^31`, where `m0` is the least
|
||||
// significant value word of `m`[] (this works only if m[] is an odd integer).
|
||||
//
|
||||
// The `tmp` array is used for temporaries; it must be large enough to accommodate
|
||||
// at least two temporary values with the same size as `m` (including the leading
|
||||
// "bit length" word).
|
||||
//
|
||||
// If there is room for more temporaries, then this function may use the extra
|
||||
// room for window-based optimisation, resulting in faster computations.
|
||||
//
|
||||
// Returned value is `true` on success, `false` on error. An error is reported if
|
||||
// the provided `tmp`array is too short.
|
||||
i31_modpow_opt :: proc "contextless" (x: []u32, e: []byte, m: []u32, m0i: u32, tmp: []u32) -> u32 {
|
||||
// NOTE/yawning: This is only used by the rsa_i31 code, with the key
|
||||
// generation taking a function pointer to either this routine,
|
||||
// or the i62 variant.
|
||||
//
|
||||
// If we ever need to support the i32 version, it is used extensively,
|
||||
// but non e-waste architecutures will all do the right thing with
|
||||
// the i62 version, albeit with a perforance hit on 32-bit CPUs.
|
||||
|
||||
unimplemented_contextless()
|
||||
|
||||
// i31_mod_pow(x, e, m, m0i, tmp[:len(m)], tmp[len(m):])
|
||||
// return 1
|
||||
}
|
||||
|
||||
// Compute `d+a*b`, result in `d`.
|
||||
//
|
||||
// The initial announced bit length of `d` MUST match that of `a`[].
|
||||
//
|
||||
// The `d` array MUST be large enough to accommodate the full result,
|
||||
// plus (possibly) an extra word. The resulting announced bit length
|
||||
// of `d` will be the sum of the announced bit lengths of `a` and `b`
|
||||
// (therefore, it may be larger than the actual bit length of the numerical result).
|
||||
//
|
||||
// `a` and `b` may be the same array. `d` must be disjoint from both `a` and `b`.
|
||||
i31_mulacc :: proc "contextless" (d: []u32, a: []u32, b: []u32) {
|
||||
a_len := uint((a[0] + 31) >> 5)
|
||||
b_len := uint((b[0] + 31) >> 5)
|
||||
|
||||
// We want to add the two bit lengths, but these are encoded,
|
||||
// which requires some extra care.
|
||||
d_l := (a[0] & 31) + (b[0] & 31)
|
||||
d_h := (a[0] >> 5) + (b[0] >> 5)
|
||||
d[0] = (d_h << 5) + d_l + (~u32(d_l - 31) >> 31)
|
||||
|
||||
for u in 0..<b_len {
|
||||
// Carry always fits on 31 bits; we want to keep it in a
|
||||
// 32-bit register on 32-bit architectures (on a 64-bit
|
||||
// architecture, cast down from 64 to 32 bits means
|
||||
// clearing the high bits, which is not free; on a 32-bit
|
||||
// architecture, the same operation really means ignoring
|
||||
// the top register, which has negative or zero cost).
|
||||
f := b[1 + u]
|
||||
cc := u64(0)
|
||||
for v in 0..<a_len {
|
||||
z := u64(d[1 + u + v]) + _mul31(f, a[1 + v]) + cc
|
||||
cc = z >> 31
|
||||
d[1 + u + v] = u32(z) & I31_MASK
|
||||
}
|
||||
d[1 + u + a_len] = u32(cc)
|
||||
}
|
||||
}
|
||||
361
core/crypto/_bigint/i62.odin
Normal file
361
core/crypto/_bigint/i62.odin
Normal file
@@ -0,0 +1,361 @@
|
||||
package _bigint
|
||||
|
||||
// Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “AS IS” AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import "base:intrinsics"
|
||||
import "core:math/bits"
|
||||
import subtle "core:crypto/_subtle"
|
||||
import "core:slice"
|
||||
|
||||
@(private="file")
|
||||
I62_MASK :: 0x3fff_ffff_ffff_ffff
|
||||
|
||||
// Compute x*y+v1+v2. Operands are 64-bit, and result is 128-bit, with
|
||||
// high word in "hi" and low word in "lo".
|
||||
@(private="file", require_results)
|
||||
_fma1 :: #force_inline proc "contextless" (x, y, v1, v2: u64) -> (hi, lo: u64) {
|
||||
hi, lo = bits.mul_u64(x, y)
|
||||
|
||||
carry: u64
|
||||
lo, carry = bits.add_u64(lo, v1, 0)
|
||||
hi += carry
|
||||
|
||||
lo, carry = bits.add_u64(lo, v2, 0)
|
||||
hi += carry
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Compute x1*y1+x2*y2+v1+v2. Operands are 64-bit, and result is 128-bit,
|
||||
// with high word in "hi" and low word in "lo".
|
||||
//
|
||||
// Callers should ensure that the two inner products, and the v1 and v2
|
||||
// operands, are multiple of 4 (this is not used by this specific definition
|
||||
// but may help other implementations).
|
||||
@(private="file", require_results)
|
||||
_fma2 :: #force_inline proc "contextless" (x1, y1, x2, y2, v1, v2: u64) -> (hi, lo: u64) {
|
||||
hi_1, lo_1 := bits.mul_u64(x1, y1)
|
||||
hi_2, lo_2 := bits.mul_u64(x2, y2)
|
||||
|
||||
carry: u64
|
||||
lo, carry = bits.add_u64(lo_1, lo_2, 0)
|
||||
hi, _ = bits.add_u64(hi_1, hi_2, carry)
|
||||
|
||||
lo, carry = bits.add_u64(lo, v1, 0)
|
||||
hi += carry
|
||||
|
||||
lo, carry = bits.add_u64(lo, v2, 0)
|
||||
hi += carry
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@(private="file", require_results)
|
||||
_mul62_lo :: #force_inline proc "contextless" (x, y: u64) -> u64 {
|
||||
return (x * y) & I62_MASK
|
||||
}
|
||||
|
||||
// Subtract b from a, and return the final carry. If 'ctl32' is 0, then
|
||||
// a[] is kept unmodified, but the final carry is still computed and
|
||||
// returned.
|
||||
@(private="file", require_results)
|
||||
_i62_sub :: proc "contextless" (a, b: []u64, num: int, ctl32: u32) -> u32 {
|
||||
cc: u64
|
||||
|
||||
ctl := -ctl32
|
||||
mask := u64(ctl) | (u64(ctl) << 32)
|
||||
for u in 0..<num {
|
||||
aw := a[u]
|
||||
bw := b[u]
|
||||
dw := aw - bw - cc
|
||||
cc = dw >> 63
|
||||
dw &= I62_MASK
|
||||
a[u] = aw ~ (mask & (dw ~ aw))
|
||||
}
|
||||
|
||||
return u32(cc)
|
||||
}
|
||||
|
||||
// Montgomery multiplication, over arrays of 62-bit values. The
|
||||
// destination array (d) must be distinct from the other operands
|
||||
// (x, y and m). All arrays are in little-endian format (least
|
||||
// significant word comes first) over 'num' words.
|
||||
@(private="file")
|
||||
_i62_montymul :: proc "contextless" (d, x, y, m: []u64, num: int, m0i: u64) {
|
||||
dh: u64
|
||||
|
||||
num4 := 1 + u64((num - 1) & ~int(3))
|
||||
intrinsics.mem_zero(raw_data(d), num * size_of(u64))
|
||||
for u in 0..<num {
|
||||
xu := x[u] << 2
|
||||
f := _mul62_lo(d[0] + _mul62_lo(x[u], y[0]), m0i) << 2
|
||||
|
||||
hi, lo := _fma2(xu, y[0], f, m[0], d[0] << 2, 0)
|
||||
r := hi
|
||||
|
||||
v: int
|
||||
for v = 1; v < int(num4); v += 4 {
|
||||
hi, lo = _fma2(xu, y[v + 0], f, m[v + 0], d[v + 0] << 2, r << 2)
|
||||
r = hi + (r >> 62)
|
||||
d[v - 1] = lo >> 2
|
||||
hi, lo = _fma2(xu, y[v + 1], f, m[v + 1], d[v + 1] << 2, r << 2)
|
||||
r = hi + (r >> 62)
|
||||
d[v + 0] = lo >> 2
|
||||
hi, lo = _fma2(xu, y[v + 2], f, m[v + 2], d[v + 2] << 2, r << 2)
|
||||
r = hi + (r >> 62)
|
||||
d[v + 1] = lo >> 2
|
||||
hi, lo = _fma2(xu, y[v + 3], f, m[v + 3], d[v + 3] << 2, r << 2)
|
||||
r = hi + (r >> 62)
|
||||
d[v + 2] = lo >> 2
|
||||
}
|
||||
for ; v < num; v += 1 {
|
||||
hi, lo = _fma2(xu, y[v], f, m[v], d[v] << 2, r << 2)
|
||||
r = hi + (r >> 62)
|
||||
d[v - 1] = lo >> 2
|
||||
}
|
||||
|
||||
zh := dh + r
|
||||
d[num - 1] = zh & I62_MASK
|
||||
dh = zh >> 62
|
||||
}
|
||||
_ = _i62_sub(d, m, num, u32(dh) | subtle.not(_i62_sub(d, m, num, 0)))
|
||||
}
|
||||
|
||||
// Conversion back from Montgomery representation.
|
||||
@(private="file")
|
||||
_i62_frommonty :: proc "contextless" (x, m: []u64, num: int, m0i: u64) {
|
||||
for _ in 0..<num {
|
||||
cc: u64
|
||||
f := _mul62_lo(x[0], m0i) << 2
|
||||
for v in 0..<num {
|
||||
hi, lo := _fma1(f, m[v], x[v] << 2, cc)
|
||||
cc = hi << 2
|
||||
if (v != 0) {
|
||||
x[v - 1] = lo >> 2
|
||||
}
|
||||
}
|
||||
x[num - 1] = cc >> 2
|
||||
}
|
||||
_ = _i62_sub(x, m, num, subtle.not(_i62_sub(x, m, num, 0)))
|
||||
}
|
||||
|
||||
// Variant of i31_modpow_opt() that internally uses 64x64->128
|
||||
// multiplications. It expects the same parameters as i31_modpow_opt(),
|
||||
// except that the temporaries should be 64-bit integers, not 32-bit
|
||||
// integers.
|
||||
i62_modpow_opt :: proc "contextless" (x31: []u32, e: []byte, m31: []u32, m0i31: u32, tmp: []u64) -> u32 {
|
||||
twlen := len(tmp)
|
||||
|
||||
// Get modulus size, in words.
|
||||
mw31num := int((m31[0] + 31) >> 5)
|
||||
mw62num := int((mw31num + 1) >> 1)
|
||||
|
||||
// In order to apply this function, we must have enough room to
|
||||
// copy the operand and modulus into the temporary array, along
|
||||
// with at least two temporaries. If there is not enough room,
|
||||
// switch to br_i31_modpow(). We also use br_i31_modpow() if the
|
||||
// modulus length is not at least four words (94 bits or more).
|
||||
if mw31num < 4 || mw62num << 2 > twlen {
|
||||
// We assume here that we can split an aligned uint64_t
|
||||
// into two properly aligned uint32_t. Since both types
|
||||
// are supposed to have an exact width with no padding,
|
||||
// then this property must hold.
|
||||
|
||||
txlen := mw31num + 1
|
||||
if twlen < txlen {
|
||||
return 0
|
||||
}
|
||||
|
||||
tmp_as_u32s := slice.reinterpret([]u32, tmp)
|
||||
t1, t2 := tmp_as_u32s[:txlen], tmp_as_u32s[txlen:]
|
||||
|
||||
i31_modpow(x31, e, m31, m0i31, t1, t2)
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
// Convert x to Montgomery representation: this means that
|
||||
// we replace x with x*2^z mod m, where z is the smallest multiple
|
||||
// of the word size such that 2^z >= m. We want to reuse the 31-bit
|
||||
// functions here (for constant-time operation), but we need z
|
||||
// for a 62-bit word size.
|
||||
for _ in 0..<mw62num {
|
||||
i31_muladd_small(x31, 0, m31)
|
||||
i31_muladd_small(x31, 0, m31)
|
||||
}
|
||||
|
||||
// Assemble operands into arrays of 62-bit words. Note that
|
||||
// all the arrays of 62-bit words that we will handle here
|
||||
// are without any leading size word.
|
||||
//
|
||||
// We also adjust tmp and twlen to account for the words used
|
||||
// for these extra arrays.
|
||||
m := tmp[:mw62num]
|
||||
x := tmp[mw62num:mw62num*2]
|
||||
tmp_ := tmp[mw62num << 1:]
|
||||
twlen -= mw62num << 1
|
||||
for u := 0; u < mw31num; u += 2 {
|
||||
v := u >> 1
|
||||
if u + 1 == mw31num {
|
||||
m[v] = u64(m31[u + 1])
|
||||
x[v] = u64(x31[u + 1])
|
||||
} else {
|
||||
m[v] = u64(m31[u + 1]) + (u64(m31[u + 2]) << 31)
|
||||
x[v] = u64(x31[u + 1]) + (u64(x31[u + 2]) << 31)
|
||||
}
|
||||
}
|
||||
|
||||
// Compute window size. We support windows up to 5 bits; for a
|
||||
// window of size k bits, we need 2^k+1 temporaries (for k = 1,
|
||||
// we use special code that uses only 2 temporaries).
|
||||
win_len: int
|
||||
for win_len = 5; win_len > 1; win_len -= 1 {
|
||||
if (1 << uint(win_len) + 1) * mw62num <= twlen {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
t1 := tmp_[:mw62num]
|
||||
t2 := tmp_[mw62num:]
|
||||
|
||||
// Compute m0i, which is equal to -(1/m0) mod 2^62. We were
|
||||
// provided with m0i31, which already fulfills this property
|
||||
// modulo 2^31; the single expression below is then sufficient.
|
||||
m0i := u64(m0i31)
|
||||
m0i = _mul62_lo(m0i, 2 + _mul62_lo(m0i, m[0]))
|
||||
|
||||
// Compute window contents. If the window has size one bit only,
|
||||
// then t2 is set to x; otherwise, t2[0] is left untouched, and
|
||||
// t2[k] is set to x^k (for k >= 1).
|
||||
if win_len == 1 {
|
||||
copy(t2, x)
|
||||
} else {
|
||||
copy(t2[mw62num:], x)
|
||||
|
||||
base := t2[mw62num:]
|
||||
for u := 2; u < 1 << uint(win_len); u += 1 {
|
||||
_i62_montymul(base[mw62num:], base, x, m, mw62num, m0i)
|
||||
base = base[mw62num:]
|
||||
}
|
||||
}
|
||||
|
||||
// Set x to 1, in Montgomery representation. We again use the
|
||||
// 31-bit code.
|
||||
i31_zero(x31, m31[0])
|
||||
x31[(m31[0] + 31) >> 5] = 1
|
||||
i31_muladd_small(x31, 0, m31)
|
||||
if mw31num & 1 != 0 {
|
||||
i31_muladd_small(x31, 0, m31)
|
||||
}
|
||||
for u := 0; u < mw31num; u+= 2 {
|
||||
v := u >> 1
|
||||
if u + 1 == mw31num {
|
||||
x[v] = u64(x31[u + 1])
|
||||
} else {
|
||||
x[v] = u64(x31[u + 1]) + (u64(x31[u + 2]) << 31)
|
||||
}
|
||||
}
|
||||
|
||||
e_, e_len := e, len(e)
|
||||
// We process bits from most to least significant. At each
|
||||
// loop iteration, we have acc_len bits in acc.
|
||||
acc: u32
|
||||
acc_len: uint
|
||||
for acc_len > 0 || e_len > 0 {
|
||||
// Get the next bits.
|
||||
k := uint(win_len)
|
||||
if acc_len < uint(win_len) {
|
||||
if e_len > 0 {
|
||||
acc = (acc << 8) | u32(e_[0])
|
||||
e_ = e_[1:]
|
||||
e_len -= 1
|
||||
acc_len += 8
|
||||
} else {
|
||||
k = acc_len
|
||||
}
|
||||
}
|
||||
bits := (acc >> (acc_len - k)) & ((u32(1) << k) - 1)
|
||||
acc_len -= k
|
||||
|
||||
// We could get exactly k bits. Compute k squarings.
|
||||
for _ in 0..<k {
|
||||
_i62_montymul(t1, x, x, m, mw62num, m0i)
|
||||
copy(x, t1)
|
||||
}
|
||||
|
||||
// Window lookup: we want to set t2 to the window
|
||||
// lookup value, assuming the bits are non-zero. If
|
||||
// the window length is 1 bit only, then t2 is
|
||||
// already set; otherwise, we do a constant-time lookup.
|
||||
if win_len > 1 {
|
||||
intrinsics.mem_zero(raw_data(t2), mw62num * size_of(u64))
|
||||
|
||||
base := t2[mw62num:]
|
||||
for u := u32(1); u < u32(1) << k; u += 1 {
|
||||
mask := -u64(subtle.eq(u, bits))
|
||||
for v in 0..<mw62num {
|
||||
t2[v] |= mask & base[v]
|
||||
}
|
||||
base = base[mw62num:]
|
||||
}
|
||||
}
|
||||
|
||||
// Multiply with the looked-up value. We keep the product
|
||||
// only if the exponent bits are not all-zero.
|
||||
_i62_montymul(t1, x, t2, m, mw62num, m0i)
|
||||
mask1 := -u64(subtle.eq(bits, 0))
|
||||
mask2 := ~mask1
|
||||
for u in 0..<mw62num {
|
||||
x[u] = (mask1 & x[u]) | (mask2 & t1[u])
|
||||
}
|
||||
}
|
||||
|
||||
// Convert back from Montgomery representation.
|
||||
_i62_frommonty(x, m, mw62num, m0i)
|
||||
|
||||
// Convert result into 31-bit words.
|
||||
for u := 0; u < mw31num; u += 2 {
|
||||
zw := u64(x[u >> 1])
|
||||
x31[u + 1] = u32(zw) & I31_MASK
|
||||
if u + 1 < mw31num {
|
||||
x31[u + 2] = u32(zw >> 31)
|
||||
}
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
// Wrapper for i62_modpow_opt() that uses the same type as
|
||||
// i31_modpow_opt(); however, it requires its 'tmp' argument to the
|
||||
// 64-bit aligned.
|
||||
i62_modpow_opt_as_i31 :: proc "contextless" (x31: []u32, e: []byte, m31: []u32, m0i31: u32, tmp: []u32) -> u32 {
|
||||
// As documented, this function expects the 'tmp' argument to be
|
||||
// 64-bit aligned. This is OK since this function is internal (it
|
||||
// is not part of BearSSL's public API).
|
||||
ensure_contextless(uintptr(raw_data(tmp)) & 7 == 0)
|
||||
ensure_contextless(len(tmp) & 1 == 0) // Length MUST be even.
|
||||
|
||||
tmp_as_u64s := slice.reinterpret([]u64, tmp)
|
||||
|
||||
return i62_modpow_opt(x31, e, m31, m0i31, tmp_as_u64s)
|
||||
}
|
||||
265
core/crypto/_bigint/i62_primes.odin
Normal file
265
core/crypto/_bigint/i62_primes.odin
Normal file
@@ -0,0 +1,265 @@
|
||||
package _bigint
|
||||
|
||||
// Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “AS IS” AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import subtle "core:crypto/_subtle"
|
||||
import "core:math/big"
|
||||
import "core:slice"
|
||||
|
||||
// Perform trial divisions on a candidate prime. We opt for the simple
|
||||
// route and "just" compute a series of trial divisions.
|
||||
//
|
||||
// Returned value is 1 on success (none of the small primes
|
||||
// divides x), 0 on error (a non-trivial GCD is obtained).
|
||||
@(private="file", require_results)
|
||||
trial_divisions :: proc "contextless" (x: []u32) -> u32 {
|
||||
for factor in big._private_prime_table {
|
||||
if factor <= 11 {
|
||||
continue
|
||||
}
|
||||
if i31_rem(x, u32(factor)) == 0 {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
// Perform n rounds of Miller-Rabin on the candidate prime x. This
|
||||
// function assumes that x = 3 mod 4.
|
||||
//
|
||||
// WARNING: t MUST be 64-bit aligned, and be large enough such that
|
||||
// it can hold 4 encoded integers that have the same number of limbs
|
||||
// as x.
|
||||
//
|
||||
// Returned value is 1 on success (all rounds completed successfully),
|
||||
// 0 otherwise.
|
||||
@(private="file", require_results)
|
||||
i62_miller_rabin :: proc(x: []u32, n: int, t: []u32) -> u32 {
|
||||
// Since x = 3 mod 4, the Miller-Rabin test is simple:
|
||||
// - get a random base a (such that 1 < a < x-1)
|
||||
// - compute z = a^((x-1)/2) mod x
|
||||
// - if z != 1 and z != x-1, the number x is composite
|
||||
//
|
||||
// We generate bases 'a' randomly with a size which is
|
||||
// one bit less than x, which ensures that a < x-1. It
|
||||
// is not useful to verify that a > 1 because the probability
|
||||
// that we get a value a equal to 0 or 1 is much smaller
|
||||
// than the probability of our Miller-Rabin tests not to
|
||||
// detect a composite, which is already quite smaller than the
|
||||
// probability of the hardware misbehaving and return a
|
||||
// composite integer because of some glitch (e.g. bad RAM
|
||||
// or ill-timed cosmic ray).
|
||||
|
||||
// Compute (x-1)/2 (encoded).
|
||||
xm1d2 := slice.reinterpret([]byte, t)
|
||||
xm1d2_len := ((x[0] - (x[0] >> 5)) + 7) >> 3
|
||||
i31_encode(xm1d2[:xm1d2_len], x)
|
||||
cc: u32
|
||||
for u in 0..<xm1d2_len {
|
||||
w := u32(xm1d2[u])
|
||||
xm1d2[u] = byte((w >> 1) | cc)
|
||||
cc = w << 7
|
||||
}
|
||||
|
||||
// We used some words of the provided buffer for (x-1)/2.
|
||||
xm1d2_len_u32 := (xm1d2_len + 3) >> 2
|
||||
t_ := t[xm1d2_len_u32:]
|
||||
tlen := len(t_)
|
||||
|
||||
xlen := (x[0] + 31) >> 5
|
||||
asize := x[0] - 1 - subtle.eq0(x[0] & 31)
|
||||
x0i := i31_ninv31(x[1])
|
||||
for _ in 0..<n {
|
||||
// Generate a random base. We don't need the base to be
|
||||
// really uniform modulo x, so we just get a random
|
||||
// number which is one bit shorter than x.
|
||||
a := t_
|
||||
a[0] = x[0]
|
||||
a[xlen] = 0
|
||||
i31_mkrand(a, asize)
|
||||
|
||||
// Compute a^((x-1)/2) mod x. We assume here that the
|
||||
// function will not fail (the temporary array is large
|
||||
// enough).
|
||||
t2 := t_[1 + xlen:]
|
||||
t2len := tlen - 1 - int(xlen)
|
||||
if (t2len & 1) != 0 {
|
||||
// Since the source array is 64-bit aligned and
|
||||
// has an even number of elements (TEMPS), we
|
||||
// can use the parity of the remaining length to
|
||||
// detect and adjust alignment.
|
||||
t2 = t2[1:]
|
||||
t2len -= 1
|
||||
}
|
||||
i62_modpow_opt_as_i31(a, xm1d2[:xm1d2_len], x, x0i, t2[:t2len])
|
||||
|
||||
// We must obtain either 1 or x-1. Note that x is odd,
|
||||
// hence x-1 differs from x only in its low word (no
|
||||
// carry).
|
||||
eq1 := a[1] ~ 1
|
||||
eqm1 := a[1] ~ (x[1] - 1)
|
||||
for u in 2..=xlen {
|
||||
eq1 |= a[u]
|
||||
eqm1 |= a[u] ~ x[u]
|
||||
}
|
||||
|
||||
if ((subtle.eq0(eq1) | subtle.eq0(eqm1)) == 0) {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
// Create a random prime of the provided size. 'esize' is the _encoded_
|
||||
// bit length. The two top bits and the two bottom bits are set to 1.
|
||||
i62_mkprime :: proc(x: []u32, esize: u32, pubexp: u32, t: []u32) {
|
||||
x[0] = esize
|
||||
_len := (esize + 31) >> 5
|
||||
|
||||
for {
|
||||
// Generate random bits. We force the two top bits and the
|
||||
// two bottom bits to 1.
|
||||
i31_mkrand(x, esize)
|
||||
if (esize & 31) == 0 {
|
||||
x[_len] |= 0x60000000
|
||||
} else if (esize & 31) == 1 {
|
||||
x[_len] |= 0x00000001
|
||||
x[_len - 1] |= 0x40000000
|
||||
} else {
|
||||
x[_len] |= 0x00000003 << ((esize & 31) - 2)
|
||||
}
|
||||
x[1] |= 0x00000003
|
||||
|
||||
// Trial division with low primes (3, 5, 7 and 11). We
|
||||
// use the following properties:
|
||||
//
|
||||
// 2^2 = 1 mod 3
|
||||
// 2^4 = 1 mod 5
|
||||
// 2^3 = 1 mod 7
|
||||
// 2^10 = 1 mod 11
|
||||
m3, m5, m7, m11: u32
|
||||
s7, s11: uint
|
||||
for u in 0..<_len {
|
||||
w := x[1 + u]
|
||||
w3 := (w & 0xFFFF) + (w >> 16) // max: 98302
|
||||
w5 := (w & 0xFFFF) + (w >> 16) // max: 98302
|
||||
w7 := (w & 0x7FFF) + (w >> 15) // max: 98302
|
||||
w11 := (w & 0xFFFFF) + (w >> 20) // max: 1050622
|
||||
|
||||
m3 += w3 << (u & 1)
|
||||
m3 = (m3 & 0xFF) + (m3 >> 8) // max: 1025
|
||||
|
||||
m5 += w5 << ((4 - u) & 3)
|
||||
m5 = (m5 & 0xFFF) + (m5 >> 12) // max: 4479
|
||||
|
||||
m7 += w7 << s7
|
||||
m7 = (m7 & 0x1FF) + (m7 >> 9) // max: 1280
|
||||
s7 += 1
|
||||
if s7 == 3 {
|
||||
s7 = 0
|
||||
}
|
||||
|
||||
m11 += w11 << s11
|
||||
s11 += 1
|
||||
if s11 == 10 {
|
||||
s11 = 0
|
||||
}
|
||||
m11 = (m11 & 0x3FF) + (m11 >> 10) // max: 526847
|
||||
}
|
||||
|
||||
m3 = (m3 & 0x3F) + (m3 >> 6) // max: 78
|
||||
m3 = (m3 & 0x0F) + (m3 >> 4) // max: 18
|
||||
m3 = ((m3 * 43) >> 5) & 3
|
||||
|
||||
m5 = (m5 & 0xFF) + (m5 >> 8) // max: 271
|
||||
m5 = (m5 & 0x0F) + (m5 >> 4) // max: 31
|
||||
m5 -= 20 & -subtle.gt(m5, 19)
|
||||
m5 -= 10 & -subtle.gt(m5, 9)
|
||||
m5 -= 5 & -subtle.gt(m5, 4)
|
||||
|
||||
m7 = (m7 & 0x3F) + (m7 >> 6) // max: 82
|
||||
m7 = (m7 & 0x07) + (m7 >> 3) // max: 16
|
||||
m7 = ((m7 * 147) >> 7) & 7
|
||||
|
||||
// 2^5 = 32 = -1 mod 11.
|
||||
m11 = (m11 & 0x3FF) + (m11 >> 10) // max: 1536
|
||||
m11 = (m11 & 0x3FF) + (m11 >> 10) // max: 1023
|
||||
m11 = (m11 & 0x1F) + 33 - (m11 >> 5) // max: 64
|
||||
m11 -= 44 & -subtle.gt(m11, 43)
|
||||
m11 -= 22 & -subtle.gt(m11, 21)
|
||||
m11 -= 11 & -subtle.gt(m11, 10)
|
||||
|
||||
// If any of these modulo is 0, then the candidate is
|
||||
// not prime. Also, if pubexp is 3, 5, 7 or 11, and the
|
||||
// corresponding modulus is 1, then the candidate must
|
||||
// be rejected, because we need e to be invertible
|
||||
// modulo p-1. We can use simple comparisons here
|
||||
// because they won't leak information on a candidate
|
||||
// that we keep, only on one that we reject (and is thus
|
||||
// not secret).
|
||||
if m3 == 0 || m5 == 0 || m7 == 0 || m11 == 0 {
|
||||
continue
|
||||
}
|
||||
if (pubexp == 3 && m3 == 1) || (pubexp == 5 && m5 == 1) || (pubexp == 7 && m7 == 1) || (pubexp == 11 && m11 == 1) {
|
||||
continue
|
||||
}
|
||||
|
||||
// More trial divisions.
|
||||
if trial_divisions(x) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Miller-Rabin algorithm. Since we selected a random
|
||||
// integer, not a maliciously crafted integer, we can use
|
||||
// relatively few rounds to lower the risk of a false
|
||||
// positive (i.e. declaring prime a non-prime) under
|
||||
// 2^(-80). It is not useful to lower the probability much
|
||||
// below that, since that would be substantially below
|
||||
// the probability of the hardware misbehaving. Sufficient
|
||||
// numbers of rounds are extracted from the Handbook of
|
||||
// Applied Cryptography, note 4.49 (page 149).
|
||||
//
|
||||
// Since we work on the encoded size (esize), we need to
|
||||
// compare with encoded thresholds.
|
||||
rounds: int
|
||||
switch {
|
||||
case esize < 309:
|
||||
rounds = 12
|
||||
case esize < 464:
|
||||
rounds = 9
|
||||
case esize < 670:
|
||||
rounds = 6
|
||||
case esize < 877:
|
||||
rounds = 4
|
||||
case esize < 1341:
|
||||
rounds = 3
|
||||
case:
|
||||
rounds = 2
|
||||
}
|
||||
|
||||
if i62_miller_rabin(x, rounds, t) == 1 {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,7 @@ fe_equal :: proc "contextless" (arg1, arg2: ^Montgomery_Domain_Field_Element) ->
|
||||
|
||||
// This will only underflow if and only if (⟺) arg1 == arg2, and we return the borrow,
|
||||
// which will be 1.
|
||||
is_eq := subtle.u64_is_zero(fe_non_zero(&tmp))
|
||||
is_eq := subtle.eq0(fe_non_zero(&tmp))
|
||||
|
||||
fe_clear(&tmp)
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ fe_equal :: proc "contextless" (arg1, arg2: ^Montgomery_Domain_Field_Element) ->
|
||||
|
||||
// This will only underflow if and only if (⟺) arg1 == arg2, and we return the borrow,
|
||||
// which will be 1.
|
||||
is_eq := subtle.u64_is_zero(fe_non_zero(&tmp))
|
||||
is_eq := subtle.eq0(fe_non_zero(&tmp))
|
||||
|
||||
fe_clear(&tmp)
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ fe_from_bytes :: proc "contextless" (
|
||||
reduced[3], borrow = bits.sub_u64(tmp[3], ELL[3], borrow)
|
||||
reduced[4], borrow = bits.sub_u64(tmp[4], ELL[4], borrow)
|
||||
reduced[5], borrow = bits.sub_u64(tmp[5], ELL[5], borrow)
|
||||
need_reduced := subtle.u64_is_zero(borrow)
|
||||
need_reduced := subtle.eq0(borrow)
|
||||
|
||||
fe_cond_select(&tmp, &tmp, &reduced, int(need_reduced))
|
||||
fe_to_montgomery(out1, &tmp)
|
||||
|
||||
@@ -130,7 +130,7 @@ poly_frommsg :: proc "contextless" (r: ^Poly, msg: []byte) #no_bounds_check {
|
||||
|
||||
for i in 0..<N/8 {
|
||||
for j in 0..<8 {
|
||||
r.coeffs[8*i+j] = subtle.csel_i16(0, (Q+1)/2, int(msg[i] >> uint(j))&1)
|
||||
r.coeffs[8*i+j] = subtle.csel_i16(0, (Q+1)/2, (msg[i] >> uint(j))&1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,76 +3,245 @@ Various useful bit operations in constant time.
|
||||
*/
|
||||
package _subtle
|
||||
|
||||
import "core:crypto/_fiat"
|
||||
import "core:math/bits"
|
||||
import "base:intrinsics"
|
||||
|
||||
// byte_eq returns 1 if and only if (⟺) a == b, 0 otherwise.
|
||||
@(optimization_mode="none")
|
||||
byte_eq :: proc "contextless" (a, b: byte) -> int {
|
||||
// Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “AS IS” AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Constant-time primitives. These functions manipulate integer values in
|
||||
// order to provide constant-time comparisons and multiplexers.
|
||||
//
|
||||
// Boolean values (the "ctl" bits) MUST have value 0 or 1.
|
||||
//
|
||||
// Implementation notes:
|
||||
// =====================
|
||||
//
|
||||
// The uintN_t types are unsigned and with width exactly N bits; the C
|
||||
// standard guarantees that computations are performed modulo 2^N, and
|
||||
// there can be no overflow. Negation (unary '-') works on unsigned types
|
||||
// as well.
|
||||
//
|
||||
// The intN_t types are guaranteed to have width exactly N bits, with no
|
||||
// padding bit, and using two's complement representation. Casting
|
||||
// intN_t to uintN_t really is conversion modulo 2^N. Beware that intN_t
|
||||
// types, being signed, trigger implementation-defined behaviour on
|
||||
// overflow (including raising some signal): with GCC, while modular
|
||||
// arithmetics are usually applied, the optimizer may assume that
|
||||
// overflows don't occur (unless the -fwrapv command-line option is
|
||||
// added); Clang has the additional -ftrapv option to explicitly trap on
|
||||
// integer overflow or underflow.
|
||||
|
||||
// This code only works on a two's complement system.
|
||||
#assert((-1 & 3) == 3)
|
||||
|
||||
// not negates a boolean which MUST be `0` or `1`
|
||||
@(optimization_mode="none", require_results)
|
||||
not :: proc "contextless" (ctrl: $T) -> T where intrinsics.type_is_unsigned(T) {
|
||||
return ctrl ~ 1
|
||||
}
|
||||
|
||||
@(optimization_mode="none", require_results)
|
||||
byte_eq :: proc "contextless" (a, b: byte) -> byte {
|
||||
v := a ~ b
|
||||
|
||||
// v == 0 if and only if (⟺) a == b. The subtraction will underflow, setting the
|
||||
// sign bit, which will get returned.
|
||||
return int((u32(v)-1) >> 31)
|
||||
return byte((u32(v)-1) >> 31)
|
||||
}
|
||||
|
||||
// u64_eq returns 1 if and only if (⟺) a == b, 0 otherwise.
|
||||
@(optimization_mode="none")
|
||||
@(optimization_mode="none", require_results)
|
||||
u32_eq :: proc "contextless" (a, b: u32) -> u32 {
|
||||
q := a ~ b
|
||||
return ((q | -q) >> 31) ~ 1
|
||||
}
|
||||
|
||||
@(optimization_mode="none", require_results)
|
||||
u64_eq :: proc "contextless" (a, b: u64) -> u64 {
|
||||
_, borrow := bits.sub_u64(0, a ~ b, 0)
|
||||
return (~borrow) & 1
|
||||
q := a ~ b
|
||||
return ((q | -q) >> 63) ~ 1
|
||||
}
|
||||
|
||||
// eq returns 1 if and only if (⟺) a == b, 0 otherwise.
|
||||
eq :: proc {
|
||||
byte_eq,
|
||||
u32_eq,
|
||||
u64_eq,
|
||||
}
|
||||
|
||||
// u64_is_zero returns 1 if and only if (⟺) a == 0, 0 otherwise.
|
||||
@(optimization_mode="none")
|
||||
u64_is_zero :: proc "contextless" (a: u64) -> u64 {
|
||||
_, borrow := bits.sub_u64(a, 1, 0)
|
||||
return borrow
|
||||
@(require_results)
|
||||
byte_neq :: proc "contextless" (a, b: byte) -> byte {
|
||||
return #force_inline byte_eq(a, b) ~ 1
|
||||
}
|
||||
|
||||
// u64_is_non_zero returns 1 if and only if (⟺) a != 0, 0 otherwise.
|
||||
@(optimization_mode="none")
|
||||
u64_is_non_zero :: proc "contextless" (a: u64) -> u64 {
|
||||
is_zero := u64_is_zero(a)
|
||||
return (~is_zero) & 1
|
||||
@(optimization_mode="none", require_results)
|
||||
u32_neq :: proc "contextless" (a, b: u32) -> u32 {
|
||||
q := a ~ b
|
||||
return (q | -q) >> 31
|
||||
}
|
||||
|
||||
@(optimization_mode="none")
|
||||
cmov_bytes :: proc "contextless" (dst, src: []byte, ctrl: int) {
|
||||
@(optimization_mode="none", require_results)
|
||||
u64_neq :: proc "contextless" (a, b: u64) -> u64 {
|
||||
q := a ~ b
|
||||
return (q | -q) >> 63
|
||||
}
|
||||
|
||||
// neq returns 1 if and only if (⟺) a != b, 0 otherwise.
|
||||
neq :: proc {
|
||||
byte_neq,
|
||||
u32_neq,
|
||||
u64_neq,
|
||||
}
|
||||
|
||||
@(optimization_mode="none", require_results)
|
||||
u32_gt :: proc "contextless" (x, y: u32) -> u32 {
|
||||
/*
|
||||
* If both x < 2^31 and y < 2^31, then y-x will have its high
|
||||
* bit set if x > y, cleared otherwise.
|
||||
*
|
||||
* If either x >= 2^31 or y >= 2^31 (but not both), then the
|
||||
* result is the high bit of x.
|
||||
*
|
||||
* If both x >= 2^31 and y >= 2^31, then we can virtually
|
||||
* subtract 2^31 from both, and we are back to the first case.
|
||||
* Since (y-2^31)-(x-2^31) = y-x, the subtraction is already
|
||||
* fine.
|
||||
*/
|
||||
z := y - x
|
||||
return (z ~ ((x ~ y) & (x ~ z))) >> 31
|
||||
}
|
||||
|
||||
@(optimization_mode="none", require_results)
|
||||
u64_gt :: proc "contextless" (x, y: u64) -> u64 {
|
||||
z := y - x
|
||||
return (z ~ ((x ~ y) & (x ~ z))) >> 63
|
||||
}
|
||||
|
||||
// gt returns 1 if x > y, 0 otherwise.
|
||||
gt :: proc {
|
||||
u32_gt,
|
||||
u64_gt,
|
||||
}
|
||||
|
||||
// gt returns 1 if x >= y, 0 otherwise.
|
||||
@(require_results)
|
||||
ge :: proc "contextless" (x, y: $T) -> T where T == u32 || T == u64 {
|
||||
return #force_inline(gt(y, x)) ~ 1
|
||||
}
|
||||
|
||||
// lt returns 1 if x < y, 0 otherwise.
|
||||
@(require_results)
|
||||
lt :: proc "contextless" (x, y: $T) -> T where T == u32 || T == u64 {
|
||||
return #force_inline(gt(y, x))
|
||||
}
|
||||
|
||||
// le returns 1 if x <= y, 0 otherwise.
|
||||
@(require_results)
|
||||
le :: proc "contextless" (x, y: $T) -> T where T == u32 || T == u64 {
|
||||
return #force_inline(gt(x, y)) ~ 1
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
u32_cmp :: proc "contextless" (x, y: u32) -> i32 {
|
||||
return i32(#force_inline gt(x, y)) | -i32(#force_inline gt(y, x))
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
u64_cmp :: proc "contextless" (x, y: u64) -> i64 {
|
||||
return i64(#force_inline gt(x, y)) | -i64(#force_inline gt(y, x))
|
||||
}
|
||||
|
||||
// cmp returns -1, 0, or 1, depending on wheter x is lower than, equal
|
||||
// to, or greater than y.
|
||||
cmp :: proc {
|
||||
u32_cmp,
|
||||
u64_cmp,
|
||||
}
|
||||
|
||||
// eq0 returns 1 if and only if (⟺) a == 0, 0 otherwise.
|
||||
@(require_results)
|
||||
eq0 :: proc "contextless" (a: $T) -> T where T == u32 || T == u64 {
|
||||
return #force_inline eq(a, 0)
|
||||
}
|
||||
|
||||
// neq0 returns 1 if and only if (⟺) a != 0, 0 otherwise.
|
||||
@(require_results)
|
||||
neq0 :: proc "contextless" (a: $T) -> T where T == u32 || T == u64 {
|
||||
return #force_inline eq(a, 0) ~ 1
|
||||
}
|
||||
|
||||
cmov_bytes :: proc "contextless" (dst, src: []byte, #any_int ctrl: int) {
|
||||
ensure_contextless(len(src) == len(dst), "crypto: cmov length mismatch")
|
||||
|
||||
cmov_impl(dst, src, ctrl)
|
||||
}
|
||||
|
||||
cmov_u32s :: proc "contextless" (dst, src: []u32, #any_int ctrl: int) {
|
||||
ensure_contextless(len(src) == len(dst), "crypto: cmov length mismatch")
|
||||
|
||||
cmov_impl(dst, src, ctrl)
|
||||
}
|
||||
|
||||
@(private="file", optimization_mode="none")
|
||||
cmov_impl :: proc "contextless"(dst, src: []$T, ctrl: int) {
|
||||
s_len := len(src)
|
||||
ensure_contextless(s_len == len(dst), "crypto: cmov length mismatch")
|
||||
|
||||
c := -(byte)(ctrl)
|
||||
c := -(T)(ctrl)
|
||||
for i in 0..<s_len {
|
||||
dst[i] ~= c & (dst[i] ~ src[i])
|
||||
}
|
||||
}
|
||||
|
||||
@(optimization_mode="none")
|
||||
csel_i16 :: proc "contextless" (a, b: i16, ctrl: int) -> i16 {
|
||||
c := -(u16)(ctrl)
|
||||
// cmov copies `src` into `dst` if and only if (⟺) ctrl == 1. `dst` and
|
||||
// `src` may overlap completely (but not partially).
|
||||
cmov :: proc {
|
||||
cmov_bytes,
|
||||
cmov_u32s,
|
||||
}
|
||||
|
||||
@(optimization_mode="none", require_results)
|
||||
csel_i16 :: proc "contextless" (a, b: i16, #any_int ctrl: u16) -> i16 {
|
||||
c := -ctrl
|
||||
return a ~ i16(c & u16(a ~ b))
|
||||
}
|
||||
|
||||
@(optimization_mode="none")
|
||||
csel_u16 :: proc "contextless" (a, b: u16, ctrl: int) -> u16 {
|
||||
c := -(u16)(ctrl)
|
||||
@(optimization_mode="none", require_results)
|
||||
csel_u16 :: proc "contextless" (a, b: u16, #any_int ctrl: u16) -> u16 {
|
||||
c := -ctrl
|
||||
return a ~ (c & (a ~ b))
|
||||
}
|
||||
|
||||
csel_u32 :: proc "contextless" (a, b: u32, ctrl: int) -> u32 {
|
||||
return _fiat.cmovznz_u32(_fiat.u1(ctrl), a, b)
|
||||
@(optimization_mode="none", require_results)
|
||||
csel_u32 :: proc "contextless" (a, b: u32, #any_int ctrl: u32) -> u32 {
|
||||
c := -ctrl
|
||||
return a ~ (c & (a ~ b))
|
||||
}
|
||||
|
||||
csel_u64 :: proc "contextless" (a, b: u64, ctrl: int) -> u64 {
|
||||
return _fiat.cmovznz_u64(_fiat.u1(ctrl), a, b)
|
||||
@(optimization_mode="none", require_results)
|
||||
csel_u64 :: proc "contextless" (a, b: u64, #any_int ctrl: u64) -> u64 {
|
||||
c := -ctrl
|
||||
return a ~ (c & (a ~ b))
|
||||
}
|
||||
|
||||
// csel returns `a` if ctl == `0`, `b` if ctl == `1`.
|
||||
csel :: proc {
|
||||
csel_i16,
|
||||
csel_u16,
|
||||
|
||||
@@ -196,10 +196,10 @@ fe_gen_y_p384r1 :: proc "contextless" (fe: ^Field_Element_p384r1) {
|
||||
|
||||
@(require_results)
|
||||
fe_is_zero_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) -> int {
|
||||
return int(subtle.u64_is_zero(p256r1.fe_non_zero(fe)))
|
||||
return int(subtle.eq0(p256r1.fe_non_zero(fe)))
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
fe_is_zero_p384r1 :: proc "contextless" (fe: ^Field_Element_p384r1) -> int {
|
||||
return int(subtle.u64_is_zero(p384r1.fe_non_zero(fe)))
|
||||
return int(subtle.eq0(p384r1.fe_non_zero(fe)))
|
||||
}
|
||||
|
||||
@@ -133,10 +133,10 @@ sc_is_zero :: proc {
|
||||
|
||||
@(require_results)
|
||||
sc_is_zero_p256r1 :: proc "contextless" (fe: ^Scalar_p256r1) -> int {
|
||||
return int(subtle.u64_is_zero(p256r1.fe_non_zero(fe)))
|
||||
return int(subtle.eq0(p256r1.fe_non_zero(fe)))
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
sc_is_zero_p384r1 :: proc "contextless" (fe: ^Scalar_p384r1) -> int {
|
||||
return int(subtle.u64_is_zero(p384r1.fe_non_zero(fe)))
|
||||
return int(subtle.eq0(p384r1.fe_non_zero(fe)))
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ when crypto.COMPACT_IMPLS == false {
|
||||
// conditionally select the right result.
|
||||
pt_add_mixed(tmp, point, &tmp.x, &tmp.y)
|
||||
|
||||
ctrl := subtle.u64_is_non_zero(idx)
|
||||
ctrl := subtle.neq0(idx)
|
||||
pt_cond_select(point, point, tmp, int(ctrl))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ compare_byte_ptrs_constant_time :: proc "contextless" (a, b: ^byte, n: int) -> i
|
||||
|
||||
// After the loop, v == 0 if and only if (⟺) a == b. The subtraction will underflow
|
||||
// if and only if (⟺) v == 0, setting the sign-bit, which gets returned.
|
||||
return subtle.eq(0, v)
|
||||
return int(subtle.eq(0, v))
|
||||
}
|
||||
|
||||
// is_zero_constant_time returns 1 if and only if (⟺) b is all 0s, 0 otherwise.
|
||||
@@ -59,7 +59,7 @@ is_zero_constant_time :: proc "contextless" (b: []byte) -> int {
|
||||
v |= b_
|
||||
}
|
||||
|
||||
return subtle.byte_eq(0, v)
|
||||
return int(subtle.byte_eq(0, v))
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -50,6 +50,7 @@ Public_Key :: struct {
|
||||
// private_key_generate uses the system entropy source to generate a new
|
||||
// Private_Key. This will only fail if and only if (⟺) the system entropy source is
|
||||
// missing or broken.
|
||||
@(require_results)
|
||||
private_key_generate :: proc(priv_key: ^Private_Key) -> bool {
|
||||
private_key_clear(priv_key)
|
||||
|
||||
@@ -61,13 +62,12 @@ private_key_generate :: proc(priv_key: ^Private_Key) -> bool {
|
||||
defer crypto.zero_explicit(&b, size_of(b))
|
||||
|
||||
crypto.rand_bytes(b[:])
|
||||
private_key_set_bytes(priv_key, b[:])
|
||||
|
||||
return true
|
||||
return private_key_set_bytes(priv_key, b[:])
|
||||
}
|
||||
|
||||
// private_key_set_bytes decodes a byte-encoded private key, and returns
|
||||
// true if and only if (⟺) the operation was successful.
|
||||
@(require_results)
|
||||
private_key_set_bytes :: proc(priv_key: ^Private_Key, b: []byte) -> bool {
|
||||
if len(b) != PRIVATE_KEY_SIZE {
|
||||
return false
|
||||
@@ -189,6 +189,7 @@ sign :: proc(priv_key: ^Private_Key, msg, sig: []byte) {
|
||||
|
||||
// public_key_set_bytes decodes a byte-encoded public key, and returns
|
||||
// true if and only if (⟺) the operation was successful.
|
||||
@(require_results)
|
||||
public_key_set_bytes :: proc "contextless" (pub_key: ^Public_Key, b: []byte) -> bool {
|
||||
if len(b) != PUBLIC_KEY_SIZE {
|
||||
return false
|
||||
@@ -237,6 +238,7 @@ public_key_bytes :: proc(pub_key: ^Public_Key, dst: []byte) {
|
||||
}
|
||||
|
||||
// public_key_equal returns true if and only if (⟺) pub_key is equal to other.
|
||||
@(require_results)
|
||||
public_key_equal :: proc(pub_key, other: ^Public_Key) -> bool {
|
||||
ensure(pub_key._is_initialized && other._is_initialized, "crypto/ed25519: uninitialized public key")
|
||||
|
||||
@@ -254,6 +256,7 @@ public_key_clear :: proc "contextless" (pub_key: ^Public_Key) {
|
||||
// implementation strictly compatible with FIPS 186-5, at the expense of
|
||||
// SBS-security. Doing so is NOT recommended, and the disallowed
|
||||
// public keys all have a known discrete-log.
|
||||
@(require_results)
|
||||
verify :: proc(pub_key: ^Public_Key, msg, sig: []byte, allow_small_order_A := false) -> bool {
|
||||
switch {
|
||||
case !pub_key._is_initialized:
|
||||
|
||||
7
core/crypto/rsa/doc.odin
Normal file
7
core/crypto/rsa/doc.odin
Normal file
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
RSA (Rivest–Shamir–Adleman) cryptosystem.
|
||||
|
||||
See:
|
||||
- [[ https://www.rfc-editor.org/info/rfc8017/ ]]
|
||||
*/
|
||||
package rsa
|
||||
444
core/crypto/rsa/rsa.odin
Normal file
444
core/crypto/rsa/rsa.odin
Normal file
@@ -0,0 +1,444 @@
|
||||
package rsa
|
||||
|
||||
// Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “AS IS” AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import "core:bytes"
|
||||
import "core:crypto"
|
||||
import subtle "core:crypto/_subtle"
|
||||
import "core:encoding/endian"
|
||||
|
||||
// Minimum size for a RSA modulus (in bits).
|
||||
//
|
||||
// Note: 1024-bits is arguably insufficient as of this writing, with
|
||||
// 2048-bits being a more sensible value, however 1024-bits is likely
|
||||
// still in frequent enough use.
|
||||
//
|
||||
// Note: CA signed TLS certificates have a strict requirement of a modulus
|
||||
// size that is at least 2048-bits [[ https://cabforum.org/working-groups/server/baseline-requirements/documents/]].
|
||||
MODULUS_MIN_SIZE :: 1024
|
||||
|
||||
// Maximum size for a RSA modulus (in bits).
|
||||
//
|
||||
// This value MUST be a multiple of 64. This value MUST NOT exceed 47666
|
||||
// (some computations in RSA key generation rely on the factor size being
|
||||
// no more than 23833 bits). RSA key sizes beyond 3072 bits don't make a
|
||||
// lot of sense anyway.
|
||||
MODULUS_MAX_SIZE :: 4096
|
||||
|
||||
// Maxmimum size for a RSA public exponent (in bits).
|
||||
//
|
||||
// Note: This implementation supports arbitrary size exponents, however
|
||||
// limit it to something sensible (some implementations are known to
|
||||
// choke on exponents >= 2^32), with the most common choice being
|
||||
// `65537`.
|
||||
EXPONENT_MAX_SIZE :: 32
|
||||
|
||||
// Maximum size for a RSA factor (in bits). This is for RSA private-key
|
||||
// operations. Default is to support factors up to a bit more than half
|
||||
// the maximum modulus size.
|
||||
//
|
||||
// This value MUST be a multiple of 32.
|
||||
FACTOR_MAX_SIZE :: (MODULUS_MAX_SIZE + 64) >> 1
|
||||
|
||||
// Default size for a RSA key (in bits).
|
||||
DEFAULT_MODULUS_SIZE :: 2048
|
||||
|
||||
// RSA public exponent used for key generation. This MUST be a prime
|
||||
// number greater than 2.
|
||||
@(private)
|
||||
PUBLIC_EXPONENT :: 65537
|
||||
|
||||
#assert(EXPONENT_MAX_SIZE <= 32)
|
||||
|
||||
// Private_Key is a RSA private key.
|
||||
Private_Key :: struct {
|
||||
_pub_key: Public_Key,
|
||||
_d: Modulus, // Private exponent has the same size as n.
|
||||
_p: Factor,
|
||||
_q: Factor,
|
||||
|
||||
// CRT coefficients.
|
||||
_dp: Factor, // d % (p - 1)
|
||||
_dq: Factor, // d % (q - 1)
|
||||
_iq: Factor, // q^(-1) mod p
|
||||
|
||||
_is_initialized: bool,
|
||||
}
|
||||
|
||||
// Public_Key is a RSA public key.
|
||||
Public_Key :: struct {
|
||||
_n: Modulus,
|
||||
_e: u32,
|
||||
_is_initialized: bool,
|
||||
}
|
||||
|
||||
// private_key_generate uses the system entropy source to generate a new
|
||||
// Private_Key. The key size is specified in bits, and must be a multiple
|
||||
// of 8.
|
||||
@(require_results)
|
||||
private_key_generate :: proc(priv_key: ^Private_Key, key_size := DEFAULT_MODULUS_SIZE) -> bool {
|
||||
if !crypto.HAS_RAND_BYTES {
|
||||
return false
|
||||
}
|
||||
if key_size < MODULUS_MIN_SIZE || key_size > MODULUS_MAX_SIZE {
|
||||
return false
|
||||
}
|
||||
if key_size % 8 != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
private_key_clear(priv_key)
|
||||
defer if !priv_key._is_initialized {
|
||||
private_key_clear(priv_key)
|
||||
}
|
||||
|
||||
for {
|
||||
// The only way this can fail is if we get extremely unlucky
|
||||
// and we fail to derive `iq` (1/d mod p).
|
||||
if keygen_inner(priv_key, key_size) == 1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
priv_key._is_initialized = true
|
||||
priv_key._pub_key._is_initialized = true
|
||||
|
||||
// Self-test the key.
|
||||
priv_key._is_initialized = pkcs1_sig_selftest(priv_key)
|
||||
|
||||
return priv_key._is_initialized
|
||||
}
|
||||
|
||||
// private_key_n copies the private key's public modulus to dst if dst is
|
||||
// non-nil and of sufficient size, and returns the number of bytes
|
||||
// copied/would be copied (ie: calling with `dst = nil` gets the required
|
||||
// size).
|
||||
@(require_results)
|
||||
private_key_n :: proc(priv_key: ^Private_Key, dst: []byte) -> (n_len: int) {
|
||||
ensure(priv_key._is_initialized, "crypto/rsa: uninitialized private key")
|
||||
|
||||
return public_key_n(&priv_key._pub_key, dst)
|
||||
}
|
||||
|
||||
// private_key_e returns the private key's public exponent as a u32.
|
||||
@(require_results)
|
||||
private_key_e :: proc(priv_key: ^Private_Key) -> u32 {
|
||||
ensure(priv_key._is_initialized, "crypto/rsa: uninitialized private key")
|
||||
|
||||
return public_key_e(&priv_key._pub_key)
|
||||
}
|
||||
|
||||
// private_key_d copies the private key's private exponent `d` to dst if
|
||||
// dst is non-nil and of sufficient size, and returns the number of bytes
|
||||
// copied/would be copied (ie: calling with `dst = nil` gets the required
|
||||
// size).
|
||||
//
|
||||
// Note: The data returned MUST be kept confidential.
|
||||
@(require_results)
|
||||
private_key_d :: proc(priv_key: ^Private_Key, dst: []byte) -> (n_len: int) {
|
||||
ensure(priv_key._is_initialized, "crypto/rsa: uninitialized private key")
|
||||
|
||||
return modulus_copyout(&priv_key._d, dst)
|
||||
}
|
||||
|
||||
// private_key_p copies the private key's first prime factor `p` to dst
|
||||
// if dst is non-nil and of sufficient size, and returns the number of
|
||||
// bytes copied/would be copied (ie: calling with `dst = nil` gets the
|
||||
// required size).
|
||||
//
|
||||
// Note: The data returned MUST be kept confidential.
|
||||
@(require_results)
|
||||
private_key_p :: proc(priv_key: ^Private_Key, dst: []byte) -> (n_len: int) {
|
||||
ensure(priv_key._is_initialized, "crypto/rsa: uninitialized private key")
|
||||
|
||||
return factor_copyout(&priv_key._p, dst)
|
||||
}
|
||||
|
||||
// private_key_q copies the private key's second prime factor `q` to dst
|
||||
// if dst is non-nil and of sufficient size, and returns the number of
|
||||
// bytes copied/would be copied (ie: calling with `dst = nil` gets the
|
||||
// required size).
|
||||
//
|
||||
// Note: The data returned MUST be kept confidential.
|
||||
@(require_results)
|
||||
private_key_q :: proc(priv_key: ^Private_Key, dst: []byte) -> (n_len: int) {
|
||||
ensure(priv_key._is_initialized, "crypto/rsa: uninitialized private key")
|
||||
|
||||
return factor_copyout(&priv_key._q, dst)
|
||||
}
|
||||
|
||||
// private_key_dp copies the private key's first reduced exponent
|
||||
// `d % (p-1)` to dst if dst is non-nil and of sufficient size, and
|
||||
// returns the number of bytes copied/would be copied (ie: calling with
|
||||
//`dst = nil` gets the required size).
|
||||
//
|
||||
// Note: The data returned MUST be kept confidential.
|
||||
@(require_results)
|
||||
private_key_dp :: proc(priv_key: ^Private_Key, dst: []byte) -> (n_len: int) {
|
||||
ensure(priv_key._is_initialized, "crypto/rsa: uninitialized private key")
|
||||
|
||||
return factor_copyout(&priv_key._dp, dst)
|
||||
}
|
||||
|
||||
// private_key_dq copies the private key's second reduced exponent
|
||||
// `d % (q-1)` to dst if dst is non-nil and of sufficient size, and
|
||||
// returns the number of bytes copied/would be copied (ie: calling with
|
||||
//`dst = nil` gets the required size).
|
||||
//
|
||||
// Note: The data returned MUST be kept confidential.
|
||||
@(require_results)
|
||||
private_key_dq :: proc(priv_key: ^Private_Key, dst: []byte) -> (n_len: int) {
|
||||
ensure(priv_key._is_initialized, "crypto/rsa: uninitialized private key")
|
||||
|
||||
return factor_copyout(&priv_key._dq, dst)
|
||||
}
|
||||
|
||||
// private_key_iq copies the private key's CRT coefficient `iq` to dst if
|
||||
// dst is non-nil and of sufficient size, and returns the number of bytes
|
||||
// copied/would be copied (ie: calling with`dst = nil` gets the required
|
||||
// size).
|
||||
//
|
||||
// Note: The data returned MUST be kept confidential.
|
||||
@(require_results)
|
||||
private_key_iq :: proc(priv_key: ^Private_Key, dst: []byte) -> (n_len: int) {
|
||||
ensure(priv_key._is_initialized, "crypto/rsa: uninitialized private key")
|
||||
|
||||
return factor_copyout(&priv_key._iq, dst)
|
||||
}
|
||||
|
||||
// private_key_size returns the size of the private key's public modulus
|
||||
// in bytes. All ciphertexts and signatures will also be this size.
|
||||
@(require_results)
|
||||
private_key_size :: proc(priv_key: ^Private_Key) -> int {
|
||||
ensure(priv_key._is_initialized, "crypto/rsa: uninitialized private key")
|
||||
|
||||
return priv_key._pub_key._n.v_len
|
||||
}
|
||||
|
||||
// private_key_set_bytes sets a private key from byte-encoded components,
|
||||
// and returns true if and only if (⟺) the operation was successful.
|
||||
//
|
||||
// Note: All values are mandatory, and match the values included in the
|
||||
// PKCS private key format.
|
||||
//
|
||||
// WARNING: This routine validates that it is possible to sign/verify with
|
||||
// the deserialized values, however d is not checked at all, nor is the
|
||||
// primality of p and q.
|
||||
@(require_results)
|
||||
private_key_set_bytes :: proc(
|
||||
priv_key: ^Private_Key,
|
||||
n: []byte,
|
||||
e: []byte,
|
||||
d: []byte,
|
||||
p: []byte,
|
||||
q: []byte,
|
||||
dp: []byte,
|
||||
dq: []byte,
|
||||
iq: []byte,
|
||||
) -> bool {
|
||||
private_key_clear(priv_key)
|
||||
defer if !priv_key._is_initialized {
|
||||
private_key_clear(priv_key)
|
||||
}
|
||||
|
||||
if !public_key_set_bytes(&priv_key._pub_key, n, e) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !modulus_set_bytes(&priv_key._d, d) {
|
||||
return false
|
||||
}
|
||||
if !factor_set_bytes(&priv_key._p, p) {
|
||||
return false
|
||||
}
|
||||
if !factor_set_bytes(&priv_key._q, q) {
|
||||
return false
|
||||
}
|
||||
if !factor_set_bytes(&priv_key._dp, dp) {
|
||||
return false
|
||||
}
|
||||
if !factor_set_bytes(&priv_key._dq, dq) {
|
||||
return false
|
||||
}
|
||||
if !factor_set_bytes(&priv_key._iq, iq) {
|
||||
return false
|
||||
}
|
||||
|
||||
priv_key._is_initialized = true
|
||||
|
||||
// Test the key.
|
||||
//
|
||||
// Note: This DOES NOT check that p/q are prime and if d is
|
||||
// consistent (as it is not used by our implementation).
|
||||
priv_key._is_initialized = pkcs1_sig_selftest(priv_key)
|
||||
|
||||
return priv_key._is_initialized
|
||||
}
|
||||
|
||||
// private_key_set sets priv_key to src.
|
||||
private_key_set :: proc(priv_key, src: ^Private_Key) {
|
||||
if src == nil || !src._is_initialized {
|
||||
private_key_clear(priv_key)
|
||||
return
|
||||
}
|
||||
|
||||
public_key_set(&priv_key._pub_key, &src._pub_key)
|
||||
modulus_set(&priv_key._d, &src._d)
|
||||
factor_set(&priv_key._p, &src._p)
|
||||
factor_set(&priv_key._q, &src._q)
|
||||
factor_set(&priv_key._dp, &src._dp)
|
||||
factor_set(&priv_key._dq, &src._dq)
|
||||
factor_set(&priv_key._iq, &src._iq)
|
||||
|
||||
priv_key._is_initialized = true
|
||||
}
|
||||
|
||||
// private_key_equal returns true if and only if (⟺) priv_key is equal to other.
|
||||
@(require_results)
|
||||
private_key_equal :: proc(priv_key, other: ^Private_Key) -> bool {
|
||||
ensure(priv_key._is_initialized && other._is_initialized, "crypto/rsa: uninitialized private key")
|
||||
|
||||
pk_eq := public_key_equal(&priv_key._pub_key, &other._pub_key)
|
||||
|
||||
eq := crypto.compare_constant_time(modulus_bytes(&priv_key._d), modulus_bytes(&other._d))
|
||||
eq &= crypto.compare_constant_time(factor_bytes(&priv_key._p), factor_bytes(&other._p))
|
||||
eq &= crypto.compare_constant_time(factor_bytes(&priv_key._q), factor_bytes(&other._q))
|
||||
eq &= crypto.compare_constant_time(factor_bytes(&priv_key._dp), factor_bytes(&other._dp))
|
||||
eq &= crypto.compare_constant_time(factor_bytes(&priv_key._dq), factor_bytes(&other._dq))
|
||||
eq &= crypto.compare_constant_time(factor_bytes(&priv_key._iq), factor_bytes(&other._iq))
|
||||
|
||||
return pk_eq & (eq == 1)
|
||||
}
|
||||
|
||||
// private_key_clear clears priv_key to the uninitialized state.
|
||||
private_key_clear :: proc "contextless" (priv_key: ^Private_Key) {
|
||||
crypto.zero_explicit(priv_key, size_of(Private_Key))
|
||||
}
|
||||
|
||||
// public_key_n copies the public key's modulus `n` to dst if dst is
|
||||
// non-nil and of sufficient size, and returns the number of bytes
|
||||
// copied/would be copied (ie: calling with `dst = nil` gets the
|
||||
// required size).
|
||||
@(require_results)
|
||||
public_key_n :: proc(pub_key: ^Public_Key, dst: []byte) -> (n_len: int) {
|
||||
ensure(pub_key._is_initialized, "crypto/rsa: uninitialized public key")
|
||||
|
||||
return modulus_copyout(&pub_key._n, dst)
|
||||
}
|
||||
|
||||
// public_key_e returns the public key's exponent `e` as a u32.
|
||||
@(require_results)
|
||||
public_key_e :: proc(pub_key: ^Public_Key) -> u32 {
|
||||
ensure(pub_key._is_initialized, "crypto/rsa: uninitialized public key")
|
||||
|
||||
return pub_key._e
|
||||
}
|
||||
|
||||
// public_key_size returns the size of the public key's modulus in bytes.
|
||||
// All ciphertexts and signatures will also be this size.
|
||||
@(require_results)
|
||||
public_key_size :: proc(pub_key: ^Public_Key) -> int {
|
||||
ensure(pub_key._is_initialized, "crypto/rsa: uninitialized public key")
|
||||
|
||||
return pub_key._n.v_len
|
||||
}
|
||||
|
||||
// public_key_set_bytes sets a public key from byte-encoded components,
|
||||
// and returns true if and only if (⟺) the operation was successful.
|
||||
@(require_results)
|
||||
public_key_set_bytes :: proc(pub_key: ^Public_Key, n, e: []byte) -> bool {
|
||||
public_key_clear(pub_key)
|
||||
defer if !pub_key._is_initialized {
|
||||
public_key_clear(pub_key)
|
||||
}
|
||||
|
||||
ok := modulus_set_bytes(&pub_key._n, n)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if modulus_len(&pub_key._n) < MODULUS_MIN_SIZE >> 3 {
|
||||
return false
|
||||
}
|
||||
if !modulus_is_odd(&pub_key._n) {
|
||||
return false
|
||||
}
|
||||
|
||||
e_ := bytes.trim_left(e, []byte{0x00})
|
||||
e_len := len(e_)
|
||||
if e_len > EXPONENT_MAX_SIZE >> 3 {
|
||||
return false
|
||||
}
|
||||
e_buf: [4]byte
|
||||
copy(e_buf[4 - e_len:], e)
|
||||
e_u32 := endian.unchecked_get_u32be(e_buf[:])
|
||||
if e_u32 < 3 || e_u32 & 1 == 0 {
|
||||
return false
|
||||
}
|
||||
pub_key._e = e_u32
|
||||
|
||||
pub_key._is_initialized = true
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// public_key_set sets pub_key to src.
|
||||
public_key_set :: proc(pub_key, src: ^Public_Key) {
|
||||
if src == nil || !src._is_initialized {
|
||||
public_key_clear(pub_key)
|
||||
return
|
||||
}
|
||||
|
||||
modulus_set(&pub_key._n, &src._n)
|
||||
pub_key._e = src._e
|
||||
pub_key._is_initialized = true
|
||||
}
|
||||
|
||||
// public_key_set_priv sets pub_key to the public component of priv_key.
|
||||
public_key_set_priv :: proc(pub_key: ^Public_Key, priv_key: ^Private_Key) {
|
||||
ensure(priv_key._is_initialized, "crypto/rsa: uninitialized private key")
|
||||
pub_key^ = priv_key._pub_key
|
||||
}
|
||||
|
||||
// public_key_equal returns true if and only if (⟺) pub_key is equal to other.
|
||||
public_key_equal :: proc(pub_key, other: ^Public_Key) -> bool {
|
||||
ensure(pub_key._is_initialized && other._is_initialized, "crypto/rsa: uninitialized public key")
|
||||
|
||||
eq := crypto.compare_constant_time(modulus_bytes(&pub_key._n), modulus_bytes(&other._n))
|
||||
eq &= int(subtle.eq(pub_key._e, other._e))
|
||||
|
||||
return eq == 1
|
||||
}
|
||||
|
||||
// public_key_clear clears pub_key to the uninitialized state.
|
||||
public_key_clear :: proc "contextless" (pub_key: ^Public_Key) {
|
||||
crypto.zero_explicit(pub_key, size_of(Public_Key))
|
||||
}
|
||||
|
||||
// size returns the size of the key's public modulus in bytes.
|
||||
// All ciphertexts and signatures will also be this size.
|
||||
size :: proc "contextless" (key: ^$T) -> int where T == Private_Key || T == Private_Key {
|
||||
when T == Private_Key {
|
||||
return private_key_size(key)
|
||||
} else {
|
||||
return public_key_size(key)
|
||||
}
|
||||
}
|
||||
197
core/crypto/rsa/rsa_dec_oaep.odin
Normal file
197
core/crypto/rsa/rsa_dec_oaep.odin
Normal file
@@ -0,0 +1,197 @@
|
||||
package rsa
|
||||
|
||||
// Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “AS IS” AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import "core:crypto"
|
||||
import subtle "core:crypto/_subtle"
|
||||
import "core:crypto/hash"
|
||||
|
||||
// decrypt_oaep returns the plaintext and true if and only if (⟺) it
|
||||
// successfully decrypts the ciphertext with OAEP parameterized by
|
||||
// label, hash_algo, and mgf1_algo, and writes the plaintext into dst.
|
||||
// If mgf1_algo is unspecified, hash_algo will be used.
|
||||
//
|
||||
// Note: dst MUST be large enough to contain the plaintext.
|
||||
@(require_results)
|
||||
decrypt_oaep :: proc(
|
||||
priv_key: ^Private_Key,
|
||||
hash_algo: hash.Algorithm,
|
||||
ciphertext: []byte,
|
||||
dst: []byte,
|
||||
label: []byte = nil,
|
||||
mgf1_algo := hash.Algorithm.Invalid,
|
||||
) -> (plaintext: []byte, ok: bool) {
|
||||
if !priv_key._is_initialized {
|
||||
return
|
||||
}
|
||||
ct_len := len(ciphertext)
|
||||
if ct_len != modulus_len(&priv_key._pub_key._n) {
|
||||
return
|
||||
}
|
||||
if hash_algo == .Invalid {
|
||||
return
|
||||
}
|
||||
mgf1_algo_ := mgf1_algo
|
||||
if mgf1_algo == .Invalid {
|
||||
mgf1_algo_ = hash_algo
|
||||
}
|
||||
|
||||
tmp: [MODULUS_MAX_SIZE >> 3]byte
|
||||
pt_buf := tmp[:ct_len]
|
||||
defer crypto.zero_explicit(raw_data(pt_buf), ct_len)
|
||||
|
||||
copy(pt_buf, ciphertext)
|
||||
r := private_modpow(pt_buf, priv_key)
|
||||
r_, l := oaep_dec_unpad(hash_algo, mgf1_algo_, label, pt_buf)
|
||||
|
||||
// Conditional branches are ok as we are past the padding
|
||||
// verification.
|
||||
if ok = r & r_ == 1; ok {
|
||||
if l <= len(dst) {
|
||||
copy(dst, pt_buf[:l])
|
||||
plaintext = dst[:l]
|
||||
} else {
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// oaep_max_plaintext_size returns the maximum supported plaintext size
|
||||
// for a given key, with OAEP parameterized by hash_algo and mgf1_algo.
|
||||
// If mgf1_algo is unspecified, hash_algo will be used.
|
||||
@(require_results)
|
||||
oaep_max_plaintext_size :: proc(
|
||||
k: ^$T,
|
||||
hash_algo: hash.Algorithm,
|
||||
mgf1_algo := hash.Algorithm.Invalid,
|
||||
) -> int where T == Private_Key || T == Public_Key {
|
||||
if !k._is_initialized {
|
||||
return 0
|
||||
}
|
||||
if hash_algo == .Invalid {
|
||||
return 0
|
||||
}
|
||||
mgf1_algo_ := mgf1_algo
|
||||
if mgf1_algo == .Invalid {
|
||||
mgf1_algo_ = hash_algo
|
||||
}
|
||||
|
||||
overhead := 2 + hash.DIGEST_SIZES[hash_algo] + hash.DIGEST_SIZES[mgf1_algo_]
|
||||
|
||||
pub_key: ^Public_Key
|
||||
when T == Private_Key {
|
||||
pub_keyk = &k._pub_key
|
||||
} else {
|
||||
pub_key = k
|
||||
}
|
||||
return modulus_len(&k._n) - overhead
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
xor_hash_data :: proc(hash_algo: hash.Algorithm, dst: []byte, src: []byte) {
|
||||
tmp: [hash.MAX_DIGEST_SIZE]byte = ---
|
||||
hash_len := hash.DIGEST_SIZES[hash_algo]
|
||||
digest := tmp[:hash_len]
|
||||
defer crypto.zero_explicit(raw_data(digest), hash_len)
|
||||
|
||||
hash.hash_bytes_to_buffer(hash_algo, src, digest)
|
||||
for v, u in digest {
|
||||
dst[u] ~= v
|
||||
}
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
oaep_dec_unpad :: proc(
|
||||
hash_algo: hash.Algorithm,
|
||||
mgf1_algo: hash.Algorithm,
|
||||
label: []byte,
|
||||
data: []byte,
|
||||
) -> (u32, int) {
|
||||
hash_len := hash.DIGEST_SIZES[hash_algo]
|
||||
k := len(data)
|
||||
buf := data
|
||||
|
||||
// There must be room for the padding.
|
||||
if k < (hash_len << 1) + 2 {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
// Unmask the seed, then the DB value.
|
||||
seed, db := buf[1:1+hash_len], buf[1+hash_len:]
|
||||
mgf1_xor(seed, mgf1_algo, db)
|
||||
mgf1_xor(db, mgf1_algo, seed)
|
||||
|
||||
// Hash the label and XOR it with the value in the array; if
|
||||
// they are equal then these should yield only zeros.
|
||||
xor_hash_data(hash_algo, db, label)
|
||||
|
||||
// At that point, if the padding was correct, when we should
|
||||
// have: 0x00 || seed || 0x00 ... 0x00 0x01 || M
|
||||
// Padding is valid as long as:
|
||||
// - There is at least hlen+1 leading bytes of value 0x00.
|
||||
// - There is at least one non-zero byte.
|
||||
// - The first (leftmost) non-zero byte has value 0x01.
|
||||
//
|
||||
// Ultimately, we may leak the resulting message length, i.e.
|
||||
// the position of the byte of value 0x01, but we must take care
|
||||
// to do so only if the number of zero bytes has been verified
|
||||
// to be at least hlen+1.
|
||||
//
|
||||
// The loop below counts the number of bytes of value 0x00, and
|
||||
// checks that the next byte has value 0x01, in constant-time.
|
||||
//
|
||||
// - If the initial byte (before the seed) is not 0x00, then
|
||||
// r and s are set to 0, and stay there.
|
||||
// - Value r is 1 until the first non-zero byte is reached
|
||||
// (after the seed); it switches to 0 at that point.
|
||||
// - Value s is set to 1 if and only if the data encountered
|
||||
// at the time of the transition of r from 1 to 0 has value
|
||||
// exactly 0x01.
|
||||
// - Value zlen counts the number of leading bytes of value zero
|
||||
// (after the seed).
|
||||
r := u32(subtle.eq(buf[0], 0))
|
||||
s, zlen: u32
|
||||
for u in hash_len + 1..<k {
|
||||
w := u32(buf[u])
|
||||
|
||||
// nz == 1 only for the first non-zero byte.
|
||||
nz := r & ((w + 0xFF) >> 8)
|
||||
s |= nz & subtle.eq(w, 0x01)
|
||||
r &= subtle.not(nz)
|
||||
zlen += r
|
||||
}
|
||||
|
||||
// Padding is correct only if s == 1, _and_ zlen >= hlen.
|
||||
s &= subtle.ge(zlen, u32(hash_len))
|
||||
|
||||
// At that point, padding was verified, and we are now allowed
|
||||
// to make conditional jumps.
|
||||
if s != 0 {
|
||||
plen := 2 + hash_len + int(zlen)
|
||||
k -= plen
|
||||
copy(buf[:k], buf[plen:])
|
||||
}
|
||||
return s, k
|
||||
}
|
||||
55
core/crypto/rsa/rsa_dec_tls_pms.odin
Normal file
55
core/crypto/rsa/rsa_dec_tls_pms.odin
Normal file
@@ -0,0 +1,55 @@
|
||||
package rsa
|
||||
|
||||
// Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “AS IS” AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import subtle "core:crypto/_subtle"
|
||||
|
||||
// unsafe_decrypt_tls_pms decrypts a TLS RSA-Encrypted Premaster Secret
|
||||
// Message, unconditionally moves the decrypted plaintext to `data[:48]`,
|
||||
// and returns 1 if and only if (⟺) the operation was successful.
|
||||
//
|
||||
// WARNING: This routine MUST only be used when implementing server-side
|
||||
// support for TLS 1.2's Client Key Exchange message, and extreme care
|
||||
// MUST be taken when handling failures. This key exchange scheme was
|
||||
// removed in TLS 1.3, and not implementing support in the first place
|
||||
// is strongly RECOMMENDED even for TLS 1.2 servers.
|
||||
@(require_results)
|
||||
unsafe_decrypt_tls_pms :: proc(priv_key: ^Private_Key, data: []byte) -> u32 {
|
||||
// A first check on length. Since this test works only on the
|
||||
// buffer length, it needs not (and cannot) be constant-time.
|
||||
_len := len(data)
|
||||
if _len < 59 || _len != priv_key._pub_key._n.v_len {
|
||||
return 0
|
||||
}
|
||||
x := private_modpow(data, priv_key)
|
||||
|
||||
x &= u32(subtle.eq(data[0], 0x00))
|
||||
x &= u32(subtle.eq(data[1], 0x02))
|
||||
for u in 2..<(_len-49) {
|
||||
x &= u32(subtle.neq(data[u], 0))
|
||||
}
|
||||
x &= u32(subtle.eq(data[_len - 49], 0x00))
|
||||
copy(data[:48], data[_len - 48:])
|
||||
|
||||
return x
|
||||
}
|
||||
105
core/crypto/rsa/rsa_enc_oaep.odin
Normal file
105
core/crypto/rsa/rsa_enc_oaep.odin
Normal file
@@ -0,0 +1,105 @@
|
||||
package rsa
|
||||
|
||||
// Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “AS IS” AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import "base:intrinsics"
|
||||
import "core:crypto"
|
||||
import "core:crypto/hash"
|
||||
|
||||
// encrypt_oaep returns true if and only if (⟺) it successfully
|
||||
// encrypts the plaintext with OAEP parameterized by label, hash_algo,
|
||||
// and mgf1_algo, and writes the cipherttext into dst. If mgf1_algo is
|
||||
// unspecified, hash_algo will be used.
|
||||
//
|
||||
// This routine will fail if the system entropy source is unavailable.
|
||||
encrypt_oaep :: proc(
|
||||
pub_key: ^Public_Key,
|
||||
hash_algo: hash.Algorithm,
|
||||
plaintext: []byte,
|
||||
dst: []byte,
|
||||
label: []byte = nil,
|
||||
mgf1_algo := hash.Algorithm.Invalid,
|
||||
) -> bool {
|
||||
if !pub_key._is_initialized {
|
||||
return false
|
||||
}
|
||||
if hash_algo == .Invalid {
|
||||
return false
|
||||
}
|
||||
mgf1_algo_ := mgf1_algo
|
||||
if mgf1_algo == .Invalid {
|
||||
mgf1_algo_ = hash_algo
|
||||
}
|
||||
if len(dst) != modulus_len(&pub_key._n) {
|
||||
return false
|
||||
}
|
||||
if len(plaintext) > oaep_max_plaintext_size(pub_key, hash_algo, mgf1_algo_) {
|
||||
return false
|
||||
}
|
||||
|
||||
if oaep_enc_pad(hash_algo, mgf1_algo_, label, dst, plaintext) != 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
return public_modpow(dst, pub_key) == 1
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
oaep_enc_pad :: proc(
|
||||
hash_algo: hash.Algorithm,
|
||||
mgf1_algo: hash.Algorithm,
|
||||
label: []byte,
|
||||
dst: []byte,
|
||||
src: []byte,
|
||||
) -> u32 {
|
||||
hash_len := hash.DIGEST_SIZES[hash_algo]
|
||||
src_len := len(src)
|
||||
k := len(dst)
|
||||
|
||||
// Note: Length checks are handled by the caller.
|
||||
|
||||
// Apply padding. At this point, things cannot fail.
|
||||
buf := dst
|
||||
|
||||
// Assemble: DB = lHash || PS || 0x01 || M
|
||||
// We first place the source message M with copy(), so that
|
||||
// overlaps between source and destination buffers are supported.
|
||||
copy(buf[k - src_len:], src)
|
||||
hash.hash_bytes_to_buffer(hash_algo, label, buf[1+hash_len:1+hash_len << 1])
|
||||
intrinsics.mem_zero(raw_data(buf[1 + hash_len << 1:]), k - src_len - (hash_len << 1) - 2)
|
||||
buf[k - src_len - 1] = 0x01
|
||||
|
||||
// Make the random seed.
|
||||
seed, db := buf[1:1+hash_len], buf[1+hash_len:]
|
||||
crypto.rand_bytes(seed)
|
||||
|
||||
// Mask DB with the mask generated from the seed.
|
||||
mgf1_xor(db, mgf1_algo, seed)
|
||||
|
||||
// Mask the seed with the mask generated from the masked DB.
|
||||
mgf1_xor(seed, mgf1_algo, db)
|
||||
|
||||
// Padding result: EM = 0x00 || maskedSeed || maskedDB.
|
||||
buf[0] = 0x00
|
||||
return 1
|
||||
}
|
||||
110
core/crypto/rsa/rsa_int.odin
Normal file
110
core/crypto/rsa/rsa_int.odin
Normal file
@@ -0,0 +1,110 @@
|
||||
#+private
|
||||
package rsa
|
||||
|
||||
import "core:bytes"
|
||||
|
||||
Big_Int :: struct($N: int) {
|
||||
v: [N]byte,
|
||||
v_len: int,
|
||||
}
|
||||
|
||||
Modulus :: Big_Int(MODULUS_MAX_SIZE >> 3)
|
||||
Factor :: Big_Int(FACTOR_MAX_SIZE >> 3)
|
||||
|
||||
@(require_results)
|
||||
modulus_set_bytes :: proc(n: ^Modulus, b: []byte) -> bool {
|
||||
b_ := bytes.trim_left(b, []byte{0x00})
|
||||
b_len := len(b_)
|
||||
|
||||
if b_len > size_of(n.v) || b_len == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
copy(n.v[:], b_)
|
||||
n.v_len = b_len
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
modulus_set :: proc "contextless" (n, other: ^Modulus) {
|
||||
// Copy the full thing.
|
||||
copy(n.v[:], other.v[:])
|
||||
n.v_len = other.v_len
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
modulus_bytes :: #force_inline proc "contextless" (n: ^Modulus) -> []byte {
|
||||
return n.v[:n.v_len]
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
modulus_len :: #force_inline proc "contextless" (n: ^Modulus) -> int {
|
||||
return n.v_len
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
modulus_copyout :: proc(n: ^Modulus, dst: []byte) -> (n_len: int) {
|
||||
if n_len = modulus_len(n); n_len == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if len(dst) > 0 {
|
||||
ensure(len(dst) >= n_len, "crypto/rsa: insufficent buffer size")
|
||||
copy(dst, modulus_bytes(n))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
modulus_is_odd :: proc "contextless" (n: ^Modulus) -> bool {
|
||||
if n.v_len == 0 || n.v[n.v_len-1] & 1 == 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
factor_set_bytes :: proc(n: ^Factor, b: []byte) -> bool {
|
||||
b_ := bytes.trim_left(b, []byte{0x00})
|
||||
b_len := len(b_)
|
||||
|
||||
if b_len > size_of(n.v) || b_len == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
copy(n.v[:], b_)
|
||||
n.v_len = b_len
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
factor_set :: proc "contextless" (n, other: ^Factor) {
|
||||
// Copy the full thing.
|
||||
copy(n.v[:], other.v[:])
|
||||
n.v_len = other.v_len
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
factor_bytes :: #force_inline proc "contextless" (n: ^Factor) -> []byte {
|
||||
return n.v[:n.v_len]
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
factor_len :: #force_inline proc "contextless" (n: ^Factor) -> int {
|
||||
return n.v_len
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
factor_copyout :: proc(n: ^Factor, dst: []byte) -> (n_len: int) {
|
||||
if n_len = factor_len(n); n_len == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if len(dst) > 0 {
|
||||
ensure(len(dst) >= n_len, "crypto/rsa: insufficent buffer size")
|
||||
copy(dst, factor_bytes(n))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
367
core/crypto/rsa/rsa_keygen.odin
Normal file
367
core/crypto/rsa/rsa_keygen.odin
Normal file
@@ -0,0 +1,367 @@
|
||||
package rsa
|
||||
|
||||
// Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “AS IS” AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import "core:crypto"
|
||||
import bigint "core:crypto/_bigint"
|
||||
import subtle "core:crypto/_subtle"
|
||||
import "core:slice"
|
||||
|
||||
// Swap two buffers in RAM. They must be disjoint.
|
||||
@(private="file")
|
||||
bufswap_u32 :: proc "contextless" (b1, b2: []u32) {
|
||||
l := len(b1)
|
||||
|
||||
for u in 0..<l {
|
||||
b1[u], b2[u] = b2[u], b1[u]
|
||||
}
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
keygen_inner :: proc(sk: ^Private_Key, key_size: int) -> u32 {
|
||||
// We need temporary values for at least 7 integers of the same size
|
||||
// as a factor (including header word); more space helps with performance
|
||||
// (in modular exponentiations), but we much prefer to remain under
|
||||
// 2 kilobytes in total, to save stack space. The macro TEMPS below
|
||||
// exceeds 512 (which is a count in 32-bit words) when MODULUS_MAX_SIZE
|
||||
// is greater than 4464 (default value is 4096, so the 2-kB limit is
|
||||
// maintained unless MODULUS_MAX_SIZE was modified).
|
||||
TEMPS :: max(512, ((((7 * ((((MODULUS_MAX_SIZE + 1) >> 1) + 61) / 31))) + 1) >> 1) << 1)
|
||||
|
||||
assert(key_size >= MODULUS_MIN_SIZE && key_size <= MODULUS_MAX_SIZE)
|
||||
|
||||
t64: [TEMPS >> 1]u64
|
||||
t32 := slice.reinterpret([]u32, t64[:])
|
||||
defer crypto.zero_explicit(&t64, size_of(t64))
|
||||
|
||||
esize_p := u32(key_size + 1) >> 1
|
||||
esize_q := u32(key_size) - esize_p
|
||||
sk._p.v_len = int((esize_p + 7) >> 3)
|
||||
sk._q.v_len = int((esize_q + 7) >> 3)
|
||||
sk._dp.v_len = sk._p.v_len
|
||||
sk._dq.v_len = sk._q.v_len
|
||||
sk._iq.v_len = sk._p.v_len
|
||||
|
||||
pk := &sk._pub_key
|
||||
pk._n.v_len = (key_size + 7) >> 3
|
||||
pk._e = PUBLIC_EXPONENT
|
||||
|
||||
sk._d.v_len = pk._n.v_len // Private exponent length is that of the modulus.
|
||||
|
||||
// We now switch to encoded sizes.
|
||||
//
|
||||
// floor((x * 16913) / (2^19)) is equal to floor(x/31) for all
|
||||
// integers x from 0 to 34966; the intermediate product fits on
|
||||
// 30 bits, thus we can use MUL31().
|
||||
esize_p += u32(bigint._mul31(esize_p, 16913) >> 19)
|
||||
esize_q += u32(bigint._mul31(esize_q, 16913) >> 19)
|
||||
plen := (esize_p + 31) >> 5
|
||||
qlen := (esize_q + 31) >> 5
|
||||
p := t32
|
||||
q := p[1 + plen:]
|
||||
t := q[1 + qlen:]
|
||||
|
||||
// Since we use a prime exponent, when searching for candidate primes,
|
||||
// checking if `GCD(e, prime - 1) = 1` is a simple matter of euclidian
|
||||
// division.
|
||||
for {
|
||||
bigint.i62_mkprime(p, esize_p, PUBLIC_EXPONENT, t)
|
||||
p[1] -= 1
|
||||
if bigint.i31_rem(p, PUBLIC_EXPONENT) != 0 {
|
||||
p[1] += 1
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
bigint.i62_mkprime(q, esize_q, PUBLIC_EXPONENT, t)
|
||||
q[1] -= 1
|
||||
if bigint.i31_rem(q, PUBLIC_EXPONENT) != 0 {
|
||||
q[1] += 1
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If p and q have the same size, then it is possible that q > p
|
||||
// (when the target modulus size is odd, we generate p with a
|
||||
// greater bit length than q). If q > p, we want to swap p and q
|
||||
// for two reasons:
|
||||
// - The final step below (inversion of q modulo p) is easier if
|
||||
// p > q.
|
||||
// - While BearSSL's RSA code is perfectly happy with RSA keys such
|
||||
// that p < q, some other implementations have restrictions and
|
||||
// require p > q.
|
||||
//
|
||||
// Note that we can do a simple non-constant-time swap here,
|
||||
// because the only information we leak here is that we insist on
|
||||
// returning p and q such that p > q, which is not a secret.
|
||||
if esize_p == esize_q && bigint.i31_sub(p, q, 0) == 1 {
|
||||
bufswap_u32(p[:1+plen], q)
|
||||
}
|
||||
|
||||
sk_p, sk_q := factor_bytes(&sk._p), factor_bytes(&sk._q)
|
||||
bigint.i31_encode(sk_p, p)
|
||||
bigint.i31_encode(sk_q, q)
|
||||
// The odds of this happening are infinitesimally small, however
|
||||
// checking for it is cheap.
|
||||
if crypto.compare_constant_time(sk_p, sk_q) == 1 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Compute the public modulus too.
|
||||
bigint.i31_zero(t, p[0])
|
||||
bigint.i31_mulacc(t, p, q)
|
||||
bigint.i31_encode(modulus_bytes(&pk._n), t)
|
||||
|
||||
// Compute the private exponent.
|
||||
//
|
||||
// Computing p - 1 and q - 1 this way is safe as p and q
|
||||
// are guaranteed to be odd, thus the LSB will always be
|
||||
// set.
|
||||
p[1], q[1] = p[1] - 1, q[1] - 1 // p = p - 1, q = q - 1
|
||||
if compute_privexp(sk, p, q, pk._e, t) != 1 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Compute `d % (p - 1)`.
|
||||
d_mod := t[:1+plen]
|
||||
bigint.i31_decode_reduce(d_mod, modulus_bytes(&sk._d), p)
|
||||
bigint.i31_encode(factor_bytes(&sk._dp), d_mod)
|
||||
|
||||
// Compute `d % (q - 1)`.
|
||||
bigint.i31_decode_reduce(d_mod, modulus_bytes(&sk._d), q)
|
||||
bigint.i31_encode(factor_bytes(&sk._dq), d_mod)
|
||||
|
||||
// Compute `q^(-1) mod p`.
|
||||
p[1], q[1] = p[1] + 1, q[1] + 1 // Restore p, q.
|
||||
return compute_qinv(sk, p, q, plen, t)
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
compute_qinv :: proc "contextless" (sk: ^Private_Key, p, q: []u32, plen: u32, t: []u32) -> u32 {
|
||||
// Per Fermat's Little Theorem, `q^(-1) mod p = q^(p-2) mod p`.
|
||||
//
|
||||
// Note: p is guaranteed to be odd as it is a large prime.
|
||||
|
||||
// Compute and encode `p-2`.
|
||||
p_minus_two := t[:1+plen]
|
||||
copy(p_minus_two, p[:1+plen])
|
||||
two := t[1+plen:] // Temporarily use this for 2.
|
||||
bigint.i31_zero(two, p[0])
|
||||
bigint.i31_decode(two, []byte{2})
|
||||
_ = bigint.i31_sub(p_minus_two, two, 1)
|
||||
iq := factor_bytes(&sk._iq) // Temporarily use this for p - 2.
|
||||
bigint.i31_encode(iq, p_minus_two)
|
||||
|
||||
// Enforce 64-bit alignment.
|
||||
t_ := t
|
||||
if len(t_) & 1 != 0 {
|
||||
t_ = t_[1:]
|
||||
}
|
||||
|
||||
m0i := bigint.i31_ninv31(p[1])
|
||||
ret := bigint.i62_modpow_opt_as_i31(q, iq, p, m0i, t)
|
||||
if ret != 0 {
|
||||
bigint.i31_encode(iq, q)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
compute_privexp :: proc "contextless" (sk: ^Private_Key, p_minus_one, q_minus_one: []u32, e: u32, tmp: []u32) -> u32 {
|
||||
// Compute phi = (p-1)*(q-1). The mulacc function sets the announced
|
||||
// bit length of t to be the sum of the announced bit lengths of
|
||||
// p-1 and q-1, which is usually exact but may overshoot by one 1
|
||||
// bit in some cases; we readjust it to its true length.
|
||||
phi := tmp
|
||||
bigint.i31_zero(phi, p_minus_one[0])
|
||||
bigint.i31_mulacc(phi, p_minus_one, q_minus_one)
|
||||
_len := (phi[0] + 31) >> 5
|
||||
phi[0] = bigint.i31_bit_length(phi[1:1+_len])
|
||||
_len = (phi[0] + 31) >> 5
|
||||
|
||||
// Divide phi by public exponent e. The final remainder r must be
|
||||
// non-zero (otherwise, the key is invalid). The quotient is k,
|
||||
// which we write over phi, since we don't need phi after that.
|
||||
r: u32
|
||||
for u := _len; u >= 1; u -= 1 {
|
||||
// Upon entry, r < e, and phi[u] < 2^31; hence,
|
||||
// hi:lo < e*2^31. Thus, the produced word k[u]
|
||||
// must be lower than 2^31, and the new remainder r
|
||||
// is lower than e.
|
||||
hi := r >> 1
|
||||
lo := (r << 31) + phi[u]
|
||||
phi[u], r = bigint.div_rem_u32(hi, lo, e)
|
||||
}
|
||||
if r == 0 {
|
||||
return 0
|
||||
}
|
||||
k := phi
|
||||
|
||||
// Compute u and v such that u*e - v*r = GCD(e,r). We use
|
||||
// a binary GCD algorithm, with 6 extra integers a, b,
|
||||
// u0, u1, v0 and v1. Initial values are:
|
||||
// a = e u0 = 1 v0 = 0
|
||||
// b = r u1 = r v1 = e-1
|
||||
// The following invariants are maintained:
|
||||
// a = u0*e - v0*r
|
||||
// b = u1*e - v1*r
|
||||
// 0 < a <= e
|
||||
// 0 < b <= r
|
||||
// 0 <= u0 <= r
|
||||
// 0 <= v0 <= e
|
||||
// 0 <= u1 <= r
|
||||
// 0 <= v1 <= e
|
||||
//
|
||||
// At each iteration, we reduce either a or b by one bit, and
|
||||
// adjust u0, u1, v0 and v1 to maintain the invariants:
|
||||
// - if a is even, then a <- a/2
|
||||
// - otherwise, if b is even, then b <- b/2
|
||||
// - otherwise, if a > b, then a <- (a-b)/2
|
||||
// - otherwise, if b > a, then b <- (b-a)/2
|
||||
// Algorithm stops when a = b. At that point, the common value
|
||||
// is the GCD of e and r; it must be 1 (otherwise, the private
|
||||
// key or public exponent is not valid). The (u0,v0) or (u1,v1)
|
||||
// pairs are the solution we are looking for.
|
||||
//
|
||||
// Since either a or b is reduced by at least 1 bit at each
|
||||
// iteration, 62 iterations are enough to reach the end
|
||||
// condition.
|
||||
//
|
||||
// To maintain the invariants, we must compute the same operations
|
||||
// on the u* and v* values that we do on a and b:
|
||||
// - When a is divided by 2, u0 and v0 must be divided by 2.
|
||||
// - When b is divided by 2, u1 and v1 must be divided by 2.
|
||||
// - When b is subtracted from a, u1 and v1 are subtracted from
|
||||
// u0 and v0, respectively.
|
||||
// - When a is subtracted from b, u0 and v0 are subtracted from
|
||||
// u1 and v1, respectively.
|
||||
//
|
||||
// However, we want to keep the u* and v* values in their proper
|
||||
// ranges. The following remarks apply:
|
||||
//
|
||||
// - When a is divided by 2, then a is even. Therefore:
|
||||
//
|
||||
// * If r is odd, then u0 and v0 must have the same parity;
|
||||
// if they are both odd, then adding r to u0 and e to v0
|
||||
// makes them both even, and the division by 2 brings them
|
||||
// back to the proper range.
|
||||
//
|
||||
// * If r is even, then u0 must be even; if v0 is odd, then
|
||||
// adding r to u0 and e to v0 makes them both even, and the
|
||||
// division by 2 brings them back to the proper range.
|
||||
//
|
||||
// Thus, all we need to do is to look at the parity of v0,
|
||||
// and add (r,e) to (u0,v0) when v0 is odd. In order to avoid
|
||||
// a 32-bit overflow, we can add ((r+1)/2,(e/2)+1) after the
|
||||
// division (r+1 does not overflow since r < e; and (e/2)+1
|
||||
// is equal to (e+1)/2 since e is odd).
|
||||
//
|
||||
// - When we subtract b from a, three cases may occur:
|
||||
//
|
||||
// * u1 <= u0 and v1 <= v0: just do the subtractions
|
||||
//
|
||||
// * u1 > u0 and v1 > v0: compute:
|
||||
// (u0, v0) <- (u0 + r - u1, v0 + e - v1)
|
||||
//
|
||||
// * u1 <= u0 and v1 > v0: compute:
|
||||
// (u0, v0) <- (u0 + r - u1, v0 + e - v1)
|
||||
//
|
||||
// The fourth case (u1 > u0 and v1 <= v0) is not possible
|
||||
// because it would contradict "b < a" (which is the reason
|
||||
// why we subtract b from a).
|
||||
//
|
||||
// The tricky case is the third one: from the equations, it
|
||||
// seems that u0 may go out of range. However, the invariants
|
||||
// and ranges of other values imply that, in that case, the
|
||||
// new u0 does not actually exceed the range.
|
||||
//
|
||||
// We can thus handle the subtraction by adding (r,e) based
|
||||
// solely on the comparison between v0 and v1.
|
||||
a, b: u32 = e, r
|
||||
u0, v0: u32 = 1, 0
|
||||
u1, v1: u32 = r, e - 1
|
||||
hr, he := (r + 1) >> 1, (e >> 1) + 1
|
||||
for _ in 0..<62 {
|
||||
oa := a & 1 // 1 if a is odd
|
||||
ob := b & 1 // 1 if b is odd
|
||||
agtb := subtle.gt(a, b) // 1 if a > b
|
||||
bgta := subtle.gt(b, a) // 1 if b > a
|
||||
|
||||
sab := oa & ob & agtb // 1 if a <- a-b
|
||||
sba := oa & ob & bgta // 1 if b <- b-a
|
||||
|
||||
// a <- a-b, u0 <- u0-u1, v0 <- v0-v1
|
||||
ctl := subtle.gt(v1, v0)
|
||||
a -= b & -sab
|
||||
u0 -= (u1 - (r & -ctl)) & -sab
|
||||
v0 -= (v1 - (e & -ctl)) & -sab
|
||||
|
||||
// b <- b-a, u1 <- u1-u0 mod r, v1 <- v1-v0 mod e
|
||||
ctl = subtle.gt(v0, v1)
|
||||
b -= a & -sba
|
||||
u1 -= (u0 - (r & -ctl)) & -sba
|
||||
v1 -= (v0 - (e & -ctl)) & -sba
|
||||
|
||||
da := subtle.not(oa) | sab // 1 if a <- a/2
|
||||
db := (oa & subtle.not(ob)) | sba // 1 if b <- b/2
|
||||
|
||||
// a <- a/2, u0 <- u0/2, v0 <- v0/2
|
||||
ctl = v0 & 1
|
||||
a ~= (a ~ (a >> 1)) & -da
|
||||
u0 ~= (u0 ~ ((u0 >> 1) + (hr & -ctl))) & -da
|
||||
v0 ~= (v0 ~ ((v0 >> 1) + (he & -ctl))) & -da
|
||||
|
||||
// b <- b/2, u1 <- u1/2 mod r, v1 <- v1/2 mod e
|
||||
ctl = v1 & 1
|
||||
b ~= (b ~ (b >> 1)) & -db
|
||||
u1 ~= (u1 ~ ((u1 >> 1) + (hr & -ctl))) & -db
|
||||
v1 ~= (v1 ~ ((v1 >> 1) + (he & -ctl))) & -db
|
||||
}
|
||||
|
||||
// Check that the GCD is indeed 1. If not, then the key is invalid
|
||||
// (and there's no harm in leaking that piece of information).
|
||||
if (a != 1) {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Now we have u0*e - v0*r = 1. Let's compute the result as:
|
||||
// d = u0 + v0*k
|
||||
// We still have k in the tmp[] array, and its announced bit
|
||||
// length is that of phi.
|
||||
m := k[1+_len:]
|
||||
m[0] = (1 << 5) + 1 // bit length is 32 bits, encoded
|
||||
m[1] = v0 & bigint.I31_MASK
|
||||
m[2] = v0 >> 31
|
||||
z := m[3:]
|
||||
bigint.i31_zero(z, k[0])
|
||||
z[1] = u0 & bigint.I31_MASK
|
||||
z[2] = u0 >> 31
|
||||
bigint.i31_mulacc(z, k, m)
|
||||
|
||||
// Encode the result.
|
||||
bigint.i31_encode(modulus_bytes(&sk._d), z)
|
||||
|
||||
return 1
|
||||
}
|
||||
49
core/crypto/rsa/rsa_mgf1.odin
Normal file
49
core/crypto/rsa/rsa_mgf1.odin
Normal file
@@ -0,0 +1,49 @@
|
||||
package rsa
|
||||
|
||||
// Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “AS IS” AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import "core:crypto/hash"
|
||||
import "core:encoding/endian"
|
||||
|
||||
@(private)
|
||||
mgf1_xor :: proc(data: []byte, hash_algo: hash.Algorithm, seed: []byte) {
|
||||
tmp: [hash.MAX_DIGEST_SIZE]byte = ---
|
||||
ctx: hash.Context = ---
|
||||
|
||||
buf, blen := data, len(data)
|
||||
hlen := hash.DIGEST_SIZES[hash_algo]
|
||||
digest := tmp[:hlen]
|
||||
for u, c := int(0), u32(0); u < blen; u, c = u + hlen, c + 1 {
|
||||
hash.init(&ctx, hash_algo)
|
||||
hash.update(&ctx, seed)
|
||||
endian.unchecked_put_u32be(tmp[:], c)
|
||||
hash.update(&ctx, tmp[:4])
|
||||
hash.final(&ctx, digest)
|
||||
for v in 0..<hlen {
|
||||
if u + v >= blen {
|
||||
break
|
||||
}
|
||||
buf[u + v] ~= digest[v]
|
||||
}
|
||||
}
|
||||
}
|
||||
165
core/crypto/rsa/rsa_modpow_priv.odin
Normal file
165
core/crypto/rsa/rsa_modpow_priv.odin
Normal file
@@ -0,0 +1,165 @@
|
||||
package rsa
|
||||
|
||||
// Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “AS IS” AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import "core:crypto"
|
||||
import bigint "core:crypto/_bigint"
|
||||
import "core:slice"
|
||||
|
||||
@(private, require_results)
|
||||
private_modpow :: proc(x: []byte, sk: ^Private_Key) -> u32 {
|
||||
U :: (2 + ((FACTOR_MAX_SIZE + 30) / 31))
|
||||
TLEN :: (4 * U) // TLEN is counted in 64-bit words
|
||||
|
||||
ensure(sk._is_initialized, "crypto/rsa: uninitialized private key")
|
||||
|
||||
// Compute the actual lengths of p and q, in bytes.
|
||||
// These lengths are not considered secret (we cannot really hide
|
||||
// them anyway in constant-time code).
|
||||
//
|
||||
// Note/yawning: The factors should already be the correct size,
|
||||
// with leading `0x00`s stripped.
|
||||
p := factor_bytes(&sk._p)
|
||||
plen := len(p)
|
||||
for plen > 0 && p[0] == 0 {
|
||||
p = p[1:]
|
||||
plen -= 1
|
||||
}
|
||||
q := factor_bytes(&sk._q)
|
||||
qlen := len(q)
|
||||
for qlen > 0 && q[0] == 0 {
|
||||
q = q[1:]
|
||||
qlen -= 1
|
||||
}
|
||||
|
||||
// Compute the maximum factor length, in 31-bit words.
|
||||
z := max(plen, qlen) << 3
|
||||
fwlen := 1
|
||||
for z > 0 {
|
||||
z -= 31
|
||||
fwlen += 1
|
||||
}
|
||||
|
||||
// Convert size to 62-bit words.
|
||||
fwlen = (fwlen + 1) >> 1
|
||||
|
||||
// We need to fit at least 6 values in the stack buffer.
|
||||
if 6 * fwlen > TLEN {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Compute signature length (in bytes).
|
||||
xlen := modulus_len(&sk._pub_key._n)
|
||||
|
||||
tmp_: [TLEN]u64 // WARNING: This must be zeroed out.
|
||||
defer crypto.zero_explicit(&tmp_, size_of(tmp_))
|
||||
tmp := tmp_[:]
|
||||
|
||||
// Decode q.
|
||||
mq := slice.reinterpret([]u32, tmp)
|
||||
bigint.i31_decode(mq, q)
|
||||
|
||||
// Decode p.
|
||||
t1 := slice.reinterpret([]u32, tmp[fwlen:])
|
||||
bigint.i31_decode(t1, p)
|
||||
|
||||
// Upstream recomputes the public modulus n, but we can just
|
||||
// decode it as our key representation stores all PKCS#1
|
||||
// private key values,
|
||||
t2 := slice.reinterpret([]u32, tmp[2*fwlen:])
|
||||
bigint.i31_decode(t2, modulus_bytes(&sk._pub_key._n))
|
||||
|
||||
// We encode the modulus into bytes, to perform the comparison
|
||||
// with bytes. We know that the product length, in bytes, is
|
||||
// exactly xlen.
|
||||
// The comparison actually computes the carry when subtracting
|
||||
// the modulus from the source value; that carry must be 1 for
|
||||
// a value in the correct range. We keep it in r, which is our
|
||||
// accumulator for the error code.
|
||||
m_buf := slice.reinterpret([]byte, tmp[4*fwlen:])
|
||||
bigint.i31_encode(m_buf[:xlen], t2)
|
||||
u := xlen
|
||||
r: u32
|
||||
for u > 0 {
|
||||
u -= 1
|
||||
wn := u32(m_buf[u])
|
||||
wx := u32(x[u])
|
||||
r = ((wx - (wn + r)) >> 8) & 1
|
||||
}
|
||||
|
||||
// Move the decoded p to another temporary buffer.
|
||||
mp := t2
|
||||
copy(mp, t1[:2*fwlen])
|
||||
|
||||
// Compute s2 = x^dq mod q.
|
||||
q0i := bigint.i31_ninv31(mq[1])
|
||||
s2 := t1
|
||||
bigint.i31_decode_reduce(s2, x, mq)
|
||||
r &= bigint.i62_modpow_opt(s2, factor_bytes(&sk._dq), mq, q0i, tmp[3*fwlen:])
|
||||
|
||||
// Compute s1 = x^dp mod p.
|
||||
p0i := bigint.i31_ninv31(mp[1])
|
||||
s1 := slice.reinterpret([]u32, tmp[3*fwlen:])
|
||||
bigint.i31_decode_reduce(s1, x, mp)
|
||||
r &= bigint.i62_modpow_opt(s1, factor_bytes(&sk._dp), mp, p0i, tmp[4*fwlen:])
|
||||
|
||||
// Compute:
|
||||
// h = (s1 - s2)*(1/q) mod p
|
||||
// s1 is an integer modulo p, but s2 is modulo q. PKCS#1 is
|
||||
// unclear about whether p may be lower than q (some existing,
|
||||
// widely deployed implementations of RSA don't tolerate p < q),
|
||||
// but we want to support that occurrence, so we need to use the
|
||||
// reduction function.
|
||||
//
|
||||
// Since we use br_i31_decode_reduce() for iq (purportedly, the
|
||||
// inverse of q modulo p), we also tolerate improperly large
|
||||
// values for this parameter.
|
||||
t1 = slice.reinterpret([]u32, tmp[4*fwlen:])
|
||||
t2 = slice.reinterpret([]u32, tmp[5*fwlen:])
|
||||
bigint.i31_reduce(t2, s2, mp)
|
||||
_ = bigint.i31_add(s1, mp, bigint.i31_sub(s1, t2, 1))
|
||||
bigint.i31_to_monty(s1, mp)
|
||||
bigint.i31_decode_reduce(t1, factor_bytes(&sk._iq), mp)
|
||||
bigint.i31_montymul(t2, s1, t1, mp, p0i)
|
||||
|
||||
// h is now in t2. We compute the final result:
|
||||
// s = s2 + q*h
|
||||
// All these operations are non-modular.
|
||||
//
|
||||
// We need mq, s2 and t2. We use the t3 buffer as destination.
|
||||
// The buffers mp, s1 and t1 are no longer needed, so we can
|
||||
// reuse them for t3. Moreover, the first step of the computation
|
||||
// is to copy s2 into t3, after which s2 is not needed. Right
|
||||
// now, mq is in slot 0, s2 is in slot 1, and t2 is in slot 5.
|
||||
// Therefore, we have ample room for t3 by simply using s2.
|
||||
t3 := s2
|
||||
bigint.i31_mulacc(t3, mq, t2)
|
||||
|
||||
// Encode the result. Since we already checked the value of xlen,
|
||||
// we can just use it right away.
|
||||
bigint.i31_encode(x, t3)
|
||||
|
||||
// The only error conditions remaining at that point are invalid
|
||||
// values for p and q (even integers).
|
||||
return p0i & q0i & r
|
||||
}
|
||||
89
core/crypto/rsa/rsa_modpow_pub.odin
Normal file
89
core/crypto/rsa/rsa_modpow_pub.odin
Normal file
@@ -0,0 +1,89 @@
|
||||
package rsa
|
||||
|
||||
// Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “AS IS” AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import bigint "core:crypto/_bigint"
|
||||
import "core:encoding/endian"
|
||||
import "core:slice"
|
||||
|
||||
@(private, require_results)
|
||||
public_modpow :: proc(x: []byte, pk: ^Public_Key) -> u32 {
|
||||
TLEN :: (2 * (2 + ((MODULUS_MAX_SIZE + 30) / 31)))
|
||||
|
||||
ensure(pk._is_initialized, "crypto/rsa: uninitialized public key")
|
||||
|
||||
// Get the actual length of the modulus, and see if it fits within
|
||||
// our stack buffer. We also check that the length of x[] is valid.
|
||||
//
|
||||
// Note/yawning: The modulus should already be the correct size,
|
||||
// with leading `0x00`s stripped.
|
||||
n := modulus_bytes(&pk._n)
|
||||
nlen := modulus_len(&pk._n)
|
||||
for nlen > 0 && n[0] == 0 {
|
||||
n = n[1:]
|
||||
nlen -= 1
|
||||
}
|
||||
if nlen == 0 || nlen > (MODULUS_MAX_SIZE >> 3) || len(x) != nlen {
|
||||
return 0
|
||||
}
|
||||
z := nlen << 3
|
||||
fwlen := 1
|
||||
for z > 0 {
|
||||
z -= 31
|
||||
fwlen += 1
|
||||
}
|
||||
// Convert fwlen to a count in 62-bit words.
|
||||
fwlen = (fwlen + 1) >> 1
|
||||
|
||||
// The modulus gets decoded into m[].
|
||||
// The value to exponentiate goes into a[].
|
||||
tmp: [TLEN]u64 // WARNING: This must be zeroed out.
|
||||
m := slice.reinterpret([]u32, tmp[:fwlen])
|
||||
a := slice.reinterpret([]u32, tmp[fwlen:2*fwlen])
|
||||
|
||||
// Decode the modulus.
|
||||
bigint.i31_decode(m, n)
|
||||
m0i := bigint.i31_ninv31(m[1])
|
||||
|
||||
// Note: if m[] is even, then m0i == 0. Otherwise, m0i must be
|
||||
// an odd integer.
|
||||
r := m0i & 1
|
||||
|
||||
// Decode x[] into a[]; we also check that its value is proper.
|
||||
r &= bigint.i31_decode_mod(a, x, m)
|
||||
|
||||
// Compute the modular exponentiation.
|
||||
e_: [EXPONENT_MAX_SIZE >> 3]byte
|
||||
e_off: int
|
||||
endian.unchecked_put_u32be(e_[:], pk._e)
|
||||
if e_[0] == 0 {
|
||||
// `e = 65537` is the most common and sensible value, so this
|
||||
// is the most sensible value.
|
||||
e_off = 1
|
||||
}
|
||||
bigint.i62_modpow_opt(a, e_[e_off:], m, m0i, tmp[2*fwlen:])
|
||||
|
||||
// Encode the result.
|
||||
bigint.i31_encode(x, a)
|
||||
return r
|
||||
}
|
||||
233
core/crypto/rsa/rsa_sig_pkcs1.odin
Normal file
233
core/crypto/rsa/rsa_sig_pkcs1.odin
Normal file
@@ -0,0 +1,233 @@
|
||||
package rsa
|
||||
|
||||
// Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “AS IS” AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import "core:bytes"
|
||||
import "core:crypto"
|
||||
import "core:crypto/hash"
|
||||
|
||||
// PKCS1_HASH_OIDS maps common hash algorithms to the OIDs for
|
||||
// use with PKCS#1 signatures.
|
||||
@(rodata)
|
||||
PKCS1_HASH_OIDS := #partial [hash.Algorithm][]byte {
|
||||
// WARNING: Legacy verification ONLY.
|
||||
.Insecure_SHA1 = []byte{
|
||||
0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A,
|
||||
},
|
||||
.SHA224 = []byte{
|
||||
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
|
||||
},
|
||||
.SHA256 = []byte{
|
||||
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
|
||||
},
|
||||
.SHA384 = []byte{
|
||||
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
|
||||
},
|
||||
.SHA512 = []byte{
|
||||
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
|
||||
},
|
||||
.SHA512_256 = []byte{
|
||||
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06,
|
||||
},
|
||||
}
|
||||
|
||||
@(private="file", rodata)
|
||||
PKCS1_SELFTEST_DIGEST_SHA256 := []byte{
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
|
||||
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
|
||||
}
|
||||
|
||||
// verify_pkcs1 returns true if and only if (⟺) sig is a valid PKCS#1
|
||||
// signature by pub_key over msg, hased using hash_algo. If pre_hashed
|
||||
// is set to true, it is assumed that msg is already hashed.
|
||||
@(require_results)
|
||||
verify_pkcs1 :: proc(pub_key: ^Public_Key, hash_algo: hash.Algorithm, msg, sig: []byte, is_prehashed := false) -> bool {
|
||||
if !pub_key._is_initialized {
|
||||
return false
|
||||
}
|
||||
if len(sig) != modulus_len(&pub_key._n) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Lookup the OID.
|
||||
oid := PKCS1_HASH_OIDS[hash_algo]
|
||||
if oid == nil {
|
||||
return false
|
||||
}
|
||||
hash_len := hash.DIGEST_SIZES[hash_algo]
|
||||
|
||||
// Compute the message hash.
|
||||
msg_hash_buf: [hash.MAX_DIGEST_SIZE]byte = ---
|
||||
msg_hash: []byte
|
||||
switch is_prehashed {
|
||||
case true:
|
||||
if len(msg) != hash_len {
|
||||
return false
|
||||
}
|
||||
msg_hash = msg
|
||||
case false:
|
||||
msg_hash = hash.hash_bytes_to_buffer(hash_algo, msg, msg_hash_buf[:])
|
||||
}
|
||||
|
||||
// PKCS #1 V2.2 (RFC 8017) 8.2.2 specifies this as computing
|
||||
// and comparing the padded hash, with unpadding and extracting
|
||||
// the hash being an alternative. Upstream BearSSL implements
|
||||
// the latter, which is not a problem if done correctly (which
|
||||
// it does), however we will opt to go for implementing this
|
||||
// as specified as it is more robust against implementation
|
||||
// errors.
|
||||
|
||||
// Compute the expected hash.
|
||||
sig_buf, padded_hash_buf: [MODULUS_MAX_SIZE >> 3]byte = ---, ---
|
||||
if len(sig) > len(sig_buf) {
|
||||
return false
|
||||
}
|
||||
padded_hash_ := padded_hash_buf[:len(sig)]
|
||||
if pkcs1_sig_pad(oid, msg_hash, padded_hash_) != 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Compute the signature's padded hash.
|
||||
sig_ := sig_buf[:len(sig)]
|
||||
copy(sig_, sig)
|
||||
if public_modpow(sig_, pub_key) != 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
return bytes.equal(sig_, padded_hash_)
|
||||
}
|
||||
|
||||
// sign_pkcs1 returns true if and only if (⟺) it successfully writes
|
||||
// the PKCS#1 signature by priv_key over msg, hashed using hash_algo.
|
||||
// If pre_hashed is set to true, it is assumed that msg is already hashed.
|
||||
@(require_results)
|
||||
sign_pkcs1 :: proc(priv_key: ^Private_Key, hash_algo: hash.Algorithm, msg, sig: []byte, is_prehashed := false) -> bool {
|
||||
if !priv_key._is_initialized {
|
||||
return false
|
||||
}
|
||||
if len(sig) != modulus_len(&priv_key._pub_key._n) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Lookup the OID.
|
||||
oid := PKCS1_HASH_OIDS[hash_algo]
|
||||
if oid == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Compute the message hash.
|
||||
msg_hash_buf: [hash.MAX_DIGEST_SIZE]byte = ---
|
||||
msg_hash: []byte
|
||||
switch is_prehashed {
|
||||
case true:
|
||||
if len(msg) != hash.DIGEST_SIZES[hash_algo] {
|
||||
return false
|
||||
}
|
||||
msg_hash = msg
|
||||
case false:
|
||||
msg_hash = hash.hash_bytes_to_buffer(hash_algo, msg, msg_hash_buf[:])
|
||||
}
|
||||
|
||||
if pkcs1_sig_pad(oid, msg_hash, sig) != 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
return private_modpow(sig, priv_key) == 1
|
||||
}
|
||||
|
||||
@(private="file", require_results)
|
||||
pkcs1_sig_pad :: proc "contextless" (hash_oid, hash, x: []byte) -> u32 {
|
||||
// Padded hash value has format:
|
||||
// 00 01 FF .. FF 00 30 x1 30 x2 06 x3 OID 05 00 04 x4 HASH
|
||||
//
|
||||
// with the following rules:
|
||||
//
|
||||
// -- Total length is equal to the modulus length (unsigned
|
||||
// encoding).
|
||||
//
|
||||
// -- There must be at least eight bytes of value 0xFF.
|
||||
//
|
||||
// -- x4 is equal to the hash length (hash_len).
|
||||
//
|
||||
// -- x3 is equal to the encoded OID value length (hash_oid[0]).
|
||||
//
|
||||
// -- x2 = x3 + 4.
|
||||
//
|
||||
// -- x1 = x2 + x4 + 4 = x3 + x4 + 8.
|
||||
//
|
||||
// Note: the "05 00" is optional (signatures with and without
|
||||
// that sequence exist in practice), but notes in PKCS#1 seem to
|
||||
// indicate that the presence of that sequence (specifically,
|
||||
// an ASN.1 NULL value for the hash parameters) may be slightly
|
||||
// more "standard" than the opposite.
|
||||
xlen, hash_len := len(x), len(hash)
|
||||
|
||||
// Note/yawning: The hash OID is mandatory, as is the "05 00".
|
||||
x3 := hash_oid[0]
|
||||
|
||||
// Check that there is enough room for all the elements,
|
||||
// including at least eight bytes of value 0xFF.
|
||||
if xlen < int(x3) + hash_len + 21 {
|
||||
return 0
|
||||
}
|
||||
x[0] = 0x00
|
||||
x[1] = 0x01
|
||||
u := xlen - int(x3) - hash_len - 11
|
||||
for i in 2..< u {
|
||||
x[i] = 0xff
|
||||
}
|
||||
x[u] = 0x00
|
||||
x[u + 1] = 0x30
|
||||
x[u + 2] = x3 + byte(hash_len) + 8
|
||||
x[u + 3] = 0x30
|
||||
x[u + 4] = x3 + 4
|
||||
x[u + 5] = 0x06
|
||||
copy(x[u+6:], hash_oid)
|
||||
u += int(x3) + 7
|
||||
x[u] = 0x05
|
||||
u += 1
|
||||
x[u] = 0x00
|
||||
u += 1
|
||||
x[u] = 0x04
|
||||
u += 1
|
||||
x[u] = byte(hash_len)
|
||||
u += 1
|
||||
copy(x[u:], hash)
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
@(private)
|
||||
pkcs1_sig_selftest :: proc(priv_key: ^Private_Key) -> bool {
|
||||
sig_buf: [MODULUS_MAX_SIZE >> 3]byte = ---
|
||||
defer crypto.zero_explicit(&sig_buf, size_of(sig_buf))
|
||||
|
||||
sig := sig_buf[:private_key_size(priv_key)]
|
||||
if !sign_pkcs1(priv_key, .SHA256, PKCS1_SELFTEST_DIGEST_SHA256, sig, true) {
|
||||
return false
|
||||
}
|
||||
|
||||
return verify_pkcs1(&priv_key._pub_key, .SHA256, PKCS1_SELFTEST_DIGEST_SHA256, sig, true)
|
||||
}
|
||||
293
core/crypto/rsa/rsa_sig_pss.odin
Normal file
293
core/crypto/rsa/rsa_sig_pss.odin
Normal file
@@ -0,0 +1,293 @@
|
||||
package rsa
|
||||
|
||||
// Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “AS IS” AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import "base:intrinsics"
|
||||
import "core:crypto"
|
||||
import bigint "core:crypto/_bigint"
|
||||
import subtle "core:crypto/_subtle"
|
||||
import "core:crypto/hash"
|
||||
|
||||
// verify_pss returns true if and only if (⟺) sig is a valid PSS
|
||||
// signature by pub_key over msg, hashed using hash_algo, and MGF1
|
||||
// parameterized by mgf1_algo and salt_len. If mgf1_algo is
|
||||
// unspecified, hash_algo will be used. If pre_hashed is set
|
||||
// to true, it is assumed that msg is already hashed.
|
||||
@(require_results)
|
||||
verify_pss :: proc(
|
||||
pub_key: ^Public_Key,
|
||||
hash_algo: hash.Algorithm,
|
||||
salt_len: int,
|
||||
msg: []byte,
|
||||
sig: []byte,
|
||||
is_prehashed := false,
|
||||
mgf1_algo := hash.Algorithm.Invalid,
|
||||
) -> bool {
|
||||
if !pub_key._is_initialized {
|
||||
return false
|
||||
}
|
||||
if hash_algo == .Invalid {
|
||||
return false
|
||||
}
|
||||
mgf1_algo_ := mgf1_algo
|
||||
if mgf1_algo == .Invalid {
|
||||
mgf1_algo_ = hash_algo
|
||||
}
|
||||
if len(sig) != modulus_len(&pub_key._n) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Compute the message hash.
|
||||
msg_hash_buf: [hash.MAX_DIGEST_SIZE]byte = ---
|
||||
hash_len := hash.DIGEST_SIZES[hash_algo]
|
||||
msg_hash: []byte
|
||||
switch is_prehashed {
|
||||
case true:
|
||||
if len(msg) != hash_len {
|
||||
return false
|
||||
}
|
||||
msg_hash = msg
|
||||
case false:
|
||||
msg_hash = hash.hash_bytes_to_buffer(hash_algo, msg, msg_hash_buf[:])
|
||||
}
|
||||
|
||||
sig_buf: [MODULUS_MAX_SIZE >> 3]byte = ---
|
||||
sig_ := sig_buf[:len(sig)]
|
||||
copy(sig_, sig)
|
||||
if public_modpow(sig_, pub_key) != 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
return pss_sig_unpad(hash_algo, mgf1_algo_, msg_hash, salt_len, pub_key, sig_) == 1
|
||||
}
|
||||
|
||||
// sign_pss returns true if and only if (⟺) it successfully writes
|
||||
// the PKCS#1 signature by priv_key over msg, hashed using hash_algo, and
|
||||
// MGF1 parameterized by mgf1_algo and salt_len. If mgf1_algo is
|
||||
// unspecified, hash_algo will be used. If pre_hashed is set to true,
|
||||
// it is assumed that msg is already hashed. A reasonable choice for
|
||||
// salt_len is the digest size of hash_algo, and FIPS 140-3 mandates
|
||||
// that as the maximum permissible size.
|
||||
//
|
||||
// This routine will fail if the system entropy source is unavailable.
|
||||
@(require_results)
|
||||
sign_pss :: proc(
|
||||
priv_key: ^Private_Key,
|
||||
hash_algo: hash.Algorithm,
|
||||
salt_len: int,
|
||||
msg: []byte,
|
||||
sig: []byte,
|
||||
is_prehashed := false,
|
||||
mgf1_algo := hash.Algorithm.Invalid,
|
||||
) -> bool {
|
||||
if !priv_key._is_initialized {
|
||||
return false
|
||||
}
|
||||
if len(sig) != modulus_len(&priv_key._pub_key._n) {
|
||||
return false
|
||||
}
|
||||
if hash_algo == .Invalid {
|
||||
return false
|
||||
}
|
||||
mgf1_algo_ := mgf1_algo
|
||||
if mgf1_algo == .Invalid {
|
||||
mgf1_algo_ = hash_algo
|
||||
}
|
||||
if !crypto.HAS_RAND_BYTES && salt_len != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Compute the message hash.
|
||||
msg_hash_buf: [hash.MAX_DIGEST_SIZE]byte = ---
|
||||
hash_len := hash.DIGEST_SIZES[hash_algo]
|
||||
msg_hash: []byte
|
||||
switch is_prehashed {
|
||||
case true:
|
||||
if len(msg) != hash_len {
|
||||
return false
|
||||
}
|
||||
msg_hash = msg
|
||||
case false:
|
||||
msg_hash = hash.hash_bytes_to_buffer(hash_algo, msg, msg_hash_buf[:])
|
||||
}
|
||||
|
||||
// Work out the exact length of n in bits.
|
||||
n := modulus_bytes(&priv_key._pub_key._n)
|
||||
assert(len(n) > 0 && n[0] != 0)
|
||||
n_bitlen := int(bigint._u32_bit_length(u32(n[0]))) + (len(n) - 1) * 8
|
||||
|
||||
if pss_sig_pad(hash_algo, mgf1_algo_, msg_hash, salt_len, n_bitlen, sig) != 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
return private_modpow(sig, priv_key) == 1
|
||||
}
|
||||
|
||||
@(private="file", require_results)
|
||||
pss_sig_unpad :: proc(
|
||||
data_algo: hash.Algorithm,
|
||||
mgf1_algo: hash.Algorithm,
|
||||
digest: []byte,
|
||||
salt_len: int,
|
||||
pk: ^Public_Key,
|
||||
sig: []byte,
|
||||
) -> u32 {
|
||||
hash_len := hash.DIGEST_SIZES[data_algo]
|
||||
x := sig
|
||||
|
||||
// Value r will be set to a non-zero value is any test fails.
|
||||
r: u32
|
||||
|
||||
// The value bit length (as an integer) must be strictly less than
|
||||
// that of the modulus.
|
||||
//
|
||||
// Note/yawning: The modulus should already be the correct size,
|
||||
// with leading `0x00`s stripped.
|
||||
n := modulus_bytes(&pk._n)
|
||||
nlen := modulus_len(&pk._n)
|
||||
u: int
|
||||
for u = 0; u < nlen; u += 1 {
|
||||
if n[u] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if u == nlen {
|
||||
return 0
|
||||
}
|
||||
n_bitlen := bigint._u32_bit_length(u32(n[u])) + (u32(nlen - u - 1) << 3)
|
||||
n_bitlen -= 1
|
||||
if (n_bitlen & 7) == 0 {
|
||||
r |= u32(x[0])
|
||||
x = x[1:]
|
||||
} else {
|
||||
r |= u32(x[0] & (0xFF << (n_bitlen & 7)))
|
||||
}
|
||||
xlen := int((n_bitlen + 7) >> 3)
|
||||
|
||||
// Check that the modulus is large enough for the hash value
|
||||
// length combined with the intended salt length.
|
||||
if hash_len > xlen || salt_len > xlen || (hash_len + salt_len + 2) > xlen {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Check value of rightmost byte.
|
||||
r |= u32(x[xlen - 1] ~ 0xBC)
|
||||
|
||||
// Generate the mask and XOR it into the first bytes to reveal PS;
|
||||
// we must also mask out the leading bits.
|
||||
seed := x[xlen - hash_len - 1:]
|
||||
mgf1_xor(x[:xlen - hash_len - 1], mgf1_algo, seed[:hash_len])
|
||||
if (n_bitlen & 7) != 0 {
|
||||
x[0] &= 0xFF >> (8 - (n_bitlen & 7))
|
||||
}
|
||||
|
||||
// Check that all padding bytes have the expected value.
|
||||
for u = 0; u < (xlen - hash_len - salt_len - 2); u += 1 {
|
||||
r |= u32(x[u])
|
||||
}
|
||||
r |= u32(x[xlen - hash_len - salt_len - 2] ~ 0x01)
|
||||
|
||||
// Recompute H.
|
||||
salt := x[xlen - hash_len - salt_len - 1:]
|
||||
tmp: [hash.MAX_DIGEST_SIZE]byte
|
||||
h := tmp[:hash_len]
|
||||
ctx: hash.Context = ---
|
||||
hash.init(&ctx, data_algo)
|
||||
hash.update(&ctx, tmp[:8])
|
||||
hash.update(&ctx, digest)
|
||||
hash.update(&ctx, salt[:salt_len])
|
||||
hash.final(&ctx, h)
|
||||
|
||||
// Check that the recomputed H value matches the one appearing
|
||||
// in the string.
|
||||
x = x[xlen - hash_len - 1:]
|
||||
r |= subtle.eq0(u32(crypto.compare_constant_time(h, x[:hash_len])))
|
||||
|
||||
return subtle.eq0(r)
|
||||
}
|
||||
|
||||
@(private="file", require_results)
|
||||
pss_sig_pad :: proc(
|
||||
data_algo: hash.Algorithm,
|
||||
mgf1_algo: hash.Algorithm,
|
||||
digest: []byte,
|
||||
salt_len: int,
|
||||
n_bitlen_: int,
|
||||
sig: []byte,
|
||||
) -> u32 {
|
||||
x, n_bitlen := sig, n_bitlen_
|
||||
hash_len := hash.DIGEST_SIZES[data_algo]
|
||||
|
||||
// The padded string is one bit smaller than the modulus;
|
||||
// notably, if the modulus length is equal to 1 modulo 8, then
|
||||
// the padded string will be one _byte_ smaller, and the first
|
||||
// byte will be set to 0. We apply these transformations here.
|
||||
n_bitlen -= 1
|
||||
if (n_bitlen & 7) == 0 {
|
||||
x[0] = 0
|
||||
x = x[1:]
|
||||
}
|
||||
xlen := int((n_bitlen + 7) >> 3)
|
||||
|
||||
// Check that the modulus is large enough for the hash value
|
||||
// length combined with the intended salt length.
|
||||
if hash_len > xlen || salt_len > xlen || (hash_len + salt_len + 2) > xlen {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Produce a random salt.
|
||||
salt := x[xlen - hash_len - salt_len - 1:]
|
||||
salt = salt[:salt_len]
|
||||
if salt_len != 0 {
|
||||
crypto.rand_bytes(salt)
|
||||
}
|
||||
|
||||
// Compute the seed for MGF1.
|
||||
seed := x[xlen - hash_len - 1:]
|
||||
seed = seed[:hash_len]
|
||||
ctx: hash.Context = ---
|
||||
hash.init(&ctx, data_algo)
|
||||
intrinsics.mem_zero(raw_data(seed), 8)
|
||||
hash.update(&ctx, seed[:8])
|
||||
hash.update(&ctx, digest)
|
||||
hash.update(&ctx, salt)
|
||||
hash.final(&ctx, seed)
|
||||
|
||||
// Prepare string PS (padded salt). The salt is already at the
|
||||
// right place.
|
||||
intrinsics.mem_zero(raw_data(x), xlen - salt_len - hash_len - 2)
|
||||
x[xlen - salt_len - hash_len - 2] = 0x01
|
||||
|
||||
// Generate the mask and XOR it into PS.
|
||||
mgf1_xor(x[:xlen - hash_len - 1], mgf1_algo, seed)
|
||||
|
||||
// Clear the top bits to ensure the value is lower than the
|
||||
// modulus.
|
||||
x[0] &= 0xFF >> ((u32(xlen) << 3) - u32(n_bitlen))
|
||||
|
||||
// The seed (H) is already in the right place. We just set the
|
||||
// last byte.
|
||||
x[xlen - 1] = 0xBC
|
||||
|
||||
return 1
|
||||
}
|
||||
180
core/crypto/rsa/rsa_test_key.odin
Normal file
180
core/crypto/rsa/rsa_test_key.odin
Normal file
@@ -0,0 +1,180 @@
|
||||
package rsa
|
||||
|
||||
// private_key_set_insecure_test sets the private key to the
|
||||
// pregenerated INSECURE test key "testRSA2048" from RFC 9500 2.1.
|
||||
//
|
||||
// WARNING: This key MUST only be used for testing purposes.
|
||||
@(require_results)
|
||||
private_key_set_insecure_test :: proc(priv_key: ^Private_Key) -> bool {
|
||||
// RFC 9500 2.1 "testRSA2048"
|
||||
return private_key_set_bytes(
|
||||
priv_key,
|
||||
// n
|
||||
[]byte{
|
||||
0xB0, 0xF9, 0xE8, 0x19, 0x43, 0xA7, 0xAE, 0x98,
|
||||
0x92, 0xAA, 0xDE, 0x17, 0xCA, 0x7C, 0x40, 0xF8,
|
||||
0x74, 0x4F, 0xED, 0x2F, 0x81, 0x48, 0xE6, 0xC8,
|
||||
0xEA, 0xA2, 0x7B, 0x7D, 0x00, 0x15, 0x48, 0xFB,
|
||||
0x51, 0x92, 0xAB, 0x28, 0xB5, 0x6C, 0x50, 0x60,
|
||||
0xB1, 0x18, 0xCC, 0xD1, 0x31, 0xE5, 0x94, 0x87,
|
||||
0x4C, 0x6C, 0xA9, 0x89, 0xB5, 0x6C, 0x27, 0x29,
|
||||
0x6F, 0x09, 0xFB, 0x93, 0xA0, 0x34, 0xDF, 0x32,
|
||||
0xE9, 0x7C, 0x6F, 0xF0, 0x99, 0x8C, 0xFD, 0x8E,
|
||||
0x6F, 0x42, 0xDD, 0xA5, 0x8A, 0xCD, 0x1F, 0xA9,
|
||||
0x79, 0x86, 0xF1, 0x44, 0xF3, 0xD1, 0x54, 0xD6,
|
||||
0x76, 0x50, 0x17, 0x5E, 0x68, 0x54, 0xB3, 0xA9,
|
||||
0x52, 0x00, 0x3B, 0xC0, 0x68, 0x87, 0xB8, 0x45,
|
||||
0x5A, 0xC2, 0xB1, 0x9F, 0x7B, 0x2F, 0x76, 0x50,
|
||||
0x4E, 0xBC, 0x98, 0xEC, 0x94, 0x55, 0x71, 0xB0,
|
||||
0x78, 0x92, 0x15, 0x0D, 0xDC, 0x6A, 0x74, 0xCA,
|
||||
0x0F, 0xBC, 0xD3, 0x54, 0x97, 0xCE, 0x81, 0x53,
|
||||
0x4D, 0xAF, 0x94, 0x18, 0x84, 0x4B, 0x13, 0xAE,
|
||||
0xA3, 0x1F, 0x9D, 0x5A, 0x6B, 0x95, 0x57, 0xBB,
|
||||
0xDF, 0x61, 0x9E, 0xFD, 0x4E, 0x88, 0x7F, 0x2D,
|
||||
0x42, 0xB8, 0xDD, 0x8B, 0xC9, 0x87, 0xEA, 0xE1,
|
||||
0xBF, 0x89, 0xCA, 0xB8, 0x5E, 0xE2, 0x1E, 0x35,
|
||||
0x63, 0x05, 0xDF, 0x6C, 0x07, 0xA8, 0x83, 0x8E,
|
||||
0x3E, 0xF4, 0x1C, 0x59, 0x5D, 0xCC, 0xE4, 0x3D,
|
||||
0xAF, 0xC4, 0x91, 0x23, 0xEF, 0x4D, 0x8A, 0xBB,
|
||||
0xA9, 0x3D, 0x39, 0x05, 0xE4, 0x02, 0x8D, 0x7B,
|
||||
0xA9, 0x14, 0x84, 0xA2, 0x75, 0x96, 0xE0, 0x7B,
|
||||
0x4B, 0x6E, 0xD9, 0x92, 0xF0, 0x77, 0xB5, 0x24,
|
||||
0xD3, 0xDC, 0xFE, 0x7D, 0xDD, 0x55, 0x49, 0xBE,
|
||||
0x7C, 0xCE, 0x8D, 0xA0, 0x35, 0xCF, 0xA0, 0xB3,
|
||||
0xFB, 0x8F, 0x9E, 0x46, 0xF7, 0x32, 0xB2, 0xA8,
|
||||
0x6B, 0x46, 0x01, 0x65, 0xC0, 0x8F, 0x53, 0x13,
|
||||
},
|
||||
// e
|
||||
[]byte{0x01, 0x00, 0x01},
|
||||
// d
|
||||
[]byte{
|
||||
0x41, 0x18, 0x8B, 0x20, 0xCF, 0xDB, 0xDB, 0xC2,
|
||||
0xCF, 0x1F, 0xFE, 0x75, 0x2D, 0xCB, 0xAA, 0x72,
|
||||
0x39, 0x06, 0x35, 0x2E, 0x26, 0x15, 0xD4, 0x9D,
|
||||
0xCE, 0x80, 0x59, 0x7F, 0xCF, 0x0A, 0x05, 0x40,
|
||||
0x3B, 0xEF, 0x00, 0xFA, 0x06, 0x51, 0x82, 0xF7,
|
||||
0x2D, 0xEC, 0xFB, 0x59, 0x6F, 0x4B, 0x0C, 0xE8,
|
||||
0xFF, 0x59, 0x70, 0xBA, 0xF0, 0x7A, 0x89, 0xA5,
|
||||
0x19, 0xEC, 0xC8, 0x16, 0xB2, 0xF4, 0xFF, 0xAC,
|
||||
0x50, 0x69, 0xAF, 0x1B, 0x06, 0xBF, 0xEF, 0x7B,
|
||||
0xF6, 0xBC, 0xD7, 0x9E, 0x4E, 0x81, 0xC8, 0xC5,
|
||||
0xA3, 0xA7, 0xD9, 0x13, 0x0D, 0xC3, 0xCF, 0xBA,
|
||||
0xDA, 0xE5, 0xF6, 0xD2, 0x88, 0xF9, 0xAE, 0xE3,
|
||||
0xF6, 0xFF, 0x92, 0xFA, 0xE0, 0xF8, 0x1A, 0xF5,
|
||||
0x97, 0xBE, 0xC9, 0x6A, 0xE9, 0xFA, 0xB9, 0x40,
|
||||
0x2C, 0xD5, 0xFE, 0x41, 0xF7, 0x05, 0xBE, 0xBD,
|
||||
0xB4, 0x7B, 0xB7, 0x36, 0xD3, 0xFE, 0x6C, 0x5A,
|
||||
0x51, 0xE0, 0xE2, 0x07, 0x32, 0xA9, 0x7B, 0x5E,
|
||||
0x46, 0xC1, 0xCB, 0xDB, 0x26, 0xD7, 0x48, 0x54,
|
||||
0xC6, 0xB6, 0x60, 0x4A, 0xED, 0x46, 0x37, 0x35,
|
||||
0xFF, 0x90, 0x76, 0x04, 0x65, 0x57, 0xCA, 0xF9,
|
||||
0x49, 0xBF, 0x44, 0x88, 0x95, 0xC2, 0x04, 0x32,
|
||||
0xC1, 0xE0, 0x9C, 0x01, 0x4E, 0xA7, 0x56, 0x60,
|
||||
0x43, 0x4F, 0x1A, 0x0F, 0x3B, 0xE2, 0x94, 0xBA,
|
||||
0xBC, 0x5D, 0x53, 0x0E, 0x6A, 0x10, 0x21, 0x3F,
|
||||
0x53, 0xB6, 0x03, 0x75, 0xFC, 0x84, 0xA7, 0x57,
|
||||
0x3F, 0x2A, 0xF1, 0x21, 0x55, 0x84, 0xF5, 0xB4,
|
||||
0xBD, 0xA6, 0xD4, 0xE8, 0xF9, 0xE1, 0x7A, 0x78,
|
||||
0xD9, 0x7E, 0x77, 0xB8, 0x6D, 0xA4, 0xA1, 0x84,
|
||||
0x64, 0x75, 0x31, 0x8A, 0x7A, 0x10, 0xA5, 0x61,
|
||||
0x01, 0x4E, 0xFF, 0xA2, 0x3A, 0x81, 0xEC, 0x56,
|
||||
0xE9, 0xE4, 0x10, 0x9D, 0xEF, 0x8C, 0xB3, 0xF7,
|
||||
0x97, 0x22, 0x3F, 0x7D, 0x8D, 0x0D, 0x43, 0x51,
|
||||
},
|
||||
// p
|
||||
[]byte{
|
||||
0xDD, 0x10, 0x57, 0x02, 0x38, 0x2F, 0x23, 0x2B,
|
||||
0x36, 0x81, 0xF5, 0x37, 0x91, 0xE2, 0x26, 0x17,
|
||||
0xC7, 0xBF, 0x4E, 0x9A, 0xCB, 0x81, 0xED, 0x48,
|
||||
0xDA, 0xF6, 0xD6, 0x99, 0x5D, 0xA3, 0xEA, 0xB6,
|
||||
0x42, 0x83, 0x9A, 0xFF, 0x01, 0x2D, 0x2E, 0xA6,
|
||||
0x28, 0xB9, 0x0A, 0xF2, 0x79, 0xFD, 0x3E, 0x6F,
|
||||
0x7C, 0x93, 0xCD, 0x80, 0xF0, 0x72, 0xF0, 0x1F,
|
||||
0xF2, 0x44, 0x3B, 0x3E, 0xE8, 0xF2, 0x4E, 0xD4,
|
||||
0x69, 0xA7, 0x96, 0x13, 0xA4, 0x1B, 0xD2, 0x40,
|
||||
0x20, 0xF9, 0x2F, 0xD1, 0x10, 0x59, 0xBD, 0x1D,
|
||||
0x0F, 0x30, 0x1B, 0x5B, 0xA7, 0xA9, 0xD3, 0x63,
|
||||
0x7C, 0xA8, 0xD6, 0x5C, 0x1A, 0x98, 0x15, 0x41,
|
||||
0x7D, 0x8E, 0xAB, 0x73, 0x4B, 0x0B, 0x4F, 0x3A,
|
||||
0x2C, 0x66, 0x1D, 0x9A, 0x1A, 0x82, 0xF3, 0xAC,
|
||||
0x73, 0x4C, 0x40, 0x53, 0x06, 0x69, 0xAB, 0x8E,
|
||||
0x47, 0x30, 0x45, 0xA5, 0x8E, 0x65, 0x53, 0x9D,
|
||||
},
|
||||
// q
|
||||
[]byte{
|
||||
0xCC, 0xF1, 0xE5, 0xBB, 0x90, 0xC8, 0xE9, 0x78,
|
||||
0x1E, 0xA7, 0x5B, 0xEB, 0xF1, 0x0B, 0xC2, 0x52,
|
||||
0xE1, 0x1E, 0xB0, 0x23, 0xA0, 0x26, 0x0F, 0x18,
|
||||
0x87, 0x55, 0x2A, 0x56, 0x86, 0x3F, 0x4A, 0x64,
|
||||
0x21, 0xE8, 0xC6, 0x00, 0xBF, 0x52, 0x3D, 0x6C,
|
||||
0xB1, 0xB0, 0xAD, 0xBD, 0xD6, 0x5B, 0xFE, 0xE4,
|
||||
0xA8, 0x8A, 0x03, 0x7E, 0x3D, 0x1A, 0x41, 0x5E,
|
||||
0x5B, 0xB9, 0x56, 0x48, 0xDA, 0x5A, 0x0C, 0xA2,
|
||||
0x6B, 0x54, 0xF4, 0xA6, 0x39, 0x48, 0x52, 0x2C,
|
||||
0x3D, 0x5F, 0x89, 0xB9, 0x4A, 0x72, 0xEF, 0xFF,
|
||||
0x95, 0x13, 0x4D, 0x59, 0x40, 0xCE, 0x45, 0x75,
|
||||
0x8F, 0x30, 0x89, 0x80, 0x90, 0x89, 0x56, 0x58,
|
||||
0x8E, 0xEF, 0x57, 0x5B, 0x3E, 0x4B, 0xC4, 0xC3,
|
||||
0x68, 0xCF, 0xE8, 0x13, 0xEE, 0x9C, 0x25, 0x2C,
|
||||
0x2B, 0x02, 0xE0, 0xDF, 0x91, 0xF1, 0xAA, 0x01,
|
||||
0x93, 0x8D, 0x38, 0x68, 0x5D, 0x60, 0xBA, 0x6F,
|
||||
},
|
||||
// dp
|
||||
[]byte{
|
||||
0x09, 0xED, 0x54, 0xEA, 0xED, 0x98, 0xF8, 0x4C,
|
||||
0x55, 0x7B, 0x4A, 0x86, 0xBF, 0x4F, 0x57, 0x84,
|
||||
0x93, 0xDC, 0xBC, 0x6B, 0xE9, 0x1D, 0xA1, 0x89,
|
||||
0x37, 0x04, 0x04, 0xA9, 0x08, 0x72, 0x76, 0xF4,
|
||||
0xCE, 0x51, 0xD8, 0xA1, 0x00, 0xED, 0x85, 0x7D,
|
||||
0xC2, 0xB0, 0x64, 0x94, 0x74, 0xF3, 0xF1, 0x5C,
|
||||
0xD2, 0x4C, 0x54, 0xDB, 0x28, 0x71, 0x10, 0xE5,
|
||||
0x6E, 0x5C, 0xB0, 0x08, 0x68, 0x2F, 0x91, 0x68,
|
||||
0xAA, 0x81, 0xF3, 0x14, 0x58, 0xB7, 0x43, 0x1E,
|
||||
0xCC, 0x1C, 0x44, 0x90, 0x6F, 0xDA, 0x87, 0xCA,
|
||||
0x89, 0x47, 0x10, 0xC3, 0x71, 0xE9, 0x07, 0x6C,
|
||||
0x1D, 0x49, 0xFB, 0xAE, 0x51, 0x27, 0x69, 0x34,
|
||||
0xF2, 0xAD, 0x78, 0x77, 0x89, 0xF4, 0x2D, 0x0F,
|
||||
0xA0, 0xB4, 0xC9, 0x39, 0x85, 0x5D, 0x42, 0x12,
|
||||
0x09, 0x6F, 0x70, 0x28, 0x0A, 0x4E, 0xAE, 0x7C,
|
||||
0x8A, 0x27, 0xD9, 0xC8, 0xD0, 0x77, 0x2E, 0x65,
|
||||
},
|
||||
// dq
|
||||
[]byte{
|
||||
0x8C, 0xB6, 0x85, 0x7A, 0x7B, 0xD5, 0x46, 0x5F,
|
||||
0x80, 0x04, 0x7E, 0x9B, 0x87, 0xBC, 0x00, 0x27,
|
||||
0x31, 0x84, 0x05, 0x81, 0xE0, 0x62, 0x61, 0x39,
|
||||
0x01, 0x2A, 0x5B, 0x50, 0x5F, 0x0A, 0x33, 0x84,
|
||||
0x7E, 0xB7, 0xB8, 0xC3, 0x28, 0x99, 0x49, 0xAD,
|
||||
0x48, 0x6F, 0x3B, 0x4B, 0x3D, 0x53, 0x9A, 0xB5,
|
||||
0xDA, 0x76, 0x30, 0x21, 0xCB, 0xC8, 0x2C, 0x1B,
|
||||
0xA2, 0x34, 0xA5, 0x66, 0x8D, 0xED, 0x08, 0x01,
|
||||
0xB8, 0x59, 0xF3, 0x43, 0xF1, 0xCE, 0x93, 0x04,
|
||||
0xE6, 0xFA, 0xA2, 0xB0, 0x02, 0xCA, 0xD9, 0xB7,
|
||||
0x8C, 0xDE, 0x5C, 0xDC, 0x2C, 0x1F, 0xB4, 0x17,
|
||||
0x1C, 0x42, 0x42, 0x16, 0x70, 0xA6, 0xAB, 0x0F,
|
||||
0x50, 0xCC, 0x4A, 0x19, 0x4E, 0xB3, 0x6D, 0x1C,
|
||||
0x91, 0xE9, 0x35, 0xBA, 0x01, 0xB9, 0x59, 0xD8,
|
||||
0x72, 0x8B, 0x9E, 0x64, 0x42, 0x6B, 0x3F, 0xC3,
|
||||
0xA7, 0x50, 0x6D, 0xEB, 0x52, 0x39, 0xA8, 0xA7,
|
||||
},
|
||||
// iq (aka u)
|
||||
[]byte{
|
||||
0x0A, 0x81, 0xD8, 0xA6, 0x18, 0x31, 0x4A, 0x80,
|
||||
0x3A, 0xF6, 0x1C, 0x06, 0x71, 0x1F, 0x2C, 0x39,
|
||||
0xB2, 0x66, 0xFF, 0x41, 0x4D, 0x53, 0x47, 0x6D,
|
||||
0x1D, 0xA5, 0x2A, 0x43, 0x18, 0xAA, 0xFE, 0x4B,
|
||||
0x96, 0xF0, 0xDA, 0x07, 0x15, 0x5F, 0x8A, 0x51,
|
||||
0x34, 0xDA, 0xB8, 0x8E, 0xE2, 0x9E, 0x81, 0x68,
|
||||
0x07, 0x6F, 0xCD, 0x78, 0xCA, 0x79, 0x1A, 0xC6,
|
||||
0x34, 0x42, 0xA8, 0x1C, 0xD0, 0x69, 0x39, 0x27,
|
||||
0xD8, 0x08, 0xE3, 0x35, 0xE8, 0xD8, 0xCB, 0xF2,
|
||||
0x12, 0x19, 0x07, 0x50, 0x9A, 0x57, 0x75, 0x9B,
|
||||
0x4F, 0x9A, 0x18, 0xFA, 0x3A, 0x7B, 0x33, 0x37,
|
||||
0x79, 0xED, 0xDE, 0x7A, 0x45, 0x93, 0x84, 0xF8,
|
||||
0x44, 0x4A, 0xDA, 0xEC, 0xFF, 0xEC, 0x95, 0xFD,
|
||||
0x55, 0x2B, 0x0C, 0xFC, 0xB6, 0xC7, 0xF6, 0x92,
|
||||
0x62, 0x6D, 0xDE, 0x1E, 0xF2, 0x68, 0xA4, 0x0D,
|
||||
0x2F, 0x67, 0xB5, 0xC8, 0xAA, 0x38, 0x7F, 0xF7,
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -411,12 +411,13 @@ _decode_bytes :: proc(d: Decoder, add: Add, type: Major = .Bytes, allocator := c
|
||||
io.copy_n(buf_stream, d.reader, i64(n)) or_return
|
||||
}
|
||||
|
||||
v = buf.buf[:]
|
||||
|
||||
// Write zero byte so this can be converted to cstring.
|
||||
strings.write_byte(&buf, 0)
|
||||
|
||||
if .Shrink_Excess in d.flags { shrink(&buf.buf) }
|
||||
|
||||
v = buf.buf[:len(buf.buf)-1]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -884,4 +885,4 @@ _encode_deterministic_f64 :: proc(w: io.Writer, v: f64) -> io.Error {
|
||||
}
|
||||
|
||||
return _encode_f64_exact(w, v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,7 +509,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
|
||||
case reflect.Type_Info_Slice:
|
||||
length, scap := err_conv(_decode_len_container(d, add)) or_return
|
||||
|
||||
data := mem.alloc_bytes_non_zeroed(t.elem.size * scap, t.elem.align, allocator=allocator, loc=loc) or_return
|
||||
data := mem.alloc_bytes(t.elem.size * scap, t.elem.align, allocator=allocator, loc=loc) or_return
|
||||
defer if err != nil { mem.free_bytes(data, allocator=allocator, loc=loc) }
|
||||
|
||||
da := mem.Raw_Dynamic_Array{raw_data(data), 0, scap, context.allocator }
|
||||
@@ -529,7 +529,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
|
||||
case reflect.Type_Info_Dynamic_Array:
|
||||
length, scap := err_conv(_decode_len_container(d, add)) or_return
|
||||
|
||||
data := mem.alloc_bytes_non_zeroed(t.elem.size * scap, t.elem.align, loc=loc) or_return
|
||||
data := mem.alloc_bytes(t.elem.size * scap, t.elem.align, loc=loc) or_return
|
||||
defer if err != nil { mem.free_bytes(data, allocator=allocator, loc=loc) }
|
||||
|
||||
raw := (^mem.Raw_Dynamic_Array)(v.data)
|
||||
|
||||
@@ -146,6 +146,7 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
|
||||
for i in 0..<count {
|
||||
write_rune(&builder, decoded[i])
|
||||
}
|
||||
prev = decoded[count - 1]
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +134,7 @@ register_user_marshaler :: proc(id: typeid, marshaler: User_Marshaler) -> Regist
|
||||
return .None
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Marshal_Error) {
|
||||
b := strings.builder_make(allocator, loc)
|
||||
defer if err != nil {
|
||||
|
||||
68
core/encoding/json/match.odin
Normal file
68
core/encoding/json/match.odin
Normal file
@@ -0,0 +1,68 @@
|
||||
package encoding_json
|
||||
|
||||
Match_Key_Variant :: union #no_nil {
|
||||
int, // Index
|
||||
string, // Key
|
||||
}
|
||||
|
||||
Match_Error :: enum {
|
||||
None,
|
||||
Invalid_Argument,
|
||||
Invalid_Type_For_Index,
|
||||
Invalid_Type_For_Key,
|
||||
Key_Not_Found,
|
||||
Out_Of_Bounds_Index,
|
||||
}
|
||||
|
||||
Match_Flags :: distinct bit_set[Match_Flag]
|
||||
Match_Flag :: enum {
|
||||
Ignore_Key_Not_Found,
|
||||
Allow_String_Indexing_By_Byte,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
match :: proc(value: Value, args: ..Match_Key_Variant, flags: Match_Flags = nil) -> (found: Value, err: Match_Error) {
|
||||
found = value
|
||||
arg_loop: for arg in args {
|
||||
switch k in arg {
|
||||
case int:
|
||||
#partial switch v in found {
|
||||
case Array:
|
||||
if 0 <= k && k < len(v) {
|
||||
found = v[k]
|
||||
continue arg_loop
|
||||
}
|
||||
err = .Out_Of_Bounds_Index
|
||||
return
|
||||
case String:
|
||||
if .Allow_String_Indexing_By_Byte in flags {
|
||||
if 0 <= k && k < len(v) {
|
||||
found = Integer(v[k])
|
||||
continue arg_loop
|
||||
}
|
||||
err = .Out_Of_Bounds_Index
|
||||
return
|
||||
}
|
||||
}
|
||||
err = .Invalid_Type_For_Index
|
||||
return
|
||||
case string:
|
||||
v, ok := found.(Object)
|
||||
if !ok {
|
||||
err = .Invalid_Type_For_Key
|
||||
return
|
||||
}
|
||||
vfound, vok := v[k]
|
||||
if vok || (.Ignore_Key_Not_Found in flags) {
|
||||
found = vfound
|
||||
continue arg_loop
|
||||
}
|
||||
err = .Key_Not_Found
|
||||
return
|
||||
case:
|
||||
err = .Invalid_Argument
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -14,9 +14,16 @@ Parser :: struct {
|
||||
parse_integers: bool,
|
||||
}
|
||||
|
||||
make_parser :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator) -> Parser {
|
||||
make_parser :: proc{
|
||||
make_parser_from_bytes,
|
||||
make_parser_from_string,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
make_parser_from_bytes :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator) -> Parser {
|
||||
return make_parser_from_string(string(data), spec, parse_integers, allocator)
|
||||
}
|
||||
@(require_results)
|
||||
make_parser_from_string :: proc(data: string, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator) -> Parser {
|
||||
p: Parser
|
||||
p.tok = make_tokenizer(data, spec, parse_integers)
|
||||
@@ -27,11 +34,18 @@ make_parser_from_string :: proc(data: string, spec := DEFAULT_SPECIFICATION, par
|
||||
return p
|
||||
}
|
||||
|
||||
parse :: proc{
|
||||
parse_bytes,
|
||||
parse_string,
|
||||
}
|
||||
|
||||
parse :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator, loc := #caller_location) -> (Value, Error) {
|
||||
|
||||
@(require_results)
|
||||
parse_bytes :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator, loc := #caller_location) -> (Value, Error) {
|
||||
return parse_string(string(data), spec, parse_integers, allocator, loc)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
parse_string :: proc(data: string, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator, loc := #caller_location) -> (Value, Error) {
|
||||
context.allocator = allocator
|
||||
p := make_parser_from_string(data, spec, parse_integers, allocator)
|
||||
@@ -51,6 +65,7 @@ parse_string :: proc(data: string, spec := DEFAULT_SPECIFICATION, parse_integers
|
||||
return parse_object(&p, loc)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
token_end_pos :: proc(tok: Token) -> Pos {
|
||||
end := tok.pos
|
||||
end.offset += len(tok.text)
|
||||
@@ -65,6 +80,7 @@ advance_token :: proc(p: ^Parser) -> (Token, Error) {
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
allow_token :: proc(p: ^Parser, kind: Token_Kind) -> bool {
|
||||
if p.curr_token.kind == kind {
|
||||
advance_token(p)
|
||||
@@ -73,6 +89,7 @@ allow_token :: proc(p: ^Parser, kind: Token_Kind) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
expect_token :: proc(p: ^Parser, kind: Token_Kind) -> Error {
|
||||
prev := p.curr_token
|
||||
advance_token(p)
|
||||
@@ -83,6 +100,7 @@ expect_token :: proc(p: ^Parser, kind: Token_Kind) -> Error {
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
parse_colon :: proc(p: ^Parser) -> (err: Error) {
|
||||
colon_err := expect_token(p, .Colon)
|
||||
if colon_err == nil {
|
||||
@@ -91,6 +109,7 @@ parse_colon :: proc(p: ^Parser) -> (err: Error) {
|
||||
return .Expected_Colon_After_Key
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
parse_comma :: proc(p: ^Parser) -> (do_break: bool) {
|
||||
switch p.spec {
|
||||
case .JSON5, .MJSON:
|
||||
@@ -106,6 +125,7 @@ parse_comma :: proc(p: ^Parser) -> (do_break: bool) {
|
||||
return false
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
parse_value :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err: Error) {
|
||||
err = .None
|
||||
token := p.curr_token
|
||||
@@ -176,6 +196,7 @@ parse_value :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err:
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
parse_array :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err: Error) {
|
||||
err = .None
|
||||
expect_token(p, .Open_Bracket) or_return
|
||||
@@ -203,7 +224,7 @@ parse_array :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err:
|
||||
return
|
||||
}
|
||||
|
||||
@(private)
|
||||
@(private, require_results)
|
||||
bytes_make :: proc(size, alignment: int, allocator: mem.Allocator, loc := #caller_location) -> (bytes: []byte, err: Error) {
|
||||
b, berr := mem.alloc_bytes(size, alignment, allocator, loc)
|
||||
if berr != nil {
|
||||
@@ -217,6 +238,7 @@ bytes_make :: proc(size, alignment: int, allocator: mem.Allocator, loc := #calle
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
clone_string :: proc(s: string, allocator: mem.Allocator, loc := #caller_location) -> (str: string, err: Error) {
|
||||
n := len(s)
|
||||
b := bytes_make(n+1, 1, allocator, loc) or_return
|
||||
@@ -228,6 +250,7 @@ clone_string :: proc(s: string, allocator: mem.Allocator, loc := #caller_locatio
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
parse_object_key :: proc(p: ^Parser, key_allocator: mem.Allocator, loc := #caller_location) -> (key: string, err: Error) {
|
||||
tok := p.curr_token
|
||||
if p.spec != .JSON {
|
||||
@@ -242,6 +265,7 @@ parse_object_key :: proc(p: ^Parser, key_allocator: mem.Allocator, loc := #calle
|
||||
return unquote_string(tok, p.spec, key_allocator, loc)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
parse_object_body :: proc(p: ^Parser, end_token: Token_Kind, loc := #caller_location) -> (obj: Object, err: Error) {
|
||||
obj = make(Object, allocator=p.allocator, loc=loc)
|
||||
|
||||
@@ -282,6 +306,7 @@ parse_object_body :: proc(p: ^Parser, end_token: Token_Kind, loc := #caller_loca
|
||||
return obj, .None
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
parse_object :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err: Error) {
|
||||
expect_token(p, .Open_Brace) or_return
|
||||
obj := parse_object_body(p, .Close_Brace, loc) or_return
|
||||
@@ -291,6 +316,7 @@ parse_object :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err:
|
||||
|
||||
|
||||
// IMPORTANT NOTE(bill): unquote_string assumes a mostly valid string
|
||||
@(require_results)
|
||||
unquote_string :: proc(token: Token, spec: Specification, allocator := context.allocator, loc := #caller_location) -> (value: string, err: Error) {
|
||||
get_u2_rune :: proc(s: string) -> rune {
|
||||
if len(s) < 4 || s[0] != '\\' || s[1] != 'x' {
|
||||
|
||||
@@ -49,11 +49,12 @@ Tokenizer :: struct {
|
||||
curr_line_offset: int,
|
||||
spec: Specification,
|
||||
parse_integers: bool,
|
||||
insert_comma: bool,
|
||||
insert_comma: bool,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(require_results)
|
||||
make_tokenizer :: proc(data: string, spec := DEFAULT_SPECIFICATION, parse_integers := false) -> Tokenizer {
|
||||
t := Tokenizer{pos = {line=1}, data = data, spec = spec, parse_integers = parse_integers}
|
||||
next_rune(&t)
|
||||
@@ -78,6 +79,7 @@ next_rune :: proc(t: ^Tokenizer) -> rune #no_bounds_check {
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
skip_digits :: proc(t: ^Tokenizer) {
|
||||
for t.offset < len(t.data) {
|
||||
@@ -101,6 +103,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
}
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
scan_escape :: proc(t: ^Tokenizer) -> bool {
|
||||
switch t.r {
|
||||
case '"', '\'', '\\', '/', 'b', 'n', 'r', 't', 'f':
|
||||
@@ -125,7 +128,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
return false
|
||||
}
|
||||
|
||||
skip_whitespace :: proc(t: ^Tokenizer, on_newline: bool) -> rune {
|
||||
skip_whitespace :: proc(t: ^Tokenizer, on_newline: bool) {
|
||||
loop: for t.offset < len(t.data) {
|
||||
switch t.r {
|
||||
case ' ', '\t', '\v', '\f', '\r':
|
||||
@@ -149,7 +152,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
break loop
|
||||
}
|
||||
}
|
||||
return t.r
|
||||
return
|
||||
}
|
||||
|
||||
skip_to_next_line :: proc(t: ^Tokenizer) {
|
||||
@@ -310,7 +313,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
break
|
||||
}
|
||||
if r == '\\' {
|
||||
scan_escape(t)
|
||||
_ = scan_escape(t)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,10 +350,8 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
case '*':
|
||||
// None-nested multi-line comments
|
||||
for t.offset < len(t.data) {
|
||||
next_rune(t)
|
||||
if t.r == '*' {
|
||||
next_rune(t)
|
||||
if t.r == '/' {
|
||||
if next_rune(t) == '*' {
|
||||
if next_rune(t) == '/' {
|
||||
next_rune(t)
|
||||
return get_token(t)
|
||||
}
|
||||
@@ -385,6 +386,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
|
||||
|
||||
|
||||
@(require_results)
|
||||
is_valid_number :: proc(str: string, spec: Specification) -> bool {
|
||||
s := str
|
||||
if s == "" {
|
||||
@@ -473,6 +475,7 @@ is_valid_number :: proc(str: string, spec: Specification) -> bool {
|
||||
return s == ""
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
is_valid_string_literal :: proc(str: string, spec: Specification) -> bool {
|
||||
s := str
|
||||
if len(s) < 2 {
|
||||
|
||||
@@ -112,6 +112,7 @@ destroy_value :: proc(value: Value, allocator := context.allocator, loc := #call
|
||||
}
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
clone_value :: proc(value: Value, allocator := context.allocator) -> Value {
|
||||
value := value
|
||||
context.allocator = allocator
|
||||
|
||||
@@ -635,7 +635,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
||||
defer p.allocator = allocator
|
||||
p.allocator = mem.nil_allocator()
|
||||
|
||||
parse_value(p) or_return
|
||||
_ = parse_value(p) or_return
|
||||
if parse_comma(p) {
|
||||
break struct_loop
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package encoding_json
|
||||
import "core:mem"
|
||||
|
||||
// NOTE(bill): is_valid will not check for duplicate keys
|
||||
@(require_results)
|
||||
is_valid :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false) -> bool {
|
||||
p := make_parser(data, spec, parse_integers, mem.nil_allocator())
|
||||
|
||||
@@ -21,6 +22,7 @@ is_valid :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers :=
|
||||
return validate_object(&p)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
validate_object_key :: proc(p: ^Parser) -> bool {
|
||||
if p.spec != .JSON {
|
||||
if allow_token(p, .Ident) {
|
||||
@@ -31,6 +33,7 @@ validate_object_key :: proc(p: ^Parser) -> bool {
|
||||
return err == .None
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
validate_object_body :: proc(p: ^Parser, end_token: Token_Kind) -> bool {
|
||||
for p.curr_token.kind != end_token {
|
||||
if !validate_object_key(p) {
|
||||
@@ -48,6 +51,7 @@ validate_object_body :: proc(p: ^Parser, end_token: Token_Kind) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
validate_object :: proc(p: ^Parser) -> bool {
|
||||
if err := expect_token(p, .Open_Brace); err != .None {
|
||||
return false
|
||||
@@ -61,6 +65,7 @@ validate_object :: proc(p: ^Parser) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
validate_array :: proc(p: ^Parser) -> bool {
|
||||
if err := expect_token(p, .Open_Bracket); err != .None {
|
||||
return false
|
||||
@@ -83,6 +88,7 @@ validate_array :: proc(p: ^Parser) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
validate_value :: proc(p: ^Parser) -> bool {
|
||||
token := p.curr_token
|
||||
|
||||
|
||||
@@ -244,27 +244,18 @@ quaternion_mul_quaternion :: proc "contextless" (q1, q2: $Q) -> Q where IS_QUATE
|
||||
|
||||
@(require_results)
|
||||
quaternion64_mul_vector3 :: proc "contextless" (q: $Q/quaternion64, v: $V/[3]$F/f16) -> V {
|
||||
q := transmute(runtime.Raw_Quaternion64_Vector_Scalar)q
|
||||
v := v
|
||||
|
||||
t := cross(2*q.vector, v)
|
||||
return V(v + q.scalar*t + cross(q.vector, t))
|
||||
t := cross(2*q.xyz, v)
|
||||
return V(v + q.w*t + cross(q.xyz, t))
|
||||
}
|
||||
@(require_results)
|
||||
quaternion128_mul_vector3 :: proc "contextless" (q: $Q/quaternion128, v: $V/[3]$F/f32) -> V {
|
||||
q := transmute(runtime.Raw_Quaternion128_Vector_Scalar)q
|
||||
v := v
|
||||
|
||||
t := cross(2*q.vector, v)
|
||||
return V(v + q.scalar*t + cross(q.vector, t))
|
||||
t := cross(2*q.xyz, v)
|
||||
return V(v + q.w*t + cross(q.xyz, t))
|
||||
}
|
||||
@(require_results)
|
||||
quaternion256_mul_vector3 :: proc "contextless" (q: $Q/quaternion256, v: $V/[3]$F/f64) -> V {
|
||||
q := transmute(runtime.Raw_Quaternion256_Vector_Scalar)q
|
||||
v := v
|
||||
|
||||
t := cross(2*q.vector, v)
|
||||
return V(v + q.scalar*t + cross(q.vector, t))
|
||||
t := cross(2*q.xyz, v)
|
||||
return V(v + q.w*t + cross(q.xyz, t))
|
||||
}
|
||||
quaternion_mul_vector3 :: proc{quaternion64_mul_vector3, quaternion128_mul_vector3, quaternion256_mul_vector3}
|
||||
|
||||
|
||||
@@ -1044,8 +1044,8 @@ Example:
|
||||
|
||||
Possible Output:
|
||||
|
||||
[7201011, 3, 9123, 231131]
|
||||
[19578, 910081, 131, 7]
|
||||
[3, 2, 0, 1]
|
||||
[1, 0, 2, 3]
|
||||
|
||||
*/
|
||||
@(require_results)
|
||||
|
||||
@@ -381,6 +381,9 @@ advance_token :: proc(p: ^Parser) -> tokenizer.Token {
|
||||
#partial switch p.curr_tok.kind {
|
||||
case .Comment:
|
||||
consume_comment_groups(p, prev)
|
||||
if p.curr_tok.kind == .Semicolon && p.expr_level > 0 && p.curr_tok.text == "\n" {
|
||||
advance_token(p)
|
||||
}
|
||||
case .Semicolon:
|
||||
if p.expr_level > 0 && p.curr_tok.text == "\n" {
|
||||
advance_token(p)
|
||||
@@ -3622,7 +3625,9 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr {
|
||||
case .If, .When:
|
||||
if p.prev_tok.pos.line < op.pos.line {
|
||||
// NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition
|
||||
break loop
|
||||
if p.expr_level <= 0 {
|
||||
break loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -536,7 +536,7 @@ is_directory :: proc(path: string) -> bool {
|
||||
}
|
||||
|
||||
/*
|
||||
`copy_file` copies a file from `src_path` to `dst_path` and returns an error if any was encountered.
|
||||
`is_tty` returns `true` if `f` is a TTY, `false` if not.
|
||||
*/
|
||||
@(require_results)
|
||||
is_tty :: proc "contextless" (f: ^File) -> bool {
|
||||
|
||||
@@ -263,8 +263,8 @@ _ram_stats :: proc "contextless" () -> (total_ram, free_ram, total_swap, free_sw
|
||||
|
||||
total_ram = i64(state.ullTotalPhys)
|
||||
free_ram = i64(state.ullAvailPhys)
|
||||
total_swap = i64(state.ullTotalPageFil)
|
||||
free_swap = i64(state.ullAvailPageFil)
|
||||
total_swap = i64(state.ullTotalPageFile)
|
||||
free_swap = i64(state.ullAvailPageFile)
|
||||
ok = true
|
||||
|
||||
return
|
||||
|
||||
@@ -4802,8 +4802,8 @@ MEMORYSTATUSEX :: struct {
|
||||
dwMemoryLoad: DWORD,
|
||||
ullTotalPhys: DWORDLONG,
|
||||
ullAvailPhys: DWORDLONG,
|
||||
ullTotalPageFil: DWORDLONG,
|
||||
ullAvailPageFil: DWORDLONG,
|
||||
ullTotalPageFile: DWORDLONG,
|
||||
ullAvailPageFile: DWORDLONG,
|
||||
ullTotalVirtual: DWORDLONG,
|
||||
ullAvailVirtual: DWORDLONG,
|
||||
ullAvailExtendedVirtual: DWORDLONG,
|
||||
|
||||
@@ -65,7 +65,7 @@ Capable of representing any time within the following range:
|
||||
- `max: 2262-04-11 23:47:16.854775807 +0000 UTC`
|
||||
*/
|
||||
Time :: struct {
|
||||
_nsec: i64, // Measured in UNIX nanonseconds
|
||||
_nsec: i64, // Measured in UNIX nanoseconds
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user