Merge remote-tracking branch 'offical/master'

This commit is contained in:
ed
2024-04-14 19:42:56 -04:00
126 changed files with 5082 additions and 561 deletions
+5 -1
View File
@@ -1,2 +1,6 @@
*.odin linguist-language=Odin *.odin linguist-language=Odin
* text=auto * text=auto
# These files must always have *nix line-endings
Makefile text eol=lf
*.sh text eol=lf
+5 -3
View File
@@ -38,9 +38,9 @@ count_leading_zeros :: proc(x: $T) -> T where type_is_integer(T) || type_is_sim
reverse_bits :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) --- reverse_bits :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) ---
byte_swap :: proc(x: $T) -> T where type_is_integer(T) || type_is_float(T) --- byte_swap :: proc(x: $T) -> T where type_is_integer(T) || type_is_float(T) ---
overflow_add :: proc(lhs, rhs: $T) -> (T, bool) #optional_ok --- overflow_add :: proc(lhs, rhs: $T) -> (T, bool) ---
overflow_sub :: proc(lhs, rhs: $T) -> (T, bool) #optional_ok --- overflow_sub :: proc(lhs, rhs: $T) -> (T, bool) ---
overflow_mul :: proc(lhs, rhs: $T) -> (T, bool) #optional_ok --- overflow_mul :: proc(lhs, rhs: $T) -> (T, bool) ---
sqrt :: proc(x: $T) -> T where type_is_float(T) || (type_is_simd_vector(T) && type_is_float(type_elem_type(T))) --- sqrt :: proc(x: $T) -> T where type_is_float(T) || (type_is_simd_vector(T) && type_is_float(type_elem_type(T))) ---
@@ -293,7 +293,9 @@ wasm_memory_size :: proc(index: uintptr) -> int ---
// 0 - indicates that the thread blocked and then was woken up // 0 - indicates that the thread blocked and then was woken up
// 1 - the loaded value from `ptr` did not match `expected`, the thread did not block // 1 - the loaded value from `ptr` did not match `expected`, the thread did not block
// 2 - the thread blocked, but the timeout // 2 - the thread blocked, but the timeout
@(enable_target_feature="atomics")
wasm_memory_atomic_wait32 :: proc(ptr: ^u32, expected: u32, timeout_ns: i64) -> u32 --- wasm_memory_atomic_wait32 :: proc(ptr: ^u32, expected: u32, timeout_ns: i64) -> u32 ---
@(enable_target_feature="atomics")
wasm_memory_atomic_notify32 :: proc(ptr: ^u32, waiters: u32) -> (waiters_woken_up: u32) --- wasm_memory_atomic_notify32 :: proc(ptr: ^u32, waiters: u32) -> (waiters_woken_up: u32) ---
// x86 Targets (i386, amd64) // x86 Targets (i386, amd64)
+3 -2
View File
@@ -597,8 +597,9 @@ type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
base := info base := info
loop: for { loop: for {
#partial switch i in base.variant { #partial switch i in base.variant {
case Type_Info_Named: base = i.base case Type_Info_Named: base = i.base
case Type_Info_Enum: base = i.base case Type_Info_Enum: base = i.base
case Type_Info_Bit_Field: base = i.backing_type
case: break loop case: break loop
} }
} }
+7 -1
View File
@@ -333,7 +333,7 @@ map_kvh_data_values_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^
} }
@(private, require_results) @(require_results)
map_total_allocation_size :: #force_inline proc "contextless" (capacity: uintptr, info: ^Map_Info) -> uintptr { map_total_allocation_size :: #force_inline proc "contextless" (capacity: uintptr, info: ^Map_Info) -> uintptr {
round :: #force_inline proc "contextless" (value: uintptr) -> uintptr { round :: #force_inline proc "contextless" (value: uintptr) -> uintptr {
CACHE_MASK :: MAP_CACHE_LINE_SIZE - 1 CACHE_MASK :: MAP_CACHE_LINE_SIZE - 1
@@ -350,6 +350,12 @@ map_total_allocation_size :: #force_inline proc "contextless" (capacity: uintptr
return size return size
} }
@(require_results)
map_total_allocation_size_from_value :: #force_inline proc "contextless" (m: $M/map[$K]$V) -> uintptr {
return map_total_allocation_size(uintptr(cap(m)), map_info(M))
}
// The only procedure which needs access to the context is the one which allocates the map. // The only procedure which needs access to the context is the one which allocates the map.
@(require_results) @(require_results)
map_alloc_dynamic :: proc "odin" (info: ^Map_Info, log2_capacity: uintptr, allocator := context.allocator, loc := #caller_location) -> (result: Raw_Map, err: Allocator_Error) { map_alloc_dynamic :: proc "odin" (info: ^Map_Info, log2_capacity: uintptr, allocator := context.allocator, loc := #caller_location) -> (result: Raw_Map, err: Allocator_Error) {
+8
View File
@@ -14,6 +14,14 @@ constant-time byte comparison.
- Best-effort is make to mitigate timing side-channels on reasonable - Best-effort is make to mitigate timing side-channels on reasonable
architectures. Architectures that are known to be unreasonable include 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, and WebAssembly.
- Implementations assume a 64-bit architecture (64-bit integer arithmetic
is fast, and includes 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.
- Fault injection attacks etc.
- Hardware vulnerabilities ("apply mitigations or buy a new CPU").
- The packages attempt to santize sensitive data, however this is, and - The packages attempt to santize sensitive data, however this is, and
will remain a "best-effort" implementation decision. As Thomas Pornin will remain a "best-effort" implementation decision. As Thomas Pornin
puts it "In general, such memory cleansing is a fool's quest." puts it "In general, such memory cleansing is a fool's quest."
+428
View File
@@ -0,0 +1,428 @@
package _edwards25519
/*
This implements the edwards25519 composite-order group, primarily for
the purpose of implementing X25519, Ed25519, and ristretto255. Use of
this package for other purposes is NOT RECOMMENDED.
See:
- https://eprint.iacr.org/2011/368.pdf
- https://datatracker.ietf.org/doc/html/rfc8032
- https://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
*/
import "base:intrinsics"
import "core:crypto"
import field "core:crypto/_fiat/field_curve25519"
import "core:mem"
// Group_Element is an edwards25519 group element, as extended homogenous
// coordinates, which represents the affine point `(x, y)` as `(X, Y, Z, T)`,
// with the relations `x = X/Z`, `y = Y/Z`, and `x * y = T/Z`.
//
// d = -121665/121666 = 37095705934669439343138083508754565189542113879843219016388785533085940283555
// a = -1
//
// Notes:
// - There is considerable scope for optimization, however that
// will not change the external API, and this is simple and reasonably
// performant.
// - The API delibarately makes it hard to create arbitrary group
// elements that are not on the curve.
// - The group element decoding routine takes the opinionated stance of
// rejecting non-canonical encodings.
FE_D := field.Tight_Field_Element {
929955233495203,
466365720129213,
1662059464998953,
2033849074728123,
1442794654840575,
}
@(private)
FE_A := field.Tight_Field_Element {
2251799813685228,
2251799813685247,
2251799813685247,
2251799813685247,
2251799813685247,
}
@(private)
FE_D2 := field.Tight_Field_Element {
1859910466990425,
932731440258426,
1072319116312658,
1815898335770999,
633789495995903,
}
@(private)
GE_BASEPOINT := Group_Element {
field.Tight_Field_Element {
1738742601995546,
1146398526822698,
2070867633025821,
562264141797630,
587772402128613,
},
field.Tight_Field_Element {
1801439850948184,
1351079888211148,
450359962737049,
900719925474099,
1801439850948198,
},
field.Tight_Field_Element{1, 0, 0, 0, 0},
field.Tight_Field_Element {
1841354044333475,
16398895984059,
755974180946558,
900171276175154,
1821297809914039,
},
}
GE_IDENTITY := Group_Element {
field.Tight_Field_Element{0, 0, 0, 0, 0},
field.Tight_Field_Element{1, 0, 0, 0, 0},
field.Tight_Field_Element{1, 0, 0, 0, 0},
field.Tight_Field_Element{0, 0, 0, 0, 0},
}
Group_Element :: struct {
x: field.Tight_Field_Element,
y: field.Tight_Field_Element,
z: field.Tight_Field_Element,
t: field.Tight_Field_Element,
}
ge_clear :: proc "contextless" (ge: ^Group_Element) {
mem.zero_explicit(ge, size_of(Group_Element))
}
ge_set :: proc "contextless" (ge, a: ^Group_Element) {
field.fe_set(&ge.x, &a.x)
field.fe_set(&ge.y, &a.y)
field.fe_set(&ge.z, &a.z)
field.fe_set(&ge.t, &a.t)
}
@(require_results)
ge_set_bytes :: proc "contextless" (ge: ^Group_Element, b: []byte) -> bool {
if len(b) != 32 {
intrinsics.trap()
}
b_ := transmute(^[32]byte)(raw_data(b))
// Do the work in a scratch element, so that ge is unchanged on
// failure.
tmp: Group_Element = ---
defer ge_clear(&tmp)
field.fe_one(&tmp.z) // Z = 1
// The encoding is the y-coordinate, with the x-coordinate polarity
// (odd/even) encoded in the MSB.
field.fe_from_bytes(&tmp.y, b_) // ignores high bit
// Recover the candidate x-coordinate via the curve equation:
// x^2 = (y^2 - 1) / (d * y^2 + 1) (mod p)
fe_tmp := &tmp.t // Use this to store intermediaries.
fe_one := &tmp.z
// x = num = y^2 - 1
field.fe_carry_square(fe_tmp, field.fe_relax_cast(&tmp.y)) // fe_tmp = y^2
field.fe_carry_sub(&tmp.x, fe_tmp, fe_one)
// den = d * y^2 + 1
field.fe_carry_mul(fe_tmp, field.fe_relax_cast(fe_tmp), field.fe_relax_cast(&FE_D))
field.fe_carry_add(fe_tmp, fe_tmp, fe_one)
// x = invsqrt(den/num)
is_square := field.fe_carry_sqrt_ratio_m1(
&tmp.x,
field.fe_relax_cast(&tmp.x),
field.fe_relax_cast(fe_tmp),
)
if is_square == 0 {
return false
}
// Pick the right x-coordinate.
field.fe_cond_negate(&tmp.x, &tmp.x, int(b[31] >> 7))
// t = x * y
field.fe_carry_mul(&tmp.t, field.fe_relax_cast(&tmp.x), field.fe_relax_cast(&tmp.y))
// Reject non-canonical encodings of ge.
buf: [32]byte = ---
field.fe_to_bytes(&buf, &tmp.y)
buf[31] |= byte(field.fe_is_negative(&tmp.x)) << 7
is_canonical := crypto.compare_constant_time(b, buf[:])
ge_cond_assign(ge, &tmp, is_canonical)
mem.zero_explicit(&buf, size_of(buf))
return is_canonical == 1
}
ge_bytes :: proc "contextless" (ge: ^Group_Element, dst: []byte) {
if len(dst) != 32 {
intrinsics.trap()
}
dst_ := transmute(^[32]byte)(raw_data(dst))
// Convert the element to affine (x, y) representation.
x, y, z_inv: field.Tight_Field_Element = ---, ---, ---
field.fe_carry_inv(&z_inv, field.fe_relax_cast(&ge.z))
field.fe_carry_mul(&x, field.fe_relax_cast(&ge.x), field.fe_relax_cast(&z_inv))
field.fe_carry_mul(&y, field.fe_relax_cast(&ge.y), field.fe_relax_cast(&z_inv))
// Encode the y-coordinate.
field.fe_to_bytes(dst_, &y)
// Copy the least significant bit of the x-coordinate to the most
// significant bit of the encoded y-coordinate.
dst_[31] |= byte((x[0] & 1) << 7)
field.fe_clear_vec([]^field.Tight_Field_Element{&x, &y, &z_inv})
}
ge_identity :: proc "contextless" (ge: ^Group_Element) {
field.fe_zero(&ge.x)
field.fe_one(&ge.y)
field.fe_one(&ge.z)
field.fe_zero(&ge.t)
}
ge_generator :: proc "contextless" (ge: ^Group_Element) {
ge_set(ge, &GE_BASEPOINT)
}
@(private)
Addend_Group_Element :: struct {
y2_minus_x2: field.Loose_Field_Element, // t1
y2_plus_x2: field.Loose_Field_Element, // t3
k_times_t2: field.Tight_Field_Element, // t4
two_times_z2: field.Loose_Field_Element, // t5
}
@(private)
ge_addend_set :: proc "contextless" (ge_a: ^Addend_Group_Element, ge: ^Group_Element) {
field.fe_sub(&ge_a.y2_minus_x2, &ge.y, &ge.x)
field.fe_add(&ge_a.y2_plus_x2, &ge.y, &ge.x)
field.fe_carry_mul(&ge_a.k_times_t2, field.fe_relax_cast(&FE_D2), field.fe_relax_cast(&ge.t))
field.fe_add(&ge_a.two_times_z2, &ge.z, &ge.z)
}
@(private)
ge_addend_conditional_assign :: proc "contextless" (ge_a, a: ^Addend_Group_Element, ctrl: int) {
field.fe_cond_select(&ge_a.y2_minus_x2, &ge_a.y2_minus_x2, &a.y2_minus_x2, ctrl)
field.fe_cond_select(&ge_a.y2_plus_x2, &ge_a.y2_plus_x2, &a.y2_plus_x2, ctrl)
field.fe_cond_select(&ge_a.k_times_t2, &ge_a.k_times_t2, &a.k_times_t2, ctrl)
field.fe_cond_select(&ge_a.two_times_z2, &ge_a.two_times_z2, &a.two_times_z2, ctrl)
}
@(private)
Add_Scratch :: struct {
A, B, C, D: field.Tight_Field_Element,
E, F, G, H: field.Loose_Field_Element,
t0, t2: field.Loose_Field_Element,
}
ge_add :: proc "contextless" (ge, a, b: ^Group_Element) {
b_: Addend_Group_Element = ---
ge_addend_set(&b_, b)
scratch: Add_Scratch = ---
ge_add_addend(ge, a, &b_, &scratch)
mem.zero_explicit(&b_, size_of(Addend_Group_Element))
mem.zero_explicit(&scratch, size_of(Add_Scratch))
}
@(private)
ge_add_addend :: proc "contextless" (
ge, a: ^Group_Element,
b: ^Addend_Group_Element,
scratch: ^Add_Scratch,
) {
// https://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3
// Assumptions: k=2*d.
//
// t0 = Y1-X1
// t1 = Y2-X2
// A = t0*t1
// t2 = Y1+X1
// t3 = Y2+X2
// B = t2*t3
// t4 = k*T2
// C = T1*t4
// t5 = 2*Z2
// D = Z1*t5
// E = B-A
// F = D-C
// G = D+C
// H = B+A
// X3 = E*F
// Y3 = G*H
// T3 = E*H
// Z3 = F*G
//
// In order to make the scalar multiply faster, the addend is provided
// as a `Addend_Group_Element` with t1, t3, t4, and t5 precomputed, as
// it is trivially obvious that those are the only values used by the
// formula that are directly dependent on `b`, and are only dependent
// on `b` and constants. This saves 1 sub, 2 adds, and 1 multiply,
// each time the intermediate representation can be reused.
A, B, C, D := &scratch.A, &scratch.B, &scratch.C, &scratch.D
E, F, G, H := &scratch.E, &scratch.F, &scratch.G, &scratch.H
t0, t2 := &scratch.t0, &scratch.t2
field.fe_sub(t0, &a.y, &a.x)
t1 := &b.y2_minus_x2
field.fe_carry_mul(A, t0, t1)
field.fe_add(t2, &a.y, &a.x)
t3 := &b.y2_plus_x2
field.fe_carry_mul(B, t2, t3)
t4 := &b.k_times_t2
field.fe_carry_mul(C, field.fe_relax_cast(&a.t), field.fe_relax_cast(t4))
t5 := &b.two_times_z2
field.fe_carry_mul(D, field.fe_relax_cast(&a.z), t5)
field.fe_sub(E, B, A)
field.fe_sub(F, D, C)
field.fe_add(G, D, C)
field.fe_add(H, B, A)
field.fe_carry_mul(&ge.x, E, F)
field.fe_carry_mul(&ge.y, G, H)
field.fe_carry_mul(&ge.t, E, H)
field.fe_carry_mul(&ge.z, F, G)
}
@(private)
Double_Scratch :: struct {
A, B, C, D, G: field.Tight_Field_Element,
t0, t2, t3: field.Tight_Field_Element,
E, F, H: field.Loose_Field_Element,
t1: field.Loose_Field_Element,
}
ge_double :: proc "contextless" (ge, a: ^Group_Element, scratch: ^Double_Scratch = nil) {
// https://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#doubling-dbl-2008-hwcd
//
// A = X1^2
// B = Y1^2
// t0 = Z1^2
// C = 2*t0
// D = a*A
// t1 = X1+Y1
// t2 = t1^2
// t3 = t2-A
// E = t3-B
// G = D+B
// F = G-C
// H = D-B
// X3 = E*F
// Y3 = G*H
// T3 = E*H
// Z3 = F*G
sanitize, scratch := scratch == nil, scratch
if sanitize {
tmp: Double_Scratch = ---
scratch = &tmp
}
A, B, C, D, G := &scratch.A, &scratch.B, &scratch.C, &scratch.D, &scratch.G
t0, t2, t3 := &scratch.t0, &scratch.t2, &scratch.t3
E, F, H := &scratch.E, &scratch.F, &scratch.H
t1 := &scratch.t1
field.fe_carry_square(A, field.fe_relax_cast(&a.x))
field.fe_carry_square(B, field.fe_relax_cast(&a.y))
field.fe_carry_square(t0, field.fe_relax_cast(&a.z))
field.fe_carry_add(C, t0, t0)
field.fe_carry_mul(D, field.fe_relax_cast(&FE_A), field.fe_relax_cast(A))
field.fe_add(t1, &a.x, &a.y)
field.fe_carry_square(t2, t1)
field.fe_carry_sub(t3, t2, A)
field.fe_sub(E, t3, B)
field.fe_carry_add(G, D, B)
field.fe_sub(F, G, C)
field.fe_sub(H, D, B)
G_ := field.fe_relax_cast(G)
field.fe_carry_mul(&ge.x, E, F)
field.fe_carry_mul(&ge.y, G_, H)
field.fe_carry_mul(&ge.t, E, H)
field.fe_carry_mul(&ge.z, F, G_)
if sanitize {
mem.zero_explicit(scratch, size_of(Double_Scratch))
}
}
ge_negate :: proc "contextless" (ge, a: ^Group_Element) {
field.fe_carry_opp(&ge.x, &a.x)
field.fe_set(&ge.y, &a.y)
field.fe_set(&ge.z, &a.z)
field.fe_carry_opp(&ge.t, &a.t)
}
ge_cond_negate :: proc "contextless" (ge, a: ^Group_Element, ctrl: int) {
tmp: Group_Element = ---
ge_negate(&tmp, a)
ge_cond_assign(ge, &tmp, ctrl)
ge_clear(&tmp)
}
ge_cond_assign :: proc "contextless" (ge, a: ^Group_Element, ctrl: int) {
field.fe_cond_assign(&ge.x, &a.x, ctrl)
field.fe_cond_assign(&ge.y, &a.y, ctrl)
field.fe_cond_assign(&ge.z, &a.z, ctrl)
field.fe_cond_assign(&ge.t, &a.t, ctrl)
}
ge_cond_select :: proc "contextless" (ge, a, b: ^Group_Element, ctrl: int) {
field.fe_cond_select(&ge.x, &a.x, &b.x, ctrl)
field.fe_cond_select(&ge.y, &a.y, &b.y, ctrl)
field.fe_cond_select(&ge.z, &a.z, &b.z, ctrl)
field.fe_cond_select(&ge.t, &a.t, &b.t, ctrl)
}
@(require_results)
ge_equal :: proc "contextless" (a, b: ^Group_Element) -> int {
// (x, y) ?= (x', y') -> (X/Z, Y/Z) ?= (X'/Z', Y'/Z')
// X/Z ?= X'/Z', Y/Z ?= Y'/Z' -> X*Z' ?= X'*Z, Y*Z' ?= Y'*Z
ax_bz, bx_az, ay_bz, by_az: field.Tight_Field_Element = ---, ---, ---, ---
field.fe_carry_mul(&ax_bz, field.fe_relax_cast(&a.x), field.fe_relax_cast(&b.z))
field.fe_carry_mul(&bx_az, field.fe_relax_cast(&b.x), field.fe_relax_cast(&a.z))
field.fe_carry_mul(&ay_bz, field.fe_relax_cast(&a.y), field.fe_relax_cast(&b.z))
field.fe_carry_mul(&by_az, field.fe_relax_cast(&b.y), field.fe_relax_cast(&a.z))
ret := field.fe_equal(&ax_bz, &bx_az) & field.fe_equal(&ay_bz, &by_az)
field.fe_clear_vec([]^field.Tight_Field_Element{&ax_bz, &ay_bz, &bx_az, &by_az})
return ret
}
@(require_results)
ge_is_small_order :: proc "contextless" (ge: ^Group_Element) -> bool {
tmp: Group_Element = ---
ge_double(&tmp, ge)
ge_double(&tmp, &tmp)
ge_double(&tmp, &tmp)
return ge_equal(&tmp, &GE_IDENTITY) == 1
}
@(require_results)
ge_in_prime_order_subgroup_vartime :: proc "contextless" (ge: ^Group_Element) -> bool {
// This is currently *very* expensive. The faster method would be
// something like (https://eprint.iacr.org/2022/1164.pdf), however
// that is a ~50% speedup, and a lot of added complexity for something
// that is better solved by "just use ristretto255".
tmp: Group_Element = ---
_ge_scalarmult(&tmp, ge, &SC_ELL, true)
return ge_equal(&tmp, &GE_IDENTITY) == 1
}
@@ -0,0 +1,61 @@
package _edwards25519
import "base:intrinsics"
import field "core:crypto/_fiat/field_scalar25519"
import "core:mem"
Scalar :: field.Montgomery_Domain_Field_Element
// WARNING: This is non-canonical and only to be used when checking if
// a group element is on the prime-order subgroup.
@(private)
SC_ELL := field.Non_Montgomery_Domain_Field_Element {
field.ELL[0],
field.ELL[1],
field.ELL[2],
field.ELL[3],
}
sc_set_u64 :: proc "contextless" (sc: ^Scalar, i: u64) {
tmp := field.Non_Montgomery_Domain_Field_Element{i, 0, 0, 0}
field.fe_to_montgomery(sc, &tmp)
mem.zero_explicit(&tmp, size_of(tmp))
}
@(require_results)
sc_set_bytes :: proc "contextless" (sc: ^Scalar, b: []byte) -> bool {
if len(b) != 32 {
intrinsics.trap()
}
b_ := transmute(^[32]byte)(raw_data(b))
return field.fe_from_bytes(sc, b_)
}
sc_set_bytes_rfc8032 :: proc "contextless" (sc: ^Scalar, b: []byte) {
if len(b) != 32 {
intrinsics.trap()
}
b_ := transmute(^[32]byte)(raw_data(b))
field.fe_from_bytes_rfc8032(sc, b_)
}
sc_clear :: proc "contextless" (sc: ^Scalar) {
mem.zero_explicit(sc, size_of(Scalar))
}
sc_set :: field.fe_set
sc_set_bytes_wide :: field.fe_from_bytes_wide
sc_bytes :: field.fe_to_bytes
sc_zero :: field.fe_zero
sc_one :: field.fe_one
sc_add :: field.fe_add
sc_sub :: field.fe_sub
sc_negate :: field.fe_opp
sc_mul :: field.fe_mul
sc_square :: field.fe_square
sc_cond_assign :: field.fe_cond_assign
sc_equal :: field.fe_equal
@@ -0,0 +1,288 @@
package _edwards25519
import field "core:crypto/_fiat/field_scalar25519"
import "core:math/bits"
import "core:mem"
// GE_BASEPOINT_TABLE is 1 * G, ... 15 * G, in precomputed format.
//
// Note: When generating, the values were reduced to Tight_Field_Element
// ranges, even though that is not required.
@(private)
GE_BASEPOINT_TABLE := Multiply_Table {
{
{62697248952638, 204681361388450, 631292143396476, 338455783676468, 1213667448819585},
{1288382639258501, 245678601348599, 269427782077623, 1462984067271730, 137412439391563},
{301289933810280, 1259582250014073, 1422107436869536, 796239922652654, 1953934009299142},
{2, 0, 0, 0, 0},
},
{
{1519297034332653, 1098796920435767, 1823476547744119, 808144629470969, 2110930855619772},
{338005982828284, 1667856962156925, 100399270107451, 1604566703601691, 1950338038771369},
{1920505767731247, 1443759578976892, 1659852098357048, 1484431291070208, 275018744912646},
{763163817085987, 2195095074806923, 2167883174351839, 1868059999999762, 911071066608705},
},
{
{960627541894068, 1314966688943942, 1126875971034044, 2059608312958945, 605975666152586},
{1714478358025626, 2209607666607510, 1600912834284834, 496072478982142, 481970031861896},
{851735079403194, 1088965826757164, 141569479297499, 602804610059257, 2004026468601520},
{197585529552380, 324719066578543, 564481854250498, 1173818332764578, 35452976395676},
},
{
{1152980410747203, 2196804280851952, 25745194962557, 1915167295473129, 1266299690309224},
{809905889679060, 979732230071345, 1509972345538142, 188492426534402, 818965583123815},
{997685409185036, 1451818320876327, 2126681166774509, 2000509606057528, 235432372486854},
{887734189279642, 1460338685162044, 877378220074262, 102436391401299, 153369156847490},
},
{
{2056621900836770, 1821657694132497, 1627986892909426, 1163363868678833, 1108873376459226},
{1187697490593623, 1066539945237335, 885654531892000, 1357534489491782, 359370291392448},
{1509033452137525, 1305318174298508, 613642471748944, 1987256352550234, 1044283663101541},
{220105720697037, 387661783287620, 328296827867762, 360035589590664, 795213236824054},
},
{
{1820794733038396, 1612235121681074, 757405923441402, 1094031020892801, 231025333128907},
{1639067873254194, 1484176557946322, 300800382144789, 1329915446659183, 1211704578730455},
{641900794791527, 1711751746971612, 179044712319955, 576455585963824, 1852617592509865},
{743549047192397, 685091042550147, 1952415336873496, 1965124675654685, 513364998442917},
},
{
{1004557076870448, 1762911374844520, 1330807633622723, 384072910939787, 953849032243810},
{2178275058221458, 257933183722891, 376684351537894, 2010189102001786, 1981824297484148},
{1332915663881114, 1286540505502549, 1741691283561518, 977214932156314, 1764059494778091},
{429702949064027, 1368332611650677, 2019867176450999, 2212258376161746, 526160996742554},
},
{
{2098932988258576, 2203688382075948, 2120400160059479, 1748488020948146, 1203264167282624},
{677131386735829, 1850249298025188, 672782146532031, 2144145693078904, 2088656272813787},
{1065622343976192, 1573853211848116, 223560413590068, 333846833073379, 27832122205830},
{1781008836504573, 917619542051793, 544322748939913, 882577394308384, 1720521246471195},
},
{
{660120928379860, 2081944024858618, 1878411111349191, 424587356517195, 2111317439894005},
{1834193977811532, 1864164086863319, 797334633289424, 150410812403062, 2085177078466389},
{1438117271371866, 783915531014482, 388731514584658, 292113935417795, 1945855002546714},
{1678140823166658, 679103239148744, 614102761596238, 1052962498997885, 1863983323810390},
},
{
{1690309392496233, 1116333140326275, 1377242323631039, 717196888780674, 82724646713353},
{1722370213432106, 74265192976253, 264239578448472, 1714909985012994, 2216984958602173},
{2010482366920922, 1294036471886319, 566466395005815, 1631955803657320, 1751698647538458},
{1073230604155753, 1159087041338551, 1664057985455483, 127472702826203, 1339591128522371},
},
{
{478053307175577, 2179515791720985, 21146535423512, 1831683844029536, 462805561553981},
{1945267486565588, 1298536818409655, 2214511796262989, 1904981051429012, 252904800782086},
{268945954671210, 222740425595395, 1208025911856230, 1080418823003555, 75929831922483},
{1884784014268948, 643868448202966, 978736549726821, 46385971089796, 1296884812292320},
},
{
{1861159462859103, 7077532564710, 963010365896826, 1938780006785270, 766241051941647},
{1778966986051906, 1713995999765361, 1394565822271816, 1366699246468722, 1213407027149475},
{1978989286560907, 2135084162045594, 1951565508865477, 671788336314416, 293123929458176},
{902608944504080, 2167765718046481, 1285718473078022, 1222562171329269, 492109027844479},
},
{
{1820807832746213, 1029220580458586, 1101997555432203, 1039081975563572, 202477981158221},
{1866134980680205, 2222325502763386, 1830284629571201, 1046966214478970, 418381946936795},
{1783460633291322, 1719505443254998, 1810489639976220, 877049370713018, 2187801198742619},
{197118243000763, 305493867565736, 518814410156522, 1656246186645170, 901894734874934},
},
{
{225454942125915, 478410476654509, 600524586037746, 643450007230715, 1018615928259319},
{1733330584845708, 881092297970296, 507039890129464, 496397090721598, 2230888519577628},
{690155664737246, 1010454785646677, 753170144375012, 1651277613844874, 1622648796364156},
{1321310321891618, 1089655277873603, 235891750867089, 815878279563688, 1709264240047556},
},
{
{805027036551342, 1387174275567452, 1156538511461704, 1465897486692171, 1208567094120903},
{2228417017817483, 202885584970535, 2182114782271881, 2077405042592934, 1029684358182774},
{460447547653983, 627817697755692, 524899434670834, 1228019344939427, 740684787777653},
{849757462467675, 447476306919899, 422618957298818, 302134659227815, 675831828440895},
},
}
ge_scalarmult :: proc "contextless" (ge, p: ^Group_Element, sc: ^Scalar) {
tmp: field.Non_Montgomery_Domain_Field_Element
field.fe_from_montgomery(&tmp, sc)
_ge_scalarmult(ge, p, &tmp)
mem.zero_explicit(&tmp, size_of(tmp))
}
ge_scalarmult_basepoint :: proc "contextless" (ge: ^Group_Element, sc: ^Scalar) {
// Something like the comb method from "Fast and compact elliptic-curve
// cryptography" Section 3.3, would be more performant, but more
// complex.
//
// - https://eprint.iacr.org/2012/309
ge_scalarmult(ge, &GE_BASEPOINT, sc)
}
ge_scalarmult_vartime :: proc "contextless" (ge, p: ^Group_Element, sc: ^Scalar) {
tmp: field.Non_Montgomery_Domain_Field_Element
field.fe_from_montgomery(&tmp, sc)
_ge_scalarmult(ge, p, &tmp, true)
}
ge_double_scalarmult_basepoint_vartime :: proc "contextless" (
ge: ^Group_Element,
a: ^Scalar,
A: ^Group_Element,
b: ^Scalar,
) {
// Strauss-Shamir, commonly referred to as the "Shamir trick",
// saves half the doublings, relative to doing this the naive way.
//
// ABGLSV-Pornin (https://eprint.iacr.org/2020/454) is faster,
// but significantly more complex, and has incompatibilities with
// mixed-order group elements.
tmp_add: Add_Scratch = ---
tmp_addend: Addend_Group_Element = ---
tmp_dbl: Double_Scratch = ---
tmp: Group_Element = ---
A_tbl: Multiply_Table = ---
mul_tbl_set(&A_tbl, A, &tmp_add)
sc_a, sc_b: field.Non_Montgomery_Domain_Field_Element
field.fe_from_montgomery(&sc_a, a)
field.fe_from_montgomery(&sc_b, b)
ge_identity(&tmp)
for i := 31; i >= 0; i = i - 1 {
limb := i / 8
shift := uint(i & 7) * 8
limb_byte_a := sc_a[limb] >> shift
limb_byte_b := sc_b[limb] >> shift
hi_a, lo_a := (limb_byte_a >> 4) & 0x0f, limb_byte_a & 0x0f
hi_b, lo_b := (limb_byte_b >> 4) & 0x0f, limb_byte_b & 0x0f
if i != 31 {
ge_double(&tmp, &tmp, &tmp_dbl)
ge_double(&tmp, &tmp, &tmp_dbl)
ge_double(&tmp, &tmp, &tmp_dbl)
ge_double(&tmp, &tmp, &tmp_dbl)
}
mul_tbl_add(&tmp, &A_tbl, hi_a, &tmp_add, &tmp_addend, true)
mul_tbl_add(&tmp, &GE_BASEPOINT_TABLE, hi_b, &tmp_add, &tmp_addend, true)
ge_double(&tmp, &tmp, &tmp_dbl)
ge_double(&tmp, &tmp, &tmp_dbl)
ge_double(&tmp, &tmp, &tmp_dbl)
ge_double(&tmp, &tmp, &tmp_dbl)
mul_tbl_add(&tmp, &A_tbl, lo_a, &tmp_add, &tmp_addend, true)
mul_tbl_add(&tmp, &GE_BASEPOINT_TABLE, lo_b, &tmp_add, &tmp_addend, true)
}
ge_set(ge, &tmp)
}
@(private)
_ge_scalarmult :: proc "contextless" (
ge, p: ^Group_Element,
sc: ^field.Non_Montgomery_Domain_Field_Element,
unsafe_is_vartime := false,
) {
// Do the simplest possible thing that works and provides adequate,
// performance, which is windowed add-then-multiply.
tmp_add: Add_Scratch = ---
tmp_addend: Addend_Group_Element = ---
tmp_dbl: Double_Scratch = ---
tmp: Group_Element = ---
p_tbl: Multiply_Table = ---
mul_tbl_set(&p_tbl, p, &tmp_add)
ge_identity(&tmp)
for i := 31; i >= 0; i = i - 1 {
limb := i / 8
shift := uint(i & 7) * 8
limb_byte := sc[limb] >> shift
hi, lo := (limb_byte >> 4) & 0x0f, limb_byte & 0x0f
if i != 31 {
ge_double(&tmp, &tmp, &tmp_dbl)
ge_double(&tmp, &tmp, &tmp_dbl)
ge_double(&tmp, &tmp, &tmp_dbl)
ge_double(&tmp, &tmp, &tmp_dbl)
}
mul_tbl_add(&tmp, &p_tbl, hi, &tmp_add, &tmp_addend, unsafe_is_vartime)
ge_double(&tmp, &tmp, &tmp_dbl)
ge_double(&tmp, &tmp, &tmp_dbl)
ge_double(&tmp, &tmp, &tmp_dbl)
ge_double(&tmp, &tmp, &tmp_dbl)
mul_tbl_add(&tmp, &p_tbl, lo, &tmp_add, &tmp_addend, unsafe_is_vartime)
}
ge_set(ge, &tmp)
if !unsafe_is_vartime {
ge_clear(&tmp)
mem.zero_explicit(&tmp_add, size_of(Add_Scratch))
mem.zero_explicit(&tmp_addend, size_of(Addend_Group_Element))
mem.zero_explicit(&tmp_dbl, size_of(Double_Scratch))
}
}
@(private)
Multiply_Table :: [15]Addend_Group_Element // 0 = inf, which is implicit.
@(private)
mul_tbl_set :: proc "contextless" (
tbl: ^Multiply_Table,
ge: ^Group_Element,
tmp_add: ^Add_Scratch,
) {
tmp: Group_Element = ---
ge_set(&tmp, ge)
ge_addend_set(&tbl[0], ge)
for i := 1; i < 15; i = i + 1 {
ge_add_addend(&tmp, &tmp, &tbl[0], tmp_add)
ge_addend_set(&tbl[i], &tmp)
}
ge_clear(&tmp)
}
@(private)
mul_tbl_add :: proc "contextless" (
ge: ^Group_Element,
tbl: ^Multiply_Table,
idx: u64,
tmp_add: ^Add_Scratch,
tmp_addend: ^Addend_Group_Element,
unsafe_is_vartime: bool,
) {
// Variable time lookup, with the addition omitted entirely if idx == 0.
if unsafe_is_vartime {
// Skip adding the point at infinity.
if idx != 0 {
ge_add_addend(ge, ge, &tbl[idx - 1], tmp_add)
}
return
}
// Constant time lookup.
tmp_addend^ = {
// Point at infinity (0, 1, 1, 0) in precomputed form
{1, 0, 0, 0, 0}, // y - x
{1, 0, 0, 0, 0}, // y + x
{0, 0, 0, 0, 0}, // t * 2d
{2, 0, 0, 0, 0}, // z * 2
}
for i := u64(1); i < 16; i = i + 1 {
_, ctrl := bits.sub_u64(0, (i ~ idx), 0)
ge_addend_conditional_assign(tmp_addend, &tbl[i - 1], int(~ctrl) & 1)
}
ge_add_addend(ge, ge, tmp_addend, tmp_add)
}
+2 -2
View File
@@ -9,7 +9,7 @@ package fiat
u1 :: distinct u8 u1 :: distinct u8
i1 :: distinct i8 i1 :: distinct i8
@(optimization_mode="none") @(optimization_mode = "none")
cmovznz_u64 :: proc "contextless" (arg1: u1, arg2, arg3: u64) -> (out1: u64) { cmovznz_u64 :: proc "contextless" (arg1: u1, arg2, arg3: u64) -> (out1: u64) {
x1 := (u64(arg1) * 0xffffffffffffffff) x1 := (u64(arg1) * 0xffffffffffffffff)
x2 := ((x1 & arg3) | ((~x1) & arg2)) x2 := ((x1 & arg3) | ((~x1) & arg2))
@@ -17,7 +17,7 @@ cmovznz_u64 :: proc "contextless" (arg1: u1, arg2, arg3: u64) -> (out1: u64) {
return return
} }
@(optimization_mode="none") @(optimization_mode = "none")
cmovznz_u32 :: proc "contextless" (arg1: u1, arg2, arg3: u32) -> (out1: u32) { cmovznz_u32 :: proc "contextless" (arg1: u1, arg2, arg3: u32) -> (out1: u32) {
x1 := (u32(arg1) * 0xffffffff) x1 := (u32(arg1) * 0xffffffff)
x2 := ((x1 & arg3) | ((~x1) & arg2)) x2 := ((x1 & arg3) | ((~x1) & arg2))
+171 -42
View File
@@ -3,14 +3,32 @@ package field_curve25519
import "core:crypto" import "core:crypto"
import "core:mem" import "core:mem"
fe_relax_cast :: #force_inline proc "contextless" (arg1: ^Tight_Field_Element) -> ^Loose_Field_Element { fe_relax_cast :: #force_inline proc "contextless" (
arg1: ^Tight_Field_Element,
) -> ^Loose_Field_Element {
return transmute(^Loose_Field_Element)(arg1) return transmute(^Loose_Field_Element)(arg1)
} }
fe_tighten_cast :: #force_inline proc "contextless" (arg1: ^Loose_Field_Element) -> ^Tight_Field_Element { fe_tighten_cast :: #force_inline proc "contextless" (
arg1: ^Loose_Field_Element,
) -> ^Tight_Field_Element {
return transmute(^Tight_Field_Element)(arg1) return transmute(^Tight_Field_Element)(arg1)
} }
fe_clear :: proc "contextless" (
arg1: $T,
) where T == ^Tight_Field_Element || T == ^Loose_Field_Element {
mem.zero_explicit(arg1, size_of(arg1^))
}
fe_clear_vec :: proc "contextless" (
arg1: $T,
) where T == []^Tight_Field_Element || T == []^Loose_Field_Element {
for fe in arg1 {
fe_clear(fe)
}
}
fe_from_bytes :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^[32]byte) { fe_from_bytes :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^[32]byte) {
// Ignore the unused bit by copying the input and masking the bit off // Ignore the unused bit by copying the input and masking the bit off
// prior to deserialization. // prior to deserialization.
@@ -23,12 +41,25 @@ fe_from_bytes :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^[32]byte
mem.zero_explicit(&tmp1, size_of(tmp1)) mem.zero_explicit(&tmp1, size_of(tmp1))
} }
fe_is_negative :: proc "contextless" (arg1: ^Tight_Field_Element) -> int {
tmp1: [32]byte = ---
fe_to_bytes(&tmp1, arg1)
ret := tmp1[0] & 1
mem.zero_explicit(&tmp1, size_of(tmp1))
return int(ret)
}
fe_equal :: proc "contextless" (arg1, arg2: ^Tight_Field_Element) -> int { fe_equal :: proc "contextless" (arg1, arg2: ^Tight_Field_Element) -> int {
tmp2: [32]byte = --- tmp1, tmp2: [32]byte = ---, ---
fe_to_bytes(&tmp1, arg1)
fe_to_bytes(&tmp2, arg2) fe_to_bytes(&tmp2, arg2)
ret := fe_equal_bytes(arg1, &tmp2) ret := crypto.compare_constant_time(tmp1[:], tmp2[:])
mem.zero_explicit(&tmp1, size_of(tmp1))
mem.zero_explicit(&tmp2, size_of(tmp2)) mem.zero_explicit(&tmp2, size_of(tmp2))
return ret return ret
@@ -46,7 +77,11 @@ fe_equal_bytes :: proc "contextless" (arg1: ^Tight_Field_Element, arg2: ^[32]byt
return ret return ret
} }
fe_carry_pow2k :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element, arg2: uint) { fe_carry_pow2k :: proc "contextless" (
out1: ^Tight_Field_Element,
arg1: ^Loose_Field_Element,
arg2: uint,
) {
// Special case: `arg1^(2 * 0) = 1`, though this should never happen. // Special case: `arg1^(2 * 0) = 1`, though this should never happen.
if arg2 == 0 { if arg2 == 0 {
fe_one(out1) fe_one(out1)
@@ -54,27 +89,46 @@ fe_carry_pow2k :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element,
} }
fe_carry_square(out1, arg1) fe_carry_square(out1, arg1)
for _ in 1..<arg2 { for _ in 1 ..< arg2 {
fe_carry_square(out1, fe_relax_cast(out1)) fe_carry_square(out1, fe_relax_cast(out1))
} }
} }
fe_carry_add :: #force_inline proc "contextless" (out1, arg1, arg2: ^Tight_Field_Element) {
fe_add(fe_relax_cast(out1), arg1, arg2)
fe_carry(out1, fe_relax_cast(out1))
}
fe_carry_sub :: #force_inline proc "contextless" (out1, arg1, arg2: ^Tight_Field_Element) {
fe_sub(fe_relax_cast(out1), arg1, arg2)
fe_carry(out1, fe_relax_cast(out1))
}
fe_carry_opp :: #force_inline proc "contextless" (out1, arg1: ^Tight_Field_Element) { fe_carry_opp :: #force_inline proc "contextless" (out1, arg1: ^Tight_Field_Element) {
fe_opp(fe_relax_cast(out1), arg1) fe_opp(fe_relax_cast(out1), arg1)
fe_carry(out1, fe_relax_cast(out1)) fe_carry(out1, fe_relax_cast(out1))
} }
fe_carry_invsqrt :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) -> int { fe_carry_abs :: #force_inline proc "contextless" (out1, arg1: ^Tight_Field_Element) {
// Inverse square root taken from Monocypher. fe_cond_negate(out1, arg1, fe_is_negative(arg1))
}
fe_carry_sqrt_ratio_m1 :: proc "contextless" (
out1: ^Tight_Field_Element,
arg1: ^Loose_Field_Element, // u
arg2: ^Loose_Field_Element, // v
) -> int {
// SQRT_RATIO_M1(u, v) from RFC 9496 - 4.2, based on the inverse
// square root from Monocypher.
w: Tight_Field_Element = ---
fe_carry_mul(&w, arg1, arg2) // u * v
// r = tmp1 = u * w^((p-5)/8)
tmp1, tmp2, tmp3: Tight_Field_Element = ---, ---, --- tmp1, tmp2, tmp3: Tight_Field_Element = ---, ---, ---
fe_carry_pow2k(&tmp1, fe_relax_cast(&w), 1)
// t0 = x^((p-5)/8)
// Can be achieved with a simple double & add ladder,
// but it would be slower.
fe_carry_pow2k(&tmp1, arg1, 1)
fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp1), 2) fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp1), 2)
fe_carry_mul(&tmp2, arg1, fe_relax_cast(&tmp2)) fe_carry_mul(&tmp2, fe_relax_cast(&w), fe_relax_cast(&tmp2))
fe_carry_mul(&tmp1, fe_relax_cast(&tmp1), fe_relax_cast(&tmp2)) fe_carry_mul(&tmp1, fe_relax_cast(&tmp1), fe_relax_cast(&tmp2))
fe_carry_pow2k(&tmp1, fe_relax_cast(&tmp1), 1) fe_carry_pow2k(&tmp1, fe_relax_cast(&tmp1), 1)
fe_carry_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1)) fe_carry_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1))
@@ -93,46 +147,121 @@ fe_carry_invsqrt :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element
fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp2), 50) fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp2), 50)
fe_carry_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1)) fe_carry_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1))
fe_carry_pow2k(&tmp1, fe_relax_cast(&tmp1), 2) fe_carry_pow2k(&tmp1, fe_relax_cast(&tmp1), 2)
fe_carry_mul(&tmp1, fe_relax_cast(&tmp1), arg1) fe_carry_mul(&tmp1, fe_relax_cast(&tmp1), fe_relax_cast(&w)) // w^((p-5)/8)
// quartic = x^((p-1)/4) fe_carry_mul(&tmp1, fe_relax_cast(&tmp1), arg1) // u * w^((p-5)/8)
quartic := &tmp2
fe_carry_square(quartic, fe_relax_cast(&tmp1))
fe_carry_mul(quartic, fe_relax_cast(quartic), arg1)
// Serialize quartic once to save on repeated serialization/sanitization. // Serialize `check` once to save on repeated serialization.
quartic_buf: [32]byte = --- r, check := &tmp1, &tmp2
fe_to_bytes(&quartic_buf, quartic) b: [32]byte = ---
check := &tmp3 fe_carry_square(check, fe_relax_cast(r))
fe_carry_mul(check, fe_relax_cast(check), arg2) // check * v
fe_to_bytes(&b, check)
fe_one(check) u, neg_u, neg_u_i := &tmp3, &w, check
p1 := fe_equal_bytes(check, &quartic_buf) fe_carry(u, arg1)
fe_carry_opp(check, check) fe_carry_opp(neg_u, u)
m1 := fe_equal_bytes(check, &quartic_buf) fe_carry_mul(neg_u_i, fe_relax_cast(neg_u), fe_relax_cast(&FE_SQRT_M1))
fe_carry_opp(check, &SQRT_M1)
ms := fe_equal_bytes(check, &quartic_buf)
// if quartic == -1 or sqrt(-1) correct_sign_sqrt := fe_equal_bytes(u, &b)
// then isr = x^((p-1)/4) * sqrt(-1) flipped_sign_sqrt := fe_equal_bytes(neg_u, &b)
// else isr = x^((p-1)/4) flipped_sign_sqrt_i := fe_equal_bytes(neg_u_i, &b)
fe_carry_mul(out1, fe_relax_cast(&tmp1), fe_relax_cast(&SQRT_M1))
fe_cond_assign(out1, &tmp1, (m1|ms) ~ 1)
mem.zero_explicit(&tmp1, size_of(tmp1)) r_prime := check
mem.zero_explicit(&tmp2, size_of(tmp2)) fe_carry_mul(r_prime, fe_relax_cast(r), fe_relax_cast(&FE_SQRT_M1))
mem.zero_explicit(&tmp3, size_of(tmp3)) fe_cond_assign(r, r_prime, flipped_sign_sqrt | flipped_sign_sqrt_i)
mem.zero_explicit(&quartic_buf, size_of(quartic_buf))
return p1 | m1 // Pick the non-negative square root.
fe_carry_abs(out1, r)
fe_clear_vec([]^Tight_Field_Element{&w, &tmp1, &tmp2, &tmp3})
mem.zero_explicit(&b, size_of(b))
return correct_sign_sqrt | flipped_sign_sqrt
} }
fe_carry_inv :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) { fe_carry_inv :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) {
tmp1: Tight_Field_Element tmp1: Tight_Field_Element
fe_carry_square(&tmp1, arg1) fe_carry_square(&tmp1, arg1)
_ = fe_carry_invsqrt(&tmp1, fe_relax_cast(&tmp1)) _ = fe_carry_sqrt_ratio_m1(&tmp1, fe_relax_cast(&FE_ONE), fe_relax_cast(&tmp1))
fe_carry_square(&tmp1, fe_relax_cast(&tmp1)) fe_carry_square(&tmp1, fe_relax_cast(&tmp1))
fe_carry_mul(out1, fe_relax_cast(&tmp1), arg1) fe_carry_mul(out1, fe_relax_cast(&tmp1), arg1)
mem.zero_explicit(&tmp1, size_of(tmp1)) fe_clear(&tmp1)
}
fe_zero :: proc "contextless" (out1: ^Tight_Field_Element) {
out1[0] = 0
out1[1] = 0
out1[2] = 0
out1[3] = 0
out1[4] = 0
}
fe_one :: proc "contextless" (out1: ^Tight_Field_Element) {
out1[0] = 1
out1[1] = 0
out1[2] = 0
out1[3] = 0
out1[4] = 0
}
fe_set :: proc "contextless" (out1, arg1: ^Tight_Field_Element) {
x1 := arg1[0]
x2 := arg1[1]
x3 := arg1[2]
x4 := arg1[3]
x5 := arg1[4]
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
out1[4] = x5
}
@(optimization_mode = "none")
fe_cond_swap :: #force_no_inline proc "contextless" (out1, out2: ^Tight_Field_Element, arg1: int) {
mask := (u64(arg1) * 0xffffffffffffffff)
x := (out1[0] ~ out2[0]) & mask
x1, y1 := out1[0] ~ x, out2[0] ~ x
x = (out1[1] ~ out2[1]) & mask
x2, y2 := out1[1] ~ x, out2[1] ~ x
x = (out1[2] ~ out2[2]) & mask
x3, y3 := out1[2] ~ x, out2[2] ~ x
x = (out1[3] ~ out2[3]) & mask
x4, y4 := out1[3] ~ x, out2[3] ~ x
x = (out1[4] ~ out2[4]) & mask
x5, y5 := out1[4] ~ x, out2[4] ~ x
out1[0], out2[0] = x1, y1
out1[1], out2[1] = x2, y2
out1[2], out2[2] = x3, y3
out1[3], out2[3] = x4, y4
out1[4], out2[4] = x5, y5
}
@(optimization_mode = "none")
fe_cond_select :: #force_no_inline proc "contextless" (
out1, arg1, arg2: $T,
arg3: int,
) where T == ^Tight_Field_Element || T == ^Loose_Field_Element {
mask := (u64(arg3) * 0xffffffffffffffff)
x1 := ((mask & arg2[0]) | ((~mask) & arg1[0]))
x2 := ((mask & arg2[1]) | ((~mask) & arg1[1]))
x3 := ((mask & arg2[2]) | ((~mask) & arg1[2]))
x4 := ((mask & arg2[3]) | ((~mask) & arg1[3]))
x5 := ((mask & arg2[4]) | ((~mask) & arg1[4]))
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
out1[4] = x5
}
fe_cond_negate :: proc "contextless" (out1, arg1: ^Tight_Field_Element, ctrl: int) {
tmp1: Tight_Field_Element = ---
fe_carry_opp(&tmp1, arg1)
fe_cond_select(out1, arg1, &tmp1, ctrl)
fe_clear(&tmp1)
} }
+29 -61
View File
@@ -30,8 +30,6 @@ package field_curve25519
// //
// While the base implementation is provably correct, this implementation // While the base implementation is provably correct, this implementation
// makes no such claims as the port and optimizations were done by hand. // makes no such claims as the port and optimizations were done by hand.
// At some point, it may be worth adding support to fiat-crypto for
// generating Odin output.
// //
// TODO: // TODO:
// * When fiat-crypto supports it, using a saturated 64-bit limbs // * When fiat-crypto supports it, using a saturated 64-bit limbs
@@ -44,7 +42,10 @@ import "core:math/bits"
Loose_Field_Element :: distinct [5]u64 Loose_Field_Element :: distinct [5]u64
Tight_Field_Element :: distinct [5]u64 Tight_Field_Element :: distinct [5]u64
SQRT_M1 := Tight_Field_Element{ FE_ZERO := Tight_Field_Element{0, 0, 0, 0, 0}
FE_ONE := Tight_Field_Element{1, 0, 0, 0, 0}
FE_SQRT_M1 := Tight_Field_Element {
1718705420411056, 1718705420411056,
234908883556509, 234908883556509,
2233514472574048, 2233514472574048,
@@ -52,7 +53,13 @@ SQRT_M1 := Tight_Field_Element{
765476049583133, 765476049583133,
} }
_addcarryx_u51 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) { _addcarryx_u51 :: #force_inline proc "contextless" (
arg1: fiat.u1,
arg2, arg3: u64,
) -> (
out1: u64,
out2: fiat.u1,
) {
x1 := ((u64(arg1) + arg2) + arg3) x1 := ((u64(arg1) + arg2) + arg3)
x2 := (x1 & 0x7ffffffffffff) x2 := (x1 & 0x7ffffffffffff)
x3 := fiat.u1((x1 >> 51)) x3 := fiat.u1((x1 >> 51))
@@ -61,7 +68,13 @@ _addcarryx_u51 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u
return return
} }
_subborrowx_u51 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) { _subborrowx_u51 :: #force_inline proc "contextless" (
arg1: fiat.u1,
arg2, arg3: u64,
) -> (
out1: u64,
out2: fiat.u1,
) {
x1 := ((i64(arg2) - i64(arg1)) - i64(arg3)) x1 := ((i64(arg2) - i64(arg1)) - i64(arg3))
x2 := fiat.i1((x1 >> 51)) x2 := fiat.i1((x1 >> 51))
x3 := (u64(x1) & 0x7ffffffffffff) x3 := (u64(x1) & 0x7ffffffffffff)
@@ -70,7 +83,7 @@ _subborrowx_u51 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3:
return return
} }
fe_carry_mul :: proc (out1: ^Tight_Field_Element, arg1, arg2: ^Loose_Field_Element) { fe_carry_mul :: proc "contextless" (out1: ^Tight_Field_Element, arg1, arg2: ^Loose_Field_Element) {
x2, x1 := bits.mul_u64(arg1[4], (arg2[4] * 0x13)) x2, x1 := bits.mul_u64(arg1[4], (arg2[4] * 0x13))
x4, x3 := bits.mul_u64(arg1[4], (arg2[3] * 0x13)) x4, x3 := bits.mul_u64(arg1[4], (arg2[3] * 0x13))
x6, x5 := bits.mul_u64(arg1[4], (arg2[2] * 0x13)) x6, x5 := bits.mul_u64(arg1[4], (arg2[2] * 0x13))
@@ -169,7 +182,7 @@ fe_carry_mul :: proc (out1: ^Tight_Field_Element, arg1, arg2: ^Loose_Field_Eleme
out1[4] = x152 out1[4] = x152
} }
fe_carry_square :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) { fe_carry_square :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) {
x1 := (arg1[4] * 0x13) x1 := (arg1[4] * 0x13)
x2 := (x1 * 0x2) x2 := (x1 * 0x2)
x3 := (arg1[4] * 0x2) x3 := (arg1[4] * 0x2)
@@ -305,8 +318,11 @@ fe_opp :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Ele
out1[4] = x5 out1[4] = x5
} }
@(optimization_mode="none") @(optimization_mode = "none")
fe_cond_assign :: #force_no_inline proc "contextless" (out1, arg1: ^Tight_Field_Element, arg2: int) { fe_cond_assign :: #force_no_inline proc "contextless" (
out1, arg1: ^Tight_Field_Element,
arg2: int,
) {
x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0]) x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0])
x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1]) x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1])
x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2]) x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2])
@@ -527,7 +543,10 @@ fe_relax :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_E
out1[4] = x5 out1[4] = x5
} }
fe_carry_scmul_121666 :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) { fe_carry_scmul_121666 :: proc "contextless" (
out1: ^Tight_Field_Element,
arg1: ^Loose_Field_Element,
) {
x2, x1 := bits.mul_u64(0x1db42, arg1[4]) x2, x1 := bits.mul_u64(0x1db42, arg1[4])
x4, x3 := bits.mul_u64(0x1db42, arg1[3]) x4, x3 := bits.mul_u64(0x1db42, arg1[3])
x6, x5 := bits.mul_u64(0x1db42, arg1[2]) x6, x5 := bits.mul_u64(0x1db42, arg1[2])
@@ -565,54 +584,3 @@ fe_carry_scmul_121666 :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_El
out1[3] = x27 out1[3] = x27
out1[4] = x32 out1[4] = x32
} }
// The following routines were added by hand, and do not come from fiat-crypto.
fe_zero :: proc "contextless" (out1: ^Tight_Field_Element) {
out1[0] = 0
out1[1] = 0
out1[2] = 0
out1[3] = 0
out1[4] = 0
}
fe_one :: proc "contextless" (out1: ^Tight_Field_Element) {
out1[0] = 1
out1[1] = 0
out1[2] = 0
out1[3] = 0
out1[4] = 0
}
fe_set :: proc "contextless" (out1, arg1: ^Tight_Field_Element) {
x1 := arg1[0]
x2 := arg1[1]
x3 := arg1[2]
x4 := arg1[3]
x5 := arg1[4]
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
out1[4] = x5
}
@(optimization_mode="none")
fe_cond_swap :: #force_no_inline proc "contextless" (out1, out2: ^Tight_Field_Element, arg1: int) {
mask := -u64(arg1)
x := (out1[0] ~ out2[0]) & mask
x1, y1 := out1[0] ~ x, out2[0] ~ x
x = (out1[1] ~ out2[1]) & mask
x2, y2 := out1[1] ~ x, out2[1] ~ x
x = (out1[2] ~ out2[2]) & mask
x3, y3 := out1[2] ~ x, out2[2] ~ x
x = (out1[3] ~ out2[3]) & mask
x4, y4 := out1[3] ~ x, out2[3] ~ x
x = (out1[4] ~ out2[4]) & mask
x5, y5 := out1[4] ~ x, out2[4] ~ x
out1[0], out2[0] = x1, y1
out1[1], out2[1] = x2, y2
out1[2], out2[2] = x3, y3
out1[3], out2[3] = x4, y4
out1[4], out2[4] = x5, y5
}
+47 -4
View File
@@ -1,17 +1,26 @@
package field_poly1305 package field_poly1305
import "base:intrinsics"
import "core:encoding/endian" import "core:encoding/endian"
import "core:mem" import "core:mem"
fe_relax_cast :: #force_inline proc "contextless" (arg1: ^Tight_Field_Element) -> ^Loose_Field_Element { fe_relax_cast :: #force_inline proc "contextless" (
arg1: ^Tight_Field_Element,
) -> ^Loose_Field_Element {
return transmute(^Loose_Field_Element)(arg1) return transmute(^Loose_Field_Element)(arg1)
} }
fe_tighten_cast :: #force_inline proc "contextless" (arg1: ^Loose_Field_Element) -> ^Tight_Field_Element { fe_tighten_cast :: #force_inline proc "contextless" (
arg1: ^Loose_Field_Element,
) -> ^Tight_Field_Element {
return transmute(^Tight_Field_Element)(arg1) return transmute(^Tight_Field_Element)(arg1)
} }
fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, arg2: byte) { fe_from_bytes :: #force_inline proc "contextless" (
out1: ^Tight_Field_Element,
arg1: []byte,
arg2: byte,
) {
// fiat-crypto's deserialization routine effectively processes a // fiat-crypto's deserialization routine effectively processes a
// single byte at a time, and wants 256-bits of input for a value // single byte at a time, and wants 256-bits of input for a value
// that will be 128-bits or 129-bits. // that will be 128-bits or 129-bits.
@@ -20,7 +29,9 @@ fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, a
// makes implementing the actual MAC block processing considerably // makes implementing the actual MAC block processing considerably
// neater. // neater.
assert(len(arg1) == 16) if len(arg1) != 16 {
intrinsics.trap()
}
// While it may be unwise to do deserialization here on our // While it may be unwise to do deserialization here on our
// own when fiat-crypto provides equivalent functionality, // own when fiat-crypto provides equivalent functionality,
@@ -51,3 +62,35 @@ fe_from_u64s :: proc "contextless" (out1: ^Tight_Field_Element, lo, hi: u64) {
// This routine is only used to deserialize `r` which is confidential. // This routine is only used to deserialize `r` which is confidential.
mem.zero_explicit(&tmp, size_of(tmp)) mem.zero_explicit(&tmp, size_of(tmp))
} }
fe_zero :: proc "contextless" (out1: ^Tight_Field_Element) {
out1[0] = 0
out1[1] = 0
out1[2] = 0
}
fe_set :: #force_inline proc "contextless" (out1, arg1: ^Tight_Field_Element) {
x1 := arg1[0]
x2 := arg1[1]
x3 := arg1[2]
out1[0] = x1
out1[1] = x2
out1[2] = x3
}
@(optimization_mode = "none")
fe_cond_swap :: #force_no_inline proc "contextless" (
out1, out2: ^Tight_Field_Element,
arg1: bool,
) {
mask := (u64(arg1) * 0xffffffffffffffff)
x := (out1[0] ~ out2[0]) & mask
x1, y1 := out1[0] ~ x, out2[0] ~ x
x = (out1[1] ~ out2[1]) & mask
x2, y2 := out1[1] ~ x, out2[1] ~ x
x = (out1[2] ~ out2[2]) & mask
x3, y3 := out1[2] ~ x, out2[2] ~ x
out1[0], out2[0] = x1, y1
out1[1], out2[1] = x2, y2
out1[2], out2[2] = x3, y3
}
+35 -39
View File
@@ -39,7 +39,13 @@ import "core:math/bits"
Loose_Field_Element :: distinct [3]u64 Loose_Field_Element :: distinct [3]u64
Tight_Field_Element :: distinct [3]u64 Tight_Field_Element :: distinct [3]u64
_addcarryx_u44 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) { _addcarryx_u44 :: #force_inline proc "contextless" (
arg1: fiat.u1,
arg2, arg3: u64,
) -> (
out1: u64,
out2: fiat.u1,
) {
x1 := ((u64(arg1) + arg2) + arg3) x1 := ((u64(arg1) + arg2) + arg3)
x2 := (x1 & 0xfffffffffff) x2 := (x1 & 0xfffffffffff)
x3 := fiat.u1((x1 >> 44)) x3 := fiat.u1((x1 >> 44))
@@ -48,7 +54,13 @@ _addcarryx_u44 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u
return return
} }
_subborrowx_u44 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) { _subborrowx_u44 :: #force_inline proc "contextless" (
arg1: fiat.u1,
arg2, arg3: u64,
) -> (
out1: u64,
out2: fiat.u1,
) {
x1 := ((i64(arg2) - i64(arg1)) - i64(arg3)) x1 := ((i64(arg2) - i64(arg1)) - i64(arg3))
x2 := fiat.i1((x1 >> 44)) x2 := fiat.i1((x1 >> 44))
x3 := (u64(x1) & 0xfffffffffff) x3 := (u64(x1) & 0xfffffffffff)
@@ -57,7 +69,13 @@ _subborrowx_u44 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3:
return return
} }
_addcarryx_u43 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) { _addcarryx_u43 :: #force_inline proc "contextless" (
arg1: fiat.u1,
arg2, arg3: u64,
) -> (
out1: u64,
out2: fiat.u1,
) {
x1 := ((u64(arg1) + arg2) + arg3) x1 := ((u64(arg1) + arg2) + arg3)
x2 := (x1 & 0x7ffffffffff) x2 := (x1 & 0x7ffffffffff)
x3 := fiat.u1((x1 >> 43)) x3 := fiat.u1((x1 >> 43))
@@ -66,7 +84,13 @@ _addcarryx_u43 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u
return return
} }
_subborrowx_u43 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) { _subborrowx_u43 :: #force_inline proc "contextless" (
arg1: fiat.u1,
arg2, arg3: u64,
) -> (
out1: u64,
out2: fiat.u1,
) {
x1 := ((i64(arg2) - i64(arg1)) - i64(arg3)) x1 := ((i64(arg2) - i64(arg1)) - i64(arg3))
x2 := fiat.i1((x1 >> 43)) x2 := fiat.i1((x1 >> 43))
x3 := (u64(x1) & 0x7ffffffffff) x3 := (u64(x1) & 0x7ffffffffff)
@@ -75,7 +99,7 @@ _subborrowx_u43 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3:
return return
} }
fe_carry_mul :: proc (out1: ^Tight_Field_Element, arg1, arg2: ^Loose_Field_Element) { fe_carry_mul :: proc "contextless" (out1: ^Tight_Field_Element, arg1, arg2: ^Loose_Field_Element) {
x2, x1 := bits.mul_u64(arg1[2], (arg2[2] * 0x5)) x2, x1 := bits.mul_u64(arg1[2], (arg2[2] * 0x5))
x4, x3 := bits.mul_u64(arg1[2], (arg2[1] * 0xa)) x4, x3 := bits.mul_u64(arg1[2], (arg2[1] * 0xa))
x6, x5 := bits.mul_u64(arg1[1], (arg2[2] * 0xa)) x6, x5 := bits.mul_u64(arg1[1], (arg2[2] * 0xa))
@@ -120,7 +144,7 @@ fe_carry_mul :: proc (out1: ^Tight_Field_Element, arg1, arg2: ^Loose_Field_Eleme
out1[2] = x62 out1[2] = x62
} }
fe_carry_square :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) { fe_carry_square :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) {
x1 := (arg1[2] * 0x5) x1 := (arg1[2] * 0x5)
x2 := (x1 * 0x2) x2 := (x1 * 0x2)
x3 := (arg1[2] * 0x2) x3 := (arg1[2] * 0x2)
@@ -201,8 +225,11 @@ fe_opp :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Ele
out1[2] = x3 out1[2] = x3
} }
@(optimization_mode="none") @(optimization_mode = "none")
fe_cond_assign :: #force_no_inline proc "contextless" (out1, arg1: ^Tight_Field_Element, arg2: bool) { fe_cond_assign :: #force_no_inline proc "contextless" (
out1, arg1: ^Tight_Field_Element,
arg2: bool,
) {
x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0]) x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0])
x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1]) x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1])
x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2]) x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2])
@@ -325,34 +352,3 @@ fe_relax :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_E
out1[1] = x2 out1[1] = x2
out1[2] = x3 out1[2] = x3
} }
// The following routines were added by hand, and do not come from fiat-crypto.
fe_zero :: proc "contextless" (out1: ^Tight_Field_Element) {
out1[0] = 0
out1[1] = 0
out1[2] = 0
}
fe_set :: #force_inline proc "contextless" (out1, arg1: ^Tight_Field_Element) {
x1 := arg1[0]
x2 := arg1[1]
x3 := arg1[2]
out1[0] = x1
out1[1] = x2
out1[2] = x3
}
@(optimization_mode="none")
fe_cond_swap :: #force_no_inline proc "contextless" (out1, out2: ^Tight_Field_Element, arg1: bool) {
mask := -u64(arg1)
x := (out1[0] ~ out2[0]) & mask
x1, y1 := out1[0] ~ x, out2[0] ~ x
x = (out1[1] ~ out2[1]) & mask
x2, y2 := out1[1] ~ x, out2[1] ~ x
x = (out1[2] ~ out2[2]) & mask
x3, y3 := out1[2] ~ x, out2[2] ~ x
out1[0], out2[0] = x1, y1
out1[1], out2[1] = x2, y2
out1[2], out2[2] = x3, y3
}
@@ -0,0 +1,153 @@
package field_scalar25519
import "base:intrinsics"
import "core:encoding/endian"
import "core:math/bits"
import "core:mem"
@(private)
_TWO_168 := Montgomery_Domain_Field_Element {
0x5b8ab432eac74798,
0x38afddd6de59d5d7,
0xa2c131b399411b7c,
0x6329a7ed9ce5a30,
}
@(private)
_TWO_336 := Montgomery_Domain_Field_Element {
0xbd3d108e2b35ecc5,
0x5c3a3718bdf9c90b,
0x63aa97a331b4f2ee,
0x3d217f5be65cb5c,
}
fe_clear :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) {
mem.zero_explicit(arg1, size_of(Montgomery_Domain_Field_Element))
}
fe_from_bytes :: proc "contextless" (
out1: ^Montgomery_Domain_Field_Element,
arg1: ^[32]byte,
unsafe_assume_canonical := false,
) -> bool {
tmp := Non_Montgomery_Domain_Field_Element {
endian.unchecked_get_u64le(arg1[0:]),
endian.unchecked_get_u64le(arg1[8:]),
endian.unchecked_get_u64le(arg1[16:]),
endian.unchecked_get_u64le(arg1[24:]),
}
defer mem.zero_explicit(&tmp, size_of(tmp))
// Check that tmp is in the the range [0, ELL).
if !unsafe_assume_canonical {
_, borrow := bits.sub_u64(ELL[0] - 1, tmp[0], 0)
_, borrow = bits.sub_u64(ELL[1], tmp[1], borrow)
_, borrow = bits.sub_u64(ELL[2], tmp[2], borrow)
_, borrow = bits.sub_u64(ELL[3], tmp[3], borrow)
if borrow != 0 {
return false
}
}
fe_to_montgomery(out1, &tmp)
return true
}
fe_from_bytes_rfc8032 :: proc "contextless" (
out1: ^Montgomery_Domain_Field_Element,
arg1: ^[32]byte,
) {
tmp: [64]byte
copy(tmp[:], arg1[:])
// Apply "clamping" as in RFC 8032.
tmp[0] &= 248
tmp[31] &= 127
tmp[31] |= 64 // Sets the 254th bit, so the encoding is non-canonical.
fe_from_bytes_wide(out1, &tmp)
mem.zero_explicit(&tmp, size_of(tmp))
}
fe_from_bytes_wide :: proc "contextless" (
out1: ^Montgomery_Domain_Field_Element,
arg1: ^[64]byte,
) {
tmp: Montgomery_Domain_Field_Element
// Use Frank Denis' trick, as documented by Filippo Valsorda
// at https://words.filippo.io/dispatches/wide-reduction/
//
// x = c * 2^336 + b * 2^168 + a mod l
_fe_from_bytes_short(out1, arg1[:21]) // a
_fe_from_bytes_short(&tmp, arg1[21:42]) // b
fe_mul(&tmp, &tmp, &_TWO_168) // b * 2^168
fe_add(out1, out1, &tmp) // a + b * 2^168
_fe_from_bytes_short(&tmp, arg1[42:]) // c
fe_mul(&tmp, &tmp, &_TWO_336) // c * 2^336
fe_add(out1, out1, &tmp) // a + b * 2^168 + c * 2^336
fe_clear(&tmp)
}
@(private)
_fe_from_bytes_short :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element, arg1: []byte) {
// INVARIANT: len(arg1) < 32.
if len(arg1) >= 32 {
intrinsics.trap()
}
tmp: [32]byte
copy(tmp[:], arg1)
_ = fe_from_bytes(out1, &tmp, true)
mem.zero_explicit(&tmp, size_of(tmp))
}
fe_to_bytes :: proc "contextless" (out1: []byte, arg1: ^Montgomery_Domain_Field_Element) {
if len(out1) != 32 {
intrinsics.trap()
}
tmp: Non_Montgomery_Domain_Field_Element
fe_from_montgomery(&tmp, arg1)
endian.unchecked_put_u64le(out1[0:], tmp[0])
endian.unchecked_put_u64le(out1[8:], tmp[1])
endian.unchecked_put_u64le(out1[16:], tmp[2])
endian.unchecked_put_u64le(out1[24:], tmp[3])
mem.zero_explicit(&tmp, size_of(tmp))
}
fe_equal :: proc "contextless" (arg1, arg2: ^Montgomery_Domain_Field_Element) -> int {
tmp: Montgomery_Domain_Field_Element
fe_sub(&tmp, arg1, arg2)
// This will only underflow iff arg1 == arg2, and we return the borrow,
// which will be 1.
_, borrow := bits.sub_u64(fe_non_zero(&tmp), 1, 0)
fe_clear(&tmp)
return int(borrow)
}
fe_zero :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element) {
out1[0] = 0
out1[1] = 0
out1[2] = 0
out1[3] = 0
}
fe_set :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) {
x1 := arg1[0]
x2 := arg1[1]
x3 := arg1[2]
x4 := arg1[3]
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
}
@@ -0,0 +1,535 @@
// The BSD 1-Clause License (BSD-1-Clause)
//
// Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file)
// 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 fiat-crypto 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 Berkeley Software Design,
// Inc. 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.
package field_scalar25519
// The file provides arithmetic on the field Z/(2^252+27742317777372353535851937790883648493)
// using a 64-bit Montgomery form internal representation. It is derived
// primarily from the machine generated Golang output from the fiat-crypto
// project.
//
// While the base implementation is provably correct, this implementation
// makes no such claims as the port and optimizations were done by hand.
import fiat "core:crypto/_fiat"
import "core:math/bits"
// ELL is the saturated representation of the field order, least-significant
// limb first.
ELL :: [4]u64{0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0x0, 0x1000000000000000}
Montgomery_Domain_Field_Element :: distinct [4]u64
Non_Montgomery_Domain_Field_Element :: distinct [4]u64
fe_mul :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) {
x1 := arg1[1]
x2 := arg1[2]
x3 := arg1[3]
x4 := arg1[0]
x6, x5 := bits.mul_u64(x4, arg2[3])
x8, x7 := bits.mul_u64(x4, arg2[2])
x10, x9 := bits.mul_u64(x4, arg2[1])
x12, x11 := bits.mul_u64(x4, arg2[0])
x13, x14 := bits.add_u64(x12, x9, u64(0x0))
x15, x16 := bits.add_u64(x10, x7, u64(fiat.u1(x14)))
x17, x18 := bits.add_u64(x8, x5, u64(fiat.u1(x16)))
x19 := (u64(fiat.u1(x18)) + x6)
_, x20 := bits.mul_u64(x11, 0xd2b51da312547e1b)
x23, x22 := bits.mul_u64(x20, 0x1000000000000000)
x25, x24 := bits.mul_u64(x20, 0x14def9dea2f79cd6)
x27, x26 := bits.mul_u64(x20, 0x5812631a5cf5d3ed)
x28, x29 := bits.add_u64(x27, x24, u64(0x0))
x30 := (u64(fiat.u1(x29)) + x25)
_, x32 := bits.add_u64(x11, x26, u64(0x0))
x33, x34 := bits.add_u64(x13, x28, u64(fiat.u1(x32)))
x35, x36 := bits.add_u64(x15, x30, u64(fiat.u1(x34)))
x37, x38 := bits.add_u64(x17, x22, u64(fiat.u1(x36)))
x39, x40 := bits.add_u64(x19, x23, u64(fiat.u1(x38)))
x42, x41 := bits.mul_u64(x1, arg2[3])
x44, x43 := bits.mul_u64(x1, arg2[2])
x46, x45 := bits.mul_u64(x1, arg2[1])
x48, x47 := bits.mul_u64(x1, arg2[0])
x49, x50 := bits.add_u64(x48, x45, u64(0x0))
x51, x52 := bits.add_u64(x46, x43, u64(fiat.u1(x50)))
x53, x54 := bits.add_u64(x44, x41, u64(fiat.u1(x52)))
x55 := (u64(fiat.u1(x54)) + x42)
x56, x57 := bits.add_u64(x33, x47, u64(0x0))
x58, x59 := bits.add_u64(x35, x49, u64(fiat.u1(x57)))
x60, x61 := bits.add_u64(x37, x51, u64(fiat.u1(x59)))
x62, x63 := bits.add_u64(x39, x53, u64(fiat.u1(x61)))
x64, x65 := bits.add_u64(u64(fiat.u1(x40)), x55, u64(fiat.u1(x63)))
_, x66 := bits.mul_u64(x56, 0xd2b51da312547e1b)
x69, x68 := bits.mul_u64(x66, 0x1000000000000000)
x71, x70 := bits.mul_u64(x66, 0x14def9dea2f79cd6)
x73, x72 := bits.mul_u64(x66, 0x5812631a5cf5d3ed)
x74, x75 := bits.add_u64(x73, x70, u64(0x0))
x76 := (u64(fiat.u1(x75)) + x71)
_, x78 := bits.add_u64(x56, x72, u64(0x0))
x79, x80 := bits.add_u64(x58, x74, u64(fiat.u1(x78)))
x81, x82 := bits.add_u64(x60, x76, u64(fiat.u1(x80)))
x83, x84 := bits.add_u64(x62, x68, u64(fiat.u1(x82)))
x85, x86 := bits.add_u64(x64, x69, u64(fiat.u1(x84)))
x87 := (u64(fiat.u1(x86)) + u64(fiat.u1(x65)))
x89, x88 := bits.mul_u64(x2, arg2[3])
x91, x90 := bits.mul_u64(x2, arg2[2])
x93, x92 := bits.mul_u64(x2, arg2[1])
x95, x94 := bits.mul_u64(x2, arg2[0])
x96, x97 := bits.add_u64(x95, x92, u64(0x0))
x98, x99 := bits.add_u64(x93, x90, u64(fiat.u1(x97)))
x100, x101 := bits.add_u64(x91, x88, u64(fiat.u1(x99)))
x102 := (u64(fiat.u1(x101)) + x89)
x103, x104 := bits.add_u64(x79, x94, u64(0x0))
x105, x106 := bits.add_u64(x81, x96, u64(fiat.u1(x104)))
x107, x108 := bits.add_u64(x83, x98, u64(fiat.u1(x106)))
x109, x110 := bits.add_u64(x85, x100, u64(fiat.u1(x108)))
x111, x112 := bits.add_u64(x87, x102, u64(fiat.u1(x110)))
_, x113 := bits.mul_u64(x103, 0xd2b51da312547e1b)
x116, x115 := bits.mul_u64(x113, 0x1000000000000000)
x118, x117 := bits.mul_u64(x113, 0x14def9dea2f79cd6)
x120, x119 := bits.mul_u64(x113, 0x5812631a5cf5d3ed)
x121, x122 := bits.add_u64(x120, x117, u64(0x0))
x123 := (u64(fiat.u1(x122)) + x118)
_, x125 := bits.add_u64(x103, x119, u64(0x0))
x126, x127 := bits.add_u64(x105, x121, u64(fiat.u1(x125)))
x128, x129 := bits.add_u64(x107, x123, u64(fiat.u1(x127)))
x130, x131 := bits.add_u64(x109, x115, u64(fiat.u1(x129)))
x132, x133 := bits.add_u64(x111, x116, u64(fiat.u1(x131)))
x134 := (u64(fiat.u1(x133)) + u64(fiat.u1(x112)))
x136, x135 := bits.mul_u64(x3, arg2[3])
x138, x137 := bits.mul_u64(x3, arg2[2])
x140, x139 := bits.mul_u64(x3, arg2[1])
x142, x141 := bits.mul_u64(x3, arg2[0])
x143, x144 := bits.add_u64(x142, x139, u64(0x0))
x145, x146 := bits.add_u64(x140, x137, u64(fiat.u1(x144)))
x147, x148 := bits.add_u64(x138, x135, u64(fiat.u1(x146)))
x149 := (u64(fiat.u1(x148)) + x136)
x150, x151 := bits.add_u64(x126, x141, u64(0x0))
x152, x153 := bits.add_u64(x128, x143, u64(fiat.u1(x151)))
x154, x155 := bits.add_u64(x130, x145, u64(fiat.u1(x153)))
x156, x157 := bits.add_u64(x132, x147, u64(fiat.u1(x155)))
x158, x159 := bits.add_u64(x134, x149, u64(fiat.u1(x157)))
_, x160 := bits.mul_u64(x150, 0xd2b51da312547e1b)
x163, x162 := bits.mul_u64(x160, 0x1000000000000000)
x165, x164 := bits.mul_u64(x160, 0x14def9dea2f79cd6)
x167, x166 := bits.mul_u64(x160, 0x5812631a5cf5d3ed)
x168, x169 := bits.add_u64(x167, x164, u64(0x0))
x170 := (u64(fiat.u1(x169)) + x165)
_, x172 := bits.add_u64(x150, x166, u64(0x0))
x173, x174 := bits.add_u64(x152, x168, u64(fiat.u1(x172)))
x175, x176 := bits.add_u64(x154, x170, u64(fiat.u1(x174)))
x177, x178 := bits.add_u64(x156, x162, u64(fiat.u1(x176)))
x179, x180 := bits.add_u64(x158, x163, u64(fiat.u1(x178)))
x181 := (u64(fiat.u1(x180)) + u64(fiat.u1(x159)))
x182, x183 := bits.sub_u64(x173, 0x5812631a5cf5d3ed, u64(0x0))
x184, x185 := bits.sub_u64(x175, 0x14def9dea2f79cd6, u64(fiat.u1(x183)))
x186, x187 := bits.sub_u64(x177, u64(0x0), u64(fiat.u1(x185)))
x188, x189 := bits.sub_u64(x179, 0x1000000000000000, u64(fiat.u1(x187)))
_, x191 := bits.sub_u64(x181, u64(0x0), u64(fiat.u1(x189)))
x192 := fiat.cmovznz_u64(fiat.u1(x191), x182, x173)
x193 := fiat.cmovznz_u64(fiat.u1(x191), x184, x175)
x194 := fiat.cmovznz_u64(fiat.u1(x191), x186, x177)
x195 := fiat.cmovznz_u64(fiat.u1(x191), x188, x179)
out1[0] = x192
out1[1] = x193
out1[2] = x194
out1[3] = x195
}
fe_square :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) {
x1 := arg1[1]
x2 := arg1[2]
x3 := arg1[3]
x4 := arg1[0]
x6, x5 := bits.mul_u64(x4, arg1[3])
x8, x7 := bits.mul_u64(x4, arg1[2])
x10, x9 := bits.mul_u64(x4, arg1[1])
x12, x11 := bits.mul_u64(x4, arg1[0])
x13, x14 := bits.add_u64(x12, x9, u64(0x0))
x15, x16 := bits.add_u64(x10, x7, u64(fiat.u1(x14)))
x17, x18 := bits.add_u64(x8, x5, u64(fiat.u1(x16)))
x19 := (u64(fiat.u1(x18)) + x6)
_, x20 := bits.mul_u64(x11, 0xd2b51da312547e1b)
x23, x22 := bits.mul_u64(x20, 0x1000000000000000)
x25, x24 := bits.mul_u64(x20, 0x14def9dea2f79cd6)
x27, x26 := bits.mul_u64(x20, 0x5812631a5cf5d3ed)
x28, x29 := bits.add_u64(x27, x24, u64(0x0))
x30 := (u64(fiat.u1(x29)) + x25)
_, x32 := bits.add_u64(x11, x26, u64(0x0))
x33, x34 := bits.add_u64(x13, x28, u64(fiat.u1(x32)))
x35, x36 := bits.add_u64(x15, x30, u64(fiat.u1(x34)))
x37, x38 := bits.add_u64(x17, x22, u64(fiat.u1(x36)))
x39, x40 := bits.add_u64(x19, x23, u64(fiat.u1(x38)))
x42, x41 := bits.mul_u64(x1, arg1[3])
x44, x43 := bits.mul_u64(x1, arg1[2])
x46, x45 := bits.mul_u64(x1, arg1[1])
x48, x47 := bits.mul_u64(x1, arg1[0])
x49, x50 := bits.add_u64(x48, x45, u64(0x0))
x51, x52 := bits.add_u64(x46, x43, u64(fiat.u1(x50)))
x53, x54 := bits.add_u64(x44, x41, u64(fiat.u1(x52)))
x55 := (u64(fiat.u1(x54)) + x42)
x56, x57 := bits.add_u64(x33, x47, u64(0x0))
x58, x59 := bits.add_u64(x35, x49, u64(fiat.u1(x57)))
x60, x61 := bits.add_u64(x37, x51, u64(fiat.u1(x59)))
x62, x63 := bits.add_u64(x39, x53, u64(fiat.u1(x61)))
x64, x65 := bits.add_u64(u64(fiat.u1(x40)), x55, u64(fiat.u1(x63)))
_, x66 := bits.mul_u64(x56, 0xd2b51da312547e1b)
x69, x68 := bits.mul_u64(x66, 0x1000000000000000)
x71, x70 := bits.mul_u64(x66, 0x14def9dea2f79cd6)
x73, x72 := bits.mul_u64(x66, 0x5812631a5cf5d3ed)
x74, x75 := bits.add_u64(x73, x70, u64(0x0))
x76 := (u64(fiat.u1(x75)) + x71)
_, x78 := bits.add_u64(x56, x72, u64(0x0))
x79, x80 := bits.add_u64(x58, x74, u64(fiat.u1(x78)))
x81, x82 := bits.add_u64(x60, x76, u64(fiat.u1(x80)))
x83, x84 := bits.add_u64(x62, x68, u64(fiat.u1(x82)))
x85, x86 := bits.add_u64(x64, x69, u64(fiat.u1(x84)))
x87 := (u64(fiat.u1(x86)) + u64(fiat.u1(x65)))
x89, x88 := bits.mul_u64(x2, arg1[3])
x91, x90 := bits.mul_u64(x2, arg1[2])
x93, x92 := bits.mul_u64(x2, arg1[1])
x95, x94 := bits.mul_u64(x2, arg1[0])
x96, x97 := bits.add_u64(x95, x92, u64(0x0))
x98, x99 := bits.add_u64(x93, x90, u64(fiat.u1(x97)))
x100, x101 := bits.add_u64(x91, x88, u64(fiat.u1(x99)))
x102 := (u64(fiat.u1(x101)) + x89)
x103, x104 := bits.add_u64(x79, x94, u64(0x0))
x105, x106 := bits.add_u64(x81, x96, u64(fiat.u1(x104)))
x107, x108 := bits.add_u64(x83, x98, u64(fiat.u1(x106)))
x109, x110 := bits.add_u64(x85, x100, u64(fiat.u1(x108)))
x111, x112 := bits.add_u64(x87, x102, u64(fiat.u1(x110)))
_, x113 := bits.mul_u64(x103, 0xd2b51da312547e1b)
x116, x115 := bits.mul_u64(x113, 0x1000000000000000)
x118, x117 := bits.mul_u64(x113, 0x14def9dea2f79cd6)
x120, x119 := bits.mul_u64(x113, 0x5812631a5cf5d3ed)
x121, x122 := bits.add_u64(x120, x117, u64(0x0))
x123 := (u64(fiat.u1(x122)) + x118)
_, x125 := bits.add_u64(x103, x119, u64(0x0))
x126, x127 := bits.add_u64(x105, x121, u64(fiat.u1(x125)))
x128, x129 := bits.add_u64(x107, x123, u64(fiat.u1(x127)))
x130, x131 := bits.add_u64(x109, x115, u64(fiat.u1(x129)))
x132, x133 := bits.add_u64(x111, x116, u64(fiat.u1(x131)))
x134 := (u64(fiat.u1(x133)) + u64(fiat.u1(x112)))
x136, x135 := bits.mul_u64(x3, arg1[3])
x138, x137 := bits.mul_u64(x3, arg1[2])
x140, x139 := bits.mul_u64(x3, arg1[1])
x142, x141 := bits.mul_u64(x3, arg1[0])
x143, x144 := bits.add_u64(x142, x139, u64(0x0))
x145, x146 := bits.add_u64(x140, x137, u64(fiat.u1(x144)))
x147, x148 := bits.add_u64(x138, x135, u64(fiat.u1(x146)))
x149 := (u64(fiat.u1(x148)) + x136)
x150, x151 := bits.add_u64(x126, x141, u64(0x0))
x152, x153 := bits.add_u64(x128, x143, u64(fiat.u1(x151)))
x154, x155 := bits.add_u64(x130, x145, u64(fiat.u1(x153)))
x156, x157 := bits.add_u64(x132, x147, u64(fiat.u1(x155)))
x158, x159 := bits.add_u64(x134, x149, u64(fiat.u1(x157)))
_, x160 := bits.mul_u64(x150, 0xd2b51da312547e1b)
x163, x162 := bits.mul_u64(x160, 0x1000000000000000)
x165, x164 := bits.mul_u64(x160, 0x14def9dea2f79cd6)
x167, x166 := bits.mul_u64(x160, 0x5812631a5cf5d3ed)
x168, x169 := bits.add_u64(x167, x164, u64(0x0))
x170 := (u64(fiat.u1(x169)) + x165)
_, x172 := bits.add_u64(x150, x166, u64(0x0))
x173, x174 := bits.add_u64(x152, x168, u64(fiat.u1(x172)))
x175, x176 := bits.add_u64(x154, x170, u64(fiat.u1(x174)))
x177, x178 := bits.add_u64(x156, x162, u64(fiat.u1(x176)))
x179, x180 := bits.add_u64(x158, x163, u64(fiat.u1(x178)))
x181 := (u64(fiat.u1(x180)) + u64(fiat.u1(x159)))
x182, x183 := bits.sub_u64(x173, 0x5812631a5cf5d3ed, u64(0x0))
x184, x185 := bits.sub_u64(x175, 0x14def9dea2f79cd6, u64(fiat.u1(x183)))
x186, x187 := bits.sub_u64(x177, u64(0x0), u64(fiat.u1(x185)))
x188, x189 := bits.sub_u64(x179, 0x1000000000000000, u64(fiat.u1(x187)))
_, x191 := bits.sub_u64(x181, u64(0x0), u64(fiat.u1(x189)))
x192 := fiat.cmovznz_u64(fiat.u1(x191), x182, x173)
x193 := fiat.cmovznz_u64(fiat.u1(x191), x184, x175)
x194 := fiat.cmovznz_u64(fiat.u1(x191), x186, x177)
x195 := fiat.cmovznz_u64(fiat.u1(x191), x188, x179)
out1[0] = x192
out1[1] = x193
out1[2] = x194
out1[3] = x195
}
fe_add :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) {
x1, x2 := bits.add_u64(arg1[0], arg2[0], u64(0x0))
x3, x4 := bits.add_u64(arg1[1], arg2[1], u64(fiat.u1(x2)))
x5, x6 := bits.add_u64(arg1[2], arg2[2], u64(fiat.u1(x4)))
x7, x8 := bits.add_u64(arg1[3], arg2[3], u64(fiat.u1(x6)))
x9, x10 := bits.sub_u64(x1, 0x5812631a5cf5d3ed, u64(0x0))
x11, x12 := bits.sub_u64(x3, 0x14def9dea2f79cd6, u64(fiat.u1(x10)))
x13, x14 := bits.sub_u64(x5, u64(0x0), u64(fiat.u1(x12)))
x15, x16 := bits.sub_u64(x7, 0x1000000000000000, u64(fiat.u1(x14)))
_, x18 := bits.sub_u64(u64(fiat.u1(x8)), u64(0x0), u64(fiat.u1(x16)))
x19 := fiat.cmovznz_u64(fiat.u1(x18), x9, x1)
x20 := fiat.cmovznz_u64(fiat.u1(x18), x11, x3)
x21 := fiat.cmovznz_u64(fiat.u1(x18), x13, x5)
x22 := fiat.cmovznz_u64(fiat.u1(x18), x15, x7)
out1[0] = x19
out1[1] = x20
out1[2] = x21
out1[3] = x22
}
fe_sub :: proc "contextless" (out1, arg1, arg2: ^Montgomery_Domain_Field_Element) {
x1, x2 := bits.sub_u64(arg1[0], arg2[0], u64(0x0))
x3, x4 := bits.sub_u64(arg1[1], arg2[1], u64(fiat.u1(x2)))
x5, x6 := bits.sub_u64(arg1[2], arg2[2], u64(fiat.u1(x4)))
x7, x8 := bits.sub_u64(arg1[3], arg2[3], u64(fiat.u1(x6)))
x9 := fiat.cmovznz_u64(fiat.u1(x8), u64(0x0), 0xffffffffffffffff)
x10, x11 := bits.add_u64(x1, (x9 & 0x5812631a5cf5d3ed), u64(0x0))
x12, x13 := bits.add_u64(x3, (x9 & 0x14def9dea2f79cd6), u64(fiat.u1(x11)))
x14, x15 := bits.add_u64(x5, u64(0x0), u64(fiat.u1(x13)))
x16, _ := bits.add_u64(x7, (x9 & 0x1000000000000000), u64(fiat.u1(x15)))
out1[0] = x10
out1[1] = x12
out1[2] = x14
out1[3] = x16
}
fe_opp :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) {
x1, x2 := bits.sub_u64(u64(0x0), arg1[0], u64(0x0))
x3, x4 := bits.sub_u64(u64(0x0), arg1[1], u64(fiat.u1(x2)))
x5, x6 := bits.sub_u64(u64(0x0), arg1[2], u64(fiat.u1(x4)))
x7, x8 := bits.sub_u64(u64(0x0), arg1[3], u64(fiat.u1(x6)))
x9 := fiat.cmovznz_u64(fiat.u1(x8), u64(0x0), 0xffffffffffffffff)
x10, x11 := bits.add_u64(x1, (x9 & 0x5812631a5cf5d3ed), u64(0x0))
x12, x13 := bits.add_u64(x3, (x9 & 0x14def9dea2f79cd6), u64(fiat.u1(x11)))
x14, x15 := bits.add_u64(x5, u64(0x0), u64(fiat.u1(x13)))
x16, _ := bits.add_u64(x7, (x9 & 0x1000000000000000), u64(fiat.u1(x15)))
out1[0] = x10
out1[1] = x12
out1[2] = x14
out1[3] = x16
}
fe_one :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element) {
out1[0] = 0xd6ec31748d98951d
out1[1] = 0xc6ef5bf4737dcf70
out1[2] = 0xfffffffffffffffe
out1[3] = 0xfffffffffffffff
}
fe_non_zero :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) -> u64 {
return arg1[0] | (arg1[1] | (arg1[2] | arg1[3]))
}
@(optimization_mode = "none")
fe_cond_assign :: #force_no_inline proc "contextless" (
out1, arg1: ^Montgomery_Domain_Field_Element,
arg2: int,
) {
x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0])
x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1])
x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2])
x4 := fiat.cmovznz_u64(fiat.u1(arg2), out1[3], arg1[3])
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
}
fe_from_montgomery :: proc "contextless" (
out1: ^Non_Montgomery_Domain_Field_Element,
arg1: ^Montgomery_Domain_Field_Element,
) {
x1 := arg1[0]
_, x2 := bits.mul_u64(x1, 0xd2b51da312547e1b)
x5, x4 := bits.mul_u64(x2, 0x1000000000000000)
x7, x6 := bits.mul_u64(x2, 0x14def9dea2f79cd6)
x9, x8 := bits.mul_u64(x2, 0x5812631a5cf5d3ed)
x10, x11 := bits.add_u64(x9, x6, u64(0x0))
_, x13 := bits.add_u64(x1, x8, u64(0x0))
x14, x15 := bits.add_u64(u64(0x0), x10, u64(fiat.u1(x13)))
x16, x17 := bits.add_u64(x14, arg1[1], u64(0x0))
_, x18 := bits.mul_u64(x16, 0xd2b51da312547e1b)
x21, x20 := bits.mul_u64(x18, 0x1000000000000000)
x23, x22 := bits.mul_u64(x18, 0x14def9dea2f79cd6)
x25, x24 := bits.mul_u64(x18, 0x5812631a5cf5d3ed)
x26, x27 := bits.add_u64(x25, x22, u64(0x0))
_, x29 := bits.add_u64(x16, x24, u64(0x0))
x30, x31 := bits.add_u64(
(u64(fiat.u1(x17)) + (u64(fiat.u1(x15)) + (u64(fiat.u1(x11)) + x7))),
x26,
u64(fiat.u1(x29)),
)
x32, x33 := bits.add_u64(x4, (u64(fiat.u1(x27)) + x23), u64(fiat.u1(x31)))
x34, x35 := bits.add_u64(x5, x20, u64(fiat.u1(x33)))
x36, x37 := bits.add_u64(x30, arg1[2], u64(0x0))
x38, x39 := bits.add_u64(x32, u64(0x0), u64(fiat.u1(x37)))
x40, x41 := bits.add_u64(x34, u64(0x0), u64(fiat.u1(x39)))
_, x42 := bits.mul_u64(x36, 0xd2b51da312547e1b)
x45, x44 := bits.mul_u64(x42, 0x1000000000000000)
x47, x46 := bits.mul_u64(x42, 0x14def9dea2f79cd6)
x49, x48 := bits.mul_u64(x42, 0x5812631a5cf5d3ed)
x50, x51 := bits.add_u64(x49, x46, u64(0x0))
_, x53 := bits.add_u64(x36, x48, u64(0x0))
x54, x55 := bits.add_u64(x38, x50, u64(fiat.u1(x53)))
x56, x57 := bits.add_u64(x40, (u64(fiat.u1(x51)) + x47), u64(fiat.u1(x55)))
x58, x59 := bits.add_u64(
(u64(fiat.u1(x41)) + (u64(fiat.u1(x35)) + x21)),
x44,
u64(fiat.u1(x57)),
)
x60, x61 := bits.add_u64(x54, arg1[3], u64(0x0))
x62, x63 := bits.add_u64(x56, u64(0x0), u64(fiat.u1(x61)))
x64, x65 := bits.add_u64(x58, u64(0x0), u64(fiat.u1(x63)))
_, x66 := bits.mul_u64(x60, 0xd2b51da312547e1b)
x69, x68 := bits.mul_u64(x66, 0x1000000000000000)
x71, x70 := bits.mul_u64(x66, 0x14def9dea2f79cd6)
x73, x72 := bits.mul_u64(x66, 0x5812631a5cf5d3ed)
x74, x75 := bits.add_u64(x73, x70, u64(0x0))
_, x77 := bits.add_u64(x60, x72, u64(0x0))
x78, x79 := bits.add_u64(x62, x74, u64(fiat.u1(x77)))
x80, x81 := bits.add_u64(x64, (u64(fiat.u1(x75)) + x71), u64(fiat.u1(x79)))
x82, x83 := bits.add_u64(
(u64(fiat.u1(x65)) + (u64(fiat.u1(x59)) + x45)),
x68,
u64(fiat.u1(x81)),
)
x84 := (u64(fiat.u1(x83)) + x69)
x85, x86 := bits.sub_u64(x78, 0x5812631a5cf5d3ed, u64(0x0))
x87, x88 := bits.sub_u64(x80, 0x14def9dea2f79cd6, u64(fiat.u1(x86)))
x89, x90 := bits.sub_u64(x82, u64(0x0), u64(fiat.u1(x88)))
x91, x92 := bits.sub_u64(x84, 0x1000000000000000, u64(fiat.u1(x90)))
_, x94 := bits.sub_u64(u64(0x0), u64(0x0), u64(fiat.u1(x92)))
x95 := fiat.cmovznz_u64(fiat.u1(x94), x85, x78)
x96 := fiat.cmovznz_u64(fiat.u1(x94), x87, x80)
x97 := fiat.cmovznz_u64(fiat.u1(x94), x89, x82)
x98 := fiat.cmovznz_u64(fiat.u1(x94), x91, x84)
out1[0] = x95
out1[1] = x96
out1[2] = x97
out1[3] = x98
}
fe_to_montgomery :: proc "contextless" (
out1: ^Montgomery_Domain_Field_Element,
arg1: ^Non_Montgomery_Domain_Field_Element,
) {
x1 := arg1[1]
x2 := arg1[2]
x3 := arg1[3]
x4 := arg1[0]
x6, x5 := bits.mul_u64(x4, 0x399411b7c309a3d)
x8, x7 := bits.mul_u64(x4, 0xceec73d217f5be65)
x10, x9 := bits.mul_u64(x4, 0xd00e1ba768859347)
x12, x11 := bits.mul_u64(x4, 0xa40611e3449c0f01)
x13, x14 := bits.add_u64(x12, x9, u64(0x0))
x15, x16 := bits.add_u64(x10, x7, u64(fiat.u1(x14)))
x17, x18 := bits.add_u64(x8, x5, u64(fiat.u1(x16)))
_, x19 := bits.mul_u64(x11, 0xd2b51da312547e1b)
x22, x21 := bits.mul_u64(x19, 0x1000000000000000)
x24, x23 := bits.mul_u64(x19, 0x14def9dea2f79cd6)
x26, x25 := bits.mul_u64(x19, 0x5812631a5cf5d3ed)
x27, x28 := bits.add_u64(x26, x23, u64(0x0))
_, x30 := bits.add_u64(x11, x25, u64(0x0))
x31, x32 := bits.add_u64(x13, x27, u64(fiat.u1(x30)))
x33, x34 := bits.add_u64(x15, (u64(fiat.u1(x28)) + x24), u64(fiat.u1(x32)))
x35, x36 := bits.add_u64(x17, x21, u64(fiat.u1(x34)))
x38, x37 := bits.mul_u64(x1, 0x399411b7c309a3d)
x40, x39 := bits.mul_u64(x1, 0xceec73d217f5be65)
x42, x41 := bits.mul_u64(x1, 0xd00e1ba768859347)
x44, x43 := bits.mul_u64(x1, 0xa40611e3449c0f01)
x45, x46 := bits.add_u64(x44, x41, u64(0x0))
x47, x48 := bits.add_u64(x42, x39, u64(fiat.u1(x46)))
x49, x50 := bits.add_u64(x40, x37, u64(fiat.u1(x48)))
x51, x52 := bits.add_u64(x31, x43, u64(0x0))
x53, x54 := bits.add_u64(x33, x45, u64(fiat.u1(x52)))
x55, x56 := bits.add_u64(x35, x47, u64(fiat.u1(x54)))
x57, x58 := bits.add_u64(
((u64(fiat.u1(x36)) + (u64(fiat.u1(x18)) + x6)) + x22),
x49,
u64(fiat.u1(x56)),
)
_, x59 := bits.mul_u64(x51, 0xd2b51da312547e1b)
x62, x61 := bits.mul_u64(x59, 0x1000000000000000)
x64, x63 := bits.mul_u64(x59, 0x14def9dea2f79cd6)
x66, x65 := bits.mul_u64(x59, 0x5812631a5cf5d3ed)
x67, x68 := bits.add_u64(x66, x63, u64(0x0))
_, x70 := bits.add_u64(x51, x65, u64(0x0))
x71, x72 := bits.add_u64(x53, x67, u64(fiat.u1(x70)))
x73, x74 := bits.add_u64(x55, (u64(fiat.u1(x68)) + x64), u64(fiat.u1(x72)))
x75, x76 := bits.add_u64(x57, x61, u64(fiat.u1(x74)))
x78, x77 := bits.mul_u64(x2, 0x399411b7c309a3d)
x80, x79 := bits.mul_u64(x2, 0xceec73d217f5be65)
x82, x81 := bits.mul_u64(x2, 0xd00e1ba768859347)
x84, x83 := bits.mul_u64(x2, 0xa40611e3449c0f01)
x85, x86 := bits.add_u64(x84, x81, u64(0x0))
x87, x88 := bits.add_u64(x82, x79, u64(fiat.u1(x86)))
x89, x90 := bits.add_u64(x80, x77, u64(fiat.u1(x88)))
x91, x92 := bits.add_u64(x71, x83, u64(0x0))
x93, x94 := bits.add_u64(x73, x85, u64(fiat.u1(x92)))
x95, x96 := bits.add_u64(x75, x87, u64(fiat.u1(x94)))
x97, x98 := bits.add_u64(
((u64(fiat.u1(x76)) + (u64(fiat.u1(x58)) + (u64(fiat.u1(x50)) + x38))) + x62),
x89,
u64(fiat.u1(x96)),
)
_, x99 := bits.mul_u64(x91, 0xd2b51da312547e1b)
x102, x101 := bits.mul_u64(x99, 0x1000000000000000)
x104, x103 := bits.mul_u64(x99, 0x14def9dea2f79cd6)
x106, x105 := bits.mul_u64(x99, 0x5812631a5cf5d3ed)
x107, x108 := bits.add_u64(x106, x103, u64(0x0))
_, x110 := bits.add_u64(x91, x105, u64(0x0))
x111, x112 := bits.add_u64(x93, x107, u64(fiat.u1(x110)))
x113, x114 := bits.add_u64(x95, (u64(fiat.u1(x108)) + x104), u64(fiat.u1(x112)))
x115, x116 := bits.add_u64(x97, x101, u64(fiat.u1(x114)))
x118, x117 := bits.mul_u64(x3, 0x399411b7c309a3d)
x120, x119 := bits.mul_u64(x3, 0xceec73d217f5be65)
x122, x121 := bits.mul_u64(x3, 0xd00e1ba768859347)
x124, x123 := bits.mul_u64(x3, 0xa40611e3449c0f01)
x125, x126 := bits.add_u64(x124, x121, u64(0x0))
x127, x128 := bits.add_u64(x122, x119, u64(fiat.u1(x126)))
x129, x130 := bits.add_u64(x120, x117, u64(fiat.u1(x128)))
x131, x132 := bits.add_u64(x111, x123, u64(0x0))
x133, x134 := bits.add_u64(x113, x125, u64(fiat.u1(x132)))
x135, x136 := bits.add_u64(x115, x127, u64(fiat.u1(x134)))
x137, x138 := bits.add_u64(
((u64(fiat.u1(x116)) + (u64(fiat.u1(x98)) + (u64(fiat.u1(x90)) + x78))) + x102),
x129,
u64(fiat.u1(x136)),
)
_, x139 := bits.mul_u64(x131, 0xd2b51da312547e1b)
x142, x141 := bits.mul_u64(x139, 0x1000000000000000)
x144, x143 := bits.mul_u64(x139, 0x14def9dea2f79cd6)
x146, x145 := bits.mul_u64(x139, 0x5812631a5cf5d3ed)
x147, x148 := bits.add_u64(x146, x143, u64(0x0))
_, x150 := bits.add_u64(x131, x145, u64(0x0))
x151, x152 := bits.add_u64(x133, x147, u64(fiat.u1(x150)))
x153, x154 := bits.add_u64(x135, (u64(fiat.u1(x148)) + x144), u64(fiat.u1(x152)))
x155, x156 := bits.add_u64(x137, x141, u64(fiat.u1(x154)))
x157 := ((u64(fiat.u1(x156)) + (u64(fiat.u1(x138)) + (u64(fiat.u1(x130)) + x118))) + x142)
x158, x159 := bits.sub_u64(x151, 0x5812631a5cf5d3ed, u64(0x0))
x160, x161 := bits.sub_u64(x153, 0x14def9dea2f79cd6, u64(fiat.u1(x159)))
x162, x163 := bits.sub_u64(x155, u64(0x0), u64(fiat.u1(x161)))
x164, x165 := bits.sub_u64(x157, 0x1000000000000000, u64(fiat.u1(x163)))
_, x167 := bits.sub_u64(u64(0x0), u64(0x0), u64(fiat.u1(x165)))
x168 := fiat.cmovznz_u64(fiat.u1(x167), x158, x151)
x169 := fiat.cmovznz_u64(fiat.u1(x167), x160, x153)
x170 := fiat.cmovznz_u64(fiat.u1(x167), x162, x155)
x171 := fiat.cmovznz_u64(fiat.u1(x167), x164, x157)
out1[0] = x168
out1[1] = x169
out1[2] = x170
out1[3] = x171
}
+10
View File
@@ -1,3 +1,7 @@
/*
package crypto implements a selection of cryptography algorithms and useful
helper routines.
*/
package crypto package crypto
import "core:mem" import "core:mem"
@@ -51,3 +55,9 @@ rand_bytes :: proc (dst: []byte) {
_rand_bytes(dst) _rand_bytes(dst)
} }
// has_rand_bytes returns true iff the target has support for accessing the
// system entropty source.
has_rand_bytes :: proc () -> bool {
return _has_rand_bytes()
}
+314
View File
@@ -0,0 +1,314 @@
/*
package ed25519 implements the Ed25519 EdDSA signature algorithm.
See:
- https://datatracker.ietf.org/doc/html/rfc8032
- https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf
- https://eprint.iacr.org/2020/1244.pdf
*/
package ed25519
import "core:crypto"
import grp "core:crypto/_edwards25519"
import "core:crypto/sha2"
import "core:mem"
// PRIVATE_KEY_SIZE is the byte-encoded private key size.
PRIVATE_KEY_SIZE :: 32
// PUBLIC_KEY_SIZE is the byte-encoded public key size.
PUBLIC_KEY_SIZE :: 32
// SIGNATURE_SIZE is the byte-encoded signature size.
SIGNATURE_SIZE :: 64
@(private)
NONCE_SIZE :: 32
// Private_Key is an Ed25519 private key.
Private_Key :: struct {
// WARNING: All of the members are to be treated as internal (ie:
// the Private_Key structure is intended to be opaque). There are
// subtle vulnerabilities that can be introduced if the internal
// values are allowed to be altered.
//
// See: https://github.com/MystenLabs/ed25519-unsafe-libs
_b: [PRIVATE_KEY_SIZE]byte,
_s: grp.Scalar,
_nonce: [NONCE_SIZE]byte,
_pub_key: Public_Key,
_is_initialized: bool,
}
// Public_Key is an Ed25519 public key.
Public_Key :: struct {
// WARNING: All of the members are to be treated as internal (ie:
// the Public_Key structure is intended to be opaque).
_b: [PUBLIC_KEY_SIZE]byte,
_neg_A: grp.Group_Element,
_is_valid: bool,
_is_initialized: bool,
}
// private_key_set_bytes decodes a byte-encoded private key, and returns
// true iff the operation was successful.
private_key_set_bytes :: proc(priv_key: ^Private_Key, b: []byte) -> bool {
if len(b) != PRIVATE_KEY_SIZE {
return false
}
// Derive the private key.
ctx: sha2.Context_512 = ---
h_bytes: [sha2.DIGEST_SIZE_512]byte = ---
sha2.init_512(&ctx)
sha2.update(&ctx, b)
sha2.final(&ctx, h_bytes[:])
copy(priv_key._b[:], b)
copy(priv_key._nonce[:], h_bytes[32:])
grp.sc_set_bytes_rfc8032(&priv_key._s, h_bytes[:32])
// Derive the corresponding public key.
A: grp.Group_Element = ---
grp.ge_scalarmult_basepoint(&A, &priv_key._s)
grp.ge_bytes(&A, priv_key._pub_key._b[:])
grp.ge_negate(&priv_key._pub_key._neg_A, &A)
priv_key._pub_key._is_valid = !grp.ge_is_small_order(&A)
priv_key._pub_key._is_initialized = true
priv_key._is_initialized = true
return true
}
// private_key_bytes sets dst to byte-encoding of priv_key.
private_key_bytes :: proc(priv_key: ^Private_Key, dst: []byte) {
if !priv_key._is_initialized {
panic("crypto/ed25519: uninitialized private key")
}
if len(dst) != PRIVATE_KEY_SIZE {
panic("crypto/ed25519: invalid destination size")
}
copy(dst, priv_key._b[:])
}
// private_key_clear clears priv_key to the uninitialized state.
private_key_clear :: proc "contextless" (priv_key: ^Private_Key) {
mem.zero_explicit(priv_key, size_of(Private_Key))
}
// sign writes the signature by priv_key over msg to sig.
sign :: proc(priv_key: ^Private_Key, msg, sig: []byte) {
if !priv_key._is_initialized {
panic("crypto/ed25519: uninitialized private key")
}
if len(sig) != SIGNATURE_SIZE {
panic("crypto/ed25519: invalid destination size")
}
// 1. Compute the hash of the private key d, H(d) = (h_0, h_1, ..., h_2b-1)
// using SHA-512 for Ed25519. H(d) may be precomputed.
//
// 2. Using the second half of the digest hdigest2 = hb || ... || h2b-1,
// define:
//
// 2.1 For Ed25519, r = SHA-512(hdigest2 || M); Interpret r as a
// 64-octet little-endian integer.
ctx: sha2.Context_512 = ---
digest_bytes: [sha2.DIGEST_SIZE_512]byte = ---
sha2.init_512(&ctx)
sha2.update(&ctx, priv_key._nonce[:])
sha2.update(&ctx, msg)
sha2.final(&ctx, digest_bytes[:])
r: grp.Scalar = ---
grp.sc_set_bytes_wide(&r, &digest_bytes)
// 3. Compute the point [r]G. The octet string R is the encoding of
// the point [r]G.
R: grp.Group_Element = ---
R_bytes := sig[:32]
grp.ge_scalarmult_basepoint(&R, &r)
grp.ge_bytes(&R, R_bytes)
// 4. Derive s from H(d) as in the key pair generation algorithm.
// Use octet strings R, Q, and M to define:
//
// 4.1 For Ed25519, digest = SHA-512(R || Q || M).
// Interpret digest as a little-endian integer.
sha2.init_512(&ctx)
sha2.update(&ctx, R_bytes)
sha2.update(&ctx, priv_key._pub_key._b[:]) // Q in NIST terminology.
sha2.update(&ctx, msg)
sha2.final(&ctx, digest_bytes[:])
sc: grp.Scalar = --- // `digest` in NIST terminology.
grp.sc_set_bytes_wide(&sc, &digest_bytes)
// 5. Compute S = (r + digest × s) mod n. The octet string S is the
// encoding of the resultant integer.
grp.sc_mul(&sc, &sc, &priv_key._s)
grp.sc_add(&sc, &sc, &r)
// 6. Form the signature as the concatenation of the octet strings
// R and S.
grp.sc_bytes(sig[32:], &sc)
grp.sc_clear(&r)
}
// public_key_set_bytes decodes a byte-encoded public key, and returns
// true iff the operation was successful.
public_key_set_bytes :: proc "contextless" (pub_key: ^Public_Key, b: []byte) -> bool {
if len(b) != PUBLIC_KEY_SIZE {
return false
}
A: grp.Group_Element = ---
if !grp.ge_set_bytes(&A, b) {
return false
}
copy(pub_key._b[:], b)
grp.ge_negate(&pub_key._neg_A, &A)
pub_key._is_valid = !grp.ge_is_small_order(&A)
pub_key._is_initialized = true
return 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) {
if !priv_key._is_initialized {
panic("crypto/ed25519: uninitialized public key")
}
src := &priv_key._pub_key
copy(pub_key._b[:], src._b[:])
grp.ge_set(&pub_key._neg_A, &src._neg_A)
pub_key._is_valid = src._is_valid
pub_key._is_initialized = src._is_initialized
}
// public_key_bytes sets dst to byte-encoding of pub_key.
public_key_bytes :: proc(pub_key: ^Public_Key, dst: []byte) {
if !pub_key._is_initialized {
panic("crypto/ed25519: uninitialized public key")
}
if len(dst) != PUBLIC_KEY_SIZE {
panic("crypto/ed25519: invalid destination size")
}
copy(dst, pub_key._b[:])
}
// public_key_equal returns true iff pub_key is equal to other.
public_key_equal :: proc(pub_key, other: ^Public_Key) -> bool {
if !pub_key._is_initialized || !other._is_initialized {
panic("crypto/ed25519: uninitialized public key")
}
return crypto.compare_constant_time(pub_key._b[:], other._b[:]) == 1
}
// verify returns true iff sig is a valid signature by pub_key over msg.
//
// The optional `allow_small_order_A` parameter will make this
// 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.
verify :: proc(pub_key: ^Public_Key, msg, sig: []byte, allow_small_order_A := false) -> bool {
switch {
case !pub_key._is_initialized:
return false
case len(sig) != SIGNATURE_SIZE:
return false
}
// TLDR: Just use ristretto255.
//
// While there are two "standards" for EdDSA, existing implementations
// diverge (sometimes dramatically). This implementation opts for
// "Algorithm 2" from "Taming the Many EdDSAs", which provides the
// strongest notion of security (SUF-CMA + SBS).
//
// The relevant properties are:
// - Reject non-canonical S.
// - Reject non-canonical A/R.
// - Reject small-order A (Extra non-standard check).
// - Cofactored verification equation.
//
// There are 19 possible non-canonical group element encodings of
// which:
// - 2 are small order
// - 10 are mixed order
// - 7 are not on the curve
//
// While historical implementations have been lax about enforcing
// that A/R are canonically encoded, that behavior is mandated by
// both the RFC and FIPS specification. No valid key generation
// or sign implementation will ever produce non-canonically encoded
// public keys or signatures.
//
// There are 8 small-order group elements, 1 which is in the
// prime-order sub-group, and thus the probability that a properly
// generated A is small-order is cryptographically insignificant.
//
// While both the RFC and FIPS standard allow for either the
// cofactored or non-cofactored equation. It is possible to
// artificially produce signatures that are valid for the former
// but not the latter. This will NEVER occur with a valid sign
// implementation. The choice of the latter is to be compatible
// with ABGLSV-Pornin, batch verification, and FROST (among other
// things).
s_bytes, r_bytes := sig[32:], sig[:32]
// 1. Reject the signature if S is not in the range [0, L).
s: grp.Scalar = ---
if !grp.sc_set_bytes(&s, s_bytes) {
return false
}
// 2. Reject the signature if the public key A is one of 8 small
// order points.
//
// As this check is optional and not part of the standard, we allow
// the caller to bypass it if desired. Disabling the check makes
// the scheme NOT SBS-secure.
if !pub_key._is_valid && !allow_small_order_A {
return false
}
// 3. Reject the signature if A or R are non-canonical.
//
// Note: All initialized public keys are guaranteed to be canonical.
neg_R: grp.Group_Element = ---
if !grp.ge_set_bytes(&neg_R, r_bytes) {
return false
}
grp.ge_negate(&neg_R, &neg_R)
// 4. Compute the hash SHA512(R||A||M) and reduce it mod L to get a
// scalar h.
ctx: sha2.Context_512 = ---
h_bytes: [sha2.DIGEST_SIZE_512]byte = ---
sha2.init_512(&ctx)
sha2.update(&ctx, r_bytes)
sha2.update(&ctx, pub_key._b[:])
sha2.update(&ctx, msg)
sha2.final(&ctx, h_bytes[:])
h: grp.Scalar = ---
grp.sc_set_bytes_wide(&h, &h_bytes)
// 5. Accept if 8(s * G) - 8R - 8(h * A) = 0
//
// > first compute V = SB R hA and then accept if V is one of
// > 8 small order points (or alternatively compute 8V with 3
// > doublings and check against the neutral element)
V: grp.Group_Element = ---
grp.ge_double_scalarmult_basepoint_vartime(&V, &h, &pub_key._neg_A, &s)
grp.ge_add(&V, &V, &neg_R)
return grp.ge_is_small_order(&V)
}
+1 -1
View File
@@ -168,7 +168,7 @@ reset :: proc(ctx: ^Context) {
} }
@(private) @(private)
_blocks :: proc(ctx: ^Context, msg: []byte, final := false) { _blocks :: proc "contextless" (ctx: ^Context, msg: []byte, final := false) {
n: field.Tight_Field_Element = --- n: field.Tight_Field_Element = ---
final_byte := byte(!final) final_byte := byte(!final)
+4
View File
@@ -10,3 +10,7 @@ foreign libc {
_rand_bytes :: proc(dst: []byte) { _rand_bytes :: proc(dst: []byte) {
arc4random_buf(raw_data(dst), len(dst)) arc4random_buf(raw_data(dst), len(dst))
} }
_has_rand_bytes :: proc() -> bool {
return true
}
+11 -5
View File
@@ -1,12 +1,18 @@
package crypto package crypto
import "core:fmt" import "core:fmt"
import "core:sys/darwin"
import CF "core:sys/darwin/CoreFoundation"
import Sec "core:sys/darwin/Security"
_rand_bytes :: proc(dst: []byte) { _rand_bytes :: proc(dst: []byte) {
res := darwin.SecRandomCopyBytes(count=len(dst), bytes=raw_data(dst)) err := Sec.RandomCopyBytes(count=len(dst), bytes=raw_data(dst))
if res != .Success { if err != .Success {
msg := darwin.CFStringCopyToOdinString(darwin.SecCopyErrorMessageString(res)) msg := CF.StringCopyToOdinString(Sec.CopyErrorMessageString(err))
panic(fmt.tprintf("crypto/rand_bytes: SecRandomCopyBytes returned non-zero result: %v %s", res, msg)) panic(fmt.tprintf("crypto/rand_bytes: SecRandomCopyBytes returned non-zero result: %v %s", err, msg))
} }
} }
_has_rand_bytes :: proc() -> bool {
return true
}
+4
View File
@@ -9,3 +9,7 @@ package crypto
_rand_bytes :: proc(dst: []byte) { _rand_bytes :: proc(dst: []byte) {
unimplemented("crypto: rand_bytes not supported on this OS") unimplemented("crypto: rand_bytes not supported on this OS")
} }
_has_rand_bytes :: proc() -> bool {
return false
}
+4
View File
@@ -18,3 +18,7 @@ _rand_bytes :: proc(dst: []byte) {
dst = dst[to_read:] dst = dst[to_read:]
} }
} }
_has_rand_bytes :: proc() -> bool {
return true
}
+4
View File
@@ -34,3 +34,7 @@ _rand_bytes :: proc (dst: []byte) {
dst = dst[n_read:] dst = dst[n_read:]
} }
} }
_has_rand_bytes :: proc() -> bool {
return true
}
+4
View File
@@ -21,3 +21,7 @@ _rand_bytes :: proc(dst: []byte) {
} }
} }
} }
_has_rand_bytes :: proc() -> bool {
return true
}
+510
View File
@@ -0,0 +1,510 @@
/*
package ristretto255 implement the ristretto255 prime-order group.
See:
- https://www.rfc-editor.org/rfc/rfc9496
*/
package ristretto255
import grp "core:crypto/_edwards25519"
import field "core:crypto/_fiat/field_curve25519"
import "core:mem"
// ELEMENT_SIZE is the size of a byte-encoded ristretto255 group element.
ELEMENT_SIZE :: 32
// WIDE_ELEMENT_SIZE is the side of a wide byte-encoded ristretto255
// group element.
WIDE_ELEMENT_SIZE :: 64
@(private)
FE_NEG_ONE := field.Tight_Field_Element {
2251799813685228,
2251799813685247,
2251799813685247,
2251799813685247,
2251799813685247,
}
@(private)
FE_INVSQRT_A_MINUS_D := field.Tight_Field_Element {
278908739862762,
821645201101625,
8113234426968,
1777959178193151,
2118520810568447,
}
@(private)
FE_ONE_MINUS_D_SQ := field.Tight_Field_Element {
1136626929484150,
1998550399581263,
496427632559748,
118527312129759,
45110755273534,
}
@(private)
FE_D_MINUS_ONE_SQUARED := field.Tight_Field_Element {
1507062230895904,
1572317787530805,
683053064812840,
317374165784489,
1572899562415810,
}
@(private)
FE_SQRT_AD_MINUS_ONE := field.Tight_Field_Element {
2241493124984347,
425987919032274,
2207028919301688,
1220490630685848,
974799131293748,
}
@(private)
GE_IDENTITY := Group_Element{grp.GE_IDENTITY, true}
// Group_Element is a ristretto255 group element. The zero-initialized
// value is invalid.
Group_Element :: struct {
// WARNING: While the internal representation is an Edwards25519
// group element, this is not guaranteed to always be the case,
// and your code *WILL* break if you mess with `_p`.
_p: grp.Group_Element,
_is_initialized: bool,
}
// ge_clear clears ge to the uninitialized state.
ge_clear :: proc "contextless" (ge: ^Group_Element) {
mem.zero_explicit(ge, size_of(Group_Element))
}
// ge_set sets `ge = a`.
ge_set :: proc(ge, a: ^Group_Element) {
_ge_assert_initialized([]^Group_Element{a})
grp.ge_set(&ge._p, &a._p)
ge._is_initialized = true
}
// ge_identity sets ge to the identity (neutral) element.
ge_identity :: proc "contextless" (ge: ^Group_Element) {
grp.ge_identity(&ge._p)
ge._is_initialized = true
}
// ge_generator sets ge to the group generator.
ge_generator :: proc "contextless" (ge: ^Group_Element) {
grp.ge_generator(&ge._p)
ge._is_initialized = true
}
// ge_set_bytes sets ge to the result of decoding b as a ristretto255
// group element, and returns true on success.
@(require_results)
ge_set_bytes :: proc "contextless" (ge: ^Group_Element, b: []byte) -> bool {
// 1. Interpret the string as an unsigned integer s in little-endian
// representation. If the length of the string is not 32 bytes or
// if the resulting value is >= p, decoding fails.
//
// 2. If IS_NEGATIVE(s) returns TRUE, decoding fails.
if len(b) != ELEMENT_SIZE {
return false
}
if b[31] & 128 != 0 || b[0] & 1 != 0 {
// Fail early if b is clearly > p, or negative.
return false
}
b_ := transmute(^[32]byte)(raw_data(b))
s: field.Tight_Field_Element = ---
defer field.fe_clear(&s)
field.fe_from_bytes(&s, b_)
if field.fe_equal_bytes(&s, b_) != 1 {
// Reject non-canonical encodings of s.
return false
}
// 3. Process s as follows:
v, u1, u2: field.Loose_Field_Element = ---, ---, ---
tmp, u2_sqr: field.Tight_Field_Element = ---, ---
// ss = s^2
// u1 = 1 - ss
// u2 = 1 + ss
// u2_sqr = u2^2
field.fe_carry_square(&tmp, field.fe_relax_cast(&s))
field.fe_sub(&u1, &field.FE_ONE, &tmp)
field.fe_add(&u2, &field.FE_ONE, &tmp)
field.fe_carry_square(&u2_sqr, &u2)
// v = -(D * u1^2) - u2_sqr
field.fe_carry_square(&tmp, &u1)
field.fe_carry_mul(&tmp, field.fe_relax_cast(&grp.FE_D), field.fe_relax_cast(&tmp))
field.fe_carry_add(&tmp, &tmp, &u2_sqr)
field.fe_opp(&v, &tmp)
// (was_square, invsqrt) = SQRT_RATIO_M1(1, v * u2_sqr)
field.fe_carry_mul(&tmp, &v, field.fe_relax_cast(&u2_sqr))
was_square := field.fe_carry_sqrt_ratio_m1(
&tmp,
field.fe_relax_cast(&field.FE_ONE),
field.fe_relax_cast(&tmp),
)
// den_x = invsqrt * u2
// den_y = invsqrt * den_x * v
x, y, t: field.Tight_Field_Element = ---, ---, ---
field.fe_carry_mul(&x, field.fe_relax_cast(&tmp), &u2)
field.fe_carry_mul(&y, field.fe_relax_cast(&tmp), field.fe_relax_cast(&x))
field.fe_carry_mul(&y, field.fe_relax_cast(&y), &v)
// x = CT_ABS(2 * s * den_x)
field.fe_carry_mul(&x, field.fe_relax_cast(&s), field.fe_relax_cast(&x))
field.fe_carry_add(&x, &x, &x)
field.fe_carry_abs(&x, &x)
// y = u1 * den_y
field.fe_carry_mul(&y, &u1, field.fe_relax_cast(&y))
// t = x * y
field.fe_carry_mul(&t, field.fe_relax_cast(&x), field.fe_relax_cast(&y))
field.fe_clear_vec([]^field.Loose_Field_Element{&v, &u1, &u2})
field.fe_clear_vec([]^field.Tight_Field_Element{&tmp, &u2_sqr})
defer field.fe_clear_vec([]^field.Tight_Field_Element{&x, &y, &t})
// 4. If was_square is FALSE, IS_NEGATIVE(t) returns TRUE, or y = 0,
// decoding fails. Otherwise, return the group element represented
// by the internal representation (x, y, 1, t) as the result of
// decoding.
switch {
case was_square == 0:
// Not sure why the RFC doesn't have this just fail early.
return false
case field.fe_is_negative(&t) != 0:
return false
case field.fe_equal(&y, &field.FE_ZERO) != 0:
return false
}
field.fe_set(&ge._p.x, &x)
field.fe_set(&ge._p.y, &y)
field.fe_one(&ge._p.z)
field.fe_set(&ge._p.t, &t)
ge._is_initialized = true
return true
}
// ge_set_wide_bytes sets ge to the result of deriving a ristretto255
// group element, from a wide (512-bit) byte string.
ge_set_wide_bytes :: proc(ge: ^Group_Element, b: []byte) {
if len(b) != WIDE_ELEMENT_SIZE {
panic("crypto/ristretto255: invalid wide input size")
}
// The element derivation function on an input string b proceeds as
// follows:
//
// 1. Compute P1 as MAP(b[0:32]).
// 2. Compute P2 as MAP(b[32:64]).
// 3. Return P1 + P2.
p1, p2: Group_Element = ---, ---
ge_map(&p1, b[0:32])
ge_map(&p2, b[32:64])
ge_add(ge, &p1, &p2)
ge_clear(&p1)
ge_clear(&p2)
}
// ge_bytes sets dst to the canonical encoding of ge.
ge_bytes :: proc(ge: ^Group_Element, dst: []byte) {
_ge_assert_initialized([]^Group_Element{ge})
if len(dst) != ELEMENT_SIZE {
panic("crypto/ristretto255: invalid destination size")
}
x0, y0, z0, t0 := &ge._p.x, &ge._p.y, &ge._p.z, &ge._p.t
// 1. Process the internal representation into a field element s as
// follows:
// u1 = (z0 + y0) * (z0 - y0)
// u2 = x0 * y0
u1, u2: field.Tight_Field_Element = ---, ---
tmp1, tmp2: field.Loose_Field_Element = ---, ---
field.fe_add(&tmp1, z0, y0)
field.fe_sub(&tmp2, z0, y0)
field.fe_carry_mul(&u1, &tmp1, &tmp2)
field.fe_carry_mul(&u2, field.fe_relax_cast(x0), field.fe_relax_cast(y0))
// Ignore was_square since this is always square.
// (_, invsqrt) = SQRT_RATIO_M1(1, u1 * u2^2)
tmp: field.Tight_Field_Element = ---
field.fe_carry_square(&tmp, field.fe_relax_cast(&u2))
field.fe_carry_mul(&tmp, field.fe_relax_cast(&u1), field.fe_relax_cast(&tmp))
_ = field.fe_carry_sqrt_ratio_m1(
&tmp,
field.fe_relax_cast(&field.FE_ONE),
field.fe_relax_cast(&tmp),
)
// den1 = invsqrt * u1
// den2 = invsqrt * u2
// z_inv = den1 * den2 * t0
den1, den2 := &u1, &u2
z_inv: field.Tight_Field_Element = ---
field.fe_carry_mul(den1, field.fe_relax_cast(&tmp), field.fe_relax_cast(&u1))
field.fe_carry_mul(den2, field.fe_relax_cast(&tmp), field.fe_relax_cast(&u2))
field.fe_carry_mul(&z_inv, field.fe_relax_cast(den1), field.fe_relax_cast(den2))
field.fe_carry_mul(&z_inv, field.fe_relax_cast(&z_inv), field.fe_relax_cast(t0))
// rotate = IS_NEGATIVE(t0 * z_inv)
// Note: Reordered from the RFC because invsqrt is no longer needed.
field.fe_carry_mul(&tmp, field.fe_relax_cast(t0), field.fe_relax_cast(&z_inv))
rotate := field.fe_is_negative(&tmp)
// ix0 = x0 * SQRT_M1
// iy0 = y0 * SQRT_M1
// enchanted_denominator = den1 * INVSQRT_A_MINUS_D
ix0, iy0: field.Tight_Field_Element = ---, ---
field.fe_carry_mul(&ix0, field.fe_relax_cast(x0), field.fe_relax_cast(&field.FE_SQRT_M1))
field.fe_carry_mul(&iy0, field.fe_relax_cast(y0), field.fe_relax_cast(&field.FE_SQRT_M1))
field.fe_carry_mul(&tmp, field.fe_relax_cast(den1), field.fe_relax_cast(&FE_INVSQRT_A_MINUS_D))
// Conditionally rotate x and y.
// x = CT_SELECT(iy0 IF rotate ELSE x0)
// y = CT_SELECT(ix0 IF rotate ELSE y0)
// z = z0
// den_inv = CT_SELECT(enchanted_denominator IF rotate ELSE den2)
x, y: field.Tight_Field_Element = ---, ---
field.fe_cond_select(&x, x0, &iy0, rotate)
field.fe_cond_select(&y, y0, &ix0, rotate)
field.fe_cond_select(&tmp, den2, &tmp, rotate)
// y = CT_SELECT(-y IF IS_NEGATIVE(x * z_inv) ELSE y)
field.fe_carry_mul(&x, field.fe_relax_cast(&x), field.fe_relax_cast(&z_inv))
field.fe_cond_negate(&y, &y, field.fe_is_negative(&x))
// s = CT_ABS(den_inv * (z - y))
field.fe_sub(&tmp1, z0, &y)
field.fe_carry_mul(&tmp, field.fe_relax_cast(&tmp), &tmp1)
field.fe_carry_abs(&tmp, &tmp)
// 2. Return the 32-byte little-endian encoding of s. More
// specifically, this is the encoding of the canonical
// representation of s as an integer between 0 and p-1, inclusive.
dst_ := transmute(^[32]byte)(raw_data(dst))
field.fe_to_bytes(dst_, &tmp)
field.fe_clear_vec([]^field.Tight_Field_Element{&u1, &u2, &tmp, &z_inv, &ix0, &iy0, &x, &y})
field.fe_clear_vec([]^field.Loose_Field_Element{&tmp1, &tmp2})
}
// ge_add sets `ge = a + b`.
ge_add :: proc(ge, a, b: ^Group_Element) {
_ge_assert_initialized([]^Group_Element{a, b})
grp.ge_add(&ge._p, &a._p, &b._p)
ge._is_initialized = true
}
// ge_double sets `ge = a + a`.
ge_double :: proc(ge, a: ^Group_Element) {
_ge_assert_initialized([]^Group_Element{a})
grp.ge_double(&ge._p, &a._p)
ge._is_initialized = true
}
// ge_negate sets `ge = -a`.
ge_negate :: proc(ge, a: ^Group_Element) {
_ge_assert_initialized([]^Group_Element{a})
grp.ge_negate(&ge._p, &a._p)
ge._is_initialized = true
}
// ge_scalarmult sets `ge = A * sc`.
ge_scalarmult :: proc(ge, A: ^Group_Element, sc: ^Scalar) {
_ge_assert_initialized([]^Group_Element{A})
grp.ge_scalarmult(&ge._p, &A._p, sc)
ge._is_initialized = true
}
// ge_scalarmult_generator sets `ge = G * sc`
ge_scalarmult_generator :: proc "contextless" (ge: ^Group_Element, sc: ^Scalar) {
grp.ge_scalarmult_basepoint(&ge._p, sc)
ge._is_initialized = true
}
// ge_scalarmult_vartime sets `ge = A * sc` in variable time.
ge_scalarmult_vartime :: proc(ge, A: ^Group_Element, sc: ^Scalar) {
_ge_assert_initialized([]^Group_Element{A})
grp.ge_scalarmult_vartime(&ge._p, &A._p, sc)
ge._is_initialized = true
}
// ge_double_scalarmult_generator_vartime sets `ge = A * a + G * b` in variable
// time.
ge_double_scalarmult_generator_vartime :: proc(
ge: ^Group_Element,
a: ^Scalar,
A: ^Group_Element,
b: ^Scalar,
) {
_ge_assert_initialized([]^Group_Element{A})
grp.ge_double_scalarmult_basepoint_vartime(&ge._p, a, &A._p, b)
ge._is_initialized = true
}
// ge_cond_negate sets `ge = a` iff `ctrl == 0` and `ge = -a` iff `ctrl == 1`.
// Behavior for all other values of ctrl are undefined,
ge_cond_negate :: proc(ge, a: ^Group_Element, ctrl: int) {
_ge_assert_initialized([]^Group_Element{a})
grp.ge_cond_negate(&ge._p, &a._p, ctrl)
ge._is_initialized = true
}
// ge_cond_assign sets `ge = ge` iff `ctrl == 0` and `ge = a` iff `ctrl == 1`.
// Behavior for all other values of ctrl are undefined,
ge_cond_assign :: proc(ge, a: ^Group_Element, ctrl: int) {
_ge_assert_initialized([]^Group_Element{ge, a})
grp.ge_cond_assign(&ge._p, &a._p, ctrl)
}
// ge_cond_select sets `ge = a` iff `ctrl == 0` and `ge = b` iff `ctrl == 1`.
// Behavior for all other values of ctrl are undefined,
ge_cond_select :: proc(ge, a, b: ^Group_Element, ctrl: int) {
_ge_assert_initialized([]^Group_Element{a, b})
grp.ge_cond_select(&ge._p, &a._p, &b._p, ctrl)
ge._is_initialized = true
}
// ge_equal returns 1 iff `a == b`, and 0 otherwise.
@(require_results)
ge_equal :: proc(a, b: ^Group_Element) -> int {
_ge_assert_initialized([]^Group_Element{a, b})
// CT_EQ(x1 * y2, y1 * x2) | CT_EQ(y1 * y2, x1 * x2)
ax_by, ay_bx, ay_by, ax_bx: field.Tight_Field_Element = ---, ---, ---, ---
field.fe_carry_mul(&ax_by, field.fe_relax_cast(&a._p.x), field.fe_relax_cast(&b._p.y))
field.fe_carry_mul(&ay_bx, field.fe_relax_cast(&a._p.y), field.fe_relax_cast(&b._p.x))
field.fe_carry_mul(&ay_by, field.fe_relax_cast(&a._p.y), field.fe_relax_cast(&b._p.y))
field.fe_carry_mul(&ax_bx, field.fe_relax_cast(&a._p.x), field.fe_relax_cast(&b._p.x))
ret := field.fe_equal(&ax_by, &ay_bx) | field.fe_equal(&ay_by, &ax_bx)
field.fe_clear_vec([]^field.Tight_Field_Element{&ax_by, &ay_bx, &ay_by, &ax_bx})
return ret
}
// ge_is_identity returns 1 iff `ge` is the identity element, and 0 otherwise.
@(require_results)
ge_is_identity :: proc(ge: ^Group_Element) -> int {
return ge_equal(ge, &GE_IDENTITY)
}
@(private)
ge_map :: proc "contextless" (ge: ^Group_Element, b: []byte) {
b_ := transmute(^[32]byte)(raw_data(b))
// The MAP function is defined on 32-byte strings as:
//
// 1. Mask the most significant bit in the final byte of the string,
// and interpret the string as an unsigned integer r in little-
// endian representation. Reduce r modulo p to obtain a field
// element t.
// * Masking the most significant bit is equivalent to interpreting
// the whole string as an unsigned integer in little-endian
// representation and then reducing it modulo 2^255.
t: field.Tight_Field_Element = ---
field.fe_from_bytes(&t, b_)
// 2. Process t as follows:
//
// r = SQRT_M1 * t^2
// u = (r + 1) * ONE_MINUS_D_SQ
// v = (-1 - r*D) * (r + D)
tmp1: field.Loose_Field_Element = ---
r, u, v: field.Tight_Field_Element = ---, ---, ---
field.fe_carry_square(&r, field.fe_relax_cast(&t))
field.fe_carry_mul(&r, field.fe_relax_cast(&field.FE_SQRT_M1), field.fe_relax_cast(&r))
field.fe_add(&tmp1, &field.FE_ONE, &r)
field.fe_carry_mul(&u, &tmp1, field.fe_relax_cast(&FE_ONE_MINUS_D_SQ))
field.fe_carry_mul(&v, field.fe_relax_cast(&r), field.fe_relax_cast(&grp.FE_D))
field.fe_carry_add(&v, &field.FE_ONE, &v)
field.fe_carry_opp(&v, &v)
field.fe_add(&tmp1, &r, &grp.FE_D)
field.fe_carry_mul(&v, field.fe_relax_cast(&v), &tmp1)
// (was_square, s) = SQRT_RATIO_M1(u, v)
// s_prime = -CT_ABS(s*t)
// s = CT_SELECT(s IF was_square ELSE s_prime)
// c = CT_SELECT(-1 IF was_square ELSE r)
s, s_prime, c: field.Tight_Field_Element = ---, ---, ---
was_square := field.fe_carry_sqrt_ratio_m1(
&s,
field.fe_relax_cast(&u),
field.fe_relax_cast(&v),
)
field.fe_carry_mul(&s_prime, field.fe_relax_cast(&s), field.fe_relax_cast(&t))
field.fe_carry_abs(&s_prime, &s_prime)
field.fe_carry_opp(&s_prime, &s_prime)
field.fe_cond_select(&s, &s_prime, &s, was_square)
field.fe_cond_select(&c, &r, &FE_NEG_ONE, was_square)
// N = c * (r - 1) * D_MINUS_ONE_SQ - v
N: field.Tight_Field_Element = ---
field.fe_sub(&tmp1, &r, &field.FE_ONE)
field.fe_carry_mul(&N, field.fe_relax_cast(&c), &tmp1)
field.fe_carry_mul(&N, field.fe_relax_cast(&N), field.fe_relax_cast(&FE_D_MINUS_ONE_SQUARED))
field.fe_carry_sub(&N, &N, &v)
// w0 = 2 * s * v
// w1 = N * SQRT_AD_MINUS_ONE
// w2 = 1 - s^2
// w3 = 1 + s^2
w0, w1: field.Tight_Field_Element = ---, ---
w2, w3: field.Loose_Field_Element = ---, ---
field.fe_carry_mul(&w0, field.fe_relax_cast(&s), field.fe_relax_cast(&v))
field.fe_carry_add(&w0, &w0, &w0)
field.fe_carry_mul(&w1, field.fe_relax_cast(&N), field.fe_relax_cast(&FE_SQRT_AD_MINUS_ONE))
field.fe_carry_square(&s, field.fe_relax_cast(&s))
field.fe_sub(&w2, &field.FE_ONE, &s)
field.fe_add(&w3, &field.FE_ONE, &s)
// 3. Return the group element represented by the internal
// representation (w0*w3, w2*w1, w1*w3, w0*w2).
field.fe_carry_mul(&ge._p.x, field.fe_relax_cast(&w0), &w3)
field.fe_carry_mul(&ge._p.y, &w2, field.fe_relax_cast(&w1))
field.fe_carry_mul(&ge._p.z, field.fe_relax_cast(&w1), &w3)
field.fe_carry_mul(&ge._p.t, field.fe_relax_cast(&w0), &w2)
ge._is_initialized = true
field.fe_clear_vec([]^field.Tight_Field_Element{&r, &u, &v, &s, &s_prime, &c, &N, &w0, &w1})
field.fe_clear_vec([]^field.Loose_Field_Element{&tmp1, &w2, &w3})
}
@(private)
_ge_assert_initialized :: proc(ges: []^Group_Element) {
for ge in ges {
if !ge._is_initialized {
panic("crypto/ristretto255: uninitialized group element")
}
}
}
@@ -0,0 +1,97 @@
package ristretto255
import grp "core:crypto/_edwards25519"
// SCALAR_SIZE is the size of a byte-encoded ristretto255 scalar.
SCALAR_SIZE :: 32
// WIDE_SCALAR_SIZE is the size of a wide byte-encoded ristretto255
// scalar.
WIDE_SCALAR_SIZE :: 64
// Scalar is a ristretto255 scalar. The zero-initialized value is valid,
// and represents `0`.
Scalar :: grp.Scalar
// sc_clear clears sc to the uninitialized state.
sc_clear :: proc "contextless" (sc: ^Scalar) {
grp.sc_clear(sc)
}
// sc_set sets `sc = a`.
sc_set :: proc "contextless" (sc, a: ^Scalar) {
grp.sc_set(sc, a)
}
// sc_set_u64 sets `sc = i`.
sc_set_u64 :: proc "contextless" (sc: ^Scalar, i: u64) {
grp.sc_set_u64(sc, i)
}
// sc_set_bytes sets sc to the result of decoding b as a ristretto255
// scalar, and returns true on success.
@(require_results)
sc_set_bytes :: proc(sc: ^Scalar, b: []byte) -> bool {
if len(b) != SCALAR_SIZE {
return false
}
return grp.sc_set_bytes(sc, b)
}
// sc_set_wide_bytes sets sc to the result of deriving a ristretto255
// scalar, from a wide (512-bit) byte string by interpreting b as a
// little-endian value, and reducing it mod the group order.
sc_set_bytes_wide :: proc(sc: ^Scalar, b: []byte) {
if len(b) != WIDE_SCALAR_SIZE {
panic("crypto/ristretto255: invalid wide input size")
}
b_ := transmute(^[WIDE_SCALAR_SIZE]byte)(raw_data(b))
grp.sc_set_bytes_wide(sc, b_)
}
// sc_bytes sets dst to the canonical encoding of sc.
sc_bytes :: proc(sc: ^Scalar, dst: []byte) {
if len(dst) != SCALAR_SIZE {
panic("crypto/ristretto255: invalid destination size")
}
grp.sc_bytes(dst, sc)
}
// sc_add sets `sc = a + b`.
sc_add :: proc "contextless" (sc, a, b: ^Scalar) {
grp.sc_add(sc, a, b)
}
// sc_sub sets `sc = a - b`.
sc_sub :: proc "contextless" (sc, a, b: ^Scalar) {
grp.sc_sub(sc, a, b)
}
// sc_negate sets `sc = -a`.
sc_negate :: proc "contextless" (sc, a: ^Scalar) {
grp.sc_negate(sc, a)
}
// sc_mul sets `sc = a * b`.
sc_mul :: proc "contextless" (sc, a, b: ^Scalar) {
grp.sc_mul(sc, a, b)
}
// sc_square sets `sc = a^2`.
sc_square :: proc "contextless" (sc, a: ^Scalar) {
grp.sc_square(sc, a)
}
// sc_cond_assign sets `sc = sc` iff `ctrl == 0` and `sc = a` iff `ctrl == 1`.
// Behavior for all other values of ctrl are undefined,
sc_cond_assign :: proc(sc, a: ^Scalar, ctrl: int) {
grp.sc_cond_assign(sc, a, ctrl)
}
// sc_equal returns 1 iff `a == b`, and 0 otherwise.
@(require_results)
sc_equal :: proc(a, b: ^Scalar) -> int {
return grp.sc_equal(a, b)
}
+3 -9
View File
@@ -27,7 +27,7 @@ _scalar_bit :: #force_inline proc "contextless" (s: ^[32]byte, i: int) -> u8 {
} }
@(private) @(private)
_scalarmult :: proc(out, scalar, point: ^[32]byte) { _scalarmult :: proc "contextless" (out, scalar, point: ^[32]byte) {
// Montgomery pseduo-multiplication taken from Monocypher. // Montgomery pseduo-multiplication taken from Monocypher.
// computes the scalar product // computes the scalar product
@@ -94,13 +94,8 @@ _scalarmult :: proc(out, scalar, point: ^[32]byte) {
field.fe_carry_mul(&x2, field.fe_relax_cast(&x2), field.fe_relax_cast(&z2)) field.fe_carry_mul(&x2, field.fe_relax_cast(&x2), field.fe_relax_cast(&z2))
field.fe_to_bytes(out, &x2) field.fe_to_bytes(out, &x2)
mem.zero_explicit(&x1, size_of(x1)) field.fe_clear_vec([]^field.Tight_Field_Element{&x1, &x2, &x3, &z2, &z3})
mem.zero_explicit(&x2, size_of(x2)) field.fe_clear_vec([]^field.Loose_Field_Element{&t0, &t1})
mem.zero_explicit(&x3, size_of(x3))
mem.zero_explicit(&z2, size_of(z2))
mem.zero_explicit(&z3, size_of(z3))
mem.zero_explicit(&t0, size_of(t0))
mem.zero_explicit(&t1, size_of(t1))
} }
// scalarmult "multiplies" the provided scalar and point, and writes the // scalarmult "multiplies" the provided scalar and point, and writes the
@@ -137,6 +132,5 @@ scalarmult :: proc(dst, scalar, point: []byte) {
// scalarmult_basepoint "multiplies" the provided scalar with the X25519 // scalarmult_basepoint "multiplies" the provided scalar with the X25519
// base point and writes the resulting point to dst. // base point and writes the resulting point to dst.
scalarmult_basepoint :: proc(dst, scalar: []byte) { scalarmult_basepoint :: proc(dst, scalar: []byte) {
// TODO/perf: Switch to using a precomputed table.
scalarmult(dst, scalar, _BASE_POINT[:]) scalarmult(dst, scalar, _BASE_POINT[:])
} }
+56 -7
View File
@@ -366,11 +366,63 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
opt_write_end(w, opt, '}') or_return opt_write_end(w, opt, '}') or_return
case runtime.Type_Info_Struct: case runtime.Type_Info_Struct:
is_omitempty :: proc(v: any) -> bool {
v := v
if v == nil {
return true
}
ti := runtime.type_info_core(type_info_of(v.id))
#partial switch info in ti.variant {
case runtime.Type_Info_String:
switch x in v {
case string:
return x == ""
case cstring:
return x == nil || x == ""
}
case runtime.Type_Info_Any:
return v.(any) == nil
case runtime.Type_Info_Type_Id:
return v.(typeid) == nil
case runtime.Type_Info_Pointer,
runtime.Type_Info_Multi_Pointer,
runtime.Type_Info_Procedure:
return (^rawptr)(v.data)^ == nil
case runtime.Type_Info_Dynamic_Array:
return (^runtime.Raw_Dynamic_Array)(v.data).len == 0
case runtime.Type_Info_Slice:
return (^runtime.Raw_Slice)(v.data).len == 0
case runtime.Type_Info_Union,
runtime.Type_Info_Bit_Set,
runtime.Type_Info_Soa_Pointer:
return reflect.is_nil(v)
case runtime.Type_Info_Map:
return (^runtime.Raw_Map)(v.data).len == 0
}
return false
}
marshal_struct_fields :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: Marshal_Error) { marshal_struct_fields :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: Marshal_Error) {
ti := runtime.type_info_base(type_info_of(v.id)) ti := runtime.type_info_base(type_info_of(v.id))
info := ti.variant.(runtime.Type_Info_Struct) info := ti.variant.(runtime.Type_Info_Struct)
for name, i in info.names { for name, i in info.names {
json_name := reflect.struct_tag_get(reflect.Struct_Tag(info.tags[i]), "json") omitempty := false
json_name, extra := json_name_from_tag_value(reflect.struct_tag_get(reflect.Struct_Tag(info.tags[i]), "json"))
for flag in strings.split_iterator(&extra, ",") {
switch flag {
case "omitempty":
omitempty = true
}
}
id := info.types[i].id
data := rawptr(uintptr(v.data) + info.offsets[i])
the_value := any{data, id}
if is_omitempty(the_value) {
continue
}
opt_write_iteration(w, opt, i) or_return opt_write_iteration(w, opt, i) or_return
if json_name != "" { if json_name != "" {
@@ -378,18 +430,15 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
} else { } else {
// Marshal the fields of 'using _: T' fields directly into the parent struct // Marshal the fields of 'using _: T' fields directly into the parent struct
if info.usings[i] && name == "_" { if info.usings[i] && name == "_" {
id := info.types[i].id marshal_struct_fields(w, the_value, opt) or_return
data := rawptr(uintptr(v.data) + info.offsets[i])
marshal_struct_fields(w, any{data, id}, opt) or_return
continue continue
} else { } else {
opt_write_key(w, opt, name) or_return opt_write_key(w, opt, name) or_return
} }
} }
id := info.types[i].id
data := rawptr(uintptr(v.data) + info.offsets[i]) marshal_to_writer(w, the_value, opt) or_return
marshal_to_writer(w, any{data, id}, opt) or_return
} }
return return
} }
+12 -1
View File
@@ -343,6 +343,16 @@ unmarshal_expect_token :: proc(p: ^Parser, kind: Token_Kind, loc := #caller_loca
return prev return prev
} }
@(private)
json_name_from_tag_value :: proc(value: string) -> (json_name, extra: string) {
json_name = value
if comma_index := strings.index_byte(json_name, ','); comma_index >= 0 {
json_name = json_name[:comma_index]
extra = json_name[comma_index:]
}
return
}
@(private) @(private)
unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unmarshal_Error) { unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unmarshal_Error) {
@@ -384,7 +394,8 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
for field, field_idx in fields { for field, field_idx in fields {
tag_value := string(reflect.struct_tag_get(field.tag, "json")) tag_value := string(reflect.struct_tag_get(field.tag, "json"))
if key == tag_value { json_name, _ := json_name_from_tag_value(tag_value)
if key == json_name {
use_field_idx = field_idx use_field_idx = field_idx
break break
} }
+1 -1
View File
@@ -2711,7 +2711,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
} }
} else { } else {
io.write_byte(fi.writer, '[' if verb != 'w' else '{', &fi.n) io.write_byte(fi.writer, '[' if verb != 'w' else '{', &fi.n)
io.write_byte(fi.writer, ']' if verb != 'w' else '}', &fi.n) defer io.write_byte(fi.writer, ']' if verb != 'w' else '}', &fi.n)
for i in 0..<info.count { for i in 0..<info.count {
if i > 0 { io.write_string(fi.writer, ", ", &fi.n) } if i > 0 { io.write_string(fi.writer, ", ", &fi.n) }
+168 -20
View File
@@ -102,37 +102,51 @@ round :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
return (x.i + (1 << (Fraction_Width - 1))) >> Fraction_Width return (x.i + (1 << (Fraction_Width - 1))) >> Fraction_Width
} }
@(require_results) @(require_results)
append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string { append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
Integer_Width :: 8*size_of(Backing) - Fraction_Width
x := x x := x
buf: [48]byte buf: [48]byte
i := 0 i := 0
if x.i < 0 {
if !intrinsics.type_is_unsigned(Backing) && x.i == min(Backing) {
// edge case handling for signed numbers
buf[i] = '-' buf[i] = '-'
i += 1 i += 1
x.i = -x.i i += copy(buf[i:], _power_of_two_table[Integer_Width])
} } else {
if x.i < 0 {
integer := x.i >> Fraction_Width buf[i] = '-'
fraction := x.i & (1<<Fraction_Width - 1)
s := strconv.append_uint(buf[i:], u64(integer), 10)
i += len(s)
if fraction != 0 {
buf[i] = '.'
i += 1
for fraction > 0 {
fraction *= 10
buf[i] = byte('0' + (fraction>>Fraction_Width))
i += 1 i += 1
fraction &= 1<<Fraction_Width - 1 x.i = -x.i
}
when size_of(Backing) < 16 {
T :: u64
append_uint :: strconv.append_uint
} else {
T :: u128
append_uint :: strconv.append_u128
}
integer := T(x.i) >> Fraction_Width
fraction := T(x.i) & (1<<Fraction_Width - 1)
s := append_uint(buf[i:], integer, 10)
i += len(s)
if fraction != 0 {
buf[i] = '.'
i += 1
for fraction > 0 {
fraction *= 10
buf[i] = byte('0' + (fraction>>Fraction_Width) % 10)
i += 1
fraction &= 1<<Fraction_Width - 1
}
} }
} }
n := copy(dst, buf[:i]) n := copy(dst, buf[:i])
return string(dst[:i]) return string(dst[:i])
} }
@@ -146,3 +160,137 @@ to_string :: proc(x: $T/Fixed($Backing, $Fraction_Width), allocator := context.a
copy(str, s) copy(str, s)
return string(str) return string(str)
} }
@(private)
_power_of_two_table := [129]string{
"0.5",
"1",
"2",
"4",
"8",
"16",
"32",
"64",
"128",
"256",
"512",
"1024",
"2048",
"4096",
"8192",
"16384",
"32768",
"65536",
"131072",
"262144",
"524288",
"1048576",
"2097152",
"4194304",
"8388608",
"16777216",
"33554432",
"67108864",
"134217728",
"268435456",
"536870912",
"1073741824",
"2147483648",
"4294967296",
"8589934592",
"17179869184",
"34359738368",
"68719476736",
"137438953472",
"274877906944",
"549755813888",
"1099511627776",
"2199023255552",
"4398046511104",
"8796093022208",
"17592186044416",
"35184372088832",
"70368744177664",
"140737488355328",
"281474976710656",
"562949953421312",
"1125899906842624",
"2251799813685248",
"4503599627370496",
"9007199254740992",
"18014398509481984",
"36028797018963968",
"72057594037927936",
"144115188075855872",
"288230376151711744",
"576460752303423488",
"1152921504606846976",
"2305843009213693952",
"4611686018427387904",
"9223372036854775808",
"18446744073709551616",
"36893488147419103232",
"73786976294838206464",
"147573952589676412928",
"295147905179352825856",
"590295810358705651712",
"1180591620717411303424",
"2361183241434822606848",
"4722366482869645213696",
"9444732965739290427392",
"18889465931478580854784",
"37778931862957161709568",
"75557863725914323419136",
"151115727451828646838272",
"302231454903657293676544",
"604462909807314587353088",
"1208925819614629174706176",
"2417851639229258349412352",
"4835703278458516698824704",
"9671406556917033397649408",
"19342813113834066795298816",
"38685626227668133590597632",
"77371252455336267181195264",
"154742504910672534362390528",
"309485009821345068724781056",
"618970019642690137449562112",
"1237940039285380274899124224",
"2475880078570760549798248448",
"4951760157141521099596496896",
"9903520314283042199192993792",
"19807040628566084398385987584",
"39614081257132168796771975168",
"79228162514264337593543950336",
"158456325028528675187087900672",
"316912650057057350374175801344",
"633825300114114700748351602688",
"1267650600228229401496703205376",
"2535301200456458802993406410752",
"5070602400912917605986812821504",
"10141204801825835211973625643008",
"20282409603651670423947251286016",
"40564819207303340847894502572032",
"81129638414606681695789005144064",
"162259276829213363391578010288128",
"324518553658426726783156020576256",
"649037107316853453566312041152512",
"1298074214633706907132624082305024",
"2596148429267413814265248164610048",
"5192296858534827628530496329220096",
"10384593717069655257060992658440192",
"20769187434139310514121985316880384",
"41538374868278621028243970633760768",
"83076749736557242056487941267521536",
"166153499473114484112975882535043072",
"332306998946228968225951765070086144",
"664613997892457936451903530140172288",
"1329227995784915872903807060280344576",
"2658455991569831745807614120560689152",
"5316911983139663491615228241121378304",
"10633823966279326983230456482242756608",
"21267647932558653966460912964485513216",
"42535295865117307932921825928971026432",
"85070591730234615865843651857942052864",
"170141183460469231731687303715884105728",
}
+27
View File
@@ -60,6 +60,7 @@ sqrt :: proc{
@(require_results) sin_f32be :: proc "contextless" (θ: f32be) -> f32be { return #force_inline f32be(sin_f32(f32(θ))) } @(require_results) sin_f32be :: proc "contextless" (θ: f32be) -> f32be { return #force_inline f32be(sin_f32(f32(θ))) }
@(require_results) sin_f64le :: proc "contextless" (θ: f64le) -> f64le { return #force_inline f64le(sin_f64(f64(θ))) } @(require_results) sin_f64le :: proc "contextless" (θ: f64le) -> f64le { return #force_inline f64le(sin_f64(f64(θ))) }
@(require_results) sin_f64be :: proc "contextless" (θ: f64be) -> f64be { return #force_inline f64be(sin_f64(f64(θ))) } @(require_results) sin_f64be :: proc "contextless" (θ: f64be) -> f64be { return #force_inline f64be(sin_f64(f64(θ))) }
// Return the sine of θ in radians.
sin :: proc{ sin :: proc{
sin_f16, sin_f16le, sin_f16be, sin_f16, sin_f16le, sin_f16be,
sin_f32, sin_f32le, sin_f32be, sin_f32, sin_f32le, sin_f32be,
@@ -72,6 +73,7 @@ sin :: proc{
@(require_results) cos_f32be :: proc "contextless" (θ: f32be) -> f32be { return #force_inline f32be(cos_f32(f32(θ))) } @(require_results) cos_f32be :: proc "contextless" (θ: f32be) -> f32be { return #force_inline f32be(cos_f32(f32(θ))) }
@(require_results) cos_f64le :: proc "contextless" (θ: f64le) -> f64le { return #force_inline f64le(cos_f64(f64(θ))) } @(require_results) cos_f64le :: proc "contextless" (θ: f64le) -> f64le { return #force_inline f64le(cos_f64(f64(θ))) }
@(require_results) cos_f64be :: proc "contextless" (θ: f64be) -> f64be { return #force_inline f64be(cos_f64(f64(θ))) } @(require_results) cos_f64be :: proc "contextless" (θ: f64be) -> f64be { return #force_inline f64be(cos_f64(f64(θ))) }
// Return the cosine of θ in radians.
cos :: proc{ cos :: proc{
cos_f16, cos_f16le, cos_f16be, cos_f16, cos_f16le, cos_f16be,
cos_f32, cos_f32le, cos_f32be, cos_f32, cos_f32le, cos_f32be,
@@ -378,6 +380,7 @@ log10 :: proc{
@(require_results) tan_f64 :: proc "contextless" (θ: f64) -> f64 { return sin(θ)/cos(θ) } @(require_results) tan_f64 :: proc "contextless" (θ: f64) -> f64 { return sin(θ)/cos(θ) }
@(require_results) tan_f64le :: proc "contextless" (θ: f64le) -> f64le { return f64le(tan_f64(f64(θ))) } @(require_results) tan_f64le :: proc "contextless" (θ: f64le) -> f64le { return f64le(tan_f64(f64(θ))) }
@(require_results) tan_f64be :: proc "contextless" (θ: f64be) -> f64be { return f64be(tan_f64(f64(θ))) } @(require_results) tan_f64be :: proc "contextless" (θ: f64be) -> f64be { return f64be(tan_f64(f64(θ))) }
// Return the tangent of θ in radians.
tan :: proc{ tan :: proc{
tan_f16, tan_f16le, tan_f16be, tan_f16, tan_f16le, tan_f16be,
tan_f32, tan_f32le, tan_f32be, tan_f32, tan_f32le, tan_f32be,
@@ -1752,7 +1755,28 @@ atan2_f64be :: proc "contextless" (y, x: f64be) -> f64be {
// TODO(bill): Better atan2_f32 // TODO(bill): Better atan2_f32
return f64be(atan2_f64(f64(y), f64(x))) return f64be(atan2_f64(f64(y), f64(x)))
} }
/*
Return the arc tangent of y/x in radians. Defined on the domain [-, ] for x and y with a range of [-π, π]
Special cases:
atan2(y, NaN) = NaN
atan2(NaN, x) = NaN
atan2(+0, x>=0) = + 0
atan2(-0, x>=0) = - 0
atan2(+0, x<=-0) = + π
atan2(-0, x<=-0) = - π
atan2(y>0, 0) = + π/2
atan2(y<0, 0) = - π/2
atan2(+, +) = + π/4
atan2(-, +) = - π/4
atan2(+, -) = 3π/4
atan2(-, -) = - 3π/4
atan2(y, +) = 0
atan2(y>0, -) = + π
atan2(y<0, -) = - π
atan2(+, x) = + π/2
atan2(-, x) = - π/2
*/
atan2 :: proc{ atan2 :: proc{
atan2_f64, atan2_f32, atan2_f16, atan2_f64, atan2_f32, atan2_f16,
atan2_f64le, atan2_f64be, atan2_f64le, atan2_f64be,
@@ -1760,6 +1784,7 @@ atan2 :: proc{
atan2_f16le, atan2_f16be, atan2_f16le, atan2_f16be,
} }
// Return the arc tangent of x, in radians. Defined on the domain of [-∞, ∞] with a range of [-π/2, π/2]
@(require_results) @(require_results)
atan :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { atan :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
return atan2(x, 1) return atan2(x, 1)
@@ -1871,6 +1896,7 @@ asin_f16le :: proc "contextless" (x: f16le) -> f16le {
asin_f16be :: proc "contextless" (x: f16be) -> f16be { asin_f16be :: proc "contextless" (x: f16be) -> f16be {
return f16be(asin_f64(f64(x))) return f16be(asin_f64(f64(x)))
} }
// Return the arc sine of x, in radians. Defined on the domain of [-1, 1] with a range of [-π/2, π/2]
asin :: proc{ asin :: proc{
asin_f64, asin_f32, asin_f16, asin_f64, asin_f32, asin_f16,
asin_f64le, asin_f64be, asin_f64le, asin_f64be,
@@ -1985,6 +2011,7 @@ acos_f16le :: proc "contextless" (x: f16le) -> f16le {
acos_f16be :: proc "contextless" (x: f16be) -> f16be { acos_f16be :: proc "contextless" (x: f16be) -> f16be {
return f16be(acos_f64(f64(x))) return f16be(acos_f64(f64(x)))
} }
// Return the arc cosine of x, in radians. Defined on the domain of [-1, 1] with a range of [0, π].
acos :: proc{ acos :: proc{
acos_f64, acos_f32, acos_f16, acos_f64, acos_f32, acos_f16,
acos_f64le, acos_f64be, acos_f64le, acos_f64be,
+15 -2
View File
@@ -21,7 +21,7 @@ import "core:strconv"
import "core:unicode/utf8" import "core:unicode/utf8"
import "core:encoding/hex" import "core:encoding/hex"
split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host, path: string, queries: map[string]string) { split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host, path: string, queries: map[string]string, fragment: string) {
s := url s := url
i := strings.index(s, "://") i := strings.index(s, "://")
@@ -30,6 +30,12 @@ split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host,
s = s[i+3:] s = s[i+3:]
} }
i = strings.index(s, "#")
if i != -1 {
fragment = s[i+1:]
s = s[:i]
}
i = strings.index(s, "?") i = strings.index(s, "?")
if i != -1 { if i != -1 {
query_str := s[i+1:] query_str := s[i+1:]
@@ -62,7 +68,7 @@ split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host,
return return
} }
join_url :: proc(scheme, host, path: string, queries: map[string]string, allocator := context.allocator) -> string { join_url :: proc(scheme, host, path: string, queries: map[string]string, fragment: string, allocator := context.allocator) -> string {
b := strings.builder_make(allocator) b := strings.builder_make(allocator)
strings.builder_grow(&b, len(scheme) + 3 + len(host) + 1 + len(path)) strings.builder_grow(&b, len(scheme) + 3 + len(host) + 1 + len(path))
@@ -95,6 +101,13 @@ join_url :: proc(scheme, host, path: string, queries: map[string]string, allocat
i += 1 i += 1
} }
if fragment != "" {
if fragment[0] != '#' {
strings.write_string(&b, "#")
}
strings.write_string(&b, strings.trim_space(fragment))
}
return strings.to_string(b) return strings.to_string(b)
} }
+21 -1
View File
@@ -617,7 +617,7 @@ field_flag_strings := [Field_Flag]string{
.Any_Int = "#any_int", .Any_Int = "#any_int",
.Subtype = "#subtype", .Subtype = "#subtype",
.By_Ptr = "#by_ptr", .By_Ptr = "#by_ptr",
.No_Broadcast ="#no_broadcast", .No_Broadcast = "#no_broadcast",
.Results = "results", .Results = "results",
.Tags = "field tag", .Tags = "field tag",
@@ -842,6 +842,23 @@ Matrix_Type :: struct {
elem: ^Expr, elem: ^Expr,
} }
Bit_Field_Type :: struct {
using node: Expr,
tok_pos: tokenizer.Pos,
backing_type: ^Expr,
open: tokenizer.Pos,
fields: []^Bit_Field_Field,
close: tokenizer.Pos,
}
Bit_Field_Field :: struct {
using node: Node,
docs: ^Comment_Group,
name: ^Expr,
type: ^Expr,
bit_size: ^Expr,
comments: ^Comment_Group,
}
Any_Node :: union { Any_Node :: union {
^Package, ^Package,
@@ -898,6 +915,7 @@ Any_Node :: union {
^Map_Type, ^Map_Type,
^Relative_Type, ^Relative_Type,
^Matrix_Type, ^Matrix_Type,
^Bit_Field_Type,
^Bad_Stmt, ^Bad_Stmt,
^Empty_Stmt, ^Empty_Stmt,
@@ -928,6 +946,7 @@ Any_Node :: union {
^Attribute, ^Attribute,
^Field, ^Field,
^Field_List, ^Field_List,
^Bit_Field_Field,
} }
@@ -982,6 +1001,7 @@ Any_Expr :: union {
^Map_Type, ^Map_Type,
^Relative_Type, ^Relative_Type,
^Matrix_Type, ^Matrix_Type,
^Bit_Field_Type,
} }
+7
View File
@@ -336,6 +336,13 @@ clone_node :: proc(node: ^Node) -> ^Node {
case ^Relative_Type: case ^Relative_Type:
r.tag = clone(r.tag) r.tag = clone(r.tag)
r.type = clone(r.type) r.type = clone(r.type)
case ^Bit_Field_Type:
r.backing_type = clone(r.backing_type)
r.fields = auto_cast clone(r.fields)
case ^Bit_Field_Field:
r.name = clone(r.name)
r.type = clone(r.type)
r.bit_size = clone(r.bit_size)
case: case:
fmt.panicf("Unhandled node kind: %v", r) fmt.panicf("Unhandled node kind: %v", r)
} }
+9 -1
View File
@@ -414,7 +414,15 @@ walk :: proc(v: ^Visitor, node: ^Node) {
walk(v, n.row_count) walk(v, n.row_count)
walk(v, n.column_count) walk(v, n.column_count)
walk(v, n.elem) walk(v, n.elem)
case ^Bit_Field_Type:
walk(v, n.backing_type)
for f in n.fields {
walk(v, f)
}
case ^Bit_Field_Field:
walk(v, n.name)
walk(v, n.type)
walk(v, n.bit_size)
case: case:
fmt.panicf("ast.walk: unexpected node type %T", n) fmt.panicf("ast.walk: unexpected node type %T", n)
} }
+58 -10
View File
@@ -416,24 +416,28 @@ end_of_line_pos :: proc(p: ^Parser, tok: tokenizer.Token) -> tokenizer.Pos {
} }
expect_closing_brace_of_field_list :: proc(p: ^Parser) -> tokenizer.Token { expect_closing_brace_of_field_list :: proc(p: ^Parser) -> tokenizer.Token {
return expect_closing_token_of_field_list(p, .Close_Brace, "field list")
}
expect_closing_token_of_field_list :: proc(p: ^Parser, closing_kind: tokenizer.Token_Kind, msg: string) -> tokenizer.Token {
token := p.curr_tok token := p.curr_tok
if allow_token(p, .Close_Brace) { if allow_token(p, closing_kind) {
return token return token
} }
if allow_token(p, .Semicolon) && !tokenizer.is_newline(token) { if allow_token(p, .Semicolon) && !tokenizer.is_newline(token) {
str := tokenizer.token_to_string(token) str := tokenizer.token_to_string(token)
error(p, end_of_line_pos(p, p.prev_tok), "expected a comma, got %s", str) error(p, end_of_line_pos(p, p.prev_tok), "expected a comma, got %s", str)
} }
expect_brace := expect_token(p, .Close_Brace) expect_closing := expect_token_after(p, closing_kind, msg)
if expect_brace.kind != .Close_Brace { if expect_closing.kind != closing_kind {
for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF && !is_non_inserted_semicolon(p.curr_tok) { for p.curr_tok.kind != closing_kind && p.curr_tok.kind != .EOF && !is_non_inserted_semicolon(p.curr_tok) {
advance_token(p) advance_token(p)
} }
return p.curr_tok return p.curr_tok
} }
return expect_brace return expect_closing
} }
expect_closing_parentheses_of_field_list :: proc(p: ^Parser) -> tokenizer.Token { expect_closing_parentheses_of_field_list :: proc(p: ^Parser) -> tokenizer.Token {
@@ -531,7 +535,7 @@ is_semicolon_optional_for_node :: proc(p: ^Parser, node: ^ast.Node) -> bool {
return is_semicolon_optional_for_node(p, n.type) return is_semicolon_optional_for_node(p, n.type)
case ^ast.Pointer_Type: case ^ast.Pointer_Type:
return is_semicolon_optional_for_node(p, n.elem) return is_semicolon_optional_for_node(p, n.elem)
case ^ast.Struct_Type, ^ast.Union_Type, ^ast.Enum_Type: case ^ast.Struct_Type, ^ast.Union_Type, ^ast.Enum_Type, ^ast.Bit_Set_Type, ^ast.Bit_Field_Type:
// Require semicolon within a procedure body // Require semicolon within a procedure body
return p.curr_proc == nil return p.curr_proc == nil
case ^ast.Proc_Lit: case ^ast.Proc_Lit:
@@ -1354,6 +1358,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
rs := ast.new(ast.Return_Stmt, tok.pos, end) rs := ast.new(ast.Return_Stmt, tok.pos, end)
rs.results = results[:] rs.results = results[:]
expect_semicolon(p, rs)
return rs return rs
case .Break, .Continue, .Fallthrough: case .Break, .Continue, .Fallthrough:
@@ -2790,6 +2795,48 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
mt.column_count = column_count mt.column_count = column_count
mt.elem = elem mt.elem = elem
return mt return mt
case .Bit_Field:
tok := expect_token(p, .Bit_Field)
backing_type := parse_type_or_ident(p)
if backing_type == nil {
token := advance_token(p)
error(p, token.pos, "Expected a backing type for a 'bit_field'")
}
skip_possible_newline_for_literal(p)
open := expect_token_after(p, .Open_Brace, "bit_field")
fields: [dynamic]^ast.Bit_Field_Field
for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF {
name := parse_ident(p)
expect_token(p, .Colon)
type := parse_type(p)
expect_token(p, .Or)
bit_size := parse_expr(p, true)
field := ast.new(ast.Bit_Field_Field, name.pos, bit_size)
field.name = name
field.type = type
field.bit_size = bit_size
append(&fields, field)
allow_token(p, .Comma) or_break
}
close := expect_closing_brace_of_field_list(p)
bf := ast.new(ast.Bit_Field_Type, tok.pos, close.pos)
bf.tok_pos = tok.pos
bf.backing_type = backing_type
bf.open = open.pos
bf.fields = fields[:]
bf.close = close.pos
return bf
case .Asm: case .Asm:
tok := expect_token(p, .Asm) tok := expect_token(p, .Asm)
@@ -2897,7 +2944,8 @@ is_literal_type :: proc(expr: ^ast.Expr) -> bool {
^ast.Map_Type, ^ast.Map_Type,
^ast.Bit_Set_Type, ^ast.Bit_Set_Type,
^ast.Matrix_Type, ^ast.Matrix_Type,
^ast.Call_Expr: ^ast.Call_Expr,
^ast.Bit_Field_Type:
return true return true
} }
return false return false
@@ -2947,8 +2995,8 @@ parse_literal_value :: proc(p: ^Parser, type: ^ast.Expr) -> ^ast.Comp_Lit {
} }
p.expr_level -= 1 p.expr_level -= 1
skip_possible_newline(p) skip_possible_newline(p)
close := expect_token_after(p, .Close_Brace, "compound literal") close := expect_closing_brace_of_field_list(p)
pos := type.pos if type != nil else open.pos pos := type.pos if type != nil else open.pos
lit := ast.new(ast.Comp_Lit, pos, end_pos(close)) lit := ast.new(ast.Comp_Lit, pos, end_pos(close))
@@ -3011,7 +3059,7 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr {
allow_token(p, .Comma) or_break allow_token(p, .Comma) or_break
} }
close := expect_token_after(p, .Close_Paren, "argument list") close := expect_closing_token_of_field_list(p, .Close_Paren, "argument list")
p.expr_level -= 1 p.expr_level -= 1
ce := ast.new(ast.Call_Expr, operand.pos, end_pos(close)) ce := ast.new(ast.Call_Expr, operand.pos, end_pos(close))
+51 -1
View File
@@ -445,7 +445,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
for value in v.values { for value in v.values {
#partial switch a in value.derived { #partial switch a in value.derived {
case ^ast.Union_Type, ^ast.Enum_Type, ^ast.Struct_Type: case ^ast.Union_Type, ^ast.Enum_Type, ^ast.Struct_Type, ^ast.Bit_Field_Type:
add_semicolon = false || called_in_stmt add_semicolon = false || called_in_stmt
case ^ast.Proc_Lit: case ^ast.Proc_Lit:
add_semicolon = false add_semicolon = false
@@ -488,6 +488,37 @@ visit_exprs :: proc(p: ^Printer, list: []^ast.Expr, options := List_Options{}) {
} }
} }
@(private)
visit_bit_field_fields :: proc(p: ^Printer, list: []^ast.Bit_Field_Field, options := List_Options{}) {
if len(list) == 0 {
return
}
// we have to newline the expressions to respect the source
for v, i in list {
// Don't move the first expression, it looks bad
if i != 0 && .Enforce_Newline in options {
newline_position(p, 1)
} else if i != 0 {
move_line_limit(p, v.pos, 1)
}
visit_expr(p, v.name, options)
push_generic_token(p, .Colon, 0)
visit_expr(p, v.type, options)
push_generic_token(p, .Or, 1)
visit_expr(p, v.bit_size, options)
if (i != len(list) - 1 || .Trailing in options) && .Add_Comma in options {
push_generic_token(p, .Comma, 0)
}
}
if len(list) > 1 && .Enforce_Newline in options {
newline_position(p, 1)
}
}
@(private) @(private)
visit_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) { visit_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) {
if len(attributes) == 0 { if len(attributes) == 0 {
@@ -1293,6 +1324,25 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
visit_expr(p, v.column_count) visit_expr(p, v.column_count)
push_generic_token(p, .Close_Bracket, 0) push_generic_token(p, .Close_Bracket, 0)
visit_expr(p, v.elem) visit_expr(p, v.elem)
case ^ast.Bit_Field_Type:
push_generic_token(p, .Bit_Field, 1)
visit_expr(p, v.backing_type)
if len(v.fields) == 0 || v.pos.line == v.close.line {
push_generic_token(p, .Open_Brace, 1)
visit_bit_field_fields(p, v.fields, {.Add_Comma})
push_generic_token(p, .Close_Brace, 0)
} else {
visit_begin_brace(p, v.pos, .Generic, len(v.fields))
newline_position(p, 1)
set_source_position(p, v.fields[0].pos)
visit_bit_field_fields(p, v.fields, {.Add_Comma, .Trailing, .Enforce_Newline})
set_source_position(p, v.close)
visit_end_brace(p, v.close)
}
set_source_position(p, v.close)
case: case:
panic(fmt.aprint(expr.derived)) panic(fmt.aprint(expr.derived))
} }
+1
View File
@@ -39,6 +39,7 @@ init :: proc(t: ^Tokenizer, src: string, path: string, err: Error_Handler = defa
t.read_offset = 0 t.read_offset = 0
t.line_offset = 0 t.line_offset = 0
t.line_count = len(src) > 0 ? 1 : 0 t.line_count = len(src) > 0 ? 1 : 0
t.insert_semicolon = false
t.error_count = 0 t.error_count = 0
t.path = path t.path = path
+2 -2
View File
@@ -3,8 +3,8 @@ package os
import "core:time" import "core:time"
File_Info :: struct { File_Info :: struct {
fullpath: string, fullpath: string, // allocated
name: string, name: string, // uses `fullpath` as underlying data
size: i64, size: i64,
mode: File_Mode, mode: File_Mode,
is_dir: bool, is_dir: bool,
+7
View File
@@ -1213,6 +1213,13 @@ Output:
append_int :: proc(buf: []byte, i: i64, base: int) -> string { append_int :: proc(buf: []byte, i: i64, base: int) -> string {
return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, nil) return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, nil)
} }
append_u128 :: proc(buf: []byte, u: u128, base: int) -> string {
return append_bits_128(buf, u, base, false, 8*size_of(uint), digits, nil)
}
/* /*
Converts an integer value to a string and stores it in the given buffer Converts an integer value to a string and stores it in the given buffer
+1 -1
View File
@@ -2,7 +2,7 @@
package sync package sync
import "core:c" import "core:c"
import "core:runtime" import "base:runtime"
import "core:sys/haiku" import "core:sys/haiku"
import "core:sys/unix" import "core:sys/unix"
import "core:time" import "core:time"
@@ -0,0 +1,34 @@
package CoreFoundation
foreign import CoreFoundation "system:CoreFoundation.framework"
TypeID :: distinct uint
OptionFlags :: distinct uint
HashCode :: distinct uint
Index :: distinct int
TypeRef :: distinct rawptr
Range :: struct {
location: Index,
length: Index,
}
foreign CoreFoundation {
// Releases a Core Foundation object.
CFRelease :: proc(cf: TypeRef) ---
}
// Releases a Core Foundation object.
Release :: proc {
ReleaseObject,
ReleaseString,
}
ReleaseObject :: #force_inline proc(cf: TypeRef) {
CFRelease(cf)
}
// Releases a Core Foundation string.
ReleaseString :: #force_inline proc(theString: String) {
CFRelease(TypeRef(theString))
}
@@ -0,0 +1,203 @@
package CoreFoundation
import "base:runtime"
foreign import CoreFoundation "system:CoreFoundation.framework"
String :: distinct TypeRef // same as CFStringRef
StringEncoding :: distinct u32
StringBuiltInEncodings :: enum StringEncoding {
MacRoman = 0,
WindowsLatin1 = 0x0500,
ISOLatin1 = 0x0201,
NextStepLatin = 0x0B01,
ASCII = 0x0600,
Unicode = 0x0100,
UTF8 = 0x08000100,
NonLossyASCII = 0x0BFF,
UTF16 = 0x0100,
UTF16BE = 0x10000100,
UTF16LE = 0x14000100,
UTF32 = 0x0c000100,
UTF32BE = 0x18000100,
UTF32LE = 0x1c000100,
}
StringEncodings :: enum Index {
MacJapanese = 1,
MacChineseTrad = 2,
MacKorean = 3,
MacArabic = 4,
MacHebrew = 5,
MacGreek = 6,
MacCyrillic = 7,
MacDevanagari = 9,
MacGurmukhi = 10,
MacGujarati = 11,
MacOriya = 12,
MacBengali = 13,
MacTamil = 14,
MacTelugu = 15,
MacKannada = 16,
MacMalayalam = 17,
MacSinhalese = 18,
MacBurmese = 19,
MacKhmer = 20,
MacThai = 21,
MacLaotian = 22,
MacGeorgian = 23,
MacArmenian = 24,
MacChineseSimp = 25,
MacTibetan = 26,
MacMongolian = 27,
MacEthiopic = 28,
MacCentralEurRoman = 29,
MacVietnamese = 30,
MacExtArabic = 31,
MacSymbol = 33,
MacDingbats = 34,
MacTurkish = 35,
MacCroatian = 36,
MacIcelandic = 37,
MacRomanian = 38,
MacCeltic = 39,
MacGaelic = 40,
MacFarsi = 0x8C,
MacUkrainian = 0x98,
MacInuit = 0xEC,
MacVT100 = 0xFC,
MacHFS = 0xFF,
ISOLatin2 = 0x0202,
ISOLatin3 = 0x0203,
ISOLatin4 = 0x0204,
ISOLatinCyrillic = 0x0205,
ISOLatinArabic = 0x0206,
ISOLatinGreek = 0x0207,
ISOLatinHebrew = 0x0208,
ISOLatin5 = 0x0209,
ISOLatin6 = 0x020A,
ISOLatinThai = 0x020B,
ISOLatin7 = 0x020D,
ISOLatin8 = 0x020E,
ISOLatin9 = 0x020F,
ISOLatin10 = 0x0210,
DOSLatinUS = 0x0400,
DOSGreek = 0x0405,
DOSBalticRim = 0x0406,
DOSLatin1 = 0x0410,
DOSGreek1 = 0x0411,
DOSLatin2 = 0x0412,
DOSCyrillic = 0x0413,
DOSTurkish = 0x0414,
DOSPortuguese = 0x0415,
DOSIcelandic = 0x0416,
DOSHebrew = 0x0417,
DOSCanadianFrench = 0x0418,
DOSArabic = 0x0419,
DOSNordic = 0x041A,
DOSRussian = 0x041B,
DOSGreek2 = 0x041C,
DOSThai = 0x041D,
DOSJapanese = 0x0420,
DOSChineseSimplif = 0x0421,
DOSKorean = 0x0422,
DOSChineseTrad = 0x0423,
WindowsLatin2 = 0x0501,
WindowsCyrillic = 0x0502,
WindowsGreek = 0x0503,
WindowsLatin5 = 0x0504,
WindowsHebrew = 0x0505,
WindowsArabic = 0x0506,
WindowsBalticRim = 0x0507,
WindowsVietnamese = 0x0508,
WindowsKoreanJohab = 0x0510,
ANSEL = 0x0601,
JIS_X0201_76 = 0x0620,
JIS_X0208_83 = 0x0621,
JIS_X0208_90 = 0x0622,
JIS_X0212_90 = 0x0623,
JIS_C6226_78 = 0x0624,
ShiftJIS_X0213 = 0x0628,
ShiftJIS_X0213_MenKuTen = 0x0629,
GB_2312_80 = 0x0630,
GBK_95 = 0x0631,
GB_18030_2000 = 0x0632,
KSC_5601_87 = 0x0640,
KSC_5601_92_Johab = 0x0641,
CNS_11643_92_P1 = 0x0651,
CNS_11643_92_P2 = 0x0652,
CNS_11643_92_P3 = 0x0653,
ISO_2022_JP = 0x0820,
ISO_2022_JP_2 = 0x0821,
ISO_2022_JP_1 = 0x0822,
ISO_2022_JP_3 = 0x0823,
ISO_2022_CN = 0x0830,
ISO_2022_CN_EXT = 0x0831,
ISO_2022_KR = 0x0840,
EUC_JP = 0x0920,
EUC_CN = 0x0930,
EUC_TW = 0x0931,
EUC_KR = 0x0940,
ShiftJIS = 0x0A01,
KOI8_R = 0x0A02,
Big5 = 0x0A03,
MacRomanLatin1 = 0x0A04,
HZ_GB_2312 = 0x0A05,
Big5_HKSCS_1999 = 0x0A06,
VISCII = 0x0A07,
KOI8_U = 0x0A08,
Big5_E = 0x0A09,
NextStepJapanese = 0x0B02,
EBCDIC_US = 0x0C01,
EBCDIC_CP037 = 0x0C02,
UTF7 = 0x04000100,
UTF7_IMAP = 0x0A10,
ShiftJIS_X0213_00 = 0x0628, // Deprecated. Use `ShiftJIS_X0213` instead.
}
@(link_prefix = "CF", default_calling_convention = "c")
foreign CoreFoundation {
// Copies the character contents of a string to a local C string buffer after converting the characters to a given encoding.
StringGetCString :: proc(theString: String, buffer: [^]byte, bufferSize: Index, encoding: StringEncoding) -> b8 ---
// Returns the number (in terms of UTF-16 code pairs) of Unicode characters in a string.
StringGetLength :: proc(theString: String) -> Index ---
// Returns the maximum number of bytes a string of a specified length (in Unicode characters) will take up if encoded in a specified encoding.
StringGetMaximumSizeForEncoding :: proc(length: Index, encoding: StringEncoding) -> Index ---
// Fetches a range of the characters from a string into a byte buffer after converting the characters to a specified encoding.
StringGetBytes :: proc(thestring: String, range: Range, encoding: StringEncoding, lossByte: u8, isExternalRepresentation: b8, buffer: [^]byte, maxBufLen: Index, usedBufLen: ^Index) -> Index ---
StringIsEncodingAvailable :: proc(encoding: StringEncoding) -> bool ---
@(link_name = "__CFStringMakeConstantString")
StringMakeConstantString :: proc "c" (#const c: cstring) -> String ---
}
STR :: StringMakeConstantString
StringCopyToOdinString :: proc(
theString: String,
allocator := context.allocator,
) -> (
str: string,
ok: bool,
) #optional_ok {
length := StringGetLength(theString)
max := StringGetMaximumSizeForEncoding(length, StringEncoding(StringBuiltInEncodings.UTF8))
buf, err := make([]byte, max, allocator)
if err != nil do return
raw_str := runtime.Raw_String {
data = raw_data(buf),
}
StringGetBytes(theString, {0, length}, StringEncoding(StringBuiltInEncodings.UTF8), 0, false, raw_data(buf), max, (^Index)(&raw_str.len))
return transmute(string)raw_str, true
}
@@ -23,12 +23,9 @@ StringEncoding :: enum UInteger {
WindowsCP1250 = 15, WindowsCP1250 = 15,
ISO2022JP = 21, ISO2022JP = 21,
MacOSRoman = 30, MacOSRoman = 30,
UTF16 = Unicode, UTF16 = Unicode,
UTF16BigEndian = 0x90000100, UTF16BigEndian = 0x90000100,
UTF16LittleEndian = 0x94000100, UTF16LittleEndian = 0x94000100,
UTF32 = 0x8c000100, UTF32 = 0x8c000100,
UTF32BigEndian = 0x98000100, UTF32BigEndian = 0x98000100,
UTF32LittleEndian = 0x9c000100, UTF32LittleEndian = 0x9c000100,
@@ -49,12 +46,9 @@ StringCompareOption :: enum UInteger {
unichar :: distinct u16 unichar :: distinct u16
@(link_prefix="NS", default_calling_convention="c")
foreign Foundation {
StringFromClass :: proc(cls: Class) -> ^String ---
}
AT :: MakeConstantString AT :: MakeConstantString
// CFString is 'toll-free bridged' with its Cocoa Foundation counterpart, NSString.
MakeConstantString :: proc "c" (#const c: cstring) -> ^String { MakeConstantString :: proc "c" (#const c: cstring) -> ^String {
foreign Foundation { foreign Foundation {
__CFStringMakeConstantString :: proc "c" (c: cstring) -> ^String --- __CFStringMakeConstantString :: proc "c" (c: cstring) -> ^String ---
@@ -62,6 +56,10 @@ MakeConstantString :: proc "c" (#const c: cstring) -> ^String {
return __CFStringMakeConstantString(c) return __CFStringMakeConstantString(c)
} }
@(link_prefix="NS", default_calling_convention="c")
foreign Foundation {
StringFromClass :: proc(cls: Class) -> ^String ---
}
@(objc_type=String, objc_name="alloc", objc_is_class_method=true) @(objc_type=String, objc_name="alloc", objc_is_class_method=true)
String_alloc :: proc "c" () -> ^String { String_alloc :: proc "c" () -> ^String {
@@ -73,7 +71,6 @@ String_init :: proc "c" (self: ^String) -> ^String {
return msgSend(^String, self, "init") return msgSend(^String, self, "init")
} }
@(objc_type=String, objc_name="initWithString") @(objc_type=String, objc_name="initWithString")
String_initWithString :: proc "c" (self: ^String, other: ^String) -> ^String { String_initWithString :: proc "c" (self: ^String, other: ^String) -> ^String {
return msgSend(^String, self, "initWithString:", other) return msgSend(^String, self, "initWithString:", other)
+386
View File
@@ -0,0 +1,386 @@
package Security
OSStatus :: distinct i32
errSec :: enum OSStatus {
Success = 0, // No error.
Unimplemented = -4, // Function or operation not implemented.
DiskFull = -34, // The disk is full.
IO = -36, // I/O error.
OpWr = -49, // File already open with with write permission.
Param = -50, // One or more parameters passed to a function were not valid.
WrPerm = -61, // Write permissions error.
Allocate = -108, // Failed to allocate memory.
UserCanceled = -128, // User canceled the operation.
BadReq = -909, // Bad parameter or invalid state for operation.
InternalComponent = -2070,
CoreFoundationUnknown = -4960,
MissingEntitlement, // A required entitlement isn't present.
RestrictedAPI, // Client is restricted and is not permitted to perform this operation.
NotAvailable = -25291, // No keychain is available. You may need to restart your computer.
ReadOnly = -25292, // This keychain cannot be modified.
AuthFailed = -25293, // The user name or passphrase you entered is not correct.
NoSuchKeychain = -25294, // The specified keychain could not be found.
InvalidKeychain = -25295, // The specified keychain is not a valid keychain file.
DuplicateKeychain = -25296, // A keychain with the same name already exists.
DuplicateCallback = -25297, // The specified callback function is already installed.
InvalidCallback = -25298, // The specified callback function is not valid.
DuplicateItem = -25299, // The specified item already exists in the keychain.
ItemNotFound = -25300, // The specified item could not be found in the keychain.
BufferTooSmall = -25301, // There is not enough memory available to use the specified item.
DataTooLarge = -25302, // This item contains information which is too large or in a format that cannot be displayed.
NoSuchAttr = -25303, // The specified attribute does not exist.
InvalidItemRef = -25304, // The specified item is no longer valid. It may have been deleted from the keychain.
InvalidSearchRef = -25305, // Unable to search the current keychain.
NoSuchClass = -25306, // The specified item does not appear to be a valid keychain item.
NoDefaultKeychain = -25307, // A default keychain could not be found.
InteractionNotAllowed = -25308, // User interaction is not allowed.
ReadOnlyAttr = -25309, // The specified attribute could not be modified.
WrongSecVersion = -25310, // This keychain was created by a different version of the system software and cannot be opened.
KeySizeNotAllowed = -25311, // This item specifies a key size which is too large or too small.
NoStorageModule = -25312, // A required component (data storage module) could not be loaded. You may need to restart your computer.
NoCertificateModule = -25313, // A required component (certificate module) could not be loaded. You may need to restart your computer.
NoPolicyModule = -25314, // A required component (policy module) could not be loaded. You may need to restart your computer.
InteractionRequired = -25315, // User interaction is required, but is currently not allowed.
DataNotAvailable = -25316, // The contents of this item cannot be retrieved.
DataNotModifiable = -25317, // The contents of this item cannot be modified.
CreateChainFailed = -25318, // One or more certificates required to validate this certificate cannot be found.
InvalidPrefsDomain = -25319, // The specified preferences domain is not valid.
InDarkWake = -25320, // In dark wake, no UI possible
ACLNotSimple = -25240, // The specified access control list is not in standard (simple) form.
PolicyNotFound = -25241, // The specified policy cannot be found.
InvalidTrustSetting = -25242, // The specified trust setting is invalid.
NoAccessForItem = -25243, // The specified item has no access control.
InvalidOwnerEdit = -25244, // Invalid attempt to change the owner of this item.
TrustNotAvailable = -25245, // No trust results are available.
UnsupportedFormat = -25256, // Import/Export format unsupported.
UnknownFormat = -25257, // Unknown format in import.
KeyIsSensitive = -25258, // Key material must be wrapped for export.
MultiplePrivKeys = -25259, // An attempt was made to import multiple private keys.
PassphraseRequired = -25260, // Passphrase is required for import/export.
InvalidPasswordRef = -25261, // The password reference was invalid.
InvalidTrustSettings = -25262, // The Trust Settings Record was corrupted.
NoTrustSettings = -25263, // No Trust Settings were found.
Pkcs12VerifyFailure = -25264, // MAC verification failed during PKCS12 import (wrong password?)
NotSigner = -26267, // A certificate was not signed by its proposed parent.
Decode = -26275, // Unable to decode the provided data.
ServiceNotAvailable = -67585, // The required service is not available.
InsufficientClientID = -67586, // The client ID is not correct.
DeviceReset = -67587, // A device reset has occurred.
DeviceFailed = -67588, // A device failure has occurred.
AppleAddAppACLSubject = -67589, // Adding an application ACL subject failed.
ApplePublicKeyIncomplete = -67590, // The public key is incomplete.
AppleSignatureMismatch = -67591, // A signature mismatch has occurred.
AppleInvalidKeyStartDate = -67592, // The specified key has an invalid start date.
AppleInvalidKeyEndDate = -67593, // The specified key has an invalid end date.
ConversionError = -67594, // A conversion error has occurred.
AppleSSLv2Rollback = -67595, // A SSLv2 rollback error has occurred.
QuotaExceeded = -67596, // The quota was exceeded.
FileTooBig = -67597, // The file is too big.
InvalidDatabaseBlob = -67598, // The specified database has an invalid blob.
InvalidKeyBlob = -67599, // The specified database has an invalid key blob.
IncompatibleDatabaseBlob = -67600, // The specified database has an incompatible blob.
IncompatibleKeyBlob = -67601, // The specified database has an incompatible key blob.
HostNameMismatch = -67602, // A host name mismatch has occurred.
UnknownCriticalExtensionFlag = -67603, // There is an unknown critical extension flag.
NoBasicConstraints = -67604, // No basic constraints were found.
NoBasicConstraintsCA = -67605, // No basic CA constraints were found.
InvalidAuthorityKeyID = -67606, // The authority key ID is not valid.
InvalidSubjectKeyID = -67607, // The subject key ID is not valid.
InvalidKeyUsageForPolicy = -67608, // The key usage is not valid for the specified policy.
InvalidExtendedKeyUsage = -67609, // The extended key usage is not valid.
InvalidIDLinkage = -67610, // The ID linkage is not valid.
PathLengthConstraintExceeded = -67611, // The path length constraint was exceeded.
InvalidRoot = -67612, // The root or anchor certificate is not valid.
CRLExpired = -67613, // The CRL has expired.
CRLNotValidYet = -67614, // The CRL is not yet valid.
CRLNotFound = -67615, // The CRL was not found.
CRLServerDown = -67616, // The CRL server is down.
CRLBadURI = -67617, // The CRL has a bad Uniform Resource Identifier.
UnknownCertExtension = -67618, // An unknown certificate extension was encountered.
UnknownCRLExtension = -67619, // An unknown CRL extension was encountered.
CRLNotTrusted = -67620, // The CRL is not trusted.
CRLPolicyFailed = -67621, // The CRL policy failed.
IDPFailure = -67622, // The issuing distribution point was not valid.
SMIMEEmailAddressesNotFound = -67623, // An email address mismatch was encountered.
SMIMEBadExtendedKeyUsage = -67624, // The appropriate extended key usage for SMIME was not found.
SMIMEBadKeyUsage = -67625, // The key usage is not compatible with SMIME.
SMIMEKeyUsageNotCritical = -67626, // The key usage extension is not marked as critical.
SMIMENoEmailAddress = -67627, // No email address was found in the certificate.
SMIMESubjAltNameNotCritical = -67628, // The subject alternative name extension is not marked as critical.
SSLBadExtendedKeyUsage = -67629, // The appropriate extended key usage for SSL was not found.
OCSPBadResponse = -67630, // The OCSP response was incorrect or could not be parsed.
OCSPBadRequest = -67631, // The OCSP request was incorrect or could not be parsed.
OCSPUnavailable = -67632, // OCSP service is unavailable.
OCSPStatusUnrecognized = -67633, // The OCSP server did not recognize this certificate.
EndOfData = -67634, // An end-of-data was detected.
IncompleteCertRevocationCheck = -67635, // An incomplete certificate revocation check occurred.
NetworkFailure = -67636, // A network failure occurred.
OCSPNotTrustedToAnchor = -67637, // The OCSP response was not trusted to a root or anchor certificate.
RecordModified = -67638, // The record was modified.
OCSPSignatureError = -67639, // The OCSP response had an invalid signature.
OCSPNoSigner = -67640, // The OCSP response had no signer.
OCSPResponderMalformedReq = -67641, // The OCSP responder was given a malformed request.
OCSPResponderInternalError = -67642, // The OCSP responder encountered an internal error.
OCSPResponderTryLater = -67643, // The OCSP responder is busy, try again later.
OCSPResponderSignatureRequired = -67644, // The OCSP responder requires a signature.
OCSPResponderUnauthorized = -67645, // The OCSP responder rejected this request as unauthorized.
OCSPResponseNonceMismatch = -67646, // The OCSP response nonce did not match the request.
CodeSigningBadCertChainLength = -67647, // Code signing encountered an incorrect certificate chain length.
CodeSigningNoBasicConstraints = -67648, // Code signing found no basic constraints.
CodeSigningBadPathLengthConstraint = -67649, // Code signing encountered an incorrect path length constraint.
CodeSigningNoExtendedKeyUsage = -67650, // Code signing found no extended key usage.
CodeSigningDevelopment = -67651, // Code signing indicated use of a development-only certificate.
ResourceSignBadCertChainLength = -67652, // Resource signing has encountered an incorrect certificate chain length.
ResourceSignBadExtKeyUsage = -67653, // Resource signing has encountered an error in the extended key usage.
TrustSettingDeny = -67654, // The trust setting for this policy was set to Deny.
InvalidSubjectName = -67655, // An invalid certificate subject name was encountered.
UnknownQualifiedCertStatement = -67656, // An unknown qualified certificate statement was encountered.
MobileMeRequestQueued = -67657,
MobileMeRequestRedirected = -67658,
MobileMeServerError = -67659,
MobileMeServerNotAvailable = -67660,
MobileMeServerAlreadyExists = -67661,
MobileMeServerServiceErr = -67662,
MobileMeRequestAlreadyPending = -67663,
MobileMeNoRequestPending = -67664,
MobileMeCSRVerifyFailure = -67665,
MobileMeFailedConsistencyCheck = -67666,
NotInitialized = -67667, // A function was called without initializing CSSM.
InvalidHandleUsage = -67668, // The CSSM handle does not match with the service type.
PVCReferentNotFound = -67669, // A reference to the calling module was not found in the list of authorized callers.
FunctionIntegrityFail = -67670, // A function address was not within the verified module.
InternalError = -67671, // An internal error has occurred.
MemoryError = -67672, // A memory error has occurred.
InvalidData = -67673, // Invalid data was encountered.
MDSError = -67674, // A Module Directory Service error has occurred.
InvalidPointer = -67675, // An invalid pointer was encountered.
SelfCheckFailed = -67676, // Self-check has failed.
FunctionFailed = -67677, // A function has failed.
ModuleManifestVerifyFailed = -67678, // A module manifest verification failure has occurred.
InvalidGUID = -67679, // An invalid GUID was encountered.
InvalidHandle = -67680, // An invalid handle was encountered.
InvalidDBList = -67681, // An invalid DB list was encountered.
InvalidPassthroughID = -67682, // An invalid passthrough ID was encountered.
InvalidNetworkAddress = -67683, // An invalid network address was encountered.
CRLAlreadySigned = -67684, // The certificate revocation list is already signed.
InvalidNumberOfFields = -67685, // An invalid number of fields were encountered.
VerificationFailure = -67686, // A verification failure occurred.
UnknownTag = -67687, // An unknown tag was encountered.
InvalidSignature = -67688, // An invalid signature was encountered.
InvalidName = -67689, // An invalid name was encountered.
InvalidCertificateRef = -67690, // An invalid certificate reference was encountered.
InvalidCertificateGroup = -67691, // An invalid certificate group was encountered.
TagNotFound = -67692, // The specified tag was not found.
InvalidQuery = -67693, // The specified query was not valid.
InvalidValue = -67694, // An invalid value was detected.
CallbackFailed = -67695, // A callback has failed.
ACLDeleteFailed = -67696, // An ACL delete operation has failed.
ACLReplaceFailed = -67697, // An ACL replace operation has failed.
ACLAddFailed = -67698, // An ACL add operation has failed.
ACLChangeFailed = -67699, // An ACL change operation has failed.
InvalidAccessCredentials = -67700, // Invalid access credentials were encountered.
InvalidRecord = -67701, // An invalid record was encountered.
InvalidACL = -67702, // An invalid ACL was encountered.
InvalidSampleValue = -67703, // An invalid sample value was encountered.
IncompatibleVersion = -67704, // An incompatible version was encountered.
PrivilegeNotGranted = -67705, // The privilege was not granted.
InvalidScope = -67706, // An invalid scope was encountered.
PVCAlreadyConfigured = -67707, // The PVC is already configured.
InvalidPVC = -67708, // An invalid PVC was encountered.
EMMLoadFailed = -67709, // The EMM load has failed.
EMMUnloadFailed = -67710, // The EMM unload has failed.
AddinLoadFailed = -67711, // The add-in load operation has failed.
InvalidKeyRef = -67712, // An invalid key was encountered.
InvalidKeyHierarchy = -67713, // An invalid key hierarchy was encountered.
AddinUnloadFailed = -67714, // The add-in unload operation has failed.
LibraryReferenceNotFound = -67715, // A library reference was not found.
InvalidAddinFunctionTable = -67716, // An invalid add-in function table was encountered.
InvalidServiceMask = -67717, // An invalid service mask was encountered.
ModuleNotLoaded = -67718, // A module was not loaded.
InvalidSubServiceID = -67719, // An invalid subservice ID was encountered.
AttributeNotInContext = -67720, // An attribute was not in the context.
ModuleManagerInitializeFailed = -67721, // A module failed to initialize.
ModuleManagerNotFound = -67722, // A module was not found.
EventNotificationCallbackNotFound = -67723, // An event notification callback was not found.
InputLengthError = -67724, // An input length error was encountered.
OutputLengthError = -67725, // An output length error was encountered.
PrivilegeNotSupported = -67726, // The privilege is not supported.
DeviceError = -67727, // A device error was encountered.
AttachHandleBusy = -67728, // The CSP handle was busy.
NotLoggedIn = -67729, // You are not logged in.
AlgorithmMismatch = -67730, // An algorithm mismatch was encountered.
KeyUsageIncorrect = -67731, // The key usage is incorrect.
KeyBlobTypeIncorrect = -67732, // The key blob type is incorrect.
KeyHeaderInconsistent = -67733, // The key header is inconsistent.
UnsupportedKeyFormat = -67734, // The key header format is not supported.
UnsupportedKeySize = -67735, // The key size is not supported.
InvalidKeyUsageMask = -67736, // The key usage mask is not valid.
UnsupportedKeyUsageMask = -67737, // The key usage mask is not supported.
InvalidKeyAttributeMask = -67738, // The key attribute mask is not valid.
UnsupportedKeyAttributeMask = -67739, // The key attribute mask is not supported.
InvalidKeyLabel = -67740, // The key label is not valid.
UnsupportedKeyLabel = -67741, // The key label is not supported.
InvalidKeyFormat = -67742, // The key format is not valid.
UnsupportedVectorOfBuffers = -67743, // The vector of buffers is not supported.
InvalidInputVector = -67744, // The input vector is not valid.
InvalidOutputVector = -67745, // The output vector is not valid.
InvalidContext = -67746, // An invalid context was encountered.
InvalidAlgorithm = -67747, // An invalid algorithm was encountered.
InvalidAttributeKey = -67748, // A key attribute was not valid.
MissingAttributeKey = -67749, // A key attribute was missing.
InvalidAttributeInitVector = -67750, // An init vector attribute was not valid.
MissingAttributeInitVector = -67751, // An init vector attribute was missing.
InvalidAttributeSalt = -67752, // A salt attribute was not valid.
MissingAttributeSalt = -67753, // A salt attribute was missing.
InvalidAttributePadding = -67754, // A padding attribute was not valid.
MissingAttributePadding = -67755, // A padding attribute was missing.
InvalidAttributeRandom = -67756, // A random number attribute was not valid.
MissingAttributeRandom = -67757, // A random number attribute was missing.
InvalidAttributeSeed = -67758, // A seed attribute was not valid.
MissingAttributeSeed = -67759, // A seed attribute was missing.
InvalidAttributePassphrase = -67760, // A passphrase attribute was not valid.
MissingAttributePassphrase = -67761, // A passphrase attribute was missing.
InvalidAttributeKeyLength = -67762, // A key length attribute was not valid.
MissingAttributeKeyLength = -67763, // A key length attribute was missing.
InvalidAttributeBlockSize = -67764, // A block size attribute was not valid.
MissingAttributeBlockSize = -67765, // A block size attribute was missing.
InvalidAttributeOutputSize = -67766, // An output size attribute was not valid.
MissingAttributeOutputSize = -67767, // An output size attribute was missing.
InvalidAttributeRounds = -67768, // The number of rounds attribute was not valid.
MissingAttributeRounds = -67769, // The number of rounds attribute was missing.
InvalidAlgorithmParms = -67770, // An algorithm parameters attribute was not valid.
MissingAlgorithmParms = -67771, // An algorithm parameters attribute was missing.
InvalidAttributeLabel = -67772, // A label attribute was not valid.
MissingAttributeLabel = -67773, // A label attribute was missing.
InvalidAttributeKeyType = -67774, // A key type attribute was not valid.
MissingAttributeKeyType = -67775, // A key type attribute was missing.
InvalidAttributeMode = -67776, // A mode attribute was not valid.
MissingAttributeMode = -67777, // A mode attribute was missing.
InvalidAttributeEffectiveBits = -67778, // An effective bits attribute was not valid.
MissingAttributeEffectiveBits = -67779, // An effective bits attribute was missing.
InvalidAttributeStartDate = -67780, // A start date attribute was not valid.
MissingAttributeStartDate = -67781, // A start date attribute was missing.
InvalidAttributeEndDate = -67782, // An end date attribute was not valid.
MissingAttributeEndDate = -67783, // An end date attribute was missing.
InvalidAttributeVersion = -67784, // A version attribute was not valid.
MissingAttributeVersion = -67785, // A version attribute was missing.
InvalidAttributePrime = -67786, // A prime attribute was not valid.
MissingAttributePrime = -67787, // A prime attribute was missing.
InvalidAttributeBase = -67788, // A base attribute was not valid.
MissingAttributeBase = -67789, // A base attribute was missing.
InvalidAttributeSubprime = -67790, // A subprime attribute was not valid.
MissingAttributeSubprime = -67791, // A subprime attribute was missing.
InvalidAttributeIterationCount = -67792, // An iteration count attribute was not valid.
MissingAttributeIterationCount = -67793, // An iteration count attribute was missing.
InvalidAttributeDLDBHandle = -67794, // A database handle attribute was not valid.
MissingAttributeDLDBHandle = -67795, // A database handle attribute was missing.
InvalidAttributeAccessCredentials = -67796, // An access credentials attribute was not valid.
MissingAttributeAccessCredentials = -67797, // An access credentials attribute was missing.
InvalidAttributePublicKeyFormat = -67798, // A public key format attribute was not valid.
MissingAttributePublicKeyFormat = -67799, // A public key format attribute was missing.
InvalidAttributePrivateKeyFormat = -67800, // A private key format attribute was not valid.
MissingAttributePrivateKeyFormat = -67801, // A private key format attribute was missing.
InvalidAttributeSymmetricKeyFormat = -67802, // A symmetric key format attribute was not valid.
MissingAttributeSymmetricKeyFormat = -67803, // A symmetric key format attribute was missing.
InvalidAttributeWrappedKeyFormat = -67804, // A wrapped key format attribute was not valid.
MissingAttributeWrappedKeyFormat = -67805, // A wrapped key format attribute was missing.
StagedOperationInProgress = -67806, // A staged operation is in progress.
StagedOperationNotStarted = -67807, // A staged operation was not started.
VerifyFailed = -67808, // A cryptographic verification failure has occurred.
QuerySizeUnknown = -67809, // The query size is unknown.
BlockSizeMismatch = -67810, // A block size mismatch occurred.
PublicKeyInconsistent = -67811, // The public key was inconsistent.
DeviceVerifyFailed = -67812, // A device verification failure has occurred.
InvalidLoginName = -67813, // An invalid login name was detected.
AlreadyLoggedIn = -67814, // The user is already logged in.
InvalidDigestAlgorithm = -67815, // An invalid digest algorithm was detected.
InvalidCRLGroup = -67816, // An invalid CRL group was detected.
CertificateCannotOperate = -67817, // The certificate cannot operate.
CertificateExpired = -67818, // An expired certificate was detected.
CertificateNotValidYet = -67819, // The certificate is not yet valid.
CertificateRevoked = -67820, // The certificate was revoked.
CertificateSuspended = -67821, // The certificate was suspended.
InsufficientCredentials = -67822, // Insufficient credentials were detected.
InvalidAction = -67823, // The action was not valid.
InvalidAuthority = -67824, // The authority was not valid.
VerifyActionFailed = -67825, // A verify action has failed.
InvalidCertAuthority = -67826, // The certificate authority was not valid.
InvalidCRLAuthority = -67827, // The CRL authority was not valid.
InvalidCRLEncoding = -67828, // The CRL encoding was not valid.
InvalidCRLType = -67829, // The CRL type was not valid.
InvalidCRL = -67830, // The CRL was not valid.
InvalidFormType = -67831, // The form type was not valid.
InvalidID = -67832, // The ID was not valid.
InvalidIdentifier = -67833, // The identifier was not valid.
InvalidIndex = -67834, // The index was not valid.
InvalidPolicyIdentifiers = -67835, // The policy identifiers are not valid.
InvalidTimeString = -67836, // The time specified was not valid.
InvalidReason = -67837, // The trust policy reason was not valid.
InvalidRequestInputs = -67838, // The request inputs are not valid.
InvalidResponseVector = -67839, // The response vector was not valid.
InvalidStopOnPolicy = -67840, // The stop-on policy was not valid.
InvalidTuple = -67841, // The tuple was not valid.
MultipleValuesUnsupported = -67842, // Multiple values are not supported.
NotTrusted = -67843, // The certificate was not trusted.
NoDefaultAuthority = -67844, // No default authority was detected.
RejectedForm = -67845, // The trust policy had a rejected form.
RequestLost = -67846, // The request was lost.
RequestRejected = -67847, // The request was rejected.
UnsupportedAddressType = -67848, // The address type is not supported.
UnsupportedService = -67849, // The service is not supported.
InvalidTupleGroup = -67850, // The tuple group was not valid.
InvalidBaseACLs = -67851, // The base ACLs are not valid.
InvalidTupleCredentials = -67852, // The tuple credentials are not valid.
InvalidEncoding = -67853, // The encoding was not valid.
InvalidValidityPeriod = -67854, // The validity period was not valid.
InvalidRequestor = -67855, // The requestor was not valid.
RequestDescriptor = -67856, // The request descriptor was not valid.
InvalidBundleInfo = -67857, // The bundle information was not valid.
InvalidCRLIndex = -67858, // The CRL index was not valid.
NoFieldValues = -67859, // No field values were detected.
UnsupportedFieldFormat = -67860, // The field format is not supported.
UnsupportedIndexInfo = -67861, // The index information is not supported.
UnsupportedLocality = -67862, // The locality is not supported.
UnsupportedNumAttributes = -67863, // The number of attributes is not supported.
UnsupportedNumIndexes = -67864, // The number of indexes is not supported.
UnsupportedNumRecordTypes = -67865, // The number of record types is not supported.
FieldSpecifiedMultiple = -67866, // Too many fields were specified.
IncompatibleFieldFormat = -67867, // The field format was incompatible.
InvalidParsingModule = -67868, // The parsing module was not valid.
DatabaseLocked = -67869, // The database is locked.
DatastoreIsOpen = -67870, // The data store is open.
MissingValue = -67871, // A missing value was detected.
UnsupportedQueryLimits = -67872, // The query limits are not supported.
UnsupportedNumSelectionPreds = -67873, // The number of selection predicates is not supported.
UnsupportedOperator = -67874, // The operator is not supported.
InvalidDBLocation = -67875, // The database location is not valid.
InvalidAccessRequest = -67876, // The access request is not valid.
InvalidIndexInfo = -67877, // The index information is not valid.
InvalidNewOwner = -67878, // The new owner is not valid.
InvalidModifyMode = -67879, // The modify mode is not valid.
MissingRequiredExtension = -67880, // A required certificate extension is missing.
ExtendedKeyUsageNotCritical = -67881, // The extended key usage extension was not marked critical.
TimestampMissing = -67882, // A timestamp was expected but was not found.
TimestampInvalid = -67883, // The timestamp was not valid.
TimestampNotTrusted = -67884, // The timestamp was not trusted.
TimestampServiceNotAvailable = -67885, // The timestamp service is not available.
TimestampBadAlg = -67886, // An unrecognized or unsupported Algorithm Identifier in timestamp.
TimestampBadRequest = -67887, // The timestamp transaction is not permitted or supported.
TimestampBadDataFormat = -67888, // The timestamp data submitted has the wrong format.
TimestampTimeNotAvailable = -67889, // The time source for the Timestamp Authority is not available.
TimestampUnacceptedPolicy = -67890, // The requested policy is not supported by the Timestamp Authority.
TimestampUnacceptedExtension = -67891, // The requested extension is not supported by the Timestamp Authority.
TimestampAddInfoNotAvailable = -67892, // The additional information requested is not available.
TimestampSystemFailure = -67893, // The timestamp request cannot be handled due to system failure.
SigningTimeMissing = -67894, // A signing time was expected but was not found.
TimestampRejection = -67895, // A timestamp transaction was rejected.
TimestampWaiting = -67896, // A timestamp transaction is waiting.
TimestampRevocationWarning = -67897, // A timestamp authority revocation warning was issued.
TimestampRevocationNotification = -67898, // A timestamp authority revocation notification was issued.
CertificatePolicyNotAllowed = -67899, // The requested policy is not allowed for this certificate.
CertificateNameNotAllowed = -67900, // The requested name is not allowed for this certificate.
CertificateValidityPeriodTooLong = -67901, // The validity period in the certificate exceeds the maximum allowed.
CertificateIsCA = -67902, // The verified certificate is a CA rather than an end-entity.
CertificateDuplicateExtension = -67903, // The certificate contains multiple extensions with the same extension ID.
}
+19
View File
@@ -0,0 +1,19 @@
package Security
import CF "core:sys/darwin/CoreFoundation"
foreign import Security "system:Security.framework"
// A reference to a random number generator.
RandomRef :: distinct rawptr
@(link_prefix="Sec", default_calling_convention="c")
foreign Security {
// Default random ref for /dev/random. Synonym for nil.
@(link_name="kSecRandomDefault") kSecRandomDefault: RandomRef
// Generates an array of cryptographically secure random bytes.
RandomCopyBytes :: proc(rnd: RandomRef = kSecRandomDefault, count: uint, bytes: [^]byte) -> errSec ---
CopyErrorMessageString :: proc(status: errSec, reserved: rawptr = nil) -> CF.String ---
}
-98
View File
@@ -1,98 +0,0 @@
//+build darwin
package darwin
import "core:runtime"
foreign import core_foundation "system:CoreFoundation.framework"
CFTypeRef :: distinct rawptr
CFStringRef :: distinct CFTypeRef
CFIndex :: int
CFRange :: struct {
location: CFIndex,
length: CFIndex,
}
CFStringEncoding :: enum u32 {
ASCII = 1,
NEXTSTEP = 2,
JapaneseEUC = 3,
UTF8 = 4,
ISOLatin1 = 5,
Symbol = 6,
NonLossyASCII = 7,
ShiftJIS = 8,
ISOLatin2 = 9,
Unicode = 10,
WindowsCP1251 = 11,
WindowsCP1252 = 12,
WindowsCP1253 = 13,
WindowsCP1254 = 14,
WindowsCP1250 = 15,
ISO2022JP = 21,
MacOSRoman = 30,
UTF16 = Unicode,
UTF16BigEndian = 0x90000100,
UTF16LittleEndian = 0x94000100,
UTF32 = 0x8c000100,
UTF32BigEndian = 0x98000100,
UTF32LittleEndian = 0x9c000100,
}
foreign core_foundation {
// Copies the character contents of a string to a local C string buffer after converting the characters to a given encoding.
CFStringGetCString :: proc(theString: CFStringRef, buffer: [^]byte, bufferSize: CFIndex, encoding: CFStringEncoding) -> Bool ---
// Returns the number (in terms of UTF-16 code pairs) of Unicode characters in a string.
CFStringGetLength :: proc(theString: CFStringRef) -> CFIndex ---
// Returns the maximum number of bytes a string of a specified length (in Unicode characters) will take up if encoded in a specified encoding.
CFStringGetMaximumSizeForEncoding :: proc(length: CFIndex, encoding: CFStringEncoding) -> CFIndex ---
// Fetches a range of the characters from a string into a byte buffer after converting the characters to a specified encoding.
CFStringGetBytes :: proc(
thestring: CFStringRef,
range: CFRange,
encoding: CFStringEncoding,
lossByte: u8,
isExternalRepresentation: Bool,
buffer: [^]byte,
maxBufLen: CFIndex,
usedBufLen: ^CFIndex,
) -> CFIndex ---
// Releases a Core Foundation object.
@(link_name="CFRelease")
_CFRelease :: proc(cf: CFTypeRef) ---
}
// Releases a Core Foundation object.
CFRelease :: proc {
CFReleaseString,
}
// Releases a Core Foundation string.
CFReleaseString :: #force_inline proc(theString: CFStringRef) {
_CFRelease(CFTypeRef(theString))
}
CFStringCopyToOdinString :: proc(theString: CFStringRef, allocator := context.allocator) -> (str: string, ok: bool) #optional_ok {
length := CFStringGetLength(theString)
max := CFStringGetMaximumSizeForEncoding(length, .UTF8)
buf, err := make([]byte, max, allocator)
if err != nil { return }
raw_str := runtime.Raw_String{
data = raw_data(buf),
}
CFStringGetBytes(theString, {0, length}, .UTF8, 0, false, raw_data(buf), max, &raw_str.len)
return transmute(string)raw_str, true
}
-26
View File
@@ -1,26 +0,0 @@
//+build darwin
package darwin
foreign import security "system:Security.framework"
// A reference to a random number generator.
SecRandomRef :: distinct rawptr
OSStatus :: distinct i32
errSec :: enum OSStatus {
Success = 0, // No error.
Unimplemented = -4, // Function or operation not implemented.
// Many more...
}
foreign security {
// Synonym for nil, uses a cryptographically secure random number generator.
kSecRandomDefault: SecRandomRef
// Generates an array of cryptographically secure random bytes.
SecRandomCopyBytes :: proc(rnd: SecRandomRef = kSecRandomDefault, count: uint, bytes: [^]byte) -> errSec ---
SecCopyErrorMessageString :: proc(status: errSec, reserved: rawptr = nil) -> CFStringRef ---
}
+7 -1
View File
@@ -2074,7 +2074,13 @@ SRWLOCK_INIT :: SRWLOCK{}
STARTF_USESTDHANDLES: DWORD : 0x00000100 STARTF_USESTDHANDLES: DWORD : 0x00000100
VOLUME_NAME_DOS: DWORD : 0x0 VOLUME_NAME_DOS: DWORD : 0x0
MOVEFILE_REPLACE_EXISTING: DWORD : 1
MOVEFILE_COPY_ALLOWED: DWORD: 0x2
MOVEFILE_CREATE_HARDLINK: DWORD: 0x10
MOVEFILE_DELAY_UNTIL_REBOOT: DWORD: 0x4
MOVEFILE_FAIL_IF_NOT_TRACKABLE: DWORD: 0x20
MOVEFILE_REPLACE_EXISTING: DWORD : 0x1
MOVEFILE_WRITE_THROUGH: DWORD: 0x8
FILE_BEGIN: DWORD : 0 FILE_BEGIN: DWORD : 0
FILE_CURRENT: DWORD : 1 FILE_CURRENT: DWORD : 1
+4 -4
View File
@@ -56,9 +56,9 @@ validate_hour_minute_second :: proc "contextless" (#any_int hour, #any_int minut
return .None return .None
} }
validate_datetime :: proc "contextless" (using datetime: DateTime) -> (err: Error) { validate_datetime :: proc "contextless" (datetime: DateTime) -> (err: Error) {
validate(date) or_return validate(datetime.date) or_return
validate(time) or_return validate(datetime.time) or_return
return .None return .None
} }
@@ -69,4 +69,4 @@ validate :: proc{
validate_hour_minute_second, validate_hour_minute_second,
validate_time, validate_time,
validate_datetime, validate_datetime,
} }
+2 -2
View File
@@ -24,9 +24,9 @@ _sleep :: proc "contextless" (d: Duration) {
_tick_now :: proc "contextless" () -> Tick { _tick_now :: proc "contextless" () -> Tick {
foreign odin_env { foreign odin_env {
tick_now :: proc "contextless" () -> i64 --- tick_now :: proc "contextless" () -> f32 ---
} }
return Tick{tick_now()*1e6} return Tick{i64(tick_now()*1e6)}
} }
_yield :: proc "contextless" () { _yield :: proc "contextless" () {
+4
View File
@@ -29,6 +29,7 @@ import blake2s "core:crypto/blake2s"
import chacha20 "core:crypto/chacha20" import chacha20 "core:crypto/chacha20"
import chacha20poly1305 "core:crypto/chacha20poly1305" import chacha20poly1305 "core:crypto/chacha20poly1305"
import crypto_hash "core:crypto/hash" import crypto_hash "core:crypto/hash"
import ed25519 "core:crypto/ed25519"
import hkdf "core:crypto/hkdf" import hkdf "core:crypto/hkdf"
import hmac "core:crypto/hmac" import hmac "core:crypto/hmac"
import kmac "core:crypto/kmac" import kmac "core:crypto/kmac"
@@ -37,6 +38,7 @@ import md5 "core:crypto/legacy/md5"
import sha1 "core:crypto/legacy/sha1" import sha1 "core:crypto/legacy/sha1"
import pbkdf2 "core:crypto/pbkdf2" import pbkdf2 "core:crypto/pbkdf2"
import poly1305 "core:crypto/poly1305" import poly1305 "core:crypto/poly1305"
import ristretto255 "core:crypto/ristretto255"
import sha2 "core:crypto/sha2" import sha2 "core:crypto/sha2"
import sha3 "core:crypto/sha3" import sha3 "core:crypto/sha3"
import shake "core:crypto/shake" import shake "core:crypto/shake"
@@ -151,6 +153,7 @@ _ :: blake2b
_ :: blake2s _ :: blake2s
_ :: chacha20 _ :: chacha20
_ :: chacha20poly1305 _ :: chacha20poly1305
_ :: ed25519
_ :: hmac _ :: hmac
_ :: hkdf _ :: hkdf
_ :: kmac _ :: kmac
@@ -158,6 +161,7 @@ _ :: keccak
_ :: md5 _ :: md5
_ :: pbkdf2 _ :: pbkdf2
_ :: poly1305 _ :: poly1305
_ :: ristretto255
_ :: sha1 _ :: sha1
_ :: sha2 _ :: sha2
_ :: sha3 _ :: sha3
+3 -1
View File
@@ -62,7 +62,7 @@ _ :: xlib
// NOTE: needed for doc generator // NOTE: needed for doc generator
import NS "vendor:darwin/Foundation" import NS "core:sys/darwin/Foundation"
import MTL "vendor:darwin/Metal" import MTL "vendor:darwin/Metal"
import MTK "vendor:darwin/MetalKit" import MTK "vendor:darwin/MetalKit"
import CA "vendor:darwin/QuartzCore" import CA "vendor:darwin/QuartzCore"
@@ -73,10 +73,12 @@ _ :: MTK
_ :: CA _ :: CA
import DXC "vendor:directx/dxc"
import D3D11 "vendor:directx/d3d11" import D3D11 "vendor:directx/d3d11"
import D3D12 "vendor:directx/d3d12" import D3D12 "vendor:directx/d3d12"
import DXGI "vendor:directx/dxgi" import DXGI "vendor:directx/dxgi"
_ :: DXC
_ :: D3D11 _ :: D3D11
_ :: D3D12 _ :: D3D12
_ :: DXGI _ :: DXGI
+1 -1
View File
@@ -7,7 +7,7 @@ import "core:os"
import "core:thread" import "core:thread"
import "core:time" import "core:time"
import "core:reflect" import "core:reflect"
import "core:runtime" import "base:runtime"
import "core:intrinsics" import "core:intrinsics"
import "core:math/big" import "core:math/big"
+26 -8
View File
@@ -272,13 +272,16 @@ enum BuildPath : u8 {
}; };
enum VetFlags : u64 { enum VetFlags : u64 {
VetFlag_NONE = 0, VetFlag_NONE = 0,
VetFlag_Unused = 1u<<0, // 1 VetFlag_Shadowing = 1u<<0,
VetFlag_Shadowing = 1u<<1, // 2 VetFlag_UsingStmt = 1u<<1,
VetFlag_UsingStmt = 1u<<2, // 4 VetFlag_UsingParam = 1u<<2,
VetFlag_UsingParam = 1u<<3, // 8 VetFlag_Style = 1u<<3,
VetFlag_Style = 1u<<4, // 16 VetFlag_Semicolon = 1u<<4,
VetFlag_Semicolon = 1u<<5, // 32 VetFlag_UnusedVariables = 1u<<5,
VetFlag_UnusedImports = 1u<<6,
VetFlag_Unused = VetFlag_UnusedVariables|VetFlag_UnusedImports,
VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt, VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt,
@@ -288,6 +291,10 @@ enum VetFlags : u64 {
u64 get_vet_flag_from_name(String const &name) { u64 get_vet_flag_from_name(String const &name) {
if (name == "unused") { if (name == "unused") {
return VetFlag_Unused; return VetFlag_Unused;
} else if (name == "unused-variables") {
return VetFlag_UnusedVariables;
} else if (name == "unused-imports") {
return VetFlag_UnusedImports;
} else if (name == "shadowing") { } else if (name == "shadowing") {
return VetFlag_Shadowing; return VetFlag_Shadowing;
} else if (name == "using-stmt") { } else if (name == "using-stmt") {
@@ -624,6 +631,15 @@ gb_global TargetMetrics target_freestanding_amd64_sysv = {
TargetABI_SysV, TargetABI_SysV,
}; };
gb_global TargetMetrics target_freestanding_amd64_win64 = {
TargetOs_freestanding,
TargetArch_amd64,
8, 8, 8, 16,
str_lit("x86_64-pc-none-msvc"),
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
TargetABI_Win64,
};
gb_global TargetMetrics target_freestanding_arm64 = { gb_global TargetMetrics target_freestanding_arm64 = {
TargetOs_freestanding, TargetOs_freestanding,
TargetArch_arm64, TargetArch_arm64,
@@ -665,7 +681,9 @@ gb_global NamedTargetMetrics named_targets[] = {
{ str_lit("js_wasm64p32"), &target_js_wasm64p32 }, { str_lit("js_wasm64p32"), &target_js_wasm64p32 },
{ str_lit("wasi_wasm64p32"), &target_wasi_wasm64p32 }, { str_lit("wasi_wasm64p32"), &target_wasi_wasm64p32 },
{ str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv }, { str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
{ str_lit("freestanding_amd64_win64"), &target_freestanding_amd64_win64 },
{ str_lit("freestanding_arm64"), &target_freestanding_arm64 }, { str_lit("freestanding_arm64"), &target_freestanding_arm64 },
}; };
+6 -2
View File
@@ -4089,8 +4089,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
} }
} }
operand->mode = Addressing_OptionalOk; operand->mode = Addressing_Value;
operand->type = default_type(x.type); operand->type = make_optional_ok_type(default_type(x.type));
} }
break; break;
@@ -6014,6 +6014,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
return false; return false;
} }
enable_target_feature({}, str_lit("atomics"));
Operand ptr = {}; Operand ptr = {};
Operand expected = {}; Operand expected = {};
Operand timeout = {}; Operand timeout = {};
@@ -6066,6 +6068,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
return false; return false;
} }
enable_target_feature({}, str_lit("atomics"));
Operand ptr = {}; Operand ptr = {};
Operand waiters = {}; Operand waiters = {};
check_expr(c, &ptr, ce->args[0]); if (ptr.mode == Addressing_Invalid) return false; check_expr(c, &ptr, ce->args[0]); if (ptr.mode == Addressing_Invalid) return false;
+17 -4
View File
@@ -4595,7 +4595,8 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v
String name = fv->field->Ident.token.string; String name = fv->field->Ident.token.string;
Selection sub_sel = lookup_field(node->tav.type, name, false); Selection sub_sel = lookup_field(node->tav.type, name, false);
defer (array_free(&sub_sel.index)); defer (array_free(&sub_sel.index));
if (sub_sel.index[0] == index) { if (sub_sel.index.count > 0 &&
sub_sel.index[0] == index) {
value = fv->value->tav.value; value = fv->value->tav.value;
found = true; found = true;
break; break;
@@ -8156,19 +8157,31 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
o->mode = Addressing_Constant; o->mode = Addressing_Constant;
String name = bd->name.string; String name = bd->name.string;
if (name == "file") { if (name == "file") {
String file = get_file_path_string(bd->token.pos.file_id);
if (build_context.obfuscate_source_code_locations) {
file = obfuscate_string(file, "F");
}
o->type = t_untyped_string; o->type = t_untyped_string;
o->value = exact_value_string(get_file_path_string(bd->token.pos.file_id)); o->value = exact_value_string(file);
} else if (name == "line") { } else if (name == "line") {
i32 line = bd->token.pos.line;
if (build_context.obfuscate_source_code_locations) {
line = obfuscate_i32(line);
}
o->type = t_untyped_integer; o->type = t_untyped_integer;
o->value = exact_value_i64(bd->token.pos.line); o->value = exact_value_i64(line);
} else if (name == "procedure") { } else if (name == "procedure") {
if (c->curr_proc_decl == nullptr) { if (c->curr_proc_decl == nullptr) {
error(node, "#procedure may only be used within procedures"); error(node, "#procedure may only be used within procedures");
o->type = t_untyped_string; o->type = t_untyped_string;
o->value = exact_value_string(str_lit("")); o->value = exact_value_string(str_lit(""));
} else { } else {
String p = c->proc_name;
if (build_context.obfuscate_source_code_locations) {
p = obfuscate_string(p, "P");
}
o->type = t_untyped_string; o->type = t_untyped_string;
o->value = exact_value_string(c->proc_name); o->value = exact_value_string(p);
} }
} else if (name == "caller_location") { } else if (name == "caller_location") {
init_core_source_code_location(c->checker); init_core_source_code_location(c->checker);
+45 -2
View File
@@ -474,16 +474,59 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
} }
Entity *e = entity_of_node(lhs->expr); Entity *e = entity_of_node(lhs->expr);
Entity *original_e = e;
Ast *name = unparen_expr(lhs->expr);
while (name->kind == Ast_SelectorExpr) {
name = name->SelectorExpr.expr;
e = entity_of_node(name);
}
if (e == nullptr) {
e = original_e;
}
gbString str = expr_to_string(lhs->expr); gbString str = expr_to_string(lhs->expr);
if (e != nullptr && e->flags & EntityFlag_Param) { if (e != nullptr && e->flags & EntityFlag_Param) {
ERROR_BLOCK();
if (e->flags & EntityFlag_Using) { if (e->flags & EntityFlag_Using) {
error(lhs->expr, "Cannot assign to '%s' which is from a 'using' procedure parameter", str); error(lhs->expr, "Cannot assign to '%s' which is from a 'using' procedure parameter", str);
} else { } else {
error(lhs->expr, "Cannot assign to '%s' which is a procedure parameter", str); error(lhs->expr, "Cannot assign to '%s' which is a procedure parameter", str);
} }
error_line("\tSuggestion: Did you mean to pass '%.*s' by pointer?\n", LIT(e->token.string));
show_error_on_line(e->token.pos, token_pos_end(e->token));
} else { } else {
ERROR_BLOCK();
error(lhs->expr, "Cannot assign to '%s'", str); error(lhs->expr, "Cannot assign to '%s'", str);
if (e && e->flags & EntityFlag_ForValue) {
isize offset = show_error_on_line(e->token.pos, token_pos_end(e->token), "Suggestion:");
if (offset < 0) {
if (is_type_map(e->type)) {
error_line("\tSuggestion: Did you mean? 'for key, &%.*s in ...'\n", LIT(e->token.string));
} else {
error_line("\tSuggestion: Did you mean? 'for &%.*s in ...'\n", LIT(e->token.string));
}
} else {
error_line("\t");
for (isize i = 0; i < offset-1; i++) {
error_line(" ");
}
error_line("'%.*s' is immutable, declare it as '&%.*s' to make it mutable\n", LIT(e->token.string), LIT(e->token.string));
}
} else if (e && e->flags & EntityFlag_SwitchValue) {
isize offset = show_error_on_line(e->token.pos, token_pos_end(e->token), "Suggestion:");
if (offset < 0) {
error_line("\tSuggestion: Did you mean? 'switch &%.*s in ...'\n", LIT(e->token.string));
} else {
error_line("\t");
for (isize i = 0; i < offset-1; i++) {
error_line(" ");
}
error_line("'%.*s' is immutable, declare it as '&%.*s' to make it mutable\n", LIT(e->token.string), LIT(e->token.string));
}
}
} }
gb_string_free(str); gb_string_free(str);
@@ -2355,14 +2398,14 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) {
unsafe_return_error(o, "the address of a compound literal"); unsafe_return_error(o, "the address of a compound literal");
} else if (x->kind == Ast_IndexExpr) { } else if (x->kind == Ast_IndexExpr) {
Entity *f = entity_of_node(x->IndexExpr.expr); Entity *f = entity_of_node(x->IndexExpr.expr);
if (is_type_array_like(f->type) || is_type_matrix(f->type)) { if (f && (is_type_array_like(f->type) || is_type_matrix(f->type))) {
if (is_entity_local_variable(f)) { if (is_entity_local_variable(f)) {
unsafe_return_error(o, "the address of an indexed variable", f->type); unsafe_return_error(o, "the address of an indexed variable", f->type);
} }
} }
} else if (x->kind == Ast_MatrixIndexExpr) { } else if (x->kind == Ast_MatrixIndexExpr) {
Entity *f = entity_of_node(x->MatrixIndexExpr.expr); Entity *f = entity_of_node(x->MatrixIndexExpr.expr);
if (is_type_matrix(f->type) && is_entity_local_variable(f)) { if (f && (is_type_matrix(f->type) && is_entity_local_variable(f))) {
unsafe_return_error(o, "the address of an indexed variable", f->type); unsafe_return_error(o, "the address of an indexed variable", f->type);
} }
} }
+6 -1
View File
@@ -1689,7 +1689,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
bool is_using = (p->flags&FieldFlag_using) != 0; bool is_using = (p->flags&FieldFlag_using) != 0;
if ((check_vet_flags(param) & VetFlag_UsingParam) && is_using) { if ((check_vet_flags(param) & VetFlag_UsingParam) && is_using) {
ERROR_BLOCK(); ERROR_BLOCK();
error(param, "'using' on a procedure parameter is now allowed when '-vet' or '-vet-using-param' is applied"); error(param, "'using' on a procedure parameter is not allowed when '-vet' or '-vet-using-param' is applied");
error_line("\t'using' is considered bad practice to use as a statement/procedure parameter outside of immediate refactoring\n"); error_line("\t'using' is considered bad practice to use as a statement/procedure parameter outside of immediate refactoring\n");
} }
@@ -3233,6 +3233,11 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
Type *elem = t_invalid; Type *elem = t_invalid;
Operand o = {}; Operand o = {};
if (unparen_expr(pt->type) == nullptr) {
error(e, "Invalid pointer type");
return false;
}
check_expr_or_type(&c, &o, pt->type); check_expr_or_type(&c, &o, pt->type);
if (o.mode != Addressing_Invalid && o.mode != Addressing_Type) { if (o.mode != Addressing_Invalid && o.mode != Addressing_Type) {
if (o.mode == Addressing_Variable) { if (o.mode == Addressing_Variable) {
+7 -4
View File
@@ -703,11 +703,11 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
array_add(&vetted_entities, ve_unused); array_add(&vetted_entities, ve_unused);
} else if (is_shadowed) { } else if (is_shadowed) {
array_add(&vetted_entities, ve_shadowed); array_add(&vetted_entities, ve_shadowed);
} else if (e->kind == Entity_Variable && (e->flags & (EntityFlag_Param|EntityFlag_Using)) == 0) { } else if (e->kind == Entity_Variable && (e->flags & (EntityFlag_Param|EntityFlag_Using|EntityFlag_Static)) == 0 && !e->Variable.is_global) {
i64 sz = type_size_of(e->type); i64 sz = type_size_of(e->type);
// TODO(bill): When is a good size warn? // TODO(bill): When is a good size warn?
// Is 128 KiB good enough? // Is >256 KiB good enough?
if (sz >= 1ll<<17) { if (sz > 1ll<<18) {
gbString type_str = type_to_string(e->type); gbString type_str = type_to_string(e->type);
warning(e->token, "Declaration of '%.*s' may cause a stack overflow due to its type '%s' having a size of %lld bytes", LIT(e->token.string), type_str, cast(long long)sz); warning(e->token, "Declaration of '%.*s' may cause a stack overflow due to its type '%s' having a size of %lld bytes", LIT(e->token.string), type_str, cast(long long)sz);
gb_string_free(type_str); gb_string_free(type_str);
@@ -728,7 +728,10 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
} else if (vet_flags) { } else if (vet_flags) {
switch (ve.kind) { switch (ve.kind) {
case VettedEntity_Unused: case VettedEntity_Unused:
if (vet_flags & VetFlag_Unused) { if (e->kind == Entity_Variable && (vet_flags & VetFlag_UnusedVariables) != 0) {
error(e->token, "'%.*s' declared but not used", LIT(name));
}
if ((e->kind == Entity_ImportName || e->kind == Entity_LibraryName) && (vet_flags & VetFlag_UnusedImports) != 0) {
error(e->token, "'%.*s' declared but not used", LIT(name)); error(e->token, "'%.*s' declared but not used", LIT(name));
} }
break; break;
+21
View File
@@ -353,6 +353,27 @@ gb_global bool global_module_path_set = false;
#include "thread_pool.cpp" #include "thread_pool.cpp"
gb_internal String obfuscate_string(String const &s, char const *prefix) {
if (s.len == 0) {
return s;
}
GB_ASSERT(prefix != nullptr);
u64 hash = gb_fnv64a(s.text, s.len);
gbString res = gb_string_make(permanent_allocator(), prefix);
res = gb_string_append_fmt(res, "x%llx", cast(long long unsigned)hash);
return make_string_c(res);
}
gb_internal i32 obfuscate_i32(i32 i) {
i32 x = cast(i32)gb_fnv64a(&i, sizeof(i));
if (x < 0) {
x = 1-x;
}
return cast(i32)x;
}
struct StringIntern { struct StringIntern {
StringIntern *next; StringIntern *next;
isize len; isize len;
+4
View File
@@ -163,6 +163,10 @@ gb_internal void platform_virtual_memory_protect(void *memory, isize size);
GB_ASSERT(is_protected); GB_ASSERT(is_protected);
} }
#else #else
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
#define MAP_ANONYMOUS MAP_ANON
#endif
gb_internal void platform_virtual_memory_init(void) { gb_internal void platform_virtual_memory_init(void) {
global_platform_memory_block_sentinel.prev = &global_platform_memory_block_sentinel; global_platform_memory_block_sentinel.prev = &global_platform_memory_block_sentinel;
global_platform_memory_block_sentinel.next = &global_platform_memory_block_sentinel; global_platform_memory_block_sentinel.next = &global_platform_memory_block_sentinel;
+1 -1
View File
@@ -496,7 +496,7 @@ gb_internal bool is_entity_local_variable(Entity *e) {
if (e->scope == nullptr) { if (e->scope == nullptr) {
return true; return true;
} }
if (e->flags & (EntityFlag_ForValue|EntityFlag_SwitchValue)) { if (e->flags & (EntityFlag_ForValue|EntityFlag_SwitchValue|EntityFlag_Static)) {
return false; return false;
} }
+24 -5
View File
@@ -84,6 +84,7 @@ gb_internal bool set_file_path_string(i32 index, String const &path) {
bool ok = false; bool ok = false;
GB_ASSERT(index >= 0); GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.path_mutex); mutex_lock(&global_error_collector.path_mutex);
mutex_lock(&global_files_mutex);
if (index >= global_file_path_strings.count) { if (index >= global_file_path_strings.count) {
array_resize(&global_file_path_strings, index+1); array_resize(&global_file_path_strings, index+1);
@@ -94,6 +95,7 @@ gb_internal bool set_file_path_string(i32 index, String const &path) {
ok = true; ok = true;
} }
mutex_unlock(&global_files_mutex);
mutex_unlock(&global_error_collector.path_mutex); mutex_unlock(&global_error_collector.path_mutex);
return ok; return ok;
} }
@@ -102,6 +104,7 @@ gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
bool ok = false; bool ok = false;
GB_ASSERT(index >= 0); GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.path_mutex); mutex_lock(&global_error_collector.path_mutex);
mutex_lock(&global_files_mutex);
if (index >= global_files.count) { if (index >= global_files.count) {
array_resize(&global_files, index+1); array_resize(&global_files, index+1);
@@ -111,7 +114,7 @@ gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
global_files[index] = file; global_files[index] = file;
ok = true; ok = true;
} }
mutex_unlock(&global_files_mutex);
mutex_unlock(&global_error_collector.path_mutex); mutex_unlock(&global_error_collector.path_mutex);
return ok; return ok;
} }
@@ -119,12 +122,14 @@ gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
gb_internal String get_file_path_string(i32 index) { gb_internal String get_file_path_string(i32 index) {
GB_ASSERT(index >= 0); GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.path_mutex); mutex_lock(&global_error_collector.path_mutex);
mutex_lock(&global_files_mutex);
String path = {}; String path = {};
if (index < global_file_path_strings.count) { if (index < global_file_path_strings.count) {
path = global_file_path_strings[index]; path = global_file_path_strings[index];
} }
mutex_unlock(&global_files_mutex);
mutex_unlock(&global_error_collector.path_mutex); mutex_unlock(&global_error_collector.path_mutex);
return path; return path;
} }
@@ -132,12 +137,14 @@ gb_internal String get_file_path_string(i32 index) {
gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) { gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) {
GB_ASSERT(index >= 0); GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.path_mutex); mutex_lock(&global_error_collector.path_mutex);
mutex_lock(&global_files_mutex);
AstFile *file = nullptr; AstFile *file = nullptr;
if (index < global_files.count) { if (index < global_files.count) {
file = global_files[index]; file = global_files[index];
} }
mutex_unlock(&global_files_mutex);
mutex_unlock(&global_error_collector.path_mutex); mutex_unlock(&global_error_collector.path_mutex);
return file; return file;
} }
@@ -247,10 +254,10 @@ gb_internal void terminal_reset_colours(void) {
} }
gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) { gb_internal isize show_error_on_line(TokenPos const &pos, TokenPos end, char const *prefix=nullptr) {
get_error_value()->end = end; get_error_value()->end = end;
if (!show_error_line()) { if (!show_error_line()) {
return false; return -1;
} }
i32 offset = 0; i32 offset = 0;
@@ -270,6 +277,10 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) {
MAX_LINE_LENGTH_PADDED = MAX_LINE_LENGTH-MAX_TAB_WIDTH-ELLIPSIS_PADDING, MAX_LINE_LENGTH_PADDED = MAX_LINE_LENGTH-MAX_TAB_WIDTH-ELLIPSIS_PADDING,
}; };
if (prefix) {
error_out("\t%s\n\n", prefix);
}
error_out("\t"); error_out("\t");
terminal_set_colours(TerminalStyle_Bold, TerminalColour_White); terminal_set_colours(TerminalStyle_Bold, TerminalColour_White);
@@ -328,9 +339,9 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) {
terminal_reset_colours(); terminal_reset_colours();
error_out("\n"); error_out("\n");
return true; return offset;
} }
return false; return -1;
} }
gb_internal void error_out_empty(void) { gb_internal void error_out_empty(void) {
@@ -667,6 +678,14 @@ gb_internal void print_all_errors(void) {
gb_fprintf(f, "\t\t{\n"); gb_fprintf(f, "\t\t{\n");
gb_fprintf(f, "\t\t\t\"type\": \"");
if (ev.kind == ErrorValue_Warning) {
gb_fprintf(f, "warning");
} else {
gb_fprintf(f, "error");
}
gb_fprintf(f, "\",\n");
gb_fprintf(f, "\t\t\t\"pos\": {\n"); gb_fprintf(f, "\t\t\t\"pos\": {\n");
if (ev.pos.file_id) { if (ev.pos.file_id) {
+1 -1
View File
@@ -384,7 +384,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
LIT(obj_file), LIT(obj_file),
LIT(build_context.extra_assembler_flags) LIT(build_context.extra_assembler_flags)
); );
if (!result) { if (result) {
gb_printf_err("executing `nasm` to assemble foreing import of %.*s failed.\n\tSuggestion: `nasm` does not ship with the compiler and should be installed with your system's package manager.\n", LIT(asm_file)); gb_printf_err("executing `nasm` to assemble foreing import of %.*s failed.\n\tSuggestion: `nasm` does not ship with the compiler and should be installed with your system's package manager.\n", LIT(asm_file));
return result; return result;
} }
+4 -22
View File
@@ -287,24 +287,6 @@ gb_internal lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type
return lb_const_value(m, t, tv.value); return lb_const_value(m, t, tv.value);
} }
gb_internal String lb_obfuscate_string(String const &s, char const *prefix) {
if (s.len == 0) {
return {};
}
GB_ASSERT(prefix != nullptr);
u64 hash = gb_fnv64a(s.text, s.len);
gbString res = gb_string_make(temporary_allocator(), prefix);
res = gb_string_append_fmt(res, "x%llx", cast(long long unsigned)hash);
return make_string_c(res);
}
gb_internal i32 lb_obfuscate_i32(i32 i) {
i32 x = cast(i32)gb_fnv64a(&i, sizeof(i));
if (x < 0) {
x = 1-x;
}
return cast(i32)x;
}
gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String const &procedure_, TokenPos const &pos) { gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String const &procedure_, TokenPos const &pos) {
String file = get_file_path_string(pos.file_id); String file = get_file_path_string(pos.file_id);
@@ -314,11 +296,11 @@ gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String cons
i32 column = pos.column; i32 column = pos.column;
if (build_context.obfuscate_source_code_locations) { if (build_context.obfuscate_source_code_locations) {
file = lb_obfuscate_string(file, "F"); file = obfuscate_string(file, "F");
procedure = lb_obfuscate_string(procedure, "P"); procedure = obfuscate_string(procedure, "P");
line = lb_obfuscate_i32(line); line = obfuscate_i32(line);
column = lb_obfuscate_i32(column); column = obfuscate_i32(column);
} }
LLVMValueRef fields[4] = {}; LLVMValueRef fields[4] = {};
+40 -6
View File
@@ -2138,14 +2138,45 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
if (is_type_array_like(dst)) { if (is_type_array_like(dst)) {
Type *elem = base_array_type(dst); Type *elem = base_array_type(dst);
lbValue e = lb_emit_conv(p, value, elem);
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
lbAddr v = lb_add_local_generated(p, t, false);
isize index_count = cast(isize)get_array_type_count(dst); isize index_count = cast(isize)get_array_type_count(dst);
for (isize i = 0; i < index_count; i++) { isize inlineable = type_size_of(dst) <= build_context.max_simd_align;
lbValue elem = lb_emit_array_epi(p, v.addr, i); lbValue e = lb_emit_conv(p, value, elem);
if (inlineable && lb_is_const(e)) {
lbAddr v = {};
if (e.value) {
TEMPORARY_ALLOCATOR_GUARD();
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, index_count);
for (isize i = 0; i < index_count; i++) {
values[i] = e.value;
}
lbValue array_const_value = {};
array_const_value.type = t;
array_const_value.value = LLVMConstArray(lb_type(m, elem), values, cast(unsigned)index_count);
v = lb_add_global_generated(m, t, array_const_value);
} else {
v = lb_add_global_generated(m, t);
}
lb_make_global_private_const(v);
return lb_addr_load(p, v);
}
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
lbAddr v = lb_add_local_generated(p, t, false);
if (!inlineable) {
auto loop_data = lb_loop_start(p, index_count, t_int);
lbValue elem = lb_emit_array_ep(p, v.addr, loop_data.idx);
lb_emit_store(p, elem, e); lb_emit_store(p, elem, e);
lb_loop_end(p, loop_data);
} else {
for (isize i = 0; i < index_count; i++) {
lbValue elem = lb_emit_array_epi(p, v.addr, i);
lb_emit_store(p, elem, e);
}
} }
return lb_addr_load(p, v); return lb_addr_load(p, v);
} }
@@ -4726,9 +4757,12 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
if (sub_sel.index.count > 0) { if (sub_sel.index.count > 0) {
ptr = lb_emit_deep_field_gep(p, ptr, sub_sel); ptr = lb_emit_deep_field_gep(p, ptr, sub_sel);
} }
if (is_type_pointer(type_deref(ptr.type))) {
ptr = lb_emit_load(p, ptr);
}
Type *bf_type = type_deref(ptr.type); Type *bf_type = type_deref(ptr.type);
bf_type = base_type(type_deref(bf_type)); bf_type = base_type(bf_type);
GB_ASSERT(bf_type->kind == Type_BitField); GB_ASSERT(bf_type->kind == Type_BitField);
i32 index = sel.index[sel.index.count-1]; i32 index = sel.index[sel.index.count-1];
+1 -11
View File
@@ -453,7 +453,7 @@ gb_internal lbAddr lb_addr_swizzle_large(lbValue addr, Type *array_type, Slice<i
gb_internal lbAddr lb_addr_bit_field(lbValue addr, Type *type, i64 index, i64 bit_offset, i64 bit_size) { gb_internal lbAddr lb_addr_bit_field(lbValue addr, Type *type, i64 index, i64 bit_offset, i64 bit_size) {
GB_ASSERT(is_type_pointer(addr.type)); GB_ASSERT(is_type_pointer(addr.type));
Type *mt = type_deref(addr.type); Type *mt = type_deref(addr.type);
GB_ASSERT(is_type_bit_field(mt)); GB_ASSERT_MSG(is_type_bit_field(mt), "%s", type_to_string(mt));
lbAddr v = {lbAddr_BitField, addr}; lbAddr v = {lbAddr_BitField, addr};
v.bitfield.type = type; v.bitfield.type = type;
@@ -954,16 +954,6 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
GB_ASSERT(value.value != nullptr); GB_ASSERT(value.value != nullptr);
value = lb_emit_conv(p, value, lb_addr_type(addr)); value = lb_emit_conv(p, value, lb_addr_type(addr));
// if (lb_is_const_or_global(value)) {
// // NOTE(bill): Just bypass the actual storage and set the initializer
// if (LLVMGetValueKind(addr.addr.value) == LLVMGlobalVariableValueKind) {
// LLVMValueRef dst = addr.addr.value;
// LLVMValueRef src = value.value;
// LLVMSetInitializer(dst, src);
// return;
// }
// }
lb_emit_store(p, addr.addr, value); lb_emit_store(p, addr.addr, value);
} }

Some files were not shown because too many files have changed in this diff Show More