Merge remote-tracking branch 'offical/master'
This commit is contained in:
commit
d68dba3677
126 files changed
+5082
-561
No files matched your search
+5
-1
@@ -1,2 +1,6 @@
|
||||
*.odin linguist-language=Odin
|
||||
* text=auto
|
||||
* text=auto
|
||||
|
||||
# These files must always have *nix line-endings
|
||||
Makefile text eol=lf
|
||||
*.sh text eol=lf
|
||||
@@ -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) ---
|
||||
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_sub :: proc(lhs, rhs: $T) -> (T, bool) #optional_ok ---
|
||||
overflow_mul :: proc(lhs, rhs: $T) -> (T, bool) #optional_ok ---
|
||||
overflow_add :: proc(lhs, rhs: $T) -> (T, bool) ---
|
||||
overflow_sub :: proc(lhs, rhs: $T) -> (T, bool) ---
|
||||
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))) ---
|
||||
|
||||
@@ -293,7 +293,9 @@ wasm_memory_size :: proc(index: uintptr) -> int ---
|
||||
// 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
|
||||
// 2 - the thread blocked, but the timeout
|
||||
@(enable_target_feature="atomics")
|
||||
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) ---
|
||||
|
||||
// x86 Targets (i386, amd64)
|
||||
|
||||
@@ -597,8 +597,9 @@ type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
|
||||
base := info
|
||||
loop: for {
|
||||
#partial switch i in base.variant {
|
||||
case Type_Info_Named: base = i.base
|
||||
case Type_Info_Enum: base = i.base
|
||||
case Type_Info_Named: base = i.base
|
||||
case Type_Info_Enum: base = i.base
|
||||
case Type_Info_Bit_Field: base = i.backing_type
|
||||
case: break loop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
round :: #force_inline proc "contextless" (value: uintptr) -> uintptr {
|
||||
CACHE_MASK :: MAP_CACHE_LINE_SIZE - 1
|
||||
@@ -350,6 +350,12 @@ map_total_allocation_size :: #force_inline proc "contextless" (capacity: uintptr
|
||||
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.
|
||||
@(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) {
|
||||
|
||||
@@ -14,6 +14,14 @@ constant-time byte comparison.
|
||||
- Best-effort is make to mitigate timing side-channels on reasonable
|
||||
architectures. Architectures that are known to be unreasonable include
|
||||
but are not limited to i386, i486, and WebAssembly.
|
||||
- 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
|
||||
will remain a "best-effort" implementation decision. As Thomas Pornin
|
||||
puts it "In general, such memory cleansing is a fool's quest."
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -9,7 +9,7 @@ package fiat
|
||||
u1 :: distinct u8
|
||||
i1 :: distinct i8
|
||||
|
||||
@(optimization_mode="none")
|
||||
@(optimization_mode = "none")
|
||||
cmovznz_u64 :: proc "contextless" (arg1: u1, arg2, arg3: u64) -> (out1: u64) {
|
||||
x1 := (u64(arg1) * 0xffffffffffffffff)
|
||||
x2 := ((x1 & arg3) | ((~x1) & arg2))
|
||||
@@ -17,7 +17,7 @@ cmovznz_u64 :: proc "contextless" (arg1: u1, arg2, arg3: u64) -> (out1: u64) {
|
||||
return
|
||||
}
|
||||
|
||||
@(optimization_mode="none")
|
||||
@(optimization_mode = "none")
|
||||
cmovznz_u32 :: proc "contextless" (arg1: u1, arg2, arg3: u32) -> (out1: u32) {
|
||||
x1 := (u32(arg1) * 0xffffffff)
|
||||
x2 := ((x1 & arg3) | ((~x1) & arg2))
|
||||
|
||||
@@ -3,14 +3,32 @@ package field_curve25519
|
||||
import "core:crypto"
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
// Ignore the unused bit by copying the input and masking the bit off
|
||||
// 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))
|
||||
}
|
||||
|
||||
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 {
|
||||
tmp2: [32]byte = ---
|
||||
tmp1, tmp2: [32]byte = ---, ---
|
||||
|
||||
fe_to_bytes(&tmp1, arg1)
|
||||
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))
|
||||
|
||||
return ret
|
||||
@@ -46,7 +77,11 @@ fe_equal_bytes :: proc "contextless" (arg1: ^Tight_Field_Element, arg2: ^[32]byt
|
||||
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.
|
||||
if arg2 == 0 {
|
||||
fe_one(out1)
|
||||
@@ -54,27 +89,46 @@ fe_carry_pow2k :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element,
|
||||
}
|
||||
|
||||
fe_carry_square(out1, arg1)
|
||||
for _ in 1..<arg2 {
|
||||
for _ in 1 ..< arg2 {
|
||||
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_opp(fe_relax_cast(out1), arg1)
|
||||
fe_carry(out1, fe_relax_cast(out1))
|
||||
}
|
||||
|
||||
fe_carry_invsqrt :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) -> int {
|
||||
// Inverse square root taken from Monocypher.
|
||||
fe_carry_abs :: #force_inline proc "contextless" (out1, arg1: ^Tight_Field_Element) {
|
||||
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 = ---, ---, ---
|
||||
|
||||
// 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(&tmp1, fe_relax_cast(&w), 1)
|
||||
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_pow2k(&tmp1, fe_relax_cast(&tmp1), 1)
|
||||
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_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1))
|
||||
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)
|
||||
quartic := &tmp2
|
||||
fe_carry_square(quartic, fe_relax_cast(&tmp1))
|
||||
fe_carry_mul(quartic, fe_relax_cast(quartic), arg1)
|
||||
fe_carry_mul(&tmp1, fe_relax_cast(&tmp1), arg1) // u * w^((p-5)/8)
|
||||
|
||||
// Serialize quartic once to save on repeated serialization/sanitization.
|
||||
quartic_buf: [32]byte = ---
|
||||
fe_to_bytes(&quartic_buf, quartic)
|
||||
check := &tmp3
|
||||
// Serialize `check` once to save on repeated serialization.
|
||||
r, check := &tmp1, &tmp2
|
||||
b: [32]byte = ---
|
||||
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)
|
||||
p1 := fe_equal_bytes(check, &quartic_buf)
|
||||
fe_carry_opp(check, check)
|
||||
m1 := fe_equal_bytes(check, &quartic_buf)
|
||||
fe_carry_opp(check, &SQRT_M1)
|
||||
ms := fe_equal_bytes(check, &quartic_buf)
|
||||
u, neg_u, neg_u_i := &tmp3, &w, check
|
||||
fe_carry(u, arg1)
|
||||
fe_carry_opp(neg_u, u)
|
||||
fe_carry_mul(neg_u_i, fe_relax_cast(neg_u), fe_relax_cast(&FE_SQRT_M1))
|
||||
|
||||
// if quartic == -1 or sqrt(-1)
|
||||
// then isr = x^((p-1)/4) * sqrt(-1)
|
||||
// else isr = x^((p-1)/4)
|
||||
fe_carry_mul(out1, fe_relax_cast(&tmp1), fe_relax_cast(&SQRT_M1))
|
||||
fe_cond_assign(out1, &tmp1, (m1|ms) ~ 1)
|
||||
correct_sign_sqrt := fe_equal_bytes(u, &b)
|
||||
flipped_sign_sqrt := fe_equal_bytes(neg_u, &b)
|
||||
flipped_sign_sqrt_i := fe_equal_bytes(neg_u_i, &b)
|
||||
|
||||
mem.zero_explicit(&tmp1, size_of(tmp1))
|
||||
mem.zero_explicit(&tmp2, size_of(tmp2))
|
||||
mem.zero_explicit(&tmp3, size_of(tmp3))
|
||||
mem.zero_explicit(&quartic_buf, size_of(quartic_buf))
|
||||
r_prime := check
|
||||
fe_carry_mul(r_prime, fe_relax_cast(r), fe_relax_cast(&FE_SQRT_M1))
|
||||
fe_cond_assign(r, r_prime, flipped_sign_sqrt | flipped_sign_sqrt_i)
|
||||
|
||||
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
|
||||
|
||||
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_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)
|
||||
}
|
||||
@@ -30,8 +30,6 @@ package field_curve25519
|
||||
//
|
||||
// While the base implementation is provably correct, this implementation
|
||||
// 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:
|
||||
// * 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
|
||||
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,
|
||||
234908883556509,
|
||||
2233514472574048,
|
||||
@@ -52,7 +53,13 @@ SQRT_M1 := Tight_Field_Element{
|
||||
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)
|
||||
x2 := (x1 & 0x7ffffffffffff)
|
||||
x3 := fiat.u1((x1 >> 51))
|
||||
@@ -61,7 +68,13 @@ _addcarryx_u51 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u
|
||||
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))
|
||||
x2 := fiat.i1((x1 >> 51))
|
||||
x3 := (u64(x1) & 0x7ffffffffffff)
|
||||
@@ -70,7 +83,7 @@ _subborrowx_u51 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3:
|
||||
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))
|
||||
x4, x3 := bits.mul_u64(arg1[4], (arg2[3] * 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
|
||||
}
|
||||
|
||||
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)
|
||||
x2 := (x1 * 0x2)
|
||||
x3 := (arg1[4] * 0x2)
|
||||
@@ -305,8 +318,11 @@ fe_opp :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Ele
|
||||
out1[4] = x5
|
||||
}
|
||||
|
||||
@(optimization_mode="none")
|
||||
fe_cond_assign :: #force_no_inline proc "contextless" (out1, arg1: ^Tight_Field_Element, arg2: int) {
|
||||
@(optimization_mode = "none")
|
||||
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])
|
||||
x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1])
|
||||
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
|
||||
}
|
||||
|
||||
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])
|
||||
x4, x3 := bits.mul_u64(0x1db42, arg1[3])
|
||||
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[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
|
||||
}
|
||||
@@ -1,17 +1,26 @@
|
||||
package field_poly1305
|
||||
|
||||
import "base:intrinsics"
|
||||
import "core:encoding/endian"
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
// single byte at a time, and wants 256-bits of input for a value
|
||||
// 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
|
||||
// neater.
|
||||
|
||||
assert(len(arg1) == 16)
|
||||
if len(arg1) != 16 {
|
||||
intrinsics.trap()
|
||||
}
|
||||
|
||||
// While it may be unwise to do deserialization here on our
|
||||
// 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.
|
||||
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
|
||||
}
|
||||
@@ -39,7 +39,13 @@ import "core:math/bits"
|
||||
Loose_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)
|
||||
x2 := (x1 & 0xfffffffffff)
|
||||
x3 := fiat.u1((x1 >> 44))
|
||||
@@ -48,7 +54,13 @@ _addcarryx_u44 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u
|
||||
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))
|
||||
x2 := fiat.i1((x1 >> 44))
|
||||
x3 := (u64(x1) & 0xfffffffffff)
|
||||
@@ -57,7 +69,13 @@ _subborrowx_u44 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3:
|
||||
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)
|
||||
x2 := (x1 & 0x7ffffffffff)
|
||||
x3 := fiat.u1((x1 >> 43))
|
||||
@@ -66,7 +84,13 @@ _addcarryx_u43 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u
|
||||
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))
|
||||
x2 := fiat.i1((x1 >> 43))
|
||||
x3 := (u64(x1) & 0x7ffffffffff)
|
||||
@@ -75,7 +99,7 @@ _subborrowx_u43 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3:
|
||||
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))
|
||||
x4, x3 := bits.mul_u64(arg1[2], (arg2[1] * 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
|
||||
}
|
||||
|
||||
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)
|
||||
x2 := (x1 * 0x2)
|
||||
x3 := (arg1[2] * 0x2)
|
||||
@@ -201,8 +225,11 @@ fe_opp :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Ele
|
||||
out1[2] = x3
|
||||
}
|
||||
|
||||
@(optimization_mode="none")
|
||||
fe_cond_assign :: #force_no_inline proc "contextless" (out1, arg1: ^Tight_Field_Element, arg2: bool) {
|
||||
@(optimization_mode = "none")
|
||||
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])
|
||||
x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1])
|
||||
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[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
|
||||
}
|
||||
@@ -1,3 +1,7 @@
|
||||
/*
|
||||
package crypto implements a selection of cryptography algorithms and useful
|
||||
helper routines.
|
||||
*/
|
||||
package crypto
|
||||
|
||||
import "core:mem"
|
||||
@@ -51,3 +55,9 @@ rand_bytes :: proc (dst: []byte) {
|
||||
|
||||
_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()
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -168,7 +168,7 @@ reset :: proc(ctx: ^Context) {
|
||||
}
|
||||
|
||||
@(private)
|
||||
_blocks :: proc(ctx: ^Context, msg: []byte, final := false) {
|
||||
_blocks :: proc "contextless" (ctx: ^Context, msg: []byte, final := false) {
|
||||
n: field.Tight_Field_Element = ---
|
||||
final_byte := byte(!final)
|
||||
|
||||
|
||||
@@ -10,3 +10,7 @@ foreign libc {
|
||||
_rand_bytes :: proc(dst: []byte) {
|
||||
arc4random_buf(raw_data(dst), len(dst))
|
||||
}
|
||||
|
||||
_has_rand_bytes :: proc() -> bool {
|
||||
return true
|
||||
}
|
||||
@@ -1,12 +1,18 @@
|
||||
package crypto
|
||||
|
||||
import "core:fmt"
|
||||
import "core:sys/darwin"
|
||||
|
||||
import CF "core:sys/darwin/CoreFoundation"
|
||||
import Sec "core:sys/darwin/Security"
|
||||
|
||||
_rand_bytes :: proc(dst: []byte) {
|
||||
res := darwin.SecRandomCopyBytes(count=len(dst), bytes=raw_data(dst))
|
||||
if res != .Success {
|
||||
msg := darwin.CFStringCopyToOdinString(darwin.SecCopyErrorMessageString(res))
|
||||
panic(fmt.tprintf("crypto/rand_bytes: SecRandomCopyBytes returned non-zero result: %v %s", res, msg))
|
||||
err := Sec.RandomCopyBytes(count=len(dst), bytes=raw_data(dst))
|
||||
if err != .Success {
|
||||
msg := CF.StringCopyToOdinString(Sec.CopyErrorMessageString(err))
|
||||
panic(fmt.tprintf("crypto/rand_bytes: SecRandomCopyBytes returned non-zero result: %v %s", err, msg))
|
||||
}
|
||||
}
|
||||
|
||||
_has_rand_bytes :: proc() -> bool {
|
||||
return true
|
||||
}
|
||||
@@ -9,3 +9,7 @@ package crypto
|
||||
_rand_bytes :: proc(dst: []byte) {
|
||||
unimplemented("crypto: rand_bytes not supported on this OS")
|
||||
}
|
||||
|
||||
_has_rand_bytes :: proc() -> bool {
|
||||
return false
|
||||
}
|
||||
@@ -18,3 +18,7 @@ _rand_bytes :: proc(dst: []byte) {
|
||||
dst = dst[to_read:]
|
||||
}
|
||||
}
|
||||
|
||||
_has_rand_bytes :: proc() -> bool {
|
||||
return true
|
||||
}
|
||||
@@ -34,3 +34,7 @@ _rand_bytes :: proc (dst: []byte) {
|
||||
dst = dst[n_read:]
|
||||
}
|
||||
}
|
||||
|
||||
_has_rand_bytes :: proc() -> bool {
|
||||
return true
|
||||
}
|
||||
@@ -21,3 +21,7 @@ _rand_bytes :: proc(dst: []byte) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_has_rand_bytes :: proc() -> bool {
|
||||
return true
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -27,7 +27,7 @@ _scalar_bit :: #force_inline proc "contextless" (s: ^[32]byte, i: int) -> u8 {
|
||||
}
|
||||
|
||||
@(private)
|
||||
_scalarmult :: proc(out, scalar, point: ^[32]byte) {
|
||||
_scalarmult :: proc "contextless" (out, scalar, point: ^[32]byte) {
|
||||
// Montgomery pseduo-multiplication taken from Monocypher.
|
||||
|
||||
// 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_to_bytes(out, &x2)
|
||||
|
||||
mem.zero_explicit(&x1, size_of(x1))
|
||||
mem.zero_explicit(&x2, size_of(x2))
|
||||
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))
|
||||
field.fe_clear_vec([]^field.Tight_Field_Element{&x1, &x2, &x3, &z2, &z3})
|
||||
field.fe_clear_vec([]^field.Loose_Field_Element{&t0, &t1})
|
||||
}
|
||||
|
||||
// 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
|
||||
// base point and writes the resulting point to dst.
|
||||
scalarmult_basepoint :: proc(dst, scalar: []byte) {
|
||||
// TODO/perf: Switch to using a precomputed table.
|
||||
scalarmult(dst, scalar, _BASE_POINT[:])
|
||||
}
|
||||
@@ -366,11 +366,63 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
|
||||
opt_write_end(w, opt, '}') or_return
|
||||
|
||||
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) {
|
||||
ti := runtime.type_info_base(type_info_of(v.id))
|
||||
info := ti.variant.(runtime.Type_Info_Struct)
|
||||
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
|
||||
if json_name != "" {
|
||||
@@ -378,18 +430,15 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
|
||||
} else {
|
||||
// Marshal the fields of 'using _: T' fields directly into the parent struct
|
||||
if info.usings[i] && name == "_" {
|
||||
id := info.types[i].id
|
||||
data := rawptr(uintptr(v.data) + info.offsets[i])
|
||||
marshal_struct_fields(w, any{data, id}, opt) or_return
|
||||
marshal_struct_fields(w, the_value, opt) or_return
|
||||
continue
|
||||
} else {
|
||||
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, any{data, id}, opt) or_return
|
||||
|
||||
marshal_to_writer(w, the_value, opt) or_return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -343,6 +343,16 @@ unmarshal_expect_token :: proc(p: ^Parser, kind: Token_Kind, loc := #caller_loca
|
||||
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)
|
||||
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 {
|
||||
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
|
||||
break
|
||||
}
|
||||
|
||||
+1
-1
@@ -2711,7 +2711,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
}
|
||||
} else {
|
||||
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 {
|
||||
if i > 0 { io.write_string(fi.writer, ", ", &fi.n) }
|
||||
|
||||
|
||||
+168
-20
@@ -102,37 +102,51 @@ round :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
|
||||
return (x.i + (1 << (Fraction_Width - 1))) >> Fraction_Width
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(require_results)
|
||||
append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
|
||||
Integer_Width :: 8*size_of(Backing) - Fraction_Width
|
||||
|
||||
x := x
|
||||
buf: [48]byte
|
||||
i := 0
|
||||
if x.i < 0 {
|
||||
|
||||
if !intrinsics.type_is_unsigned(Backing) && x.i == min(Backing) {
|
||||
// edge case handling for signed numbers
|
||||
buf[i] = '-'
|
||||
i += 1
|
||||
x.i = -x.i
|
||||
}
|
||||
|
||||
integer := x.i >> Fraction_Width
|
||||
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 += copy(buf[i:], _power_of_two_table[Integer_Width])
|
||||
} else {
|
||||
if x.i < 0 {
|
||||
buf[i] = '-'
|
||||
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])
|
||||
return string(dst[:i])
|
||||
}
|
||||
@@ -146,3 +160,137 @@ to_string :: proc(x: $T/Fixed($Backing, $Fraction_Width), allocator := context.a
|
||||
copy(str, s)
|
||||
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",
|
||||
}
|
||||
@@ -60,6 +60,7 @@ sqrt :: proc{
|
||||
@(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_f64be :: proc "contextless" (θ: f64be) -> f64be { return #force_inline f64be(sin_f64(f64(θ))) }
|
||||
// Return the sine of θ in radians.
|
||||
sin :: proc{
|
||||
sin_f16, sin_f16le, sin_f16be,
|
||||
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_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(θ))) }
|
||||
// Return the cosine of θ in radians.
|
||||
cos :: proc{
|
||||
cos_f16, cos_f16le, cos_f16be,
|
||||
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_f64le :: proc "contextless" (θ: f64le) -> f64le { return f64le(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_f16, tan_f16le, tan_f16be,
|
||||
tan_f32, tan_f32le, tan_f32be,
|
||||
@@ -1752,7 +1755,28 @@ atan2_f64be :: proc "contextless" (y, x: f64be) -> f64be {
|
||||
// TODO(bill): Better atan2_f32
|
||||
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_f64, atan2_f32, atan2_f16,
|
||||
atan2_f64le, atan2_f64be,
|
||||
@@ -1760,6 +1784,7 @@ atan2 :: proc{
|
||||
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)
|
||||
atan :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
|
||||
return atan2(x, 1)
|
||||
@@ -1871,6 +1896,7 @@ asin_f16le :: proc "contextless" (x: f16le) -> f16le {
|
||||
asin_f16be :: proc "contextless" (x: f16be) -> f16be {
|
||||
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_f64, asin_f32, asin_f16,
|
||||
asin_f64le, asin_f64be,
|
||||
@@ -1985,6 +2011,7 @@ acos_f16le :: proc "contextless" (x: f16le) -> f16le {
|
||||
acos_f16be :: proc "contextless" (x: f16be) -> f16be {
|
||||
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_f64, acos_f32, acos_f16,
|
||||
acos_f64le, acos_f64be,
|
||||
|
||||
+15
-2
@@ -21,7 +21,7 @@ import "core:strconv"
|
||||
import "core:unicode/utf8"
|
||||
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
|
||||
|
||||
i := strings.index(s, "://")
|
||||
@@ -30,6 +30,12 @@ split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host,
|
||||
s = s[i+3:]
|
||||
}
|
||||
|
||||
i = strings.index(s, "#")
|
||||
if i != -1 {
|
||||
fragment = s[i+1:]
|
||||
s = s[:i]
|
||||
}
|
||||
|
||||
i = strings.index(s, "?")
|
||||
if i != -1 {
|
||||
query_str := s[i+1:]
|
||||
@@ -62,7 +68,7 @@ split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host,
|
||||
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)
|
||||
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
|
||||
}
|
||||
|
||||
if fragment != "" {
|
||||
if fragment[0] != '#' {
|
||||
strings.write_string(&b, "#")
|
||||
}
|
||||
strings.write_string(&b, strings.trim_space(fragment))
|
||||
}
|
||||
|
||||
return strings.to_string(b)
|
||||
}
|
||||
|
||||
|
||||
+21
-1
@@ -617,7 +617,7 @@ field_flag_strings := [Field_Flag]string{
|
||||
.Any_Int = "#any_int",
|
||||
.Subtype = "#subtype",
|
||||
.By_Ptr = "#by_ptr",
|
||||
.No_Broadcast ="#no_broadcast",
|
||||
.No_Broadcast = "#no_broadcast",
|
||||
|
||||
.Results = "results",
|
||||
.Tags = "field tag",
|
||||
@@ -842,6 +842,23 @@ Matrix_Type :: struct {
|
||||
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 {
|
||||
^Package,
|
||||
@@ -898,6 +915,7 @@ Any_Node :: union {
|
||||
^Map_Type,
|
||||
^Relative_Type,
|
||||
^Matrix_Type,
|
||||
^Bit_Field_Type,
|
||||
|
||||
^Bad_Stmt,
|
||||
^Empty_Stmt,
|
||||
@@ -928,6 +946,7 @@ Any_Node :: union {
|
||||
^Attribute,
|
||||
^Field,
|
||||
^Field_List,
|
||||
^Bit_Field_Field,
|
||||
}
|
||||
|
||||
|
||||
@@ -982,6 +1001,7 @@ Any_Expr :: union {
|
||||
^Map_Type,
|
||||
^Relative_Type,
|
||||
^Matrix_Type,
|
||||
^Bit_Field_Type,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -336,6 +336,13 @@ clone_node :: proc(node: ^Node) -> ^Node {
|
||||
case ^Relative_Type:
|
||||
r.tag = clone(r.tag)
|
||||
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:
|
||||
fmt.panicf("Unhandled node kind: %v", r)
|
||||
}
|
||||
|
||||
@@ -414,7 +414,15 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
||||
walk(v, n.row_count)
|
||||
walk(v, n.column_count)
|
||||
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:
|
||||
fmt.panicf("ast.walk: unexpected node type %T", n)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
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
|
||||
if allow_token(p, .Close_Brace) {
|
||||
if allow_token(p, closing_kind) {
|
||||
return token
|
||||
}
|
||||
if allow_token(p, .Semicolon) && !tokenizer.is_newline(token) {
|
||||
str := tokenizer.token_to_string(token)
|
||||
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 {
|
||||
for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF && !is_non_inserted_semicolon(p.curr_tok) {
|
||||
if expect_closing.kind != closing_kind {
|
||||
for p.curr_tok.kind != closing_kind && p.curr_tok.kind != .EOF && !is_non_inserted_semicolon(p.curr_tok) {
|
||||
advance_token(p)
|
||||
}
|
||||
return p.curr_tok
|
||||
}
|
||||
|
||||
return expect_brace
|
||||
return expect_closing
|
||||
}
|
||||
|
||||
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)
|
||||
case ^ast.Pointer_Type:
|
||||
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
|
||||
return p.curr_proc == nil
|
||||
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.results = results[:]
|
||||
expect_semicolon(p, rs)
|
||||
return rs
|
||||
|
||||
case .Break, .Continue, .Fallthrough:
|
||||
@@ -2790,6 +2795,48 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
mt.column_count = column_count
|
||||
mt.elem = elem
|
||||
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:
|
||||
tok := expect_token(p, .Asm)
|
||||
@@ -2897,7 +2944,8 @@ is_literal_type :: proc(expr: ^ast.Expr) -> bool {
|
||||
^ast.Map_Type,
|
||||
^ast.Bit_Set_Type,
|
||||
^ast.Matrix_Type,
|
||||
^ast.Call_Expr:
|
||||
^ast.Call_Expr,
|
||||
^ast.Bit_Field_Type:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -2947,8 +2995,8 @@ parse_literal_value :: proc(p: ^Parser, type: ^ast.Expr) -> ^ast.Comp_Lit {
|
||||
}
|
||||
p.expr_level -= 1
|
||||
|
||||
skip_possible_newline(p)
|
||||
close := expect_token_after(p, .Close_Brace, "compound literal")
|
||||
skip_possible_newline(p)
|
||||
close := expect_closing_brace_of_field_list(p)
|
||||
|
||||
pos := type.pos if type != nil else open.pos
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
ce := ast.new(ast.Call_Expr, operand.pos, end_pos(close))
|
||||
|
||||
@@ -445,7 +445,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
|
||||
|
||||
for value in v.values {
|
||||
#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
|
||||
case ^ast.Proc_Lit:
|
||||
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)
|
||||
visit_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) {
|
||||
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)
|
||||
push_generic_token(p, .Close_Bracket, 0)
|
||||
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:
|
||||
panic(fmt.aprint(expr.derived))
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ init :: proc(t: ^Tokenizer, src: string, path: string, err: Error_Handler = defa
|
||||
t.read_offset = 0
|
||||
t.line_offset = 0
|
||||
t.line_count = len(src) > 0 ? 1 : 0
|
||||
t.insert_semicolon = false
|
||||
t.error_count = 0
|
||||
t.path = path
|
||||
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@ package os
|
||||
import "core:time"
|
||||
|
||||
File_Info :: struct {
|
||||
fullpath: string,
|
||||
name: string,
|
||||
fullpath: string, // allocated
|
||||
name: string, // uses `fullpath` as underlying data
|
||||
size: i64,
|
||||
mode: File_Mode,
|
||||
is_dir: bool,
|
||||
|
||||
@@ -1213,6 +1213,13 @@ Output:
|
||||
append_int :: proc(buf: []byte, i: i64, base: int) -> string {
|
||||
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
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package sync
|
||||
|
||||
import "core:c"
|
||||
import "core:runtime"
|
||||
import "base:runtime"
|
||||
import "core:sys/haiku"
|
||||
import "core:sys/unix"
|
||||
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
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -23,12 +23,9 @@ StringEncoding :: enum UInteger {
|
||||
WindowsCP1250 = 15,
|
||||
ISO2022JP = 21,
|
||||
MacOSRoman = 30,
|
||||
|
||||
UTF16 = Unicode,
|
||||
|
||||
UTF16BigEndian = 0x90000100,
|
||||
UTF16LittleEndian = 0x94000100,
|
||||
|
||||
UTF32 = 0x8c000100,
|
||||
UTF32BigEndian = 0x98000100,
|
||||
UTF32LittleEndian = 0x9c000100,
|
||||
@@ -49,12 +46,9 @@ StringCompareOption :: enum UInteger {
|
||||
|
||||
unichar :: distinct u16
|
||||
|
||||
@(link_prefix="NS", default_calling_convention="c")
|
||||
foreign Foundation {
|
||||
StringFromClass :: proc(cls: Class) -> ^String ---
|
||||
}
|
||||
|
||||
AT :: MakeConstantString
|
||||
|
||||
// CFString is 'toll-free bridged' with its Cocoa Foundation counterpart, NSString.
|
||||
MakeConstantString :: proc "c" (#const c: cstring) -> ^String {
|
||||
foreign Foundation {
|
||||
__CFStringMakeConstantString :: proc "c" (c: cstring) -> ^String ---
|
||||
@@ -62,6 +56,10 @@ MakeConstantString :: proc "c" (#const c: cstring) -> ^String {
|
||||
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)
|
||||
String_alloc :: proc "c" () -> ^String {
|
||||
@@ -73,7 +71,6 @@ String_init :: proc "c" (self: ^String) -> ^String {
|
||||
return msgSend(^String, self, "init")
|
||||
}
|
||||
|
||||
|
||||
@(objc_type=String, objc_name="initWithString")
|
||||
String_initWithString :: proc "c" (self: ^String, other: ^String) -> ^String {
|
||||
return msgSend(^String, self, "initWithString:", other)
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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.
|
||||
}
|
||||
@@ -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 ---
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 ---
|
||||
}
|
||||
@@ -2074,7 +2074,13 @@ SRWLOCK_INIT :: SRWLOCK{}
|
||||
STARTF_USESTDHANDLES: DWORD : 0x00000100
|
||||
|
||||
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_CURRENT: DWORD : 1
|
||||
|
||||
@@ -56,9 +56,9 @@ validate_hour_minute_second :: proc "contextless" (#any_int hour, #any_int minut
|
||||
return .None
|
||||
}
|
||||
|
||||
validate_datetime :: proc "contextless" (using datetime: DateTime) -> (err: Error) {
|
||||
validate(date) or_return
|
||||
validate(time) or_return
|
||||
validate_datetime :: proc "contextless" (datetime: DateTime) -> (err: Error) {
|
||||
validate(datetime.date) or_return
|
||||
validate(datetime.time) or_return
|
||||
return .None
|
||||
}
|
||||
|
||||
@@ -69,4 +69,4 @@ validate :: proc{
|
||||
validate_hour_minute_second,
|
||||
validate_time,
|
||||
validate_datetime,
|
||||
}
|
||||
}
|
||||
@@ -24,9 +24,9 @@ _sleep :: proc "contextless" (d: Duration) {
|
||||
|
||||
_tick_now :: proc "contextless" () -> Tick {
|
||||
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" () {
|
||||
|
||||
@@ -29,6 +29,7 @@ import blake2s "core:crypto/blake2s"
|
||||
import chacha20 "core:crypto/chacha20"
|
||||
import chacha20poly1305 "core:crypto/chacha20poly1305"
|
||||
import crypto_hash "core:crypto/hash"
|
||||
import ed25519 "core:crypto/ed25519"
|
||||
import hkdf "core:crypto/hkdf"
|
||||
import hmac "core:crypto/hmac"
|
||||
import kmac "core:crypto/kmac"
|
||||
@@ -37,6 +38,7 @@ import md5 "core:crypto/legacy/md5"
|
||||
import sha1 "core:crypto/legacy/sha1"
|
||||
import pbkdf2 "core:crypto/pbkdf2"
|
||||
import poly1305 "core:crypto/poly1305"
|
||||
import ristretto255 "core:crypto/ristretto255"
|
||||
import sha2 "core:crypto/sha2"
|
||||
import sha3 "core:crypto/sha3"
|
||||
import shake "core:crypto/shake"
|
||||
@@ -151,6 +153,7 @@ _ :: blake2b
|
||||
_ :: blake2s
|
||||
_ :: chacha20
|
||||
_ :: chacha20poly1305
|
||||
_ :: ed25519
|
||||
_ :: hmac
|
||||
_ :: hkdf
|
||||
_ :: kmac
|
||||
@@ -158,6 +161,7 @@ _ :: keccak
|
||||
_ :: md5
|
||||
_ :: pbkdf2
|
||||
_ :: poly1305
|
||||
_ :: ristretto255
|
||||
_ :: sha1
|
||||
_ :: sha2
|
||||
_ :: sha3
|
||||
|
||||
@@ -62,7 +62,7 @@ _ :: xlib
|
||||
|
||||
// NOTE: needed for doc generator
|
||||
|
||||
import NS "vendor:darwin/Foundation"
|
||||
import NS "core:sys/darwin/Foundation"
|
||||
import MTL "vendor:darwin/Metal"
|
||||
import MTK "vendor:darwin/MetalKit"
|
||||
import CA "vendor:darwin/QuartzCore"
|
||||
@@ -73,10 +73,12 @@ _ :: MTK
|
||||
_ :: CA
|
||||
|
||||
|
||||
import DXC "vendor:directx/dxc"
|
||||
import D3D11 "vendor:directx/d3d11"
|
||||
import D3D12 "vendor:directx/d3d12"
|
||||
import DXGI "vendor:directx/dxgi"
|
||||
|
||||
_ :: DXC
|
||||
_ :: D3D11
|
||||
_ :: D3D12
|
||||
_ :: DXGI
|
||||
|
||||
@@ -7,7 +7,7 @@ import "core:os"
|
||||
import "core:thread"
|
||||
import "core:time"
|
||||
import "core:reflect"
|
||||
import "core:runtime"
|
||||
import "base:runtime"
|
||||
import "core:intrinsics"
|
||||
import "core:math/big"
|
||||
|
||||
|
||||
+26
-8
@@ -272,13 +272,16 @@ enum BuildPath : u8 {
|
||||
};
|
||||
|
||||
enum VetFlags : u64 {
|
||||
VetFlag_NONE = 0,
|
||||
VetFlag_Unused = 1u<<0, // 1
|
||||
VetFlag_Shadowing = 1u<<1, // 2
|
||||
VetFlag_UsingStmt = 1u<<2, // 4
|
||||
VetFlag_UsingParam = 1u<<3, // 8
|
||||
VetFlag_Style = 1u<<4, // 16
|
||||
VetFlag_Semicolon = 1u<<5, // 32
|
||||
VetFlag_NONE = 0,
|
||||
VetFlag_Shadowing = 1u<<0,
|
||||
VetFlag_UsingStmt = 1u<<1,
|
||||
VetFlag_UsingParam = 1u<<2,
|
||||
VetFlag_Style = 1u<<3,
|
||||
VetFlag_Semicolon = 1u<<4,
|
||||
VetFlag_UnusedVariables = 1u<<5,
|
||||
VetFlag_UnusedImports = 1u<<6,
|
||||
|
||||
VetFlag_Unused = VetFlag_UnusedVariables|VetFlag_UnusedImports,
|
||||
|
||||
VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt,
|
||||
|
||||
@@ -288,6 +291,10 @@ enum VetFlags : u64 {
|
||||
u64 get_vet_flag_from_name(String const &name) {
|
||||
if (name == "unused") {
|
||||
return VetFlag_Unused;
|
||||
} else if (name == "unused-variables") {
|
||||
return VetFlag_UnusedVariables;
|
||||
} else if (name == "unused-imports") {
|
||||
return VetFlag_UnusedImports;
|
||||
} else if (name == "shadowing") {
|
||||
return VetFlag_Shadowing;
|
||||
} else if (name == "using-stmt") {
|
||||
@@ -624,6 +631,15 @@ gb_global TargetMetrics target_freestanding_amd64_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 = {
|
||||
TargetOs_freestanding,
|
||||
TargetArch_arm64,
|
||||
@@ -665,7 +681,9 @@ gb_global NamedTargetMetrics named_targets[] = {
|
||||
{ str_lit("js_wasm64p32"), &target_js_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 },
|
||||
};
|
||||
|
||||
|
||||
@@ -4089,8 +4089,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
}
|
||||
}
|
||||
|
||||
operand->mode = Addressing_OptionalOk;
|
||||
operand->type = default_type(x.type);
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = make_optional_ok_type(default_type(x.type));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -6014,6 +6014,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
return false;
|
||||
}
|
||||
|
||||
enable_target_feature({}, str_lit("atomics"));
|
||||
|
||||
Operand ptr = {};
|
||||
Operand expected = {};
|
||||
Operand timeout = {};
|
||||
@@ -6066,6 +6068,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
return false;
|
||||
}
|
||||
|
||||
enable_target_feature({}, str_lit("atomics"));
|
||||
|
||||
Operand ptr = {};
|
||||
Operand waiters = {};
|
||||
check_expr(c, &ptr, ce->args[0]); if (ptr.mode == Addressing_Invalid) return false;
|
||||
|
||||
+17
-4
@@ -4595,7 +4595,8 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v
|
||||
String name = fv->field->Ident.token.string;
|
||||
Selection sub_sel = lookup_field(node->tav.type, name, false);
|
||||
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;
|
||||
found = true;
|
||||
break;
|
||||
@@ -8156,19 +8157,31 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
|
||||
o->mode = Addressing_Constant;
|
||||
String name = bd->name.string;
|
||||
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->value = exact_value_string(get_file_path_string(bd->token.pos.file_id));
|
||||
o->value = exact_value_string(file);
|
||||
} 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->value = exact_value_i64(bd->token.pos.line);
|
||||
o->value = exact_value_i64(line);
|
||||
} else if (name == "procedure") {
|
||||
if (c->curr_proc_decl == nullptr) {
|
||||
error(node, "#procedure may only be used within procedures");
|
||||
o->type = t_untyped_string;
|
||||
o->value = exact_value_string(str_lit(""));
|
||||
} else {
|
||||
String p = c->proc_name;
|
||||
if (build_context.obfuscate_source_code_locations) {
|
||||
p = obfuscate_string(p, "P");
|
||||
}
|
||||
o->type = t_untyped_string;
|
||||
o->value = exact_value_string(c->proc_name);
|
||||
o->value = exact_value_string(p);
|
||||
}
|
||||
} else if (name == "caller_location") {
|
||||
init_core_source_code_location(c->checker);
|
||||
|
||||
+45
-2
@@ -474,16 +474,59 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
|
||||
}
|
||||
|
||||
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);
|
||||
if (e != nullptr && e->flags & EntityFlag_Param) {
|
||||
ERROR_BLOCK();
|
||||
if (e->flags & EntityFlag_Using) {
|
||||
error(lhs->expr, "Cannot assign to '%s' which is from a 'using' procedure parameter", str);
|
||||
} else {
|
||||
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 {
|
||||
ERROR_BLOCK();
|
||||
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);
|
||||
|
||||
@@ -2355,14 +2398,14 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) {
|
||||
unsafe_return_error(o, "the address of a compound literal");
|
||||
} else if (x->kind == Ast_IndexExpr) {
|
||||
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)) {
|
||||
unsafe_return_error(o, "the address of an indexed variable", f->type);
|
||||
}
|
||||
}
|
||||
} else if (x->kind == Ast_MatrixIndexExpr) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-1
@@ -1689,7 +1689,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
|
||||
bool is_using = (p->flags&FieldFlag_using) != 0;
|
||||
if ((check_vet_flags(param) & VetFlag_UsingParam) && is_using) {
|
||||
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");
|
||||
|
||||
}
|
||||
@@ -3233,6 +3233,11 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
|
||||
Type *elem = t_invalid;
|
||||
Operand o = {};
|
||||
|
||||
if (unparen_expr(pt->type) == nullptr) {
|
||||
error(e, "Invalid pointer type");
|
||||
return false;
|
||||
}
|
||||
|
||||
check_expr_or_type(&c, &o, pt->type);
|
||||
if (o.mode != Addressing_Invalid && o.mode != Addressing_Type) {
|
||||
if (o.mode == Addressing_Variable) {
|
||||
|
||||
+7
-4
@@ -703,11 +703,11 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
|
||||
array_add(&vetted_entities, ve_unused);
|
||||
} else if (is_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);
|
||||
// TODO(bill): When is a good size warn?
|
||||
// Is 128 KiB good enough?
|
||||
if (sz >= 1ll<<17) {
|
||||
// Is >256 KiB good enough?
|
||||
if (sz > 1ll<<18) {
|
||||
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);
|
||||
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) {
|
||||
switch (ve.kind) {
|
||||
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));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -353,6 +353,27 @@ gb_global bool global_module_path_set = false;
|
||||
#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 {
|
||||
StringIntern *next;
|
||||
isize len;
|
||||
|
||||
@@ -163,6 +163,10 @@ gb_internal void platform_virtual_memory_protect(void *memory, isize size);
|
||||
GB_ASSERT(is_protected);
|
||||
}
|
||||
#else
|
||||
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
gb_internal void platform_virtual_memory_init(void) {
|
||||
global_platform_memory_block_sentinel.prev = &global_platform_memory_block_sentinel;
|
||||
global_platform_memory_block_sentinel.next = &global_platform_memory_block_sentinel;
|
||||
|
||||
+1
-1
@@ -496,7 +496,7 @@ gb_internal bool is_entity_local_variable(Entity *e) {
|
||||
if (e->scope == nullptr) {
|
||||
return true;
|
||||
}
|
||||
if (e->flags & (EntityFlag_ForValue|EntityFlag_SwitchValue)) {
|
||||
if (e->flags & (EntityFlag_ForValue|EntityFlag_SwitchValue|EntityFlag_Static)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+24
-5
@@ -84,6 +84,7 @@ gb_internal bool set_file_path_string(i32 index, String const &path) {
|
||||
bool ok = false;
|
||||
GB_ASSERT(index >= 0);
|
||||
mutex_lock(&global_error_collector.path_mutex);
|
||||
mutex_lock(&global_files_mutex);
|
||||
|
||||
if (index >= global_file_path_strings.count) {
|
||||
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;
|
||||
}
|
||||
|
||||
mutex_unlock(&global_files_mutex);
|
||||
mutex_unlock(&global_error_collector.path_mutex);
|
||||
return ok;
|
||||
}
|
||||
@@ -102,6 +104,7 @@ gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
|
||||
bool ok = false;
|
||||
GB_ASSERT(index >= 0);
|
||||
mutex_lock(&global_error_collector.path_mutex);
|
||||
mutex_lock(&global_files_mutex);
|
||||
|
||||
if (index >= global_files.count) {
|
||||
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;
|
||||
ok = true;
|
||||
}
|
||||
|
||||
mutex_unlock(&global_files_mutex);
|
||||
mutex_unlock(&global_error_collector.path_mutex);
|
||||
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_ASSERT(index >= 0);
|
||||
mutex_lock(&global_error_collector.path_mutex);
|
||||
mutex_lock(&global_files_mutex);
|
||||
|
||||
String path = {};
|
||||
if (index < global_file_path_strings.count) {
|
||||
path = global_file_path_strings[index];
|
||||
}
|
||||
|
||||
mutex_unlock(&global_files_mutex);
|
||||
mutex_unlock(&global_error_collector.path_mutex);
|
||||
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_ASSERT(index >= 0);
|
||||
mutex_lock(&global_error_collector.path_mutex);
|
||||
mutex_lock(&global_files_mutex);
|
||||
|
||||
AstFile *file = nullptr;
|
||||
if (index < global_files.count) {
|
||||
file = global_files[index];
|
||||
}
|
||||
|
||||
mutex_unlock(&global_files_mutex);
|
||||
mutex_unlock(&global_error_collector.path_mutex);
|
||||
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;
|
||||
if (!show_error_line()) {
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
if (prefix) {
|
||||
error_out("\t%s\n\n", prefix);
|
||||
}
|
||||
|
||||
error_out("\t");
|
||||
|
||||
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();
|
||||
|
||||
error_out("\n");
|
||||
return true;
|
||||
return offset;
|
||||
}
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
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\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");
|
||||
|
||||
if (ev.pos.file_id) {
|
||||
|
||||
+1
-1
@@ -384,7 +384,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
LIT(obj_file),
|
||||
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));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
|
||||
if (build_context.obfuscate_source_code_locations) {
|
||||
file = lb_obfuscate_string(file, "F");
|
||||
procedure = lb_obfuscate_string(procedure, "P");
|
||||
file = obfuscate_string(file, "F");
|
||||
procedure = obfuscate_string(procedure, "P");
|
||||
|
||||
line = lb_obfuscate_i32(line);
|
||||
column = lb_obfuscate_i32(column);
|
||||
line = obfuscate_i32(line);
|
||||
column = obfuscate_i32(column);
|
||||
}
|
||||
|
||||
LLVMValueRef fields[4] = {};
|
||||
|
||||
@@ -2138,14 +2138,45 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
|
||||
if (is_type_array_like(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);
|
||||
|
||||
for (isize i = 0; i < index_count; i++) {
|
||||
lbValue elem = lb_emit_array_epi(p, v.addr, i);
|
||||
isize inlineable = type_size_of(dst) <= build_context.max_simd_align;
|
||||
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_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);
|
||||
}
|
||||
@@ -4726,9 +4757,12 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
|
||||
if (sub_sel.index.count > 0) {
|
||||
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);
|
||||
bf_type = base_type(type_deref(bf_type));
|
||||
bf_type = base_type(bf_type);
|
||||
GB_ASSERT(bf_type->kind == Type_BitField);
|
||||
|
||||
i32 index = sel.index[sel.index.count-1];
|
||||
|
||||
@@ -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_ASSERT(is_type_pointer(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};
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
Loaded 100 of 126 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user