mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-12 06:18:39 +00:00
Merge branch 'odin-lang:master' into vet_flags
This commit is contained in:
@@ -122,6 +122,7 @@ Type_Info_Struct_Flag :: enum u8 {
|
||||
raw_union = 1,
|
||||
all_or_none = 2,
|
||||
align = 3,
|
||||
simple = 4,
|
||||
}
|
||||
|
||||
Type_Info_Struct :: struct {
|
||||
|
||||
@@ -204,10 +204,10 @@ when ODIN_NO_RTTI {
|
||||
@(cold, no_instrumentation)
|
||||
handle_error :: proc "odin" (file: string, line, column: i32, from, to: typeid) -> ! {
|
||||
do_msg :: proc "contextless" (i: ^int, buf: []byte, file: string, line, column: i32, from, to: typeid) -> bool {
|
||||
try_copy_string(i, buf, "Invalid type assertion from ") or_return
|
||||
try_copy_typeid(i, buf, from) or_return
|
||||
try_copy_string(i, buf, " to ") or_return
|
||||
try_copy_typeid(i, buf, to) or_return
|
||||
write_string(i, buf, "Invalid type assertion from ") or_return
|
||||
write_typeid(i, buf, from) or_return
|
||||
write_string(i, buf, " to ") or_return
|
||||
write_typeid(i, buf, to) or_return
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -285,13 +285,13 @@ when ODIN_NO_RTTI {
|
||||
@(cold, no_instrumentation)
|
||||
handle_error :: proc "odin" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) -> ! {
|
||||
do_msg :: proc "contextless" (i: ^int, buf: []byte, file: string, line, column: i32, from, to, actual: typeid) -> bool {
|
||||
try_copy_string(i, buf, "Invalid type assertion from ") or_return
|
||||
try_copy_typeid(i, buf, from) or_return
|
||||
try_copy_string(i, buf, " to ") or_return
|
||||
try_copy_typeid(i, buf, to) or_return
|
||||
write_string(i, buf, "Invalid type assertion from ") or_return
|
||||
write_typeid(i, buf, from) or_return
|
||||
write_string(i, buf, " to ") or_return
|
||||
write_typeid(i, buf, to) or_return
|
||||
if actual != from {
|
||||
try_copy_string(i, buf, ", actual type: ") or_return
|
||||
try_copy_typeid(i, buf, actual) or_return
|
||||
write_string(i, buf, ", actual type: ") or_return
|
||||
write_typeid(i, buf, actual) or_return
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -280,11 +280,22 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) {
|
||||
print_byte('i' if info.signed else 'u')
|
||||
print_u64(u64(8*ti.size))
|
||||
}
|
||||
switch info.endianness {
|
||||
case .Platform: // nothing
|
||||
case .Little: print_string("le")
|
||||
case .Big: print_string("be")
|
||||
}
|
||||
|
||||
case Type_Info_Rune:
|
||||
print_string("rune")
|
||||
case Type_Info_Float:
|
||||
print_byte('f')
|
||||
print_u64(u64(8*ti.size))
|
||||
switch info.endianness {
|
||||
case .Platform: // nothing
|
||||
case .Little: print_string("le")
|
||||
case .Big: print_string("be")
|
||||
}
|
||||
case Type_Info_Complex:
|
||||
print_string("complex")
|
||||
print_u64(u64(8*ti.size))
|
||||
@@ -410,6 +421,7 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) {
|
||||
if .packed in info.flags { print_string("#packed ") }
|
||||
if .raw_union in info.flags { print_string("#raw_union ") }
|
||||
if .all_or_none in info.flags { print_string("#all_or_none ") }
|
||||
if .simple in info.flags { print_string("#simple ") }
|
||||
if .align in info.flags {
|
||||
print_string("#align(")
|
||||
print_u64(u64(ti.align))
|
||||
@@ -494,6 +506,9 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) {
|
||||
print_type(info.elem)
|
||||
|
||||
case Type_Info_Matrix:
|
||||
if info.layout == .Row_Major {
|
||||
print_string("#row_major ")
|
||||
}
|
||||
print_string("matrix[")
|
||||
print_u64(u64(info.row_count))
|
||||
print_string(", ")
|
||||
@@ -505,7 +520,7 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) {
|
||||
|
||||
|
||||
@(require_results)
|
||||
try_copy_string :: proc "contextless" (i: ^int, dst: []byte, src: string) -> bool {
|
||||
write_string :: proc "contextless" (i: ^int, dst: []byte, src: string) -> bool {
|
||||
if i^ < len(dst) {
|
||||
i^ += copy(dst[i^:], src)
|
||||
return true
|
||||
@@ -515,7 +530,7 @@ try_copy_string :: proc "contextless" (i: ^int, dst: []byte, src: string) -> boo
|
||||
|
||||
|
||||
@(require_results)
|
||||
try_copy_byte :: proc "contextless" (i: ^int, dst: []byte, src: byte) -> bool {
|
||||
write_byte :: proc "contextless" (i: ^int, dst: []byte, src: byte) -> bool {
|
||||
if i^ < len(dst) {
|
||||
dst[i^] = src
|
||||
i^ += 1
|
||||
@@ -526,7 +541,7 @@ try_copy_byte :: proc "contextless" (i: ^int, dst: []byte, src: byte) -> bool {
|
||||
|
||||
|
||||
@(require_results)
|
||||
try_copy_u64 :: proc "contextless" (j: ^int, dst: []byte, x: u64) -> bool {
|
||||
write_u64 :: proc "contextless" (j: ^int, dst: []byte, x: u64) -> bool {
|
||||
if j^ < len(dst) {
|
||||
b :: u64(10)
|
||||
u := x
|
||||
@@ -539,33 +554,56 @@ try_copy_u64 :: proc "contextless" (j: ^int, dst: []byte, x: u64) -> bool {
|
||||
}
|
||||
i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b]
|
||||
|
||||
return try_copy_string(j, dst, string(a[i:]))
|
||||
return write_string(j, dst, string(a[i:]))
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
write_i64 :: proc "contextless" (j: ^int, dst: []byte, x: i64) -> bool {
|
||||
if j^ < len(dst) {
|
||||
b :: u64(10)
|
||||
u := u64(abs(x))
|
||||
neg := x < 0
|
||||
|
||||
a: [129]byte
|
||||
i := len(a)
|
||||
for u >= b {
|
||||
i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b]
|
||||
u /= b
|
||||
}
|
||||
i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b]
|
||||
if neg {
|
||||
i -= 1; a[i] = '-'
|
||||
}
|
||||
|
||||
return write_string(j, dst, string(a[i:]))
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
try_copy_caller_location :: #force_no_inline proc "contextless" (i: ^int, buf: []byte, loc: Source_Code_Location) -> bool {
|
||||
try_copy_string(i, buf, loc.file_path) or_return
|
||||
write_caller_location :: #force_no_inline proc "contextless" (i: ^int, buf: []byte, loc: Source_Code_Location) -> bool {
|
||||
write_string(i, buf, loc.file_path) or_return
|
||||
|
||||
when ODIN_ERROR_POS_STYLE == .Default {
|
||||
try_copy_byte(i, buf, '(') or_return
|
||||
try_copy_u64(i, buf, u64(loc.line)) or_return
|
||||
write_byte(i, buf, '(') or_return
|
||||
write_u64 (i, buf, u64(loc.line)) or_return
|
||||
if loc.column != 0 {
|
||||
try_copy_byte(i, buf, ':') or_return
|
||||
try_copy_u64(i, buf, u64(loc.column)) or_return
|
||||
write_byte(i, buf, ':') or_return
|
||||
write_u64 (i, buf, u64(loc.column)) or_return
|
||||
}
|
||||
try_copy_byte(i, buf, ')') or_return
|
||||
write_byte(i, buf, ')') or_return
|
||||
return true
|
||||
} else when ODIN_ERROR_POS_STYLE == .Unix {
|
||||
try_copy_byte(i, buf, ':') or_return
|
||||
try_copy_u64(i, buf, u64(loc.line)) or_return
|
||||
write_byte(i, buf, ':') or_return
|
||||
write_u64 (i, buf, u64(loc.line)) or_return
|
||||
if loc.column != 0 {
|
||||
try_copy_try_copy_bytetring(i, buf, ':') or_return
|
||||
try_copy_u64(i, buf, u64(loc.column)) or_return
|
||||
write_byte(i, buf, ':') or_return
|
||||
write_u64 (i, buf, u64(loc.column)) or_return
|
||||
}
|
||||
try_copy_byte(i, buf, ':') or_return
|
||||
write_byte(i, buf, ':') or_return
|
||||
return true
|
||||
} else {
|
||||
#panic("unhandled ODIN_ERROR_POS_STYLE")
|
||||
@@ -573,263 +611,325 @@ try_copy_caller_location :: #force_no_inline proc "contextless" (i: ^int, buf: [
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
try_copy_typeid :: #force_no_inline proc "contextless" (i: ^int, buf: []byte, id: typeid) -> bool {
|
||||
write_typeid :: #force_no_inline proc "contextless" (i: ^int, buf: []byte, id: typeid) -> bool {
|
||||
when ODIN_NO_RTTI {
|
||||
if id == nil {
|
||||
try_copy_string(i, buf, "nil") or_return
|
||||
write_string(i, buf, "nil") or_return
|
||||
} else {
|
||||
try_copy_string(i, buf, "<unknown type>") or_return
|
||||
write_string(i, buf, "<unknown type>") or_return
|
||||
}
|
||||
} else {
|
||||
if id == nil {
|
||||
try_copy_string(i, buf, "nil") or_return
|
||||
write_string(i, buf, "nil") or_return
|
||||
} else {
|
||||
ti := type_info_of(id)
|
||||
try_copy_write_type(i, buf, ti) or_return
|
||||
write_write_type(i, buf, ti) or_return
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
write_rune :: #force_no_inline proc "contextless" (i: ^int, buf: []byte, r: rune) -> (written: int, ok: bool) #no_bounds_check {
|
||||
RUNE_SELF :: 0x80
|
||||
|
||||
if r < RUNE_SELF {
|
||||
write_byte(i, buf,byte(r)) or_return
|
||||
return 1, true
|
||||
}
|
||||
|
||||
b, n := encode_rune(r)
|
||||
prev := i^
|
||||
write_string(i, buf, string(b[:n])) or_return
|
||||
return i^ - prev, true
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
write_encoded_rune :: #force_no_inline proc "contextless" (i: ^int, buf: []byte, r: rune) -> bool {
|
||||
write_byte(i, buf, '\'') or_return
|
||||
|
||||
switch r {
|
||||
case '\a': write_string(i, buf, "\\a") or_return
|
||||
case '\b': write_string(i, buf, "\\b") or_return
|
||||
case '\e': write_string(i, buf, "\\e") or_return
|
||||
case '\f': write_string(i, buf, "\\f") or_return
|
||||
case '\n': write_string(i, buf, "\\n") or_return
|
||||
case '\r': write_string(i, buf, "\\r") or_return
|
||||
case '\t': write_string(i, buf, "\\t") or_return
|
||||
case '\v': write_string(i, buf, "\\v") or_return
|
||||
case:
|
||||
if r <= 0 {
|
||||
write_string(i, buf, "\\x00") or_return
|
||||
} else if r < 32 {
|
||||
n0, n1 := u8(r) >> 4, u8(r) & 0xf
|
||||
write_string(i, buf, "\\x") or_return
|
||||
write_byte (i, buf, _INTEGER_DIGITS_VAR[n0]) or_return
|
||||
write_byte (i, buf, _INTEGER_DIGITS_VAR[n1]) or_return
|
||||
} else {
|
||||
_ = write_rune(i, buf, r) or_return
|
||||
}
|
||||
}
|
||||
|
||||
write_byte(i, buf, '\'') or_return
|
||||
return true
|
||||
}
|
||||
|
||||
@(optimization_mode="favor_size")
|
||||
try_copy_write_type :: #force_no_inline proc "contextless" (i: ^int, buf: []byte, ti: ^Type_Info) -> bool {
|
||||
write_write_type :: #force_no_inline proc "contextless" (i: ^int, buf: []byte, ti: ^Type_Info) -> bool {
|
||||
if ti == nil {
|
||||
try_copy_string(i, buf, "nil") or_return
|
||||
write_string(i, buf, "nil") or_return
|
||||
return true
|
||||
}
|
||||
|
||||
switch info in ti.variant {
|
||||
case Type_Info_Named:
|
||||
try_copy_string(i, buf, info.name) or_return
|
||||
write_string(i, buf, info.name) or_return
|
||||
case Type_Info_Integer:
|
||||
switch ti.id {
|
||||
case int: try_copy_string(i, buf, "int") or_return
|
||||
case uint: try_copy_string(i, buf, "uint") or_return
|
||||
case uintptr: try_copy_string(i, buf, "uintptr") or_return
|
||||
case int: write_string(i, buf, "int") or_return
|
||||
case uint: write_string(i, buf, "uint") or_return
|
||||
case uintptr: write_string(i, buf, "uintptr") or_return
|
||||
case:
|
||||
try_copy_byte(i, buf, 'i' if info.signed else 'u') or_return
|
||||
try_copy_u64(i, buf, u64(8*ti.size)) or_return
|
||||
write_byte(i, buf, 'i' if info.signed else 'u') or_return
|
||||
write_u64 (i, buf, u64(8*ti.size)) or_return
|
||||
}
|
||||
switch info.endianness {
|
||||
case .Platform: // nothing
|
||||
case .Little: write_string(i, buf, "le") or_return
|
||||
case .Big: write_string(i, buf, "be") or_return
|
||||
}
|
||||
|
||||
case Type_Info_Rune:
|
||||
try_copy_string(i, buf, "rune") or_return
|
||||
write_string(i, buf, "rune") or_return
|
||||
case Type_Info_Float:
|
||||
try_copy_byte(i, buf, 'f') or_return
|
||||
try_copy_u64(i, buf, u64(8*ti.size)) or_return
|
||||
write_byte(i, buf, 'f') or_return
|
||||
write_u64(i, buf, u64(8*ti.size)) or_return
|
||||
switch info.endianness {
|
||||
case .Platform: // nothing
|
||||
case .Little: write_string(i, buf, "le") or_return
|
||||
case .Big: write_string(i, buf, "be") or_return
|
||||
}
|
||||
|
||||
case Type_Info_Complex:
|
||||
try_copy_string(i, buf, "complex") or_return
|
||||
try_copy_u64(i, buf, u64(8*ti.size)) or_return
|
||||
write_string(i, buf, "complex") or_return
|
||||
write_u64 (i, buf, u64(8*ti.size)) or_return
|
||||
case Type_Info_Quaternion:
|
||||
try_copy_string(i, buf, "quaternion") or_return
|
||||
try_copy_u64(i, buf, u64(8*ti.size)) or_return
|
||||
write_string(i, buf, "quaternion") or_return
|
||||
write_u64 (i, buf, u64(8*ti.size)) or_return
|
||||
case Type_Info_String:
|
||||
if info.is_cstring {
|
||||
try_copy_byte(i, buf, 'c') or_return
|
||||
write_byte(i, buf, 'c') or_return
|
||||
}
|
||||
try_copy_string(i, buf, "string") or_return
|
||||
write_string(i, buf, "string") or_return
|
||||
switch info.encoding {
|
||||
case .UTF_8: /**/
|
||||
case .UTF_16: try_copy_string(i, buf, "16") or_return
|
||||
case .UTF_16: write_string(i, buf, "16") or_return
|
||||
}
|
||||
case Type_Info_Boolean:
|
||||
switch ti.id {
|
||||
case bool: try_copy_string(i, buf, "bool") or_return
|
||||
case bool: write_string(i, buf, "bool") or_return
|
||||
case:
|
||||
try_copy_byte(i, buf, 'b') or_return
|
||||
try_copy_u64(i, buf, u64(8*ti.size)) or_return
|
||||
write_byte(i, buf, 'b') or_return
|
||||
write_u64 (i, buf, u64(8*ti.size)) or_return
|
||||
}
|
||||
case Type_Info_Any:
|
||||
try_copy_string(i, buf, "any") or_return
|
||||
write_string(i, buf, "any") or_return
|
||||
case Type_Info_Type_Id:
|
||||
try_copy_string(i, buf, "typeid") or_return
|
||||
write_string(i, buf, "typeid") or_return
|
||||
|
||||
case Type_Info_Pointer:
|
||||
if info.elem == nil {
|
||||
try_copy_string(i, buf, "rawptr") or_return
|
||||
write_string(i, buf, "rawptr") or_return
|
||||
} else {
|
||||
try_copy_string(i, buf, "^") or_return
|
||||
try_copy_write_type(i, buf, info.elem) or_return
|
||||
write_string (i, buf, "^") or_return
|
||||
write_write_type(i, buf, info.elem) or_return
|
||||
}
|
||||
case Type_Info_Multi_Pointer:
|
||||
try_copy_string(i, buf, "[^]") or_return
|
||||
try_copy_write_type(i, buf, info.elem) or_return
|
||||
write_string (i, buf, "[^]") or_return
|
||||
write_write_type(i, buf, info.elem) or_return
|
||||
case Type_Info_Soa_Pointer:
|
||||
try_copy_string(i, buf, "#soa ^") or_return
|
||||
try_copy_write_type(i, buf, info.elem) or_return
|
||||
write_string (i, buf, "#soa ^") or_return
|
||||
write_write_type(i, buf, info.elem) or_return
|
||||
case Type_Info_Procedure:
|
||||
try_copy_string(i, buf, "proc") or_return
|
||||
write_string(i, buf, "proc") or_return
|
||||
if info.params == nil {
|
||||
try_copy_string(i, buf, "()") or_return
|
||||
write_string(i, buf, "()") or_return
|
||||
} else {
|
||||
t := info.params.variant.(Type_Info_Parameters)
|
||||
try_copy_byte(i, buf, '(') or_return
|
||||
write_byte(i, buf, '(') or_return
|
||||
for t, j in t.types {
|
||||
if j > 0 { try_copy_string(i, buf, ", ") or_return }
|
||||
try_copy_write_type(i, buf, t) or_return
|
||||
if j > 0 { write_string(i, buf, ", ") or_return }
|
||||
write_write_type(i, buf, t) or_return
|
||||
}
|
||||
try_copy_string(i, buf, ")") or_return
|
||||
write_string(i, buf, ")") or_return
|
||||
}
|
||||
if info.results != nil {
|
||||
try_copy_string(i, buf, " -> ") or_return
|
||||
try_copy_write_type(i, buf, info.results) or_return
|
||||
write_string (i, buf, " -> ") or_return
|
||||
write_write_type(i, buf, info.results) or_return
|
||||
}
|
||||
case Type_Info_Parameters:
|
||||
count := len(info.names)
|
||||
if count != 1 { try_copy_byte(i, buf, '(') or_return }
|
||||
if count != 1 { write_byte(i, buf, '(') or_return }
|
||||
for name, j in info.names {
|
||||
if j > 0 { try_copy_string(i, buf, ", ") or_return }
|
||||
if j > 0 { write_string(i, buf, ", ") or_return }
|
||||
|
||||
t := info.types[j]
|
||||
|
||||
if len(name) > 0 {
|
||||
try_copy_string(i, buf, name) or_return
|
||||
try_copy_string(i, buf, ": ") or_return
|
||||
write_string(i, buf, name) or_return
|
||||
write_string(i, buf, ": ") or_return
|
||||
}
|
||||
try_copy_write_type(i, buf, t) or_return
|
||||
write_write_type(i, buf, t) or_return
|
||||
}
|
||||
if count != 1 { try_copy_string(i, buf, ")") or_return }
|
||||
if count != 1 { write_string(i, buf, ")") or_return }
|
||||
|
||||
case Type_Info_Array:
|
||||
try_copy_byte(i, buf, '[') or_return
|
||||
try_copy_u64(i, buf, u64(info.count)) or_return
|
||||
try_copy_byte(i, buf, ']') or_return
|
||||
try_copy_write_type(i, buf, info.elem) or_return
|
||||
write_byte (i, buf, '[') or_return
|
||||
write_u64 (i, buf, u64(info.count)) or_return
|
||||
write_byte (i, buf, ']') or_return
|
||||
write_write_type(i, buf, info.elem) or_return
|
||||
|
||||
case Type_Info_Enumerated_Array:
|
||||
if info.is_sparse {
|
||||
try_copy_string(i, buf, "#sparse") or_return
|
||||
write_string(i, buf, "#sparse") or_return
|
||||
}
|
||||
try_copy_byte(i, buf, '[') or_return
|
||||
try_copy_write_type(i, buf, info.index) or_return
|
||||
try_copy_byte(i, buf, ']') or_return
|
||||
try_copy_write_type(i, buf, info.elem) or_return
|
||||
write_byte (i, buf, '[') or_return
|
||||
write_write_type(i, buf, info.index) or_return
|
||||
write_byte (i, buf, ']') or_return
|
||||
write_write_type(i, buf, info.elem) or_return
|
||||
|
||||
|
||||
case Type_Info_Dynamic_Array:
|
||||
try_copy_string(i, buf, "[dynamic]") or_return
|
||||
try_copy_write_type(i, buf, info.elem) or_return
|
||||
write_string (i, buf, "[dynamic]") or_return
|
||||
write_write_type(i, buf, info.elem) or_return
|
||||
case Type_Info_Slice:
|
||||
try_copy_string(i, buf, "[]") or_return
|
||||
try_copy_write_type(i, buf, info.elem) or_return
|
||||
write_string (i, buf, "[]") or_return
|
||||
write_write_type(i, buf, info.elem) or_return
|
||||
|
||||
case Type_Info_Map:
|
||||
try_copy_string(i, buf, "map[") or_return
|
||||
try_copy_write_type(i, buf, info.key) or_return
|
||||
try_copy_byte(i, buf, ']') or_return
|
||||
try_copy_write_type(i, buf, info.value) or_return
|
||||
write_string (i, buf, "map[") or_return
|
||||
write_write_type(i, buf, info.key) or_return
|
||||
write_byte (i, buf, ']') or_return
|
||||
write_write_type(i, buf, info.value) or_return
|
||||
|
||||
case Type_Info_Struct:
|
||||
switch info.soa_kind {
|
||||
case .None: // Ignore
|
||||
case .Fixed:
|
||||
try_copy_string(i, buf, "#soa[") or_return
|
||||
try_copy_u64(i, buf, u64(info.soa_len)) or_return
|
||||
try_copy_byte(i, buf, ']') or_return
|
||||
try_copy_write_type(i, buf, info.soa_base_type) or_return
|
||||
write_string (i, buf, "#soa[") or_return
|
||||
write_u64 (i, buf, u64(info.soa_len)) or_return
|
||||
write_byte (i, buf, ']') or_return
|
||||
write_write_type(i, buf, info.soa_base_type) or_return
|
||||
return true
|
||||
case .Slice:
|
||||
try_copy_string(i, buf, "#soa[]") or_return
|
||||
try_copy_write_type(i, buf, info.soa_base_type) or_return
|
||||
write_string (i, buf, "#soa[]") or_return
|
||||
write_write_type(i, buf, info.soa_base_type) or_return
|
||||
return true
|
||||
case .Dynamic:
|
||||
try_copy_string(i, buf, "#soa[dynamic]") or_return
|
||||
try_copy_write_type(i, buf, info.soa_base_type) or_return
|
||||
write_string (i, buf, "#soa[dynamic]") or_return
|
||||
write_write_type(i, buf, info.soa_base_type) or_return
|
||||
return true
|
||||
}
|
||||
|
||||
try_copy_string(i, buf, "struct ") or_return
|
||||
if .packed in info.flags { try_copy_string(i, buf, "#packed ") or_return }
|
||||
if .raw_union in info.flags { try_copy_string(i, buf, "#raw_union ") or_return }
|
||||
if .all_or_none in info.flags { try_copy_string(i, buf, "#all_or_none ") or_return }
|
||||
write_string(i, buf, "struct ") or_return
|
||||
if .packed in info.flags { write_string(i, buf, "#packed ") or_return }
|
||||
if .raw_union in info.flags { write_string(i, buf, "#raw_union ") or_return }
|
||||
if .all_or_none in info.flags { write_string(i, buf, "#all_or_none ") or_return }
|
||||
if .simple in info.flags { write_string(i, buf, "#simple ") or_return }
|
||||
if .align in info.flags {
|
||||
try_copy_string(i, buf, "#align(") or_return
|
||||
try_copy_u64(i, buf, u64(ti.align)) or_return
|
||||
try_copy_string(i, buf, ") ") or_return
|
||||
write_string(i, buf, "#align(") or_return
|
||||
write_u64(i, buf, u64(ti.align)) or_return
|
||||
write_string(i, buf, ") ") or_return
|
||||
}
|
||||
try_copy_byte(i, buf, '{') or_return
|
||||
write_byte(i, buf, '{') or_return
|
||||
for name, j in info.names[:info.field_count] {
|
||||
if j > 0 { try_copy_string(i, buf, ", ") or_return }
|
||||
try_copy_string(i, buf, name) or_return
|
||||
try_copy_string(i, buf, ": ") or_return
|
||||
try_copy_write_type(i, buf, info.types[j]) or_return
|
||||
if j > 0 { write_string(i, buf, ", ") or_return }
|
||||
write_string (i, buf, name) or_return
|
||||
write_string (i, buf, ": ") or_return
|
||||
write_write_type(i, buf, info.types[j]) or_return
|
||||
}
|
||||
try_copy_byte(i, buf, '}') or_return
|
||||
write_byte(i, buf, '}') or_return
|
||||
|
||||
case Type_Info_Union:
|
||||
try_copy_string(i, buf, "union ") or_return
|
||||
write_string(i, buf, "union ") or_return
|
||||
if info.custom_align {
|
||||
try_copy_string(i, buf, "#align(") or_return
|
||||
try_copy_u64(i, buf, u64(ti.align)) or_return
|
||||
try_copy_string(i, buf, ") ") or_return
|
||||
write_string(i, buf, "#align(") or_return
|
||||
write_u64 (i, buf, u64(ti.align)) or_return
|
||||
write_string(i, buf, ") ") or_return
|
||||
}
|
||||
if info.no_nil {
|
||||
try_copy_string(i, buf, "#no_nil ") or_return
|
||||
write_string(i, buf, "#no_nil ") or_return
|
||||
}
|
||||
try_copy_byte(i, buf, '{') or_return
|
||||
write_byte(i, buf, '{') or_return
|
||||
for variant, j in info.variants {
|
||||
if j > 0 { try_copy_string(i, buf, ", ") or_return }
|
||||
try_copy_write_type(i, buf, variant) or_return
|
||||
if j > 0 { write_string(i, buf, ", ") or_return }
|
||||
write_write_type(i, buf, variant) or_return
|
||||
}
|
||||
try_copy_string(i, buf, "}") or_return
|
||||
write_string(i, buf, "}") or_return
|
||||
|
||||
case Type_Info_Enum:
|
||||
try_copy_string(i, buf, "enum ") or_return
|
||||
try_copy_write_type(i, buf, info.base) or_return
|
||||
try_copy_string(i, buf, " {") or_return
|
||||
write_string (i, buf, "enum ") or_return
|
||||
write_write_type(i, buf, info.base) or_return
|
||||
write_string (i, buf, " {") or_return
|
||||
for name, j in info.names {
|
||||
if j > 0 { try_copy_string(i, buf, ", ") or_return }
|
||||
try_copy_string(i, buf, name) or_return
|
||||
if j > 0 { write_string(i, buf, ", ") or_return }
|
||||
write_string(i, buf, name) or_return
|
||||
}
|
||||
try_copy_string(i, buf, "}") or_return
|
||||
write_string(i, buf, "}") or_return
|
||||
|
||||
case Type_Info_Bit_Set:
|
||||
try_copy_string(i, buf, "bit_set[") or_return
|
||||
write_string(i, buf, "bit_set[") or_return
|
||||
|
||||
#partial switch elem in type_info_base(info.elem).variant {
|
||||
case Type_Info_Enum:
|
||||
try_copy_write_type(i, buf, info.elem) or_return
|
||||
write_write_type(i, buf, info.elem) or_return
|
||||
case Type_Info_Rune:
|
||||
print_encoded_rune(rune(info.lower))
|
||||
try_copy_string(i, buf, "..") or_return
|
||||
print_encoded_rune(rune(info.upper))
|
||||
write_encoded_rune(i, buf, rune(info.lower)) or_return
|
||||
write_string (i, buf, "..") or_return
|
||||
write_encoded_rune(i, buf, rune(info.upper)) or_return
|
||||
case:
|
||||
print_i64(info.lower)
|
||||
try_copy_string(i, buf, "..") or_return
|
||||
print_i64(info.upper)
|
||||
write_i64 (i, buf, info.lower) or_return
|
||||
write_string(i, buf, "..") or_return
|
||||
write_i64 (i, buf, info.upper) or_return
|
||||
}
|
||||
if info.underlying != nil {
|
||||
try_copy_string(i, buf, "; ") or_return
|
||||
try_copy_write_type(i, buf, info.underlying) or_return
|
||||
write_string (i, buf, "; ") or_return
|
||||
write_write_type(i, buf, info.underlying) or_return
|
||||
}
|
||||
try_copy_byte(i, buf, ']') or_return
|
||||
write_byte(i, buf, ']') or_return
|
||||
|
||||
case Type_Info_Bit_Field:
|
||||
try_copy_string(i, buf, "bit_field ") or_return
|
||||
try_copy_write_type(i, buf, info.backing_type) or_return
|
||||
try_copy_string(i, buf, " {") or_return
|
||||
write_string (i, buf, "bit_field ") or_return
|
||||
write_write_type(i, buf, info.backing_type) or_return
|
||||
write_string (i, buf, " {") or_return
|
||||
for name, j in info.names[:info.field_count] {
|
||||
if j > 0 { try_copy_string(i, buf, ", ") or_return }
|
||||
try_copy_string(i, buf, name) or_return
|
||||
try_copy_string(i, buf, ": ") or_return
|
||||
try_copy_write_type(i, buf, info.types[j]) or_return
|
||||
try_copy_string(i, buf, " | ") or_return
|
||||
try_copy_u64(i, buf, u64(info.bit_sizes[j])) or_return
|
||||
if j > 0 { write_string(i, buf, ", ") or_return }
|
||||
write_string (i, buf, name) or_return
|
||||
write_string (i, buf, ": ") or_return
|
||||
write_write_type(i, buf, info.types[j]) or_return
|
||||
write_string (i, buf, " | ") or_return
|
||||
write_u64 (i, buf, u64(info.bit_sizes[j])) or_return
|
||||
}
|
||||
try_copy_byte(i, buf, '}') or_return
|
||||
write_byte(i, buf, '}') or_return
|
||||
|
||||
|
||||
case Type_Info_Simd_Vector:
|
||||
try_copy_string(i, buf, "#simd[") or_return
|
||||
try_copy_u64(i, buf, u64(info.count)) or_return
|
||||
try_copy_byte(i, buf, ']') or_return
|
||||
try_copy_write_type(i, buf, info.elem) or_return
|
||||
write_string (i, buf, "#simd[") or_return
|
||||
write_u64 (i, buf, u64(info.count)) or_return
|
||||
write_byte (i, buf, ']') or_return
|
||||
write_write_type(i, buf, info.elem) or_return
|
||||
|
||||
case Type_Info_Matrix:
|
||||
try_copy_string(i, buf, "matrix[") or_return
|
||||
try_copy_u64(i, buf, u64(info.row_count)) or_return
|
||||
try_copy_string(i, buf, ", ") or_return
|
||||
try_copy_u64(i, buf, u64(info.column_count)) or_return
|
||||
try_copy_string(i, buf, "]") or_return
|
||||
try_copy_write_type(i, buf, info.elem) or_return
|
||||
if info.layout == .Row_Major {
|
||||
write_string(i, buf, "#row_major ") or_return
|
||||
}
|
||||
write_string (i, buf, "matrix[") or_return
|
||||
write_u64 (i, buf, u64(info.row_count)) or_return
|
||||
write_string (i, buf, ", ") or_return
|
||||
write_u64 (i, buf, u64(info.column_count)) or_return
|
||||
write_string (i, buf, "]") or_return
|
||||
write_write_type(i, buf, info.elem) or_return
|
||||
}
|
||||
return true
|
||||
}
|
||||
56
core/container/handle_map/doc.odin
Normal file
56
core/container/handle_map/doc.odin
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Handle-based map using fixed-length arrays.
|
||||
|
||||
Example:
|
||||
import hm "core:container/handle_map"
|
||||
|
||||
Handle :: hm.Handle32
|
||||
|
||||
Entity :: struct {
|
||||
handle: Handle,
|
||||
pos: [2]f32,
|
||||
}
|
||||
|
||||
{ // static map
|
||||
entities: hm.Static_Handle_Map(1024, Entity, Handle)
|
||||
|
||||
h1 := hm.add(&entities, Entity{pos = {1, 4}})
|
||||
h2 := hm.add(&entities, Entity{pos = {9, 16}})
|
||||
|
||||
if e, ok := hm.get(&entities, h2); ok {
|
||||
e.pos.x += 32
|
||||
}
|
||||
|
||||
hm.remove(&entities, h1)
|
||||
|
||||
h3 := hm.add(&entities, Entity{pos = {6, 7}})
|
||||
|
||||
it := hm.iterator_make(&entities)
|
||||
for e, h in hm.iterate(&it) {
|
||||
e.pos += {1, 2}
|
||||
}
|
||||
}
|
||||
|
||||
{ // dynamic map
|
||||
entities: hm.Dynamic_Handle_Map(Entity, Handle)
|
||||
hm.dynamic_init(&entities, context.allocator)
|
||||
defer hm.dynamic_destroy(&entities)
|
||||
|
||||
h1 := hm.add(&entities, Entity{pos = {1, 4}})
|
||||
h2 := hm.add(&entities, Entity{pos = {9, 16}})
|
||||
|
||||
if e, ok := hm.get(&entities, h2); ok {
|
||||
e.pos.x += 32
|
||||
}
|
||||
|
||||
hm.remove(&entities, h1)
|
||||
|
||||
h3 := hm.add(&entities, Entity{pos = {6, 7}})
|
||||
|
||||
it := hm.iterator_make(&entities)
|
||||
for e, h in hm.iterate(&it) {
|
||||
e.pos += {1, 2}
|
||||
}
|
||||
}
|
||||
*/
|
||||
package container_handle_map
|
||||
141
core/container/handle_map/dynamic_handle_map.odin
Normal file
141
core/container/handle_map/dynamic_handle_map.odin
Normal file
@@ -0,0 +1,141 @@
|
||||
package container_handle_map
|
||||
|
||||
import "base:runtime"
|
||||
import "base:builtin"
|
||||
import "base:intrinsics"
|
||||
@(require) import "core:container/xar"
|
||||
|
||||
Dynamic_Handle_Map :: struct($T: typeid, $Handle_Type: typeid)
|
||||
where
|
||||
intrinsics.type_has_field(Handle_Type, "idx"),
|
||||
intrinsics.type_has_field(Handle_Type, "gen"),
|
||||
intrinsics.type_is_unsigned(intrinsics.type_field_type(Handle_Type, "idx")),
|
||||
intrinsics.type_is_unsigned(intrinsics.type_field_type(Handle_Type, "gen")),
|
||||
intrinsics.type_field_type(Handle_Type, "idx") == intrinsics.type_field_type(Handle_Type, "gen"),
|
||||
|
||||
intrinsics.type_has_field (T, "handle"),
|
||||
intrinsics.type_field_type(T, "handle") == Handle_Type {
|
||||
|
||||
items: xar.Array(T, 4),
|
||||
unused_items: xar.Array(u32, 4),
|
||||
}
|
||||
|
||||
dynamic_init :: proc(m: ^$D/Dynamic_Handle_Map($T, $Handle_Type), allocator: runtime.Allocator) {
|
||||
xar.init(&m.items, allocator)
|
||||
xar.init(&m.unused_items, allocator)
|
||||
}
|
||||
|
||||
dynamic_destroy :: proc(m: ^$D/Dynamic_Handle_Map($T, $Handle_Type)) {
|
||||
xar.destroy(&m.unused_items)
|
||||
xar.destroy(&m.items)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
dynamic_add :: proc(m: ^$D/Dynamic_Handle_Map($T, $Handle_Type), item: T, loc := #caller_location) -> (handle: Handle_Type, err: runtime.Allocator_Error) {
|
||||
if xar.len(m.unused_items) > 0 {
|
||||
i := xar.pop(&m.unused_items)
|
||||
ptr := xar.get_ptr_unsafe(&m.items, i)
|
||||
prev_gen := ptr.handle.gen
|
||||
ptr^ = item
|
||||
|
||||
ptr.handle.idx = auto_cast i
|
||||
ptr.handle.gen = auto_cast (prev_gen + 1)
|
||||
return ptr.handle, nil
|
||||
}
|
||||
|
||||
if xar.len(m.items) == 0 {
|
||||
// initialize the zero-value sentinel
|
||||
xar.append(&m.items, T{}, loc) or_return
|
||||
}
|
||||
|
||||
i := xar.append(&m.items, item, loc) or_return
|
||||
|
||||
ptr := xar.get_ptr_unsafe(&m.items, i)
|
||||
ptr^ = item
|
||||
|
||||
ptr.handle.idx = auto_cast i
|
||||
ptr.handle.gen = 1
|
||||
return ptr.handle, nil
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
dynamic_get :: proc "contextless" (m: ^$D/Dynamic_Handle_Map($T, $Handle_Type), h: Handle_Type) -> (^T, bool) #optional_ok {
|
||||
if h.idx <= 0 || int(u32(h.idx)) >= xar.len(m.items) {
|
||||
return nil, false
|
||||
}
|
||||
if e := xar.get_ptr_unsafe(&m.items, h.idx); e.handle == h {
|
||||
return e, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
dynamic_remove :: proc(m: ^$D/Dynamic_Handle_Map($T, $Handle_Type), h: Handle_Type, loc := #caller_location) -> (found: bool, err: runtime.Allocator_Error) {
|
||||
if h.idx <= 0 || int(u32(h.idx)) >= xar.len(m.items) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if item := xar.get_ptr(&m.items, h.idx); item.handle == h {
|
||||
xar.append(&m.unused_items, u32(h.idx), loc) or_return
|
||||
item.handle.idx = 0
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
dynamic_is_valid :: proc "contextless" (m: ^$D/Dynamic_Handle_Map($T, $Handle_Type), h: Handle_Type) -> bool {
|
||||
return h.idx > 0 && int(u32(h.idx)) < xar.len(m.items) && xar.get_ptr_unsafe(&m.items, h.idx).handle == h
|
||||
}
|
||||
|
||||
// Returns the number of possibly valid items in the handle map.
|
||||
@(require_results)
|
||||
dynamic_len :: proc "contextless" (m: $D/Dynamic_Handle_Map($T, $Handle_Type)) -> uint {
|
||||
n := xar.len(m.items) - xar.len(m.unused_items)
|
||||
return uint(n-1 if n > 0 else 0)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
dynamic_cap :: proc "contextless" (m: $D/Dynamic_Handle_Map($T, $Handle_Type)) -> uint {
|
||||
n := xar.cap(m.items)
|
||||
return uint(n-1 if n > 0 else 0)
|
||||
}
|
||||
|
||||
dynamic_clear :: proc "contextless" (m: ^$D/Dynamic_Handle_Map($T, $Handle_Type)) {
|
||||
xar.clear(&m.items)
|
||||
xar.clear(&m.unused_items)
|
||||
}
|
||||
|
||||
|
||||
// An iterator for a handle map.
|
||||
Dynamic_Handle_Map_Iterator :: struct($D: typeid) {
|
||||
m: ^D,
|
||||
index: int,
|
||||
}
|
||||
|
||||
// Makes an iterator from a handle map.
|
||||
@(require_results)
|
||||
dynamic_iterator_make :: proc "contextless" (m: ^$D/Dynamic_Handle_Map($T, $Handle_Type)) -> Dynamic_Handle_Map_Iterator(D) {
|
||||
return {m, 1}
|
||||
}
|
||||
|
||||
/*
|
||||
Iterate over a handle map. It will skip over unused item slots (e.g. handle.idx == 0).
|
||||
Usage:
|
||||
it := hm.dynamic_iterator_make(&the_dynamic_handle_map)
|
||||
for item, handle in hm.iterate(&it) {
|
||||
...
|
||||
}
|
||||
*/
|
||||
@(require_results)
|
||||
dynamic_iterate :: proc "contextless" (it: ^$DHI/Dynamic_Handle_Map_Iterator($D/Dynamic_Handle_Map($T, $Handle_Type))) -> (val: ^T, h: Handle_Type, ok: bool) {
|
||||
for _ in it.index..<xar.len(it.m.items) {
|
||||
e := xar.get_ptr_unsafe(&it.m.items, it.index)
|
||||
it.index += 1
|
||||
|
||||
if e.handle.idx != 0 {
|
||||
return e, e.handle, true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
221
core/container/handle_map/static_handle_map.odin
Normal file
221
core/container/handle_map/static_handle_map.odin
Normal file
@@ -0,0 +1,221 @@
|
||||
package container_handle_map
|
||||
|
||||
import "base:builtin"
|
||||
import "base:intrinsics"
|
||||
|
||||
// Default 16-bit Handle type which can be used for handle maps which only need a maximum of 254 (1<<8 - 2) items
|
||||
Handle16 :: struct {
|
||||
idx: u8,
|
||||
gen: u8,
|
||||
}
|
||||
|
||||
// Default 32-bit Handle type which can be used for handle maps which only need a maximum of 65534 (1<<16 - 2) items
|
||||
Handle32 :: struct {
|
||||
idx: u16,
|
||||
gen: u16,
|
||||
}
|
||||
|
||||
// Default 64-bit Handle type which can be used for handle maps which only need a maximum of 4294967294 (1<<32 - 2) items
|
||||
Handle64 :: struct {
|
||||
idx: u32,
|
||||
gen: u32,
|
||||
}
|
||||
|
||||
Static_Handle_Map :: struct($N: uint, $T: typeid, $Handle_Type: typeid)
|
||||
where
|
||||
0 < N, N < uint(1<<31 - 1),
|
||||
|
||||
intrinsics.type_has_field(Handle_Type, "idx"),
|
||||
intrinsics.type_has_field(Handle_Type, "gen"),
|
||||
intrinsics.type_is_unsigned(intrinsics.type_field_type(Handle_Type, "idx")),
|
||||
intrinsics.type_is_unsigned(intrinsics.type_field_type(Handle_Type, "gen")),
|
||||
intrinsics.type_field_type(Handle_Type, "idx") == intrinsics.type_field_type(Handle_Type, "gen"),
|
||||
|
||||
N < uint(max(intrinsics.type_field_type(Handle_Type, "idx"))),
|
||||
|
||||
intrinsics.type_has_field (T, "handle"),
|
||||
intrinsics.type_field_type(T, "handle") == Handle_Type {
|
||||
|
||||
// The zero element represent a zero-value sentinel (dummy value), allowing for `idx == 0` to mean a no-handle.
|
||||
// This means the capacity is actually N-1 items.
|
||||
items: [N]T,
|
||||
|
||||
used_len: u32, // How many of the items are in use
|
||||
unused_len: u32, // Use to calculate the number of valid items
|
||||
unused_items: [N]u32,
|
||||
next_unused: u32,
|
||||
}
|
||||
|
||||
|
||||
// `add` a value of type `T` to the handle map. This will return a pointer to the item and an optional boolean to check for validity.
|
||||
@(require_results)
|
||||
static_add :: proc "contextless" (m: ^$H/Static_Handle_Map($N, $T, $Handle_Type), item: T) -> (handle: Handle_Type, ok: bool) #optional_ok {
|
||||
if i := m.next_unused; i != 0 {
|
||||
ptr := &m.items[i]
|
||||
|
||||
m.next_unused = m.unused_items[i]
|
||||
m.unused_items[i] = 0
|
||||
|
||||
prev_gen := ptr.handle.gen
|
||||
ptr^ = item
|
||||
|
||||
ptr.handle.idx = auto_cast i
|
||||
ptr.handle.gen = auto_cast (prev_gen + 1)
|
||||
m.unused_len -= 1
|
||||
return ptr.handle, true
|
||||
}
|
||||
|
||||
if m.used_len == 0 {
|
||||
// initialize the zero-value sentinel
|
||||
m.items[0] = {}
|
||||
m.used_len += 1
|
||||
}
|
||||
|
||||
if m.used_len == builtin.len(m.items) {
|
||||
return {}, false
|
||||
}
|
||||
|
||||
ptr := &m.items[m.used_len]
|
||||
ptr^ = item
|
||||
|
||||
ptr.handle.idx = auto_cast m.used_len
|
||||
ptr.handle.gen = 1
|
||||
m.used_len += 1
|
||||
return ptr.handle, true
|
||||
}
|
||||
|
||||
// `get` a stable pointer of type `^T` by resolving the handle `h`. If the handle is not valid, then `nil, false` is returned.
|
||||
@(require_results)
|
||||
static_get :: proc "contextless" (m: ^$H/Static_Handle_Map($N, $T, $Handle_Type), h: Handle_Type) -> (^T, bool) #optional_ok {
|
||||
if h.idx <= 0 || u32(h.idx) >= m.used_len {
|
||||
return nil, false
|
||||
}
|
||||
if e := &m.items[h.idx]; e.handle == h {
|
||||
return e, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// `remove` an item from the handle map from the handle `h`.
|
||||
static_remove :: proc "contextless" (m: ^$H/Static_Handle_Map($N, $T, $Handle_Type), h: Handle_Type) -> bool {
|
||||
if h.idx <= 0 || u32(h.idx) >= m.used_len {
|
||||
return false
|
||||
}
|
||||
|
||||
if item := &m.items[h.idx]; item.handle == h {
|
||||
m.unused_items[h.idx] = m.next_unused
|
||||
m.next_unused = u32(h.idx)
|
||||
m.unused_len += 1
|
||||
item.handle.idx = 0
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns true when the handle `h` is valid relating to the handle map.
|
||||
@(require_results)
|
||||
static_is_valid :: proc "contextless" (m: $H/Static_Handle_Map($N, $T, $Handle_Type), h: Handle_Type) -> bool {
|
||||
return h.idx > 0 && u32(h.idx) < m.used_len && m.items[h.idx].handle == h
|
||||
}
|
||||
|
||||
// Returns the number of possibly valid items in the handle map.
|
||||
@(require_results)
|
||||
static_len :: proc "contextless" (m: $H/Static_Handle_Map($N, $T, $Handle_Type)) -> uint {
|
||||
n := uint(m.used_len) - uint(m.unused_len)
|
||||
return n-1 if n > 0 else 0
|
||||
}
|
||||
|
||||
// Returns the capacity of the items in a handle map.
|
||||
// This is equivalent to `N-1` as the zero value is reserved for the zero-value sentinel.
|
||||
@(require_results)
|
||||
static_cap :: proc "contextless" (m: $H/Static_Handle_Map($N, $T, $Handle_Type)) -> uint {
|
||||
// We could just return `N` but I am doing this for clarity
|
||||
return builtin.len(m.items)-1
|
||||
}
|
||||
|
||||
// `clear` the handle map by zeroing all of the memory.
|
||||
// Internally this does not do `m^ = {}` but rather uses `intrinsics.mem_zero` explicitly improve performance.
|
||||
static_clear :: proc "contextless" (m: ^$H/Static_Handle_Map($N, $T, $Handle_Type)) {
|
||||
intrinsics.mem_zero(m, size_of(m^))
|
||||
}
|
||||
|
||||
// An iterator for a handle map.
|
||||
Static_Handle_Map_Iterator :: struct($H: typeid) {
|
||||
m: ^H,
|
||||
index: u32,
|
||||
}
|
||||
|
||||
// Makes an iterator from a handle map.
|
||||
@(require_results)
|
||||
static_iterator_make :: proc "contextless" (m: ^$H/Static_Handle_Map($N, $T, $Handle_Type)) -> Static_Handle_Map_Iterator(H) {
|
||||
return {m, 1}
|
||||
}
|
||||
|
||||
/*
|
||||
Iterate over a handle map. It will skip over unused item slots (e.g. handle.idx == 0).
|
||||
Usage:
|
||||
it := hm.iterator_make(&the_handle_map)
|
||||
for item, handle in hm.iterate(&it) {
|
||||
...
|
||||
}
|
||||
*/
|
||||
@(require_results)
|
||||
static_iterate :: proc "contextless" (it: ^$HI/Static_Handle_Map_Iterator($H/Static_Handle_Map($N, $T, $Handle_Type))) -> (val: ^T, h: Handle_Type, ok: bool) {
|
||||
for _ in it.index..<it.m.used_len {
|
||||
e := &it.m.items[it.index]
|
||||
it.index += 1
|
||||
|
||||
if e.handle.idx != 0 {
|
||||
return e, e.handle, true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
add :: proc{
|
||||
static_add,
|
||||
dynamic_add,
|
||||
}
|
||||
|
||||
get :: proc{
|
||||
static_get,
|
||||
dynamic_get,
|
||||
}
|
||||
|
||||
remove :: proc{
|
||||
static_remove,
|
||||
dynamic_remove,
|
||||
}
|
||||
|
||||
is_valid :: proc{
|
||||
static_is_valid,
|
||||
dynamic_is_valid,
|
||||
}
|
||||
|
||||
len :: proc{
|
||||
static_len,
|
||||
dynamic_len,
|
||||
}
|
||||
|
||||
cap :: proc{
|
||||
static_cap,
|
||||
dynamic_cap,
|
||||
}
|
||||
|
||||
clear :: proc{
|
||||
static_clear,
|
||||
dynamic_clear,
|
||||
}
|
||||
|
||||
iterator_make :: proc{
|
||||
static_iterator_make,
|
||||
dynamic_iterator_make,
|
||||
}
|
||||
|
||||
iterate :: proc{
|
||||
static_iterate,
|
||||
dynamic_iterate,
|
||||
}
|
||||
@@ -109,19 +109,19 @@ destroy :: proc(x: ^$X/Array($T, $SHIFT)) {
|
||||
Resets the array's length to zero without freeing memory.
|
||||
Allocated chunks are retained for reuse.
|
||||
*/
|
||||
clear :: proc(x: ^$X/Array($T, $SHIFT)) {
|
||||
clear :: proc "contextless" (x: ^$X/Array($T, $SHIFT)) {
|
||||
x.len = 0
|
||||
}
|
||||
|
||||
// Returns the length of the exponential-array
|
||||
@(require_results)
|
||||
len :: proc(x: $X/Array($T, $SHIFT)) -> int {
|
||||
len :: proc "contextless" (x: $X/Array($T, $SHIFT)) -> int {
|
||||
return x.len
|
||||
}
|
||||
|
||||
// Returns the number of allocated elements
|
||||
@(require_results)
|
||||
cap :: proc(x: $X/Array($T, $SHIFT)) -> int {
|
||||
cap :: proc "contextless" (x: $X/Array($T, $SHIFT)) -> int {
|
||||
#reverse for c, i in x.chunks {
|
||||
if c != nil {
|
||||
return 1 << (SHIFT + uint(i if i > 0 else 1))
|
||||
@@ -132,7 +132,7 @@ cap :: proc(x: $X/Array($T, $SHIFT)) -> int {
|
||||
|
||||
// Internal: computes chunk index, element index within chunk, and chunk capacity for a given index.
|
||||
@(require_results)
|
||||
_meta_get :: #force_inline proc($SHIFT: uint, index: uint) -> (chunk_idx, elem_idx, chunk_cap: uint) {
|
||||
_meta_get :: #force_inline proc "contextless" ($SHIFT: uint, index: uint) -> (chunk_idx, elem_idx, chunk_cap: uint) {
|
||||
elem_idx = index
|
||||
chunk_cap = uint(1) << SHIFT
|
||||
chunk_idx = 0
|
||||
@@ -206,6 +206,13 @@ get_ptr :: proc(x: ^$X/Array($T, $SHIFT), #any_int index: int, loc := #caller_lo
|
||||
return &x.chunks[chunk_idx][elem_idx]
|
||||
}
|
||||
|
||||
// No bounds checking
|
||||
@(require_results)
|
||||
get_ptr_unsafe :: proc "contextless" (x: ^$X/Array($T, $SHIFT), #any_int index: int) -> (val: ^T) #no_bounds_check {
|
||||
chunk_idx, elem_idx, _ := _meta_get(SHIFT, uint(index))
|
||||
return &x.chunks[chunk_idx][elem_idx]
|
||||
}
|
||||
|
||||
/*
|
||||
Set the element at the specified index to the given value.
|
||||
|
||||
|
||||
@@ -4,133 +4,68 @@ import "core:crypto/_chacha20"
|
||||
import "core:encoding/endian"
|
||||
import "core:math/bits"
|
||||
|
||||
// At least with LLVM21 force_inline produces identical perf to
|
||||
// manual inlining, yay.
|
||||
@(private)
|
||||
quarter_round :: #force_inline proc "contextless" (a, b, c, d: u32) -> (u32, u32, u32, u32) {
|
||||
a, b, c, d := a, b, c, d
|
||||
|
||||
a += b
|
||||
d ~= a
|
||||
d = bits.rotate_left32(d, 16)
|
||||
|
||||
c += d
|
||||
b ~= c
|
||||
b = bits.rotate_left32(b, 12)
|
||||
|
||||
a += b
|
||||
d ~= a
|
||||
d = bits.rotate_left32(d, 8)
|
||||
|
||||
c += d
|
||||
b ~= c
|
||||
b = bits.rotate_left32(b, 7)
|
||||
|
||||
return a, b, c, d
|
||||
}
|
||||
|
||||
stream_blocks :: proc(ctx: ^_chacha20.Context, dst, src: []byte, nr_blocks: int) {
|
||||
// Enforce the maximum consumed keystream per IV.
|
||||
_chacha20.check_counter_limit(ctx, nr_blocks)
|
||||
|
||||
dst, src := dst, src
|
||||
x := &ctx._s
|
||||
|
||||
|
||||
// Filippo Valsorda made an observation that only one of the column
|
||||
// round depends on the counter (s12), so it is worth precomputing
|
||||
// and reusing across multiple blocks. As far as I know, only Go's
|
||||
// chacha implementation does this.
|
||||
|
||||
p1, p5, p9, p13 := quarter_round(_chacha20.SIGMA_1, x[5], x[9], x[13])
|
||||
p2, p6, p10, p14 := quarter_round(_chacha20.SIGMA_2, x[6], x[10], x[14])
|
||||
p3, p7, p11, p15 := quarter_round(_chacha20.SIGMA_3, x[7], x[11], x[15])
|
||||
|
||||
for n := 0; n < nr_blocks; n = n + 1 {
|
||||
x0, x1, x2, x3 :=
|
||||
_chacha20.SIGMA_0, _chacha20.SIGMA_1, _chacha20.SIGMA_2, _chacha20.SIGMA_3
|
||||
x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 :=
|
||||
x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15]
|
||||
// First column round that depends on the counter
|
||||
p0, p4, p8, p12 := quarter_round(_chacha20.SIGMA_0, x[4], x[8], x[12])
|
||||
|
||||
for i := _chacha20.ROUNDS; i > 0; i = i - 2 {
|
||||
// Even when forcing inlining manually inlining all of
|
||||
// these is decently faster.
|
||||
// First diagonal round
|
||||
x0, x5, x10, x15 := quarter_round(p0, p5, p10, p15)
|
||||
x1, x6, x11, x12 := quarter_round(p1, p6, p11, p12)
|
||||
x2, x7, x8, x13 := quarter_round(p2, p7, p8, p13)
|
||||
x3, x4, x9, x14 := quarter_round(p3, p4, p9, p14)
|
||||
|
||||
// quarterround(x, 0, 4, 8, 12)
|
||||
x0 += x4
|
||||
x12 ~= x0
|
||||
x12 = bits.rotate_left32(x12, 16)
|
||||
x8 += x12
|
||||
x4 ~= x8
|
||||
x4 = bits.rotate_left32(x4, 12)
|
||||
x0 += x4
|
||||
x12 ~= x0
|
||||
x12 = bits.rotate_left32(x12, 8)
|
||||
x8 += x12
|
||||
x4 ~= x8
|
||||
x4 = bits.rotate_left32(x4, 7)
|
||||
for i := _chacha20.ROUNDS - 2; i > 0; i = i - 2 {
|
||||
x0, x4, x8, x12 = quarter_round(x0, x4, x8, x12)
|
||||
x1, x5, x9, x13 = quarter_round(x1, x5, x9, x13)
|
||||
x2, x6, x10, x14 = quarter_round(x2, x6, x10, x14)
|
||||
x3, x7, x11, x15 = quarter_round(x3, x7, x11, x15)
|
||||
|
||||
// quarterround(x, 1, 5, 9, 13)
|
||||
x1 += x5
|
||||
x13 ~= x1
|
||||
x13 = bits.rotate_left32(x13, 16)
|
||||
x9 += x13
|
||||
x5 ~= x9
|
||||
x5 = bits.rotate_left32(x5, 12)
|
||||
x1 += x5
|
||||
x13 ~= x1
|
||||
x13 = bits.rotate_left32(x13, 8)
|
||||
x9 += x13
|
||||
x5 ~= x9
|
||||
x5 = bits.rotate_left32(x5, 7)
|
||||
|
||||
// quarterround(x, 2, 6, 10, 14)
|
||||
x2 += x6
|
||||
x14 ~= x2
|
||||
x14 = bits.rotate_left32(x14, 16)
|
||||
x10 += x14
|
||||
x6 ~= x10
|
||||
x6 = bits.rotate_left32(x6, 12)
|
||||
x2 += x6
|
||||
x14 ~= x2
|
||||
x14 = bits.rotate_left32(x14, 8)
|
||||
x10 += x14
|
||||
x6 ~= x10
|
||||
x6 = bits.rotate_left32(x6, 7)
|
||||
|
||||
// quarterround(x, 3, 7, 11, 15)
|
||||
x3 += x7
|
||||
x15 ~= x3
|
||||
x15 = bits.rotate_left32(x15, 16)
|
||||
x11 += x15
|
||||
x7 ~= x11
|
||||
x7 = bits.rotate_left32(x7, 12)
|
||||
x3 += x7
|
||||
x15 ~= x3
|
||||
x15 = bits.rotate_left32(x15, 8)
|
||||
x11 += x15
|
||||
x7 ~= x11
|
||||
x7 = bits.rotate_left32(x7, 7)
|
||||
|
||||
// quarterround(x, 0, 5, 10, 15)
|
||||
x0 += x5
|
||||
x15 ~= x0
|
||||
x15 = bits.rotate_left32(x15, 16)
|
||||
x10 += x15
|
||||
x5 ~= x10
|
||||
x5 = bits.rotate_left32(x5, 12)
|
||||
x0 += x5
|
||||
x15 ~= x0
|
||||
x15 = bits.rotate_left32(x15, 8)
|
||||
x10 += x15
|
||||
x5 ~= x10
|
||||
x5 = bits.rotate_left32(x5, 7)
|
||||
|
||||
// quarterround(x, 1, 6, 11, 12)
|
||||
x1 += x6
|
||||
x12 ~= x1
|
||||
x12 = bits.rotate_left32(x12, 16)
|
||||
x11 += x12
|
||||
x6 ~= x11
|
||||
x6 = bits.rotate_left32(x6, 12)
|
||||
x1 += x6
|
||||
x12 ~= x1
|
||||
x12 = bits.rotate_left32(x12, 8)
|
||||
x11 += x12
|
||||
x6 ~= x11
|
||||
x6 = bits.rotate_left32(x6, 7)
|
||||
|
||||
// quarterround(x, 2, 7, 8, 13)
|
||||
x2 += x7
|
||||
x13 ~= x2
|
||||
x13 = bits.rotate_left32(x13, 16)
|
||||
x8 += x13
|
||||
x7 ~= x8
|
||||
x7 = bits.rotate_left32(x7, 12)
|
||||
x2 += x7
|
||||
x13 ~= x2
|
||||
x13 = bits.rotate_left32(x13, 8)
|
||||
x8 += x13
|
||||
x7 ~= x8
|
||||
x7 = bits.rotate_left32(x7, 7)
|
||||
|
||||
// quarterround(x, 3, 4, 9, 14)
|
||||
x3 += x4
|
||||
x14 ~= x3
|
||||
x14 = bits.rotate_left32(x14, 16)
|
||||
x9 += x14
|
||||
x4 ~= x9
|
||||
x4 = bits.rotate_left32(x4, 12)
|
||||
x3 += x4
|
||||
x14 ~= x3
|
||||
x14 = bits.rotate_left32(x14, 8)
|
||||
x9 += x14
|
||||
x4 ~= x9
|
||||
x4 = bits.rotate_left32(x4, 7)
|
||||
x0, x5, x10, x15 = quarter_round(x0, x5, x10, x15)
|
||||
x1, x6, x11, x12 = quarter_round(x1, x6, x11, x12)
|
||||
x2, x7, x8, x13 = quarter_round(x2, x7, x8, x13)
|
||||
x3, x4, x9, x14 = quarter_round(x3, x4, x9, x14)
|
||||
}
|
||||
|
||||
x0 += _chacha20.SIGMA_0
|
||||
@@ -236,117 +171,15 @@ hchacha20 :: proc "contextless" (dst, key, iv: []byte) {
|
||||
x15 := endian.unchecked_get_u32le(iv[12:16])
|
||||
|
||||
for i := _chacha20.ROUNDS; i > 0; i = i - 2 {
|
||||
// quarterround(x, 0, 4, 8, 12)
|
||||
x0 += x4
|
||||
x12 ~= x0
|
||||
x12 = bits.rotate_left32(x12, 16)
|
||||
x8 += x12
|
||||
x4 ~= x8
|
||||
x4 = bits.rotate_left32(x4, 12)
|
||||
x0 += x4
|
||||
x12 ~= x0
|
||||
x12 = bits.rotate_left32(x12, 8)
|
||||
x8 += x12
|
||||
x4 ~= x8
|
||||
x4 = bits.rotate_left32(x4, 7)
|
||||
x0, x4, x8, x12 = quarter_round(x0, x4, x8, x12)
|
||||
x1, x5, x9, x13 = quarter_round(x1, x5, x9, x13)
|
||||
x2, x6, x10, x14 = quarter_round(x2, x6, x10, x14)
|
||||
x3, x7, x11, x15 = quarter_round(x3, x7, x11, x15)
|
||||
|
||||
// quarterround(x, 1, 5, 9, 13)
|
||||
x1 += x5
|
||||
x13 ~= x1
|
||||
x13 = bits.rotate_left32(x13, 16)
|
||||
x9 += x13
|
||||
x5 ~= x9
|
||||
x5 = bits.rotate_left32(x5, 12)
|
||||
x1 += x5
|
||||
x13 ~= x1
|
||||
x13 = bits.rotate_left32(x13, 8)
|
||||
x9 += x13
|
||||
x5 ~= x9
|
||||
x5 = bits.rotate_left32(x5, 7)
|
||||
|
||||
// quarterround(x, 2, 6, 10, 14)
|
||||
x2 += x6
|
||||
x14 ~= x2
|
||||
x14 = bits.rotate_left32(x14, 16)
|
||||
x10 += x14
|
||||
x6 ~= x10
|
||||
x6 = bits.rotate_left32(x6, 12)
|
||||
x2 += x6
|
||||
x14 ~= x2
|
||||
x14 = bits.rotate_left32(x14, 8)
|
||||
x10 += x14
|
||||
x6 ~= x10
|
||||
x6 = bits.rotate_left32(x6, 7)
|
||||
|
||||
// quarterround(x, 3, 7, 11, 15)
|
||||
x3 += x7
|
||||
x15 ~= x3
|
||||
x15 = bits.rotate_left32(x15, 16)
|
||||
x11 += x15
|
||||
x7 ~= x11
|
||||
x7 = bits.rotate_left32(x7, 12)
|
||||
x3 += x7
|
||||
x15 ~= x3
|
||||
x15 = bits.rotate_left32(x15, 8)
|
||||
x11 += x15
|
||||
x7 ~= x11
|
||||
x7 = bits.rotate_left32(x7, 7)
|
||||
|
||||
// quarterround(x, 0, 5, 10, 15)
|
||||
x0 += x5
|
||||
x15 ~= x0
|
||||
x15 = bits.rotate_left32(x15, 16)
|
||||
x10 += x15
|
||||
x5 ~= x10
|
||||
x5 = bits.rotate_left32(x5, 12)
|
||||
x0 += x5
|
||||
x15 ~= x0
|
||||
x15 = bits.rotate_left32(x15, 8)
|
||||
x10 += x15
|
||||
x5 ~= x10
|
||||
x5 = bits.rotate_left32(x5, 7)
|
||||
|
||||
// quarterround(x, 1, 6, 11, 12)
|
||||
x1 += x6
|
||||
x12 ~= x1
|
||||
x12 = bits.rotate_left32(x12, 16)
|
||||
x11 += x12
|
||||
x6 ~= x11
|
||||
x6 = bits.rotate_left32(x6, 12)
|
||||
x1 += x6
|
||||
x12 ~= x1
|
||||
x12 = bits.rotate_left32(x12, 8)
|
||||
x11 += x12
|
||||
x6 ~= x11
|
||||
x6 = bits.rotate_left32(x6, 7)
|
||||
|
||||
// quarterround(x, 2, 7, 8, 13)
|
||||
x2 += x7
|
||||
x13 ~= x2
|
||||
x13 = bits.rotate_left32(x13, 16)
|
||||
x8 += x13
|
||||
x7 ~= x8
|
||||
x7 = bits.rotate_left32(x7, 12)
|
||||
x2 += x7
|
||||
x13 ~= x2
|
||||
x13 = bits.rotate_left32(x13, 8)
|
||||
x8 += x13
|
||||
x7 ~= x8
|
||||
x7 = bits.rotate_left32(x7, 7)
|
||||
|
||||
// quarterround(x, 3, 4, 9, 14)
|
||||
x3 += x4
|
||||
x14 ~= x3
|
||||
x14 = bits.rotate_left32(x14, 16)
|
||||
x9 += x14
|
||||
x4 ~= x9
|
||||
x4 = bits.rotate_left32(x4, 12)
|
||||
x3 += x4
|
||||
x14 ~= x3
|
||||
x14 = bits.rotate_left32(x14, 8)
|
||||
x9 += x14
|
||||
x4 ~= x9
|
||||
x4 = bits.rotate_left32(x4, 7)
|
||||
x0, x5, x10, x15 = quarter_round(x0, x5, x10, x15)
|
||||
x1, x6, x11, x12 = quarter_round(x1, x6, x11, x12)
|
||||
x2, x7, x8, x13 = quarter_round(x2, x7, x8, x13)
|
||||
x3, x4, x9, x14 = quarter_round(x3, x4, x9, x14)
|
||||
}
|
||||
|
||||
endian.unchecked_put_u32le(dst[0:4], x0)
|
||||
|
||||
@@ -195,7 +195,6 @@ 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
|
||||
@@ -203,7 +202,6 @@ Addend_Group_Element :: struct {
|
||||
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)
|
||||
@@ -420,6 +418,6 @@ ge_in_prime_order_subgroup_vartime :: proc "contextless" (ge: ^Group_Element) ->
|
||||
// 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)
|
||||
ge_scalarmult_raw(&tmp, ge, &SC_ELL, true)
|
||||
return ge_equal(&tmp, &GE_IDENTITY) == 1
|
||||
}
|
||||
|
||||
@@ -1,130 +1,24 @@
|
||||
package _edwards25519
|
||||
|
||||
import "core:crypto"
|
||||
import field "core:crypto/_fiat/field_scalar25519"
|
||||
import "core:math/bits"
|
||||
import subtle "core:crypto/_subtle"
|
||||
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)
|
||||
ge_scalarmult_raw(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_scalarmult_raw(ge, p, &tmp, true)
|
||||
}
|
||||
|
||||
ge_double_scalarmult_basepoint_vartime :: proc "contextless" (
|
||||
@@ -147,6 +41,12 @@ ge_double_scalarmult_basepoint_vartime :: proc "contextless" (
|
||||
|
||||
A_tbl: Multiply_Table = ---
|
||||
mul_tbl_set(&A_tbl, A, &tmp_add)
|
||||
when crypto.COMPACT_IMPLS == true {
|
||||
G_tbl: Multiply_Table = ---
|
||||
mul_tbl_set(&G_tbl, &GE_BASEPOINT, &tmp_add)
|
||||
} else {
|
||||
tmp_bp_addend: Basepoint_Addend_Group_Element = ---
|
||||
}
|
||||
|
||||
sc_a, sc_b: field.Non_Montgomery_Domain_Field_Element
|
||||
field.fe_from_montgomery(&sc_a, a)
|
||||
@@ -170,21 +70,28 @@ ge_double_scalarmult_basepoint_vartime :: proc "contextless" (
|
||||
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)
|
||||
when crypto.COMPACT_IMPLS == true {
|
||||
mul_tbl_add(&tmp, &G_tbl, hi_b, &tmp_add, &tmp_addend, true)
|
||||
} else {
|
||||
mul_bp_tbl_add(&tmp, GE_BASEPOINT_TABLE, hi_b, &tmp_add, &tmp_bp_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)
|
||||
when crypto.COMPACT_IMPLS == true {
|
||||
mul_tbl_add(&tmp, &G_tbl, lo_b, &tmp_add, &tmp_addend, true)
|
||||
} else {
|
||||
mul_bp_tbl_add(&tmp, GE_BASEPOINT_TABLE, lo_b, &tmp_add, &tmp_bp_addend, true)
|
||||
}
|
||||
}
|
||||
|
||||
ge_set(ge, &tmp)
|
||||
}
|
||||
|
||||
@(private)
|
||||
_ge_scalarmult :: proc "contextless" (
|
||||
ge_scalarmult_raw :: proc "contextless" (
|
||||
ge, p: ^Group_Element,
|
||||
sc: ^field.Non_Montgomery_Domain_Field_Element,
|
||||
unsafe_is_vartime := false,
|
||||
@@ -281,8 +188,8 @@ mul_tbl_add :: proc "contextless" (
|
||||
{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)
|
||||
ctrl := subtle.eq(i, idx)
|
||||
ge_addend_conditional_assign(tmp_addend, &tbl[i - 1], int(ctrl))
|
||||
}
|
||||
ge_add_addend(ge, ge, tmp_addend, tmp_add)
|
||||
}
|
||||
|
||||
147
core/crypto/_edwards25519/edwards25519_scalar_mul_base.odin
Normal file
147
core/crypto/_edwards25519/edwards25519_scalar_mul_base.odin
Normal file
@@ -0,0 +1,147 @@
|
||||
package _edwards25519
|
||||
|
||||
import "core:crypto"
|
||||
import field "core:crypto/_fiat/field_curve25519"
|
||||
import scalar "core:crypto/_fiat/field_scalar25519"
|
||||
import subtle "core:crypto/_subtle"
|
||||
import "core:mem"
|
||||
|
||||
ge_scalarmult_basepoint :: proc "contextless" (ge: ^Group_Element, sc: ^Scalar) {
|
||||
when crypto.COMPACT_IMPLS == true {
|
||||
ge_scalarmult(ge, &GE_BASEPOINT, sc)
|
||||
} else {
|
||||
tmp_sc: scalar.Non_Montgomery_Domain_Field_Element
|
||||
scalar.fe_from_montgomery(&tmp_sc, sc)
|
||||
|
||||
tmp_add: Add_Scratch = ---
|
||||
tmp_addend: Basepoint_Addend_Group_Element = ---
|
||||
|
||||
ge_identity(ge)
|
||||
for i in 0..<32 {
|
||||
limb := i / 8
|
||||
shift := uint(i & 7) * 8
|
||||
limb_byte := tmp_sc[limb] >> shift
|
||||
|
||||
hi, lo := (limb_byte >> 4) & 0x0f, limb_byte & 0x0f
|
||||
mul_bp_tbl_add(ge, &Gen_Multiply_Table_edwards25519_lo[i], lo, &tmp_add, &tmp_addend, false)
|
||||
mul_bp_tbl_add(ge, &Gen_Multiply_Table_edwards25519_hi[i], hi, &tmp_add, &tmp_addend, false)
|
||||
}
|
||||
|
||||
mem.zero_explicit(&tmp_sc, size_of(tmp_sc))
|
||||
mem.zero_explicit(&tmp_add, size_of(Add_Scratch))
|
||||
mem.zero_explicit(&tmp_addend, size_of(Basepoint_Addend_Group_Element))
|
||||
}
|
||||
}
|
||||
|
||||
when crypto.COMPACT_IMPLS == false {
|
||||
@(private="file",rodata)
|
||||
TWO_TIMES_Z2 := field.Loose_Field_Element{2, 0, 0, 0, 0}
|
||||
|
||||
@(private)
|
||||
Basepoint_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
|
||||
}
|
||||
|
||||
@(private)
|
||||
Basepoint_Multiply_Table :: [15]Basepoint_Addend_Group_Element
|
||||
|
||||
@(private)
|
||||
ge_bp_addend_conditional_assign :: proc "contextless" (ge_a, a: ^Basepoint_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)
|
||||
}
|
||||
|
||||
@(private)
|
||||
ge_add_bp_addend :: proc "contextless" (
|
||||
ge, a: ^Group_Element,
|
||||
b: ^Basepoint_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, z = 1 (precomputation ftw)
|
||||
//
|
||||
// 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))
|
||||
field.fe_carry_mul(D, field.fe_relax_cast(&a.z), &TWO_TIMES_Z2)
|
||||
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)
|
||||
mul_bp_tbl_add :: proc "contextless" (
|
||||
ge: ^Group_Element,
|
||||
tbl: ^Basepoint_Multiply_Table,
|
||||
idx: u64,
|
||||
tmp_add: ^Add_Scratch,
|
||||
tmp_addend: ^Basepoint_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_bp_addend(ge, ge, &tbl[idx-1], tmp_add)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Constant time lookup.
|
||||
tmp_addend^ = {
|
||||
// Point at infinity (0, 1, 1, 0) in precomputed form, note
|
||||
// that the precomputed tables rescale so that `Z = 1`.
|
||||
{1, 0, 0, 0, 0}, // y - x
|
||||
{1, 0, 0, 0, 0}, // y + x
|
||||
{0, 0, 0, 0, 0}, // t * 2d
|
||||
}
|
||||
for i := u64(1); i < 16; i = i + 1 {
|
||||
ctrl := subtle.eq(i, idx)
|
||||
ge_bp_addend_conditional_assign(tmp_addend, &tbl[i - 1], int(ctrl))
|
||||
}
|
||||
ge_add_bp_addend(ge, ge, tmp_addend, tmp_add)
|
||||
}
|
||||
}
|
||||
4947
core/crypto/_edwards25519/edwards25519_table.odin
Normal file
4947
core/crypto/_edwards25519/edwards25519_table.odin
Normal file
File diff suppressed because it is too large
Load Diff
134
core/crypto/_edwards25519/tools/edwards_gen_tables.odin
Normal file
134
core/crypto/_edwards25519/tools/edwards_gen_tables.odin
Normal file
@@ -0,0 +1,134 @@
|
||||
package weistrass_tools
|
||||
|
||||
import ed "core:crypto/_edwards25519"
|
||||
import field "core:crypto/_fiat/field_curve25519"
|
||||
import scalar "core:crypto/_fiat/field_scalar25519"
|
||||
import "core:encoding/endian"
|
||||
import "core:fmt"
|
||||
import path "core:path/filepath"
|
||||
import "core:os"
|
||||
import "core:strings"
|
||||
|
||||
// Yes this leaks memory, fite me IRL.
|
||||
|
||||
GENERATED :: `/*
|
||||
------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------
|
||||
*/`
|
||||
|
||||
@(private, rodata)
|
||||
FE_D2 := field.Tight_Field_Element {
|
||||
1859910466990425,
|
||||
932731440258426,
|
||||
1072319116312658,
|
||||
1815898335770999,
|
||||
633789495995903,
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
Basepoint_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
|
||||
}
|
||||
Basepoint_Multiply_Table :: [15]Basepoint_Addend_Group_Element
|
||||
|
||||
ge_bp_addend_set := proc(ge_a: ^Basepoint_Addend_Group_Element, ge: ^ed.Group_Element) {
|
||||
// We rescale so Z == 1, so T = X * Y
|
||||
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))
|
||||
|
||||
field.fe_sub(&ge_a.y2_minus_x2, &y_, &x_)
|
||||
field.fe_add(&ge_a.y2_plus_x2, &y_, &x_)
|
||||
field.fe_carry_mul(&ge_a.k_times_t2, field.fe_relax_cast(&x_), field.fe_relax_cast(&y_))
|
||||
field.fe_carry_mul(&ge_a.k_times_t2, field.fe_relax_cast(&ge_a.k_times_t2), field.fe_relax_cast(&FE_D2))
|
||||
}
|
||||
|
||||
Multiply_Table_hi: [32]Basepoint_Multiply_Table
|
||||
Multiply_Table_lo: [32]Basepoint_Multiply_Table
|
||||
|
||||
sc_set_unchecked := proc(sc: ^scalar.Non_Montgomery_Domain_Field_Element, b: []byte) {
|
||||
sc[0] = endian.unchecked_get_u64le(b[0:])
|
||||
sc[1] = endian.unchecked_get_u64le(b[8:])
|
||||
sc[2] = endian.unchecked_get_u64le(b[16:])
|
||||
sc[3] = endian.unchecked_get_u64le(b[24:])
|
||||
}
|
||||
|
||||
g, p: ed.Group_Element
|
||||
ed.ge_generator(&g)
|
||||
|
||||
sc: scalar.Non_Montgomery_Domain_Field_Element
|
||||
|
||||
// Precompute ([1,15] << n) * G multiples of G, LSB->MSB
|
||||
for i in 0..<32 {
|
||||
b: [32]byte
|
||||
for j in 1..<16 {
|
||||
b[i] = u8(j)
|
||||
sc_set_unchecked(&sc, b[:])
|
||||
ed.ge_scalarmult_raw(&p, &g, &sc, true)
|
||||
ge_bp_addend_set(&Multiply_Table_lo[i][j-1], &p)
|
||||
|
||||
b[i] = u8(j) << 4
|
||||
sc_set_unchecked(&sc, b[:])
|
||||
ed.ge_scalarmult_raw(&p, &g, &sc, true)
|
||||
ge_bp_addend_set(&Multiply_Table_hi[i][j-1], &p)
|
||||
|
||||
b[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
fn := path.join({ODIN_ROOT, "core", "crypto", "_edwards25519", "edwards25519_table.odin"})
|
||||
bld: strings.Builder
|
||||
w := strings.to_writer(&bld)
|
||||
|
||||
fmt.wprintln(w, "package _edwards25519")
|
||||
fmt.wprintln(w, "")
|
||||
fmt.wprintln(w, GENERATED)
|
||||
fmt.wprintln(w, "")
|
||||
fmt.wprintln(w, "import \"core:crypto\"")
|
||||
fmt.wprintln(w, "")
|
||||
fmt.wprintln(w, "when crypto.COMPACT_IMPLS == false {")
|
||||
|
||||
fmt.wprintln(w, "\t@(private,rodata)")
|
||||
fmt.wprintln(w, "\tGen_Multiply_Table_edwards25519_lo := [32]Basepoint_Multiply_Table {")
|
||||
for &v in Multiply_Table_lo {
|
||||
fmt.wprintln(w, "\t\t{")
|
||||
for &ap in v {
|
||||
fmt.wprintln(w, "\t\t\t{")
|
||||
|
||||
t1, t3, t4 := &ap.y2_minus_x2, &ap.y2_plus_x2, &ap.k_times_t2
|
||||
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d, %d},\n", t1[0], t1[1], t1[2], t1[3], t1[4])
|
||||
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d, %d},\n", t3[0], t3[1], t3[2], t3[3], t3[4])
|
||||
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d, %d},\n", t4[0], t4[1], t4[2], t4[3], t4[4])
|
||||
|
||||
fmt.wprintln(w, "\t\t\t},")
|
||||
}
|
||||
fmt.wprintln(w, "\t\t},")
|
||||
}
|
||||
fmt.wprintln(w, "\t}\n")
|
||||
|
||||
fmt.wprintln(w, "\t@(private,rodata)")
|
||||
fmt.wprintln(w, "\tGen_Multiply_Table_edwards25519_hi := [32]Basepoint_Multiply_Table {")
|
||||
for &v in Multiply_Table_hi {
|
||||
fmt.wprintln(w, "\t\t{")
|
||||
for &ap in v {
|
||||
fmt.wprintln(w, "\t\t\t{")
|
||||
|
||||
t1, t3, t4 := &ap.y2_minus_x2, &ap.y2_plus_x2, &ap.k_times_t2
|
||||
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d, %d},\n", t1[0], t1[1], t1[2], t1[3], t1[4])
|
||||
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d, %d},\n", t3[0], t3[1], t3[2], t3[3], t3[4])
|
||||
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d, %d},\n", t4[0], t4[1], t4[2], t4[3], t4[4])
|
||||
|
||||
fmt.wprintln(w, "\t\t\t},")
|
||||
}
|
||||
fmt.wprintln(w, "\t\t},")
|
||||
}
|
||||
fmt.wprintln(w, "\t}\n")
|
||||
|
||||
fmt.wprintln(w, "\tGE_BASEPOINT_TABLE := &Gen_Multiply_Table_edwards25519_lo[0]")
|
||||
|
||||
fmt.wprintln(w, "}")
|
||||
|
||||
_ = os.write_entire_file(fn, transmute([]byte)(strings.to_string(bld)))
|
||||
}
|
||||
346
core/crypto/_fiat/field_p256r1/field.odin
Normal file
346
core/crypto/_fiat/field_p256r1/field.odin
Normal file
@@ -0,0 +1,346 @@
|
||||
package field_p256r1
|
||||
|
||||
import subtle "core:crypto/_subtle"
|
||||
import "core:encoding/endian"
|
||||
import "core:math/bits"
|
||||
import "core:mem"
|
||||
|
||||
fe_clear :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) {
|
||||
mem.zero_explicit(arg1, size_of(Montgomery_Domain_Field_Element))
|
||||
}
|
||||
|
||||
fe_clear_vec :: proc "contextless" (
|
||||
arg1: []^Montgomery_Domain_Field_Element,
|
||||
) {
|
||||
for fe in arg1 {
|
||||
fe_clear(fe)
|
||||
}
|
||||
}
|
||||
|
||||
fe_from_bytes :: proc "contextless" (
|
||||
out1: ^Montgomery_Domain_Field_Element,
|
||||
arg1: []byte,
|
||||
unsafe_assume_canonical := false,
|
||||
) -> bool {
|
||||
ensure_contextless(len(arg1) == 32, "p256r1: invalid fe input buffer")
|
||||
|
||||
// Note: We assume the input is in big-endian.
|
||||
tmp := Non_Montgomery_Domain_Field_Element {
|
||||
endian.unchecked_get_u64be(arg1[24:]),
|
||||
endian.unchecked_get_u64be(arg1[16:]),
|
||||
endian.unchecked_get_u64be(arg1[8:]),
|
||||
endian.unchecked_get_u64be(arg1[0:]),
|
||||
}
|
||||
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_to_bytes :: proc "contextless" (out1: []byte, arg1: ^Montgomery_Domain_Field_Element) {
|
||||
ensure_contextless(len(out1) == 32, "p256r1: invalid fe output buffer")
|
||||
|
||||
tmp: Non_Montgomery_Domain_Field_Element
|
||||
fe_from_montgomery(&tmp, arg1)
|
||||
|
||||
// Note: Likewise, output in big-endian.
|
||||
endian.unchecked_put_u64be(out1[24:], tmp[0])
|
||||
endian.unchecked_put_u64be(out1[16:], tmp[1])
|
||||
endian.unchecked_put_u64be(out1[8:], tmp[2])
|
||||
endian.unchecked_put_u64be(out1[0:], tmp[3])
|
||||
|
||||
mem.zero_explicit(&tmp, size_of(tmp))
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
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.
|
||||
is_eq := subtle.u64_is_zero(fe_non_zero(&tmp))
|
||||
|
||||
fe_clear(&tmp)
|
||||
|
||||
return int(is_eq)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
fe_is_odd :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) -> int {
|
||||
tmp: Non_Montgomery_Domain_Field_Element
|
||||
defer mem.zero_explicit(&tmp, size_of(tmp))
|
||||
|
||||
fe_from_montgomery(&tmp, arg1)
|
||||
return int(tmp[0] & 1)
|
||||
}
|
||||
|
||||
fe_pow2k :: proc "contextless" (
|
||||
out1: ^Montgomery_Domain_Field_Element,
|
||||
arg1: ^Montgomery_Domain_Field_Element,
|
||||
arg2: uint,
|
||||
) {
|
||||
// Special case: `arg1^(2 * 0) = 1`, though this should never happen.
|
||||
if arg2 == 0 {
|
||||
fe_one(out1)
|
||||
return
|
||||
}
|
||||
|
||||
fe_square(out1, arg1)
|
||||
for _ in 1 ..< arg2 {
|
||||
fe_square(out1, out1)
|
||||
}
|
||||
}
|
||||
|
||||
fe_inv :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) {
|
||||
// Inversion computation is derived from the addition chain:
|
||||
//
|
||||
// _10 = 2*1
|
||||
// _11 = 1 + _10
|
||||
// _110 = 2*_11
|
||||
// _111 = 1 + _110
|
||||
// _111000 = _111 << 3
|
||||
// _111111 = _111 + _111000
|
||||
// x12 = _111111 << 6 + _111111
|
||||
// x15 = x12 << 3 + _111
|
||||
// x16 = 2*x15 + 1
|
||||
// x32 = x16 << 16 + x16
|
||||
// i53 = x32 << 15
|
||||
// x47 = x15 + i53
|
||||
// i263 = ((i53 << 17 + 1) << 143 + x47) << 47
|
||||
// return (x47 + i263) << 2
|
||||
//
|
||||
// Operations: 255 squares 11 multiplies
|
||||
//
|
||||
// Generated by github.com/mmcloughlin/addchain v0.4.0.
|
||||
|
||||
// Note: Need to stash `arg1` (`xx`) in the case that `out1`/`arg1` alias,
|
||||
// as `arg1` is used after `out1` has been altered.
|
||||
t0, t1, xx: Montgomery_Domain_Field_Element = ---, ---, arg1^
|
||||
|
||||
// Step 1: z = x^0x2
|
||||
fe_square(out1, arg1)
|
||||
|
||||
// Step 2: z = x^0x3
|
||||
fe_mul(out1, &xx, out1)
|
||||
|
||||
// Step 3: z = x^0x6
|
||||
fe_square(out1, out1)
|
||||
|
||||
// Step 4: z = x^0x7
|
||||
fe_mul(out1, &xx, out1)
|
||||
|
||||
// Step 7: t0 = x^0x38
|
||||
fe_pow2k(&t0, out1, 3)
|
||||
|
||||
// Step 8: t0 = x^0x3f
|
||||
fe_mul(&t0, out1, &t0)
|
||||
|
||||
// Step 14: t1 = x^0xfc0
|
||||
fe_pow2k(&t1, &t0, 6)
|
||||
|
||||
// Step 15: t0 = x^0xfff
|
||||
fe_mul(&t0, &t0, &t1)
|
||||
|
||||
// Step 18: t0 = x^0x7ff8
|
||||
fe_pow2k(&t0, &t0, 3)
|
||||
|
||||
// Step 19: z = x^0x7fff
|
||||
fe_mul(out1, out1, &t0)
|
||||
|
||||
// Step 20: t0 = x^0xfffe
|
||||
fe_square(&t0, out1)
|
||||
|
||||
// Step 21: t0 = x^0xffff
|
||||
fe_mul(&t0, &xx, &t0)
|
||||
|
||||
// Step 37: t1 = x^0xffff0000
|
||||
fe_pow2k(&t1, &t0, 16)
|
||||
|
||||
// Step 38: t0 = x^0xffffffff
|
||||
fe_mul(&t0, &t0, &t1)
|
||||
|
||||
// Step 53: t0 = x^0x7fffffff8000
|
||||
fe_pow2k(&t0, &t0, 15)
|
||||
|
||||
// Step 54: z = x^0x7fffffffffff
|
||||
fe_mul(out1, out1, &t0)
|
||||
|
||||
// Step 71: t0 = x^0xffffffff00000000
|
||||
fe_pow2k(&t0, &t0, 17)
|
||||
|
||||
// Step 72: t0 = x^0xffffffff00000001
|
||||
fe_mul(&t0, &xx, &t0)
|
||||
|
||||
// Step 215: t0 = x^0x7fffffff80000000800000000000000000000000000000000000
|
||||
fe_pow2k(&t0, &t0, 143)
|
||||
|
||||
// Step 216: t0 = x^0x7fffffff800000008000000000000000000000007fffffffffff
|
||||
fe_mul(&t0, out1, &t0)
|
||||
|
||||
// Step 263: t0 = x^0x3fffffffc00000004000000000000000000000003fffffffffff800000000000
|
||||
fe_pow2k(&t0, &t0, 47)
|
||||
|
||||
// Step 264: z = x^0x3fffffffc00000004000000000000000000000003fffffffffffffffffffffff
|
||||
fe_mul(out1, out1, &t0)
|
||||
|
||||
// Step 266: z = x^0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc
|
||||
fe_pow2k(out1, out1, 2)
|
||||
|
||||
fe_mul(out1, out1, &xx)
|
||||
|
||||
fe_clear_vec([]^Montgomery_Domain_Field_Element{&t0, &t1, &xx})
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
fe_sqrt :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element) -> int {
|
||||
// Square root candidate can be derived via exponentiation by `(p + 1) / 4`
|
||||
// From sage: 28948022302589062190674361737351893382521535853822578548883407827216774463488
|
||||
//
|
||||
// // Inversion computation is derived from the addition chain:
|
||||
//
|
||||
// _10 = 2*1
|
||||
// _11 = 1 + _10
|
||||
// _1100 = _11 << 2
|
||||
// _1111 = _11 + _1100
|
||||
// _11110000 = _1111 << 4
|
||||
// _11111111 = _1111 + _11110000
|
||||
// x16 = _11111111 << 8 + _11111111
|
||||
// x32 = x16 << 16 + x16
|
||||
// return ((x32 << 32 + 1) << 96 + 1) << 94
|
||||
//
|
||||
// Operations: 253 squares 7 multiplies
|
||||
//
|
||||
// Generated by github.com/mmcloughlin/addchain v0.4.0.
|
||||
|
||||
// Likewise this tramples over arg1, so stash another copy.
|
||||
t0, xx: Montgomery_Domain_Field_Element = ---, arg1^
|
||||
|
||||
// Step 1: z = x^0x2
|
||||
fe_square(out1, arg1)
|
||||
|
||||
// Step 2: z = x^0x3
|
||||
fe_mul(out1, &xx, out1)
|
||||
|
||||
// Step 4: t0 = x^0xc
|
||||
fe_pow2k(&t0, &xx, 2)
|
||||
|
||||
// Step 5: z = x^0xf
|
||||
fe_mul(out1, out1, &t0)
|
||||
|
||||
// Step 9: t0 = x^0xf0
|
||||
fe_pow2k(&t0, out1, 4)
|
||||
|
||||
// Step 10: z = x^0xff
|
||||
fe_mul(out1, out1, &t0)
|
||||
|
||||
// Step 18: t0 = x^0xff00
|
||||
fe_pow2k(&t0, out1, 8)
|
||||
|
||||
// Step 19: z = x^0xffff
|
||||
fe_mul(out1, out1, &t0)
|
||||
|
||||
// Step 35: t0 = x^0xffff0000
|
||||
fe_pow2k(&t0, out1, 16)
|
||||
|
||||
// Step 36: z = x^0xffffffff
|
||||
fe_mul(out1, out1, &t0)
|
||||
|
||||
// Step 68: z = x^0xffffffff00000000
|
||||
fe_pow2k(out1, out1, 32)
|
||||
|
||||
// Step 69: z = x^0xffffffff00000001
|
||||
fe_mul(out1, &xx, out1)
|
||||
|
||||
// Step 165: z = x^0xffffffff00000001000000000000000000000000
|
||||
fe_pow2k(out1, out1, 96)
|
||||
|
||||
// Step 166: z = x^0xffffffff00000001000000000000000000000001
|
||||
fe_mul(out1, &xx, out1)
|
||||
|
||||
// Step 260: z = x^0x3fffffffc0000000400000000000000000000000400000000000000000000000
|
||||
fe_pow2k(out1, out1, 94)
|
||||
|
||||
// Ensure that our candidate is actually the square root.
|
||||
check, zero: Montgomery_Domain_Field_Element
|
||||
fe_square(&check, out1)
|
||||
|
||||
is_valid := fe_equal(&check, &xx)
|
||||
fe_cond_select(out1, &zero, out1, is_valid)
|
||||
|
||||
fe_clear_vec([]^Montgomery_Domain_Field_Element{&t0, &xx, &check})
|
||||
|
||||
return is_valid
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@(optimization_mode = "none")
|
||||
fe_cond_swap :: #force_no_inline proc "contextless" (out1, out2: ^Montgomery_Domain_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
|
||||
out1[0], out2[0] = x1, y1
|
||||
out1[1], out2[1] = x2, y2
|
||||
out1[2], out2[2] = x3, y3
|
||||
out1[3], out2[3] = x4, y4
|
||||
}
|
||||
|
||||
@(optimization_mode = "none")
|
||||
fe_cond_select :: #force_no_inline proc "contextless" (
|
||||
out1, arg1, arg2: ^Montgomery_Domain_Field_Element,
|
||||
arg3: int,
|
||||
) {
|
||||
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]))
|
||||
out1[0] = x1
|
||||
out1[1] = x2
|
||||
out1[2] = x3
|
||||
out1[3] = x4
|
||||
}
|
||||
|
||||
fe_cond_negate :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element, ctrl: int) {
|
||||
tmp1: Montgomery_Domain_Field_Element = ---
|
||||
fe_opp(&tmp1, arg1)
|
||||
fe_cond_select(out1, arg1, &tmp1, ctrl)
|
||||
|
||||
fe_clear(&tmp1)
|
||||
}
|
||||
501
core/crypto/_fiat/field_p256r1/field64.odin
Normal file
501
core/crypto/_fiat/field_p256r1/field64.odin
Normal file
@@ -0,0 +1,501 @@
|
||||
// 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_p256r1
|
||||
|
||||
// The file provides arithmetic on the field Z/(2^256 - 2^224 + 2^192 + 2^96 - 1)
|
||||
// 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.
|
||||
//
|
||||
// WARNING: While big-endian is the common representation used for this
|
||||
// curve, the fiat output uses least-significant-limb first.
|
||||
|
||||
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{0xffffffffffffffff, 0xffffffff, 0x0, 0xffffffff00000001}
|
||||
|
||||
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)
|
||||
x21, x20 := bits.mul_u64(x11, 0xffffffff00000001)
|
||||
x23, x22 := bits.mul_u64(x11, 0xffffffff)
|
||||
x25, x24 := bits.mul_u64(x11, 0xffffffffffffffff)
|
||||
x26, x27 := bits.add_u64(x25, x22, u64(0x0))
|
||||
x28 := (u64(fiat.u1(x27)) + x23)
|
||||
_, x30 := bits.add_u64(x11, x24, u64(0x0))
|
||||
x31, x32 := bits.add_u64(x13, x26, u64(fiat.u1(x30)))
|
||||
x33, x34 := bits.add_u64(x15, x28, u64(fiat.u1(x32)))
|
||||
x35, x36 := bits.add_u64(x17, x20, u64(fiat.u1(x34)))
|
||||
x37, x38 := bits.add_u64(x19, x21, u64(fiat.u1(x36)))
|
||||
x40, x39 := bits.mul_u64(x1, arg2[3])
|
||||
x42, x41 := bits.mul_u64(x1, arg2[2])
|
||||
x44, x43 := bits.mul_u64(x1, arg2[1])
|
||||
x46, x45 := bits.mul_u64(x1, arg2[0])
|
||||
x47, x48 := bits.add_u64(x46, x43, u64(0x0))
|
||||
x49, x50 := bits.add_u64(x44, x41, u64(fiat.u1(x48)))
|
||||
x51, x52 := bits.add_u64(x42, x39, u64(fiat.u1(x50)))
|
||||
x53 := (u64(fiat.u1(x52)) + x40)
|
||||
x54, x55 := bits.add_u64(x31, x45, u64(0x0))
|
||||
x56, x57 := bits.add_u64(x33, x47, u64(fiat.u1(x55)))
|
||||
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(u64(fiat.u1(x38)), x53, u64(fiat.u1(x61)))
|
||||
x65, x64 := bits.mul_u64(x54, 0xffffffff00000001)
|
||||
x67, x66 := bits.mul_u64(x54, 0xffffffff)
|
||||
x69, x68 := bits.mul_u64(x54, 0xffffffffffffffff)
|
||||
x70, x71 := bits.add_u64(x69, x66, u64(0x0))
|
||||
x72 := (u64(fiat.u1(x71)) + x67)
|
||||
_, x74 := bits.add_u64(x54, x68, u64(0x0))
|
||||
x75, x76 := bits.add_u64(x56, x70, u64(fiat.u1(x74)))
|
||||
x77, x78 := bits.add_u64(x58, x72, u64(fiat.u1(x76)))
|
||||
x79, x80 := bits.add_u64(x60, x64, u64(fiat.u1(x78)))
|
||||
x81, x82 := bits.add_u64(x62, x65, u64(fiat.u1(x80)))
|
||||
x83 := (u64(fiat.u1(x82)) + u64(fiat.u1(x63)))
|
||||
x85, x84 := bits.mul_u64(x2, arg2[3])
|
||||
x87, x86 := bits.mul_u64(x2, arg2[2])
|
||||
x89, x88 := bits.mul_u64(x2, arg2[1])
|
||||
x91, x90 := bits.mul_u64(x2, arg2[0])
|
||||
x92, x93 := bits.add_u64(x91, x88, u64(0x0))
|
||||
x94, x95 := bits.add_u64(x89, x86, u64(fiat.u1(x93)))
|
||||
x96, x97 := bits.add_u64(x87, x84, u64(fiat.u1(x95)))
|
||||
x98 := (u64(fiat.u1(x97)) + x85)
|
||||
x99, x100 := bits.add_u64(x75, x90, u64(0x0))
|
||||
x101, x102 := bits.add_u64(x77, x92, u64(fiat.u1(x100)))
|
||||
x103, x104 := bits.add_u64(x79, x94, u64(fiat.u1(x102)))
|
||||
x105, x106 := bits.add_u64(x81, x96, u64(fiat.u1(x104)))
|
||||
x107, x108 := bits.add_u64(x83, x98, u64(fiat.u1(x106)))
|
||||
x110, x109 := bits.mul_u64(x99, 0xffffffff00000001)
|
||||
x112, x111 := bits.mul_u64(x99, 0xffffffff)
|
||||
x114, x113 := bits.mul_u64(x99, 0xffffffffffffffff)
|
||||
x115, x116 := bits.add_u64(x114, x111, u64(0x0))
|
||||
x117 := (u64(fiat.u1(x116)) + x112)
|
||||
_, x119 := bits.add_u64(x99, x113, u64(0x0))
|
||||
x120, x121 := bits.add_u64(x101, x115, u64(fiat.u1(x119)))
|
||||
x122, x123 := bits.add_u64(x103, x117, u64(fiat.u1(x121)))
|
||||
x124, x125 := bits.add_u64(x105, x109, u64(fiat.u1(x123)))
|
||||
x126, x127 := bits.add_u64(x107, x110, u64(fiat.u1(x125)))
|
||||
x128 := (u64(fiat.u1(x127)) + u64(fiat.u1(x108)))
|
||||
x130, x129 := bits.mul_u64(x3, arg2[3])
|
||||
x132, x131 := bits.mul_u64(x3, arg2[2])
|
||||
x134, x133 := bits.mul_u64(x3, arg2[1])
|
||||
x136, x135 := bits.mul_u64(x3, arg2[0])
|
||||
x137, x138 := bits.add_u64(x136, x133, u64(0x0))
|
||||
x139, x140 := bits.add_u64(x134, x131, u64(fiat.u1(x138)))
|
||||
x141, x142 := bits.add_u64(x132, x129, u64(fiat.u1(x140)))
|
||||
x143 := (u64(fiat.u1(x142)) + x130)
|
||||
x144, x145 := bits.add_u64(x120, x135, u64(0x0))
|
||||
x146, x147 := bits.add_u64(x122, x137, u64(fiat.u1(x145)))
|
||||
x148, x149 := bits.add_u64(x124, x139, u64(fiat.u1(x147)))
|
||||
x150, x151 := bits.add_u64(x126, x141, u64(fiat.u1(x149)))
|
||||
x152, x153 := bits.add_u64(x128, x143, u64(fiat.u1(x151)))
|
||||
x155, x154 := bits.mul_u64(x144, 0xffffffff00000001)
|
||||
x157, x156 := bits.mul_u64(x144, 0xffffffff)
|
||||
x159, x158 := bits.mul_u64(x144, 0xffffffffffffffff)
|
||||
x160, x161 := bits.add_u64(x159, x156, u64(0x0))
|
||||
x162 := (u64(fiat.u1(x161)) + x157)
|
||||
_, x164 := bits.add_u64(x144, x158, u64(0x0))
|
||||
x165, x166 := bits.add_u64(x146, x160, u64(fiat.u1(x164)))
|
||||
x167, x168 := bits.add_u64(x148, x162, u64(fiat.u1(x166)))
|
||||
x169, x170 := bits.add_u64(x150, x154, u64(fiat.u1(x168)))
|
||||
x171, x172 := bits.add_u64(x152, x155, u64(fiat.u1(x170)))
|
||||
x173 := (u64(fiat.u1(x172)) + u64(fiat.u1(x153)))
|
||||
x174, x175 := bits.sub_u64(x165, 0xffffffffffffffff, u64(0x0))
|
||||
x176, x177 := bits.sub_u64(x167, 0xffffffff, u64(fiat.u1(x175)))
|
||||
x178, x179 := bits.sub_u64(x169, u64(0x0), u64(fiat.u1(x177)))
|
||||
x180, x181 := bits.sub_u64(x171, 0xffffffff00000001, u64(fiat.u1(x179)))
|
||||
_, x183 := bits.sub_u64(x173, u64(0x0), u64(fiat.u1(x181)))
|
||||
x184 := fiat.cmovznz_u64(fiat.u1(x183), x174, x165)
|
||||
x185 := fiat.cmovznz_u64(fiat.u1(x183), x176, x167)
|
||||
x186 := fiat.cmovznz_u64(fiat.u1(x183), x178, x169)
|
||||
x187 := fiat.cmovznz_u64(fiat.u1(x183), x180, x171)
|
||||
out1[0] = x184
|
||||
out1[1] = x185
|
||||
out1[2] = x186
|
||||
out1[3] = x187
|
||||
}
|
||||
|
||||
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)
|
||||
x21, x20 := bits.mul_u64(x11, 0xffffffff00000001)
|
||||
x23, x22 := bits.mul_u64(x11, 0xffffffff)
|
||||
x25, x24 := bits.mul_u64(x11, 0xffffffffffffffff)
|
||||
x26, x27 := bits.add_u64(x25, x22, u64(0x0))
|
||||
x28 := (u64(fiat.u1(x27)) + x23)
|
||||
_, x30 := bits.add_u64(x11, x24, u64(0x0))
|
||||
x31, x32 := bits.add_u64(x13, x26, u64(fiat.u1(x30)))
|
||||
x33, x34 := bits.add_u64(x15, x28, u64(fiat.u1(x32)))
|
||||
x35, x36 := bits.add_u64(x17, x20, u64(fiat.u1(x34)))
|
||||
x37, x38 := bits.add_u64(x19, x21, u64(fiat.u1(x36)))
|
||||
x40, x39 := bits.mul_u64(x1, arg1[3])
|
||||
x42, x41 := bits.mul_u64(x1, arg1[2])
|
||||
x44, x43 := bits.mul_u64(x1, arg1[1])
|
||||
x46, x45 := bits.mul_u64(x1, arg1[0])
|
||||
x47, x48 := bits.add_u64(x46, x43, u64(0x0))
|
||||
x49, x50 := bits.add_u64(x44, x41, u64(fiat.u1(x48)))
|
||||
x51, x52 := bits.add_u64(x42, x39, u64(fiat.u1(x50)))
|
||||
x53 := (u64(fiat.u1(x52)) + x40)
|
||||
x54, x55 := bits.add_u64(x31, x45, u64(0x0))
|
||||
x56, x57 := bits.add_u64(x33, x47, u64(fiat.u1(x55)))
|
||||
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(u64(fiat.u1(x38)), x53, u64(fiat.u1(x61)))
|
||||
x65, x64 := bits.mul_u64(x54, 0xffffffff00000001)
|
||||
x67, x66 := bits.mul_u64(x54, 0xffffffff)
|
||||
x69, x68 := bits.mul_u64(x54, 0xffffffffffffffff)
|
||||
x70, x71 := bits.add_u64(x69, x66, u64(0x0))
|
||||
x72 := (u64(fiat.u1(x71)) + x67)
|
||||
_, x74 := bits.add_u64(x54, x68, u64(0x0))
|
||||
x75, x76 := bits.add_u64(x56, x70, u64(fiat.u1(x74)))
|
||||
x77, x78 := bits.add_u64(x58, x72, u64(fiat.u1(x76)))
|
||||
x79, x80 := bits.add_u64(x60, x64, u64(fiat.u1(x78)))
|
||||
x81, x82 := bits.add_u64(x62, x65, u64(fiat.u1(x80)))
|
||||
x83 := (u64(fiat.u1(x82)) + u64(fiat.u1(x63)))
|
||||
x85, x84 := bits.mul_u64(x2, arg1[3])
|
||||
x87, x86 := bits.mul_u64(x2, arg1[2])
|
||||
x89, x88 := bits.mul_u64(x2, arg1[1])
|
||||
x91, x90 := bits.mul_u64(x2, arg1[0])
|
||||
x92, x93 := bits.add_u64(x91, x88, u64(0x0))
|
||||
x94, x95 := bits.add_u64(x89, x86, u64(fiat.u1(x93)))
|
||||
x96, x97 := bits.add_u64(x87, x84, u64(fiat.u1(x95)))
|
||||
x98 := (u64(fiat.u1(x97)) + x85)
|
||||
x99, x100 := bits.add_u64(x75, x90, u64(0x0))
|
||||
x101, x102 := bits.add_u64(x77, x92, u64(fiat.u1(x100)))
|
||||
x103, x104 := bits.add_u64(x79, x94, u64(fiat.u1(x102)))
|
||||
x105, x106 := bits.add_u64(x81, x96, u64(fiat.u1(x104)))
|
||||
x107, x108 := bits.add_u64(x83, x98, u64(fiat.u1(x106)))
|
||||
x110, x109 := bits.mul_u64(x99, 0xffffffff00000001)
|
||||
x112, x111 := bits.mul_u64(x99, 0xffffffff)
|
||||
x114, x113 := bits.mul_u64(x99, 0xffffffffffffffff)
|
||||
x115, x116 := bits.add_u64(x114, x111, u64(0x0))
|
||||
x117 := (u64(fiat.u1(x116)) + x112)
|
||||
_, x119 := bits.add_u64(x99, x113, u64(0x0))
|
||||
x120, x121 := bits.add_u64(x101, x115, u64(fiat.u1(x119)))
|
||||
x122, x123 := bits.add_u64(x103, x117, u64(fiat.u1(x121)))
|
||||
x124, x125 := bits.add_u64(x105, x109, u64(fiat.u1(x123)))
|
||||
x126, x127 := bits.add_u64(x107, x110, u64(fiat.u1(x125)))
|
||||
x128 := (u64(fiat.u1(x127)) + u64(fiat.u1(x108)))
|
||||
x130, x129 := bits.mul_u64(x3, arg1[3])
|
||||
x132, x131 := bits.mul_u64(x3, arg1[2])
|
||||
x134, x133 := bits.mul_u64(x3, arg1[1])
|
||||
x136, x135 := bits.mul_u64(x3, arg1[0])
|
||||
x137, x138 := bits.add_u64(x136, x133, u64(0x0))
|
||||
x139, x140 := bits.add_u64(x134, x131, u64(fiat.u1(x138)))
|
||||
x141, x142 := bits.add_u64(x132, x129, u64(fiat.u1(x140)))
|
||||
x143 := (u64(fiat.u1(x142)) + x130)
|
||||
x144, x145 := bits.add_u64(x120, x135, u64(0x0))
|
||||
x146, x147 := bits.add_u64(x122, x137, u64(fiat.u1(x145)))
|
||||
x148, x149 := bits.add_u64(x124, x139, u64(fiat.u1(x147)))
|
||||
x150, x151 := bits.add_u64(x126, x141, u64(fiat.u1(x149)))
|
||||
x152, x153 := bits.add_u64(x128, x143, u64(fiat.u1(x151)))
|
||||
x155, x154 := bits.mul_u64(x144, 0xffffffff00000001)
|
||||
x157, x156 := bits.mul_u64(x144, 0xffffffff)
|
||||
x159, x158 := bits.mul_u64(x144, 0xffffffffffffffff)
|
||||
x160, x161 := bits.add_u64(x159, x156, u64(0x0))
|
||||
x162 := (u64(fiat.u1(x161)) + x157)
|
||||
_, x164 := bits.add_u64(x144, x158, u64(0x0))
|
||||
x165, x166 := bits.add_u64(x146, x160, u64(fiat.u1(x164)))
|
||||
x167, x168 := bits.add_u64(x148, x162, u64(fiat.u1(x166)))
|
||||
x169, x170 := bits.add_u64(x150, x154, u64(fiat.u1(x168)))
|
||||
x171, x172 := bits.add_u64(x152, x155, u64(fiat.u1(x170)))
|
||||
x173 := (u64(fiat.u1(x172)) + u64(fiat.u1(x153)))
|
||||
x174, x175 := bits.sub_u64(x165, 0xffffffffffffffff, u64(0x0))
|
||||
x176, x177 := bits.sub_u64(x167, 0xffffffff, u64(fiat.u1(x175)))
|
||||
x178, x179 := bits.sub_u64(x169, u64(0x0), u64(fiat.u1(x177)))
|
||||
x180, x181 := bits.sub_u64(x171, 0xffffffff00000001, u64(fiat.u1(x179)))
|
||||
_, x183 := bits.sub_u64(x173, u64(0x0), u64(fiat.u1(x181)))
|
||||
x184 := fiat.cmovznz_u64(fiat.u1(x183), x174, x165)
|
||||
x185 := fiat.cmovznz_u64(fiat.u1(x183), x176, x167)
|
||||
x186 := fiat.cmovznz_u64(fiat.u1(x183), x178, x169)
|
||||
x187 := fiat.cmovznz_u64(fiat.u1(x183), x180, x171)
|
||||
out1[0] = x184
|
||||
out1[1] = x185
|
||||
out1[2] = x186
|
||||
out1[3] = x187
|
||||
}
|
||||
|
||||
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, 0xffffffffffffffff, u64(0x0))
|
||||
x11, x12 := bits.sub_u64(x3, 0xffffffff, u64(fiat.u1(x10)))
|
||||
x13, x14 := bits.sub_u64(x5, u64(0x0), u64(fiat.u1(x12)))
|
||||
x15, x16 := bits.sub_u64(x7, 0xffffffff00000001, 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, u64(0x0))
|
||||
x12, x13 := bits.add_u64(x3, (x9 & 0xffffffff), u64(fiat.u1(x11)))
|
||||
x14, x15 := bits.add_u64(x5, u64(0x0), u64(fiat.u1(x13)))
|
||||
x16, _ := bits.add_u64(x7, (x9 & 0xffffffff00000001), 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, u64(0x0))
|
||||
x12, x13 := bits.add_u64(x3, (x9 & 0xffffffff), u64(fiat.u1(x11)))
|
||||
x14, x15 := bits.add_u64(x5, u64(0x0), u64(fiat.u1(x13)))
|
||||
x16, _ := bits.add_u64(x7, (x9 & 0xffffffff00000001), 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] = 0x1
|
||||
out1[1] = 0xffffffff00000000
|
||||
out1[2] = 0xffffffffffffffff
|
||||
out1[3] = 0xfffffffe
|
||||
}
|
||||
|
||||
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]
|
||||
x3, x2 := bits.mul_u64(x1, 0xffffffff00000001)
|
||||
x5, x4 := bits.mul_u64(x1, 0xffffffff)
|
||||
x7, x6 := bits.mul_u64(x1, 0xffffffffffffffff)
|
||||
x8, x9 := bits.add_u64(x7, x4, u64(0x0))
|
||||
_, x11 := bits.add_u64(x1, x6, u64(0x0))
|
||||
x12, x13 := bits.add_u64(u64(0x0), x8, u64(fiat.u1(x11)))
|
||||
x14, x15 := bits.add_u64(x12, arg1[1], u64(0x0))
|
||||
x17, x16 := bits.mul_u64(x14, 0xffffffff00000001)
|
||||
x19, x18 := bits.mul_u64(x14, 0xffffffff)
|
||||
x21, x20 := bits.mul_u64(x14, 0xffffffffffffffff)
|
||||
x22, x23 := bits.add_u64(x21, x18, u64(0x0))
|
||||
_, x25 := bits.add_u64(x14, x20, u64(0x0))
|
||||
x26, x27 := bits.add_u64((u64(fiat.u1(x15)) + (u64(fiat.u1(x13)) + (u64(fiat.u1(x9)) + x5))), x22, u64(fiat.u1(x25)))
|
||||
x28, x29 := bits.add_u64(x2, (u64(fiat.u1(x23)) + x19), u64(fiat.u1(x27)))
|
||||
x30, x31 := bits.add_u64(x3, x16, u64(fiat.u1(x29)))
|
||||
x32, x33 := bits.add_u64(x26, arg1[2], u64(0x0))
|
||||
x34, x35 := bits.add_u64(x28, u64(0x0), u64(fiat.u1(x33)))
|
||||
x36, x37 := bits.add_u64(x30, u64(0x0), u64(fiat.u1(x35)))
|
||||
x39, x38 := bits.mul_u64(x32, 0xffffffff00000001)
|
||||
x41, x40 := bits.mul_u64(x32, 0xffffffff)
|
||||
x43, x42 := bits.mul_u64(x32, 0xffffffffffffffff)
|
||||
x44, x45 := bits.add_u64(x43, x40, u64(0x0))
|
||||
_, x47 := bits.add_u64(x32, x42, u64(0x0))
|
||||
x48, x49 := bits.add_u64(x34, x44, u64(fiat.u1(x47)))
|
||||
x50, x51 := bits.add_u64(x36, (u64(fiat.u1(x45)) + x41), u64(fiat.u1(x49)))
|
||||
x52, x53 := bits.add_u64((u64(fiat.u1(x37)) + (u64(fiat.u1(x31)) + x17)), x38, u64(fiat.u1(x51)))
|
||||
x54, x55 := bits.add_u64(x48, arg1[3], u64(0x0))
|
||||
x56, x57 := bits.add_u64(x50, u64(0x0), u64(fiat.u1(x55)))
|
||||
x58, x59 := bits.add_u64(x52, u64(0x0), u64(fiat.u1(x57)))
|
||||
x61, x60 := bits.mul_u64(x54, 0xffffffff00000001)
|
||||
x63, x62 := bits.mul_u64(x54, 0xffffffff)
|
||||
x65, x64 := bits.mul_u64(x54, 0xffffffffffffffff)
|
||||
x66, x67 := bits.add_u64(x65, x62, u64(0x0))
|
||||
_, x69 := bits.add_u64(x54, x64, u64(0x0))
|
||||
x70, x71 := bits.add_u64(x56, x66, u64(fiat.u1(x69)))
|
||||
x72, x73 := bits.add_u64(x58, (u64(fiat.u1(x67)) + x63), u64(fiat.u1(x71)))
|
||||
x74, x75 := bits.add_u64((u64(fiat.u1(x59)) + (u64(fiat.u1(x53)) + x39)), x60, u64(fiat.u1(x73)))
|
||||
x76 := (u64(fiat.u1(x75)) + x61)
|
||||
x77, x78 := bits.sub_u64(x70, 0xffffffffffffffff, u64(0x0))
|
||||
x79, x80 := bits.sub_u64(x72, 0xffffffff, u64(fiat.u1(x78)))
|
||||
x81, x82 := bits.sub_u64(x74, u64(0x0), u64(fiat.u1(x80)))
|
||||
x83, x84 := bits.sub_u64(x76, 0xffffffff00000001, u64(fiat.u1(x82)))
|
||||
_, x86 := bits.sub_u64(u64(0x0), u64(0x0), u64(fiat.u1(x84)))
|
||||
x87 := fiat.cmovznz_u64(fiat.u1(x86), x77, x70)
|
||||
x88 := fiat.cmovznz_u64(fiat.u1(x86), x79, x72)
|
||||
x89 := fiat.cmovznz_u64(fiat.u1(x86), x81, x74)
|
||||
x90 := fiat.cmovznz_u64(fiat.u1(x86), x83, x76)
|
||||
out1[0] = x87
|
||||
out1[1] = x88
|
||||
out1[2] = x89
|
||||
out1[3] = x90
|
||||
}
|
||||
|
||||
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, 0x4fffffffd)
|
||||
x8, x7 := bits.mul_u64(x4, 0xfffffffffffffffe)
|
||||
x10, x9 := bits.mul_u64(x4, 0xfffffffbffffffff)
|
||||
x12, x11 := bits.mul_u64(x4, 0x3)
|
||||
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)))
|
||||
x20, x19 := bits.mul_u64(x11, 0xffffffff00000001)
|
||||
x22, x21 := bits.mul_u64(x11, 0xffffffff)
|
||||
x24, x23 := bits.mul_u64(x11, 0xffffffffffffffff)
|
||||
x25, x26 := bits.add_u64(x24, x21, u64(0x0))
|
||||
_, x28 := bits.add_u64(x11, x23, u64(0x0))
|
||||
x29, x30 := bits.add_u64(x13, x25, u64(fiat.u1(x28)))
|
||||
x31, x32 := bits.add_u64(x15, (u64(fiat.u1(x26)) + x22), u64(fiat.u1(x30)))
|
||||
x33, x34 := bits.add_u64(x17, x19, u64(fiat.u1(x32)))
|
||||
x35, x36 := bits.add_u64((u64(fiat.u1(x18)) + x6), x20, u64(fiat.u1(x34)))
|
||||
x38, x37 := bits.mul_u64(x1, 0x4fffffffd)
|
||||
x40, x39 := bits.mul_u64(x1, 0xfffffffffffffffe)
|
||||
x42, x41 := bits.mul_u64(x1, 0xfffffffbffffffff)
|
||||
x44, x43 := bits.mul_u64(x1, 0x3)
|
||||
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(x29, x43, u64(0x0))
|
||||
x53, x54 := bits.add_u64(x31, x45, u64(fiat.u1(x52)))
|
||||
x55, x56 := bits.add_u64(x33, x47, u64(fiat.u1(x54)))
|
||||
x57, x58 := bits.add_u64(x35, x49, u64(fiat.u1(x56)))
|
||||
x60, x59 := bits.mul_u64(x51, 0xffffffff00000001)
|
||||
x62, x61 := bits.mul_u64(x51, 0xffffffff)
|
||||
x64, x63 := bits.mul_u64(x51, 0xffffffffffffffff)
|
||||
x65, x66 := bits.add_u64(x64, x61, u64(0x0))
|
||||
_, x68 := bits.add_u64(x51, x63, u64(0x0))
|
||||
x69, x70 := bits.add_u64(x53, x65, u64(fiat.u1(x68)))
|
||||
x71, x72 := bits.add_u64(x55, (u64(fiat.u1(x66)) + x62), u64(fiat.u1(x70)))
|
||||
x73, x74 := bits.add_u64(x57, x59, u64(fiat.u1(x72)))
|
||||
x75, x76 := bits.add_u64(((u64(fiat.u1(x58)) + u64(fiat.u1(x36))) + (u64(fiat.u1(x50)) + x38)), x60, u64(fiat.u1(x74)))
|
||||
x78, x77 := bits.mul_u64(x2, 0x4fffffffd)
|
||||
x80, x79 := bits.mul_u64(x2, 0xfffffffffffffffe)
|
||||
x82, x81 := bits.mul_u64(x2, 0xfffffffbffffffff)
|
||||
x84, x83 := bits.mul_u64(x2, 0x3)
|
||||
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(x69, x83, u64(0x0))
|
||||
x93, x94 := bits.add_u64(x71, x85, u64(fiat.u1(x92)))
|
||||
x95, x96 := bits.add_u64(x73, x87, u64(fiat.u1(x94)))
|
||||
x97, x98 := bits.add_u64(x75, x89, u64(fiat.u1(x96)))
|
||||
x100, x99 := bits.mul_u64(x91, 0xffffffff00000001)
|
||||
x102, x101 := bits.mul_u64(x91, 0xffffffff)
|
||||
x104, x103 := bits.mul_u64(x91, 0xffffffffffffffff)
|
||||
x105, x106 := bits.add_u64(x104, x101, u64(0x0))
|
||||
_, x108 := bits.add_u64(x91, x103, u64(0x0))
|
||||
x109, x110 := bits.add_u64(x93, x105, u64(fiat.u1(x108)))
|
||||
x111, x112 := bits.add_u64(x95, (u64(fiat.u1(x106)) + x102), u64(fiat.u1(x110)))
|
||||
x113, x114 := bits.add_u64(x97, x99, u64(fiat.u1(x112)))
|
||||
x115, x116 := bits.add_u64(((u64(fiat.u1(x98)) + u64(fiat.u1(x76))) + (u64(fiat.u1(x90)) + x78)), x100, u64(fiat.u1(x114)))
|
||||
x118, x117 := bits.mul_u64(x3, 0x4fffffffd)
|
||||
x120, x119 := bits.mul_u64(x3, 0xfffffffffffffffe)
|
||||
x122, x121 := bits.mul_u64(x3, 0xfffffffbffffffff)
|
||||
x124, x123 := bits.mul_u64(x3, 0x3)
|
||||
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(x109, x123, u64(0x0))
|
||||
x133, x134 := bits.add_u64(x111, x125, u64(fiat.u1(x132)))
|
||||
x135, x136 := bits.add_u64(x113, x127, u64(fiat.u1(x134)))
|
||||
x137, x138 := bits.add_u64(x115, x129, u64(fiat.u1(x136)))
|
||||
x140, x139 := bits.mul_u64(x131, 0xffffffff00000001)
|
||||
x142, x141 := bits.mul_u64(x131, 0xffffffff)
|
||||
x144, x143 := bits.mul_u64(x131, 0xffffffffffffffff)
|
||||
x145, x146 := bits.add_u64(x144, x141, u64(0x0))
|
||||
_, x148 := bits.add_u64(x131, x143, u64(0x0))
|
||||
x149, x150 := bits.add_u64(x133, x145, u64(fiat.u1(x148)))
|
||||
x151, x152 := bits.add_u64(x135, (u64(fiat.u1(x146)) + x142), u64(fiat.u1(x150)))
|
||||
x153, x154 := bits.add_u64(x137, x139, u64(fiat.u1(x152)))
|
||||
x155, x156 := bits.add_u64(((u64(fiat.u1(x138)) + u64(fiat.u1(x116))) + (u64(fiat.u1(x130)) + x118)), x140, u64(fiat.u1(x154)))
|
||||
x157, x158 := bits.sub_u64(x149, 0xffffffffffffffff, u64(0x0))
|
||||
x159, x160 := bits.sub_u64(x151, 0xffffffff, u64(fiat.u1(x158)))
|
||||
x161, x162 := bits.sub_u64(x153, u64(0x0), u64(fiat.u1(x160)))
|
||||
x163, x164 := bits.sub_u64(x155, 0xffffffff00000001, u64(fiat.u1(x162)))
|
||||
_, x166 := bits.sub_u64(u64(fiat.u1(x156)), u64(0x0), u64(fiat.u1(x164)))
|
||||
x167 := fiat.cmovznz_u64(fiat.u1(x166), x157, x149)
|
||||
x168 := fiat.cmovznz_u64(fiat.u1(x166), x159, x151)
|
||||
x169 := fiat.cmovznz_u64(fiat.u1(x166), x161, x153)
|
||||
x170 := fiat.cmovznz_u64(fiat.u1(x166), x163, x155)
|
||||
out1[0] = x167
|
||||
out1[1] = x168
|
||||
out1[2] = x169
|
||||
out1[3] = x170
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package field_scalar25519
|
||||
|
||||
import subtle "core:crypto/_subtle"
|
||||
import "core:encoding/endian"
|
||||
import "core:math/bits"
|
||||
import "core:mem"
|
||||
@@ -121,13 +122,11 @@ fe_equal :: proc "contextless" (arg1, arg2: ^Montgomery_Domain_Field_Element) ->
|
||||
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)
|
||||
is_eq := subtle.eq(fe_non_zero(&tmp), 0)
|
||||
|
||||
fe_clear(&tmp)
|
||||
|
||||
return int(borrow)
|
||||
return int(is_eq)
|
||||
}
|
||||
|
||||
fe_zero :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element) {
|
||||
|
||||
210
core/crypto/_fiat/field_scalarp256r1/field.odin
Normal file
210
core/crypto/_fiat/field_scalarp256r1/field.odin
Normal file
@@ -0,0 +1,210 @@
|
||||
package field_scalarp256r1
|
||||
|
||||
import subtle "core:crypto/_subtle"
|
||||
import "core:encoding/endian"
|
||||
import "core:math/bits"
|
||||
import "core:mem"
|
||||
|
||||
@(private, rodata)
|
||||
TWO_192 := Montgomery_Domain_Field_Element{
|
||||
2482910415990817935,
|
||||
2879494685571067143,
|
||||
8732918506673730078,
|
||||
85565669603516024,
|
||||
}
|
||||
@(private, rodata)
|
||||
TWO_384 := Montgomery_Domain_Field_Element{
|
||||
2127524300190691059,
|
||||
17014302137236182484,
|
||||
16604910261202196099,
|
||||
3621421107472562910,
|
||||
}
|
||||
// 2^384 % p (From sage)
|
||||
// 0x431905529c0166ce652e96b7ccca0a99679b73e19ad16947f01cf013fc632551
|
||||
|
||||
fe_clear :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) {
|
||||
mem.zero_explicit(arg1, size_of(Montgomery_Domain_Field_Element))
|
||||
}
|
||||
|
||||
fe_clear_vec :: proc "contextless" (
|
||||
arg1: []^Montgomery_Domain_Field_Element,
|
||||
) {
|
||||
for fe in arg1 {
|
||||
fe_clear(fe)
|
||||
}
|
||||
}
|
||||
|
||||
fe_from_bytes :: proc "contextless" (
|
||||
out1: ^Montgomery_Domain_Field_Element,
|
||||
arg1: []byte,
|
||||
) -> bool {
|
||||
ensure_contextless(len(out1) <= 64, "p256r1: invalid scalar input buffer")
|
||||
|
||||
is_canonical := false
|
||||
s_len := len(arg1)
|
||||
switch {
|
||||
case s_len < 32:
|
||||
// No way this can be greater than the order.
|
||||
fe_unchecked_set(out1, arg1)
|
||||
is_canonical = true
|
||||
case s_len == 32:
|
||||
// It is quite likely that a reduction mod p is required,
|
||||
// as the order of the curve is sufficiently smaller than
|
||||
// 2^256-1, so just check if we actually needed to reduced
|
||||
// and do the reduction anyway, so that things that require
|
||||
// canonical scalars can reject non-canonical encodings.
|
||||
is_canonical = fe_is_canonical(arg1)
|
||||
fallthrough
|
||||
case:
|
||||
// Use Frank Denis' trick, as documented by Filippo Valsorda
|
||||
// at https://words.filippo.io/dispatches/wide-reduction/
|
||||
//
|
||||
// "I represent the value as a+b*2^192+c*2^384"
|
||||
//
|
||||
// Note: Omitting the `c` computation is fine as, reduction
|
||||
// being length dependent provides no useful timing information.
|
||||
|
||||
// Zero extend to 512-bits.
|
||||
src_512: [64]byte
|
||||
copy(src_512[64-s_len:], arg1)
|
||||
defer mem.zero_explicit(&src_512, size_of(src_512))
|
||||
|
||||
fe_unchecked_set(out1, src_512[40:]) // a
|
||||
b: Montgomery_Domain_Field_Element
|
||||
fe_unchecked_set(&b, src_512[16:40]) // b
|
||||
|
||||
fe_mul(&b, &b, &TWO_192)
|
||||
fe_add(out1, out1, &b)
|
||||
if s_len >= 48 {
|
||||
c: Montgomery_Domain_Field_Element
|
||||
fe_unchecked_set(&c, src_512[:16]) // c
|
||||
fe_mul(&c, &c, &TWO_384)
|
||||
fe_add(out1, out1, &c)
|
||||
|
||||
fe_clear(&c)
|
||||
}
|
||||
|
||||
fe_clear(&b)
|
||||
}
|
||||
|
||||
return !is_canonical
|
||||
}
|
||||
|
||||
@(private)
|
||||
fe_is_canonical :: proc "contextless" (arg1: []byte) -> bool {
|
||||
_, borrow := bits.sub_u64(ELL[0] - 1, endian.unchecked_get_u64be(arg1[24:]), 0)
|
||||
_, borrow = bits.sub_u64(ELL[1], endian.unchecked_get_u64be(arg1[16:]), borrow)
|
||||
_, borrow = bits.sub_u64(ELL[2], endian.unchecked_get_u64be(arg1[8:]), borrow)
|
||||
_, borrow = bits.sub_u64(ELL[3], endian.unchecked_get_u64be(arg1[0:]), borrow)
|
||||
return borrow == 0
|
||||
}
|
||||
|
||||
@(private)
|
||||
fe_unchecked_set :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element, arg1: []byte) {
|
||||
arg1_256: [32]byte
|
||||
defer mem.zero_explicit(&arg1_256, size_of(arg1_256))
|
||||
copy(arg1_256[32-len(arg1):], arg1)
|
||||
|
||||
tmp := Non_Montgomery_Domain_Field_Element {
|
||||
endian.unchecked_get_u64be(arg1_256[24:]),
|
||||
endian.unchecked_get_u64be(arg1_256[16:]),
|
||||
endian.unchecked_get_u64be(arg1_256[8:]),
|
||||
endian.unchecked_get_u64be(arg1_256[0:]),
|
||||
}
|
||||
defer mem.zero_explicit(&tmp, size_of(tmp))
|
||||
|
||||
fe_to_montgomery(out1, &tmp)
|
||||
}
|
||||
|
||||
fe_to_bytes :: proc "contextless" (out1: []byte, arg1: ^Montgomery_Domain_Field_Element) {
|
||||
ensure_contextless(len(out1) == 32, "p256r1: invalid scalar output buffer")
|
||||
|
||||
tmp: Non_Montgomery_Domain_Field_Element
|
||||
fe_from_montgomery(&tmp, arg1)
|
||||
|
||||
// Note: Likewise, output in big-endian.
|
||||
endian.unchecked_put_u64be(out1[24:], tmp[0])
|
||||
endian.unchecked_put_u64be(out1[16:], tmp[1])
|
||||
endian.unchecked_put_u64be(out1[8:], tmp[2])
|
||||
endian.unchecked_put_u64be(out1[0:], 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)
|
||||
|
||||
is_eq := subtle.u64_is_zero(fe_non_zero(&tmp))
|
||||
|
||||
fe_clear(&tmp)
|
||||
|
||||
return int(is_eq)
|
||||
}
|
||||
|
||||
fe_is_odd :: proc "contextless" (arg1: ^Montgomery_Domain_Field_Element) -> int {
|
||||
tmp: Non_Montgomery_Domain_Field_Element
|
||||
defer mem.zero_explicit(&tmp, size_of(tmp))
|
||||
|
||||
fe_from_montgomery(&tmp, arg1)
|
||||
return int(tmp[0] & 1)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@(optimization_mode = "none")
|
||||
fe_cond_swap :: #force_no_inline proc "contextless" (out1, out2: ^Montgomery_Domain_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
|
||||
out1[0], out2[0] = x1, y1
|
||||
out1[1], out2[1] = x2, y2
|
||||
out1[2], out2[2] = x3, y3
|
||||
out1[3], out2[3] = x4, y4
|
||||
}
|
||||
|
||||
@(optimization_mode = "none")
|
||||
fe_cond_select :: #force_no_inline proc "contextless" (
|
||||
out1, arg1, arg2: ^Montgomery_Domain_Field_Element,
|
||||
arg3: int,
|
||||
) {
|
||||
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]))
|
||||
out1[0] = x1
|
||||
out1[1] = x2
|
||||
out1[2] = x3
|
||||
out1[3] = x4
|
||||
}
|
||||
|
||||
fe_cond_negate :: proc "contextless" (out1, arg1: ^Montgomery_Domain_Field_Element, ctrl: int) {
|
||||
tmp1: Montgomery_Domain_Field_Element = ---
|
||||
fe_opp(&tmp1, arg1)
|
||||
fe_cond_select(out1, arg1, &tmp1, ctrl)
|
||||
|
||||
fe_clear(&tmp1)
|
||||
}
|
||||
569
core/crypto/_fiat/field_scalarp256r1/field64.odin
Normal file
569
core/crypto/_fiat/field_scalarp256r1/field64.odin
Normal file
@@ -0,0 +1,569 @@
|
||||
// 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_scalarp256r1
|
||||
|
||||
// The file provides arithmetic on the field Z/(2^256 - 2^224 + 2^192 -
|
||||
// 89188191075325690597107910205041859247) 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.
|
||||
//
|
||||
// WARNING: While big-endian is the common representation used for this
|
||||
// curve, the fiat output uses least-significant-limb first.
|
||||
|
||||
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{0xf3b9cac2fc632551, 0xbce6faada7179e84, 0xffffffffffffffff, 0xffffffff00000000}
|
||||
|
||||
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, 0xccd1c8aaee00bc4f)
|
||||
x23, x22 := bits.mul_u64(x20, 0xffffffff00000000)
|
||||
x25, x24 := bits.mul_u64(x20, 0xffffffffffffffff)
|
||||
x27, x26 := bits.mul_u64(x20, 0xbce6faada7179e84)
|
||||
x29, x28 := bits.mul_u64(x20, 0xf3b9cac2fc632551)
|
||||
x30, x31 := bits.add_u64(x29, x26, u64(0x0))
|
||||
x32, x33 := bits.add_u64(x27, x24, u64(fiat.u1(x31)))
|
||||
x34, x35 := bits.add_u64(x25, x22, u64(fiat.u1(x33)))
|
||||
x36 := (u64(fiat.u1(x35)) + x23)
|
||||
_, x38 := bits.add_u64(x11, x28, u64(0x0))
|
||||
x39, x40 := bits.add_u64(x13, x30, u64(fiat.u1(x38)))
|
||||
x41, x42 := bits.add_u64(x15, x32, u64(fiat.u1(x40)))
|
||||
x43, x44 := bits.add_u64(x17, x34, u64(fiat.u1(x42)))
|
||||
x45, x46 := bits.add_u64(x19, x36, u64(fiat.u1(x44)))
|
||||
x48, x47 := bits.mul_u64(x1, arg2[3])
|
||||
x50, x49 := bits.mul_u64(x1, arg2[2])
|
||||
x52, x51 := bits.mul_u64(x1, arg2[1])
|
||||
x54, x53 := bits.mul_u64(x1, arg2[0])
|
||||
x55, x56 := bits.add_u64(x54, x51, u64(0x0))
|
||||
x57, x58 := bits.add_u64(x52, x49, u64(fiat.u1(x56)))
|
||||
x59, x60 := bits.add_u64(x50, x47, u64(fiat.u1(x58)))
|
||||
x61 := (u64(fiat.u1(x60)) + x48)
|
||||
x62, x63 := bits.add_u64(x39, x53, u64(0x0))
|
||||
x64, x65 := bits.add_u64(x41, x55, u64(fiat.u1(x63)))
|
||||
x66, x67 := bits.add_u64(x43, x57, u64(fiat.u1(x65)))
|
||||
x68, x69 := bits.add_u64(x45, x59, u64(fiat.u1(x67)))
|
||||
x70, x71 := bits.add_u64(u64(fiat.u1(x46)), x61, u64(fiat.u1(x69)))
|
||||
_, x72 := bits.mul_u64(x62, 0xccd1c8aaee00bc4f)
|
||||
x75, x74 := bits.mul_u64(x72, 0xffffffff00000000)
|
||||
x77, x76 := bits.mul_u64(x72, 0xffffffffffffffff)
|
||||
x79, x78 := bits.mul_u64(x72, 0xbce6faada7179e84)
|
||||
x81, x80 := bits.mul_u64(x72, 0xf3b9cac2fc632551)
|
||||
x82, x83 := bits.add_u64(x81, x78, u64(0x0))
|
||||
x84, x85 := bits.add_u64(x79, x76, u64(fiat.u1(x83)))
|
||||
x86, x87 := bits.add_u64(x77, x74, u64(fiat.u1(x85)))
|
||||
x88 := (u64(fiat.u1(x87)) + x75)
|
||||
_, x90 := bits.add_u64(x62, x80, u64(0x0))
|
||||
x91, x92 := bits.add_u64(x64, x82, u64(fiat.u1(x90)))
|
||||
x93, x94 := bits.add_u64(x66, x84, u64(fiat.u1(x92)))
|
||||
x95, x96 := bits.add_u64(x68, x86, u64(fiat.u1(x94)))
|
||||
x97, x98 := bits.add_u64(x70, x88, u64(fiat.u1(x96)))
|
||||
x99 := (u64(fiat.u1(x98)) + u64(fiat.u1(x71)))
|
||||
x101, x100 := bits.mul_u64(x2, arg2[3])
|
||||
x103, x102 := bits.mul_u64(x2, arg2[2])
|
||||
x105, x104 := bits.mul_u64(x2, arg2[1])
|
||||
x107, x106 := bits.mul_u64(x2, arg2[0])
|
||||
x108, x109 := bits.add_u64(x107, x104, u64(0x0))
|
||||
x110, x111 := bits.add_u64(x105, x102, u64(fiat.u1(x109)))
|
||||
x112, x113 := bits.add_u64(x103, x100, u64(fiat.u1(x111)))
|
||||
x114 := (u64(fiat.u1(x113)) + x101)
|
||||
x115, x116 := bits.add_u64(x91, x106, u64(0x0))
|
||||
x117, x118 := bits.add_u64(x93, x108, u64(fiat.u1(x116)))
|
||||
x119, x120 := bits.add_u64(x95, x110, u64(fiat.u1(x118)))
|
||||
x121, x122 := bits.add_u64(x97, x112, u64(fiat.u1(x120)))
|
||||
x123, x124 := bits.add_u64(x99, x114, u64(fiat.u1(x122)))
|
||||
_, x125 := bits.mul_u64(x115, 0xccd1c8aaee00bc4f)
|
||||
x128, x127 := bits.mul_u64(x125, 0xffffffff00000000)
|
||||
x130, x129 := bits.mul_u64(x125, 0xffffffffffffffff)
|
||||
x132, x131 := bits.mul_u64(x125, 0xbce6faada7179e84)
|
||||
x134, x133 := bits.mul_u64(x125, 0xf3b9cac2fc632551)
|
||||
x135, x136 := bits.add_u64(x134, x131, u64(0x0))
|
||||
x137, x138 := bits.add_u64(x132, x129, u64(fiat.u1(x136)))
|
||||
x139, x140 := bits.add_u64(x130, x127, u64(fiat.u1(x138)))
|
||||
x141 := (u64(fiat.u1(x140)) + x128)
|
||||
_, x143 := bits.add_u64(x115, x133, u64(0x0))
|
||||
x144, x145 := bits.add_u64(x117, x135, u64(fiat.u1(x143)))
|
||||
x146, x147 := bits.add_u64(x119, x137, u64(fiat.u1(x145)))
|
||||
x148, x149 := bits.add_u64(x121, x139, u64(fiat.u1(x147)))
|
||||
x150, x151 := bits.add_u64(x123, x141, u64(fiat.u1(x149)))
|
||||
x152 := (u64(fiat.u1(x151)) + u64(fiat.u1(x124)))
|
||||
x154, x153 := bits.mul_u64(x3, arg2[3])
|
||||
x156, x155 := bits.mul_u64(x3, arg2[2])
|
||||
x158, x157 := bits.mul_u64(x3, arg2[1])
|
||||
x160, x159 := bits.mul_u64(x3, arg2[0])
|
||||
x161, x162 := bits.add_u64(x160, x157, u64(0x0))
|
||||
x163, x164 := bits.add_u64(x158, x155, u64(fiat.u1(x162)))
|
||||
x165, x166 := bits.add_u64(x156, x153, u64(fiat.u1(x164)))
|
||||
x167 := (u64(fiat.u1(x166)) + x154)
|
||||
x168, x169 := bits.add_u64(x144, x159, u64(0x0))
|
||||
x170, x171 := bits.add_u64(x146, x161, u64(fiat.u1(x169)))
|
||||
x172, x173 := bits.add_u64(x148, x163, u64(fiat.u1(x171)))
|
||||
x174, x175 := bits.add_u64(x150, x165, u64(fiat.u1(x173)))
|
||||
x176, x177 := bits.add_u64(x152, x167, u64(fiat.u1(x175)))
|
||||
_, x178 := bits.mul_u64(x168, 0xccd1c8aaee00bc4f)
|
||||
x181, x180 := bits.mul_u64(x178, 0xffffffff00000000)
|
||||
x183, x182 := bits.mul_u64(x178, 0xffffffffffffffff)
|
||||
x185, x184 := bits.mul_u64(x178, 0xbce6faada7179e84)
|
||||
x187, x186 := bits.mul_u64(x178, 0xf3b9cac2fc632551)
|
||||
x188, x189 := bits.add_u64(x187, x184, u64(0x0))
|
||||
x190, x191 := bits.add_u64(x185, x182, u64(fiat.u1(x189)))
|
||||
x192, x193 := bits.add_u64(x183, x180, u64(fiat.u1(x191)))
|
||||
x194 := (u64(fiat.u1(x193)) + x181)
|
||||
_, x196 := bits.add_u64(x168, x186, u64(0x0))
|
||||
x197, x198 := bits.add_u64(x170, x188, u64(fiat.u1(x196)))
|
||||
x199, x200 := bits.add_u64(x172, x190, u64(fiat.u1(x198)))
|
||||
x201, x202 := bits.add_u64(x174, x192, u64(fiat.u1(x200)))
|
||||
x203, x204 := bits.add_u64(x176, x194, u64(fiat.u1(x202)))
|
||||
x205 := (u64(fiat.u1(x204)) + u64(fiat.u1(x177)))
|
||||
x206, x207 := bits.sub_u64(x197, 0xf3b9cac2fc632551, u64(0x0))
|
||||
x208, x209 := bits.sub_u64(x199, 0xbce6faada7179e84, u64(fiat.u1(x207)))
|
||||
x210, x211 := bits.sub_u64(x201, 0xffffffffffffffff, u64(fiat.u1(x209)))
|
||||
x212, x213 := bits.sub_u64(x203, 0xffffffff00000000, u64(fiat.u1(x211)))
|
||||
_, x215 := bits.sub_u64(x205, u64(0x0), u64(fiat.u1(x213)))
|
||||
x216 := fiat.cmovznz_u64(fiat.u1(x215), x206, x197)
|
||||
x217 := fiat.cmovznz_u64(fiat.u1(x215), x208, x199)
|
||||
x218 := fiat.cmovznz_u64(fiat.u1(x215), x210, x201)
|
||||
x219 := fiat.cmovznz_u64(fiat.u1(x215), x212, x203)
|
||||
out1[0] = x216
|
||||
out1[1] = x217
|
||||
out1[2] = x218
|
||||
out1[3] = x219
|
||||
}
|
||||
|
||||
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, 0xccd1c8aaee00bc4f)
|
||||
x23, x22 := bits.mul_u64(x20, 0xffffffff00000000)
|
||||
x25, x24 := bits.mul_u64(x20, 0xffffffffffffffff)
|
||||
x27, x26 := bits.mul_u64(x20, 0xbce6faada7179e84)
|
||||
x29, x28 := bits.mul_u64(x20, 0xf3b9cac2fc632551)
|
||||
x30, x31 := bits.add_u64(x29, x26, u64(0x0))
|
||||
x32, x33 := bits.add_u64(x27, x24, u64(fiat.u1(x31)))
|
||||
x34, x35 := bits.add_u64(x25, x22, u64(fiat.u1(x33)))
|
||||
x36 := (u64(fiat.u1(x35)) + x23)
|
||||
_, x38 := bits.add_u64(x11, x28, u64(0x0))
|
||||
x39, x40 := bits.add_u64(x13, x30, u64(fiat.u1(x38)))
|
||||
x41, x42 := bits.add_u64(x15, x32, u64(fiat.u1(x40)))
|
||||
x43, x44 := bits.add_u64(x17, x34, u64(fiat.u1(x42)))
|
||||
x45, x46 := bits.add_u64(x19, x36, u64(fiat.u1(x44)))
|
||||
x48, x47 := bits.mul_u64(x1, arg1[3])
|
||||
x50, x49 := bits.mul_u64(x1, arg1[2])
|
||||
x52, x51 := bits.mul_u64(x1, arg1[1])
|
||||
x54, x53 := bits.mul_u64(x1, arg1[0])
|
||||
x55, x56 := bits.add_u64(x54, x51, u64(0x0))
|
||||
x57, x58 := bits.add_u64(x52, x49, u64(fiat.u1(x56)))
|
||||
x59, x60 := bits.add_u64(x50, x47, u64(fiat.u1(x58)))
|
||||
x61 := (u64(fiat.u1(x60)) + x48)
|
||||
x62, x63 := bits.add_u64(x39, x53, u64(0x0))
|
||||
x64, x65 := bits.add_u64(x41, x55, u64(fiat.u1(x63)))
|
||||
x66, x67 := bits.add_u64(x43, x57, u64(fiat.u1(x65)))
|
||||
x68, x69 := bits.add_u64(x45, x59, u64(fiat.u1(x67)))
|
||||
x70, x71 := bits.add_u64(u64(fiat.u1(x46)), x61, u64(fiat.u1(x69)))
|
||||
_, x72 := bits.mul_u64(x62, 0xccd1c8aaee00bc4f)
|
||||
x75, x74 := bits.mul_u64(x72, 0xffffffff00000000)
|
||||
x77, x76 := bits.mul_u64(x72, 0xffffffffffffffff)
|
||||
x79, x78 := bits.mul_u64(x72, 0xbce6faada7179e84)
|
||||
x81, x80 := bits.mul_u64(x72, 0xf3b9cac2fc632551)
|
||||
x82, x83 := bits.add_u64(x81, x78, u64(0x0))
|
||||
x84, x85 := bits.add_u64(x79, x76, u64(fiat.u1(x83)))
|
||||
x86, x87 := bits.add_u64(x77, x74, u64(fiat.u1(x85)))
|
||||
x88 := (u64(fiat.u1(x87)) + x75)
|
||||
_, x90 := bits.add_u64(x62, x80, u64(0x0))
|
||||
x91, x92 := bits.add_u64(x64, x82, u64(fiat.u1(x90)))
|
||||
x93, x94 := bits.add_u64(x66, x84, u64(fiat.u1(x92)))
|
||||
x95, x96 := bits.add_u64(x68, x86, u64(fiat.u1(x94)))
|
||||
x97, x98 := bits.add_u64(x70, x88, u64(fiat.u1(x96)))
|
||||
x99 := (u64(fiat.u1(x98)) + u64(fiat.u1(x71)))
|
||||
x101, x100 := bits.mul_u64(x2, arg1[3])
|
||||
x103, x102 := bits.mul_u64(x2, arg1[2])
|
||||
x105, x104 := bits.mul_u64(x2, arg1[1])
|
||||
x107, x106 := bits.mul_u64(x2, arg1[0])
|
||||
x108, x109 := bits.add_u64(x107, x104, u64(0x0))
|
||||
x110, x111 := bits.add_u64(x105, x102, u64(fiat.u1(x109)))
|
||||
x112, x113 := bits.add_u64(x103, x100, u64(fiat.u1(x111)))
|
||||
x114 := (u64(fiat.u1(x113)) + x101)
|
||||
x115, x116 := bits.add_u64(x91, x106, u64(0x0))
|
||||
x117, x118 := bits.add_u64(x93, x108, u64(fiat.u1(x116)))
|
||||
x119, x120 := bits.add_u64(x95, x110, u64(fiat.u1(x118)))
|
||||
x121, x122 := bits.add_u64(x97, x112, u64(fiat.u1(x120)))
|
||||
x123, x124 := bits.add_u64(x99, x114, u64(fiat.u1(x122)))
|
||||
_, x125 := bits.mul_u64(x115, 0xccd1c8aaee00bc4f)
|
||||
x128, x127 := bits.mul_u64(x125, 0xffffffff00000000)
|
||||
x130, x129 := bits.mul_u64(x125, 0xffffffffffffffff)
|
||||
x132, x131 := bits.mul_u64(x125, 0xbce6faada7179e84)
|
||||
x134, x133 := bits.mul_u64(x125, 0xf3b9cac2fc632551)
|
||||
x135, x136 := bits.add_u64(x134, x131, u64(0x0))
|
||||
x137, x138 := bits.add_u64(x132, x129, u64(fiat.u1(x136)))
|
||||
x139, x140 := bits.add_u64(x130, x127, u64(fiat.u1(x138)))
|
||||
x141 := (u64(fiat.u1(x140)) + x128)
|
||||
_, x143 := bits.add_u64(x115, x133, u64(0x0))
|
||||
x144, x145 := bits.add_u64(x117, x135, u64(fiat.u1(x143)))
|
||||
x146, x147 := bits.add_u64(x119, x137, u64(fiat.u1(x145)))
|
||||
x148, x149 := bits.add_u64(x121, x139, u64(fiat.u1(x147)))
|
||||
x150, x151 := bits.add_u64(x123, x141, u64(fiat.u1(x149)))
|
||||
x152 := (u64(fiat.u1(x151)) + u64(fiat.u1(x124)))
|
||||
x154, x153 := bits.mul_u64(x3, arg1[3])
|
||||
x156, x155 := bits.mul_u64(x3, arg1[2])
|
||||
x158, x157 := bits.mul_u64(x3, arg1[1])
|
||||
x160, x159 := bits.mul_u64(x3, arg1[0])
|
||||
x161, x162 := bits.add_u64(x160, x157, u64(0x0))
|
||||
x163, x164 := bits.add_u64(x158, x155, u64(fiat.u1(x162)))
|
||||
x165, x166 := bits.add_u64(x156, x153, u64(fiat.u1(x164)))
|
||||
x167 := (u64(fiat.u1(x166)) + x154)
|
||||
x168, x169 := bits.add_u64(x144, x159, u64(0x0))
|
||||
x170, x171 := bits.add_u64(x146, x161, u64(fiat.u1(x169)))
|
||||
x172, x173 := bits.add_u64(x148, x163, u64(fiat.u1(x171)))
|
||||
x174, x175 := bits.add_u64(x150, x165, u64(fiat.u1(x173)))
|
||||
x176, x177 := bits.add_u64(x152, x167, u64(fiat.u1(x175)))
|
||||
_, x178 := bits.mul_u64(x168, 0xccd1c8aaee00bc4f)
|
||||
x181, x180 := bits.mul_u64(x178, 0xffffffff00000000)
|
||||
x183, x182 := bits.mul_u64(x178, 0xffffffffffffffff)
|
||||
x185, x184 := bits.mul_u64(x178, 0xbce6faada7179e84)
|
||||
x187, x186 := bits.mul_u64(x178, 0xf3b9cac2fc632551)
|
||||
x188, x189 := bits.add_u64(x187, x184, u64(0x0))
|
||||
x190, x191 := bits.add_u64(x185, x182, u64(fiat.u1(x189)))
|
||||
x192, x193 := bits.add_u64(x183, x180, u64(fiat.u1(x191)))
|
||||
x194 := (u64(fiat.u1(x193)) + x181)
|
||||
_, x196 := bits.add_u64(x168, x186, u64(0x0))
|
||||
x197, x198 := bits.add_u64(x170, x188, u64(fiat.u1(x196)))
|
||||
x199, x200 := bits.add_u64(x172, x190, u64(fiat.u1(x198)))
|
||||
x201, x202 := bits.add_u64(x174, x192, u64(fiat.u1(x200)))
|
||||
x203, x204 := bits.add_u64(x176, x194, u64(fiat.u1(x202)))
|
||||
x205 := (u64(fiat.u1(x204)) + u64(fiat.u1(x177)))
|
||||
x206, x207 := bits.sub_u64(x197, 0xf3b9cac2fc632551, u64(0x0))
|
||||
x208, x209 := bits.sub_u64(x199, 0xbce6faada7179e84, u64(fiat.u1(x207)))
|
||||
x210, x211 := bits.sub_u64(x201, 0xffffffffffffffff, u64(fiat.u1(x209)))
|
||||
x212, x213 := bits.sub_u64(x203, 0xffffffff00000000, u64(fiat.u1(x211)))
|
||||
_, x215 := bits.sub_u64(x205, u64(0x0), u64(fiat.u1(x213)))
|
||||
x216 := fiat.cmovznz_u64(fiat.u1(x215), x206, x197)
|
||||
x217 := fiat.cmovznz_u64(fiat.u1(x215), x208, x199)
|
||||
x218 := fiat.cmovznz_u64(fiat.u1(x215), x210, x201)
|
||||
x219 := fiat.cmovznz_u64(fiat.u1(x215), x212, x203)
|
||||
out1[0] = x216
|
||||
out1[1] = x217
|
||||
out1[2] = x218
|
||||
out1[3] = x219
|
||||
}
|
||||
|
||||
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, 0xf3b9cac2fc632551, u64(0x0))
|
||||
x11, x12 := bits.sub_u64(x3, 0xbce6faada7179e84, u64(fiat.u1(x10)))
|
||||
x13, x14 := bits.sub_u64(x5, 0xffffffffffffffff, u64(fiat.u1(x12)))
|
||||
x15, x16 := bits.sub_u64(x7, 0xffffffff00000000, 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 & 0xf3b9cac2fc632551), u64(0x0))
|
||||
x12, x13 := bits.add_u64(x3, (x9 & 0xbce6faada7179e84), u64(fiat.u1(x11)))
|
||||
x14, x15 := bits.add_u64(x5, x9, u64(fiat.u1(x13)))
|
||||
x16, _ := bits.add_u64(x7, (x9 & 0xffffffff00000000), 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 & 0xf3b9cac2fc632551), u64(0x0))
|
||||
x12, x13 := bits.add_u64(x3, (x9 & 0xbce6faada7179e84), u64(fiat.u1(x11)))
|
||||
x14, x15 := bits.add_u64(x5, x9, u64(fiat.u1(x13)))
|
||||
x16, _ := bits.add_u64(x7, (x9 & 0xffffffff00000000), 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] = 0xc46353d039cdaaf
|
||||
out1[1] = 0x4319055258e8617b
|
||||
out1[2] = u64(0x0)
|
||||
out1[3] = 0xffffffff
|
||||
}
|
||||
|
||||
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, 0xccd1c8aaee00bc4f)
|
||||
x5, x4 := bits.mul_u64(x2, 0xffffffff00000000)
|
||||
x7, x6 := bits.mul_u64(x2, 0xffffffffffffffff)
|
||||
x9, x8 := bits.mul_u64(x2, 0xbce6faada7179e84)
|
||||
x11, x10 := bits.mul_u64(x2, 0xf3b9cac2fc632551)
|
||||
x12, x13 := bits.add_u64(x11, x8, u64(0x0))
|
||||
x14, x15 := bits.add_u64(x9, x6, u64(fiat.u1(x13)))
|
||||
x16, x17 := bits.add_u64(x7, x4, u64(fiat.u1(x15)))
|
||||
_, x19 := bits.add_u64(x1, x10, u64(0x0))
|
||||
x20, x21 := bits.add_u64(u64(0x0), x12, u64(fiat.u1(x19)))
|
||||
x22, x23 := bits.add_u64(u64(0x0), x14, u64(fiat.u1(x21)))
|
||||
x24, x25 := bits.add_u64(u64(0x0), x16, u64(fiat.u1(x23)))
|
||||
x26, x27 := bits.add_u64(x20, arg1[1], u64(0x0))
|
||||
x28, x29 := bits.add_u64(x22, u64(0x0), u64(fiat.u1(x27)))
|
||||
x30, x31 := bits.add_u64(x24, u64(0x0), u64(fiat.u1(x29)))
|
||||
_, x32 := bits.mul_u64(x26, 0xccd1c8aaee00bc4f)
|
||||
x35, x34 := bits.mul_u64(x32, 0xffffffff00000000)
|
||||
x37, x36 := bits.mul_u64(x32, 0xffffffffffffffff)
|
||||
x39, x38 := bits.mul_u64(x32, 0xbce6faada7179e84)
|
||||
x41, x40 := bits.mul_u64(x32, 0xf3b9cac2fc632551)
|
||||
x42, x43 := bits.add_u64(x41, x38, u64(0x0))
|
||||
x44, x45 := bits.add_u64(x39, x36, u64(fiat.u1(x43)))
|
||||
x46, x47 := bits.add_u64(x37, x34, u64(fiat.u1(x45)))
|
||||
_, x49 := bits.add_u64(x26, x40, u64(0x0))
|
||||
x50, x51 := bits.add_u64(x28, x42, u64(fiat.u1(x49)))
|
||||
x52, x53 := bits.add_u64(x30, x44, u64(fiat.u1(x51)))
|
||||
x54, x55 := bits.add_u64((u64(fiat.u1(x31)) + (u64(fiat.u1(x25)) + (u64(fiat.u1(x17)) + x5))), x46, u64(fiat.u1(x53)))
|
||||
x56, x57 := bits.add_u64(x50, arg1[2], u64(0x0))
|
||||
x58, x59 := bits.add_u64(x52, u64(0x0), u64(fiat.u1(x57)))
|
||||
x60, x61 := bits.add_u64(x54, u64(0x0), u64(fiat.u1(x59)))
|
||||
_, x62 := bits.mul_u64(x56, 0xccd1c8aaee00bc4f)
|
||||
x65, x64 := bits.mul_u64(x62, 0xffffffff00000000)
|
||||
x67, x66 := bits.mul_u64(x62, 0xffffffffffffffff)
|
||||
x69, x68 := bits.mul_u64(x62, 0xbce6faada7179e84)
|
||||
x71, x70 := bits.mul_u64(x62, 0xf3b9cac2fc632551)
|
||||
x72, x73 := bits.add_u64(x71, x68, u64(0x0))
|
||||
x74, x75 := bits.add_u64(x69, x66, u64(fiat.u1(x73)))
|
||||
x76, x77 := bits.add_u64(x67, x64, u64(fiat.u1(x75)))
|
||||
_, x79 := bits.add_u64(x56, x70, u64(0x0))
|
||||
x80, x81 := bits.add_u64(x58, x72, u64(fiat.u1(x79)))
|
||||
x82, x83 := bits.add_u64(x60, x74, u64(fiat.u1(x81)))
|
||||
x84, x85 := bits.add_u64((u64(fiat.u1(x61)) + (u64(fiat.u1(x55)) + (u64(fiat.u1(x47)) + x35))), x76, u64(fiat.u1(x83)))
|
||||
x86, x87 := bits.add_u64(x80, arg1[3], u64(0x0))
|
||||
x88, x89 := bits.add_u64(x82, u64(0x0), u64(fiat.u1(x87)))
|
||||
x90, x91 := bits.add_u64(x84, u64(0x0), u64(fiat.u1(x89)))
|
||||
_, x92 := bits.mul_u64(x86, 0xccd1c8aaee00bc4f)
|
||||
x95, x94 := bits.mul_u64(x92, 0xffffffff00000000)
|
||||
x97, x96 := bits.mul_u64(x92, 0xffffffffffffffff)
|
||||
x99, x98 := bits.mul_u64(x92, 0xbce6faada7179e84)
|
||||
x101, x100 := bits.mul_u64(x92, 0xf3b9cac2fc632551)
|
||||
x102, x103 := bits.add_u64(x101, x98, u64(0x0))
|
||||
x104, x105 := bits.add_u64(x99, x96, u64(fiat.u1(x103)))
|
||||
x106, x107 := bits.add_u64(x97, x94, u64(fiat.u1(x105)))
|
||||
_, x109 := bits.add_u64(x86, x100, u64(0x0))
|
||||
x110, x111 := bits.add_u64(x88, x102, u64(fiat.u1(x109)))
|
||||
x112, x113 := bits.add_u64(x90, x104, u64(fiat.u1(x111)))
|
||||
x114, x115 := bits.add_u64((u64(fiat.u1(x91)) + (u64(fiat.u1(x85)) + (u64(fiat.u1(x77)) + x65))), x106, u64(fiat.u1(x113)))
|
||||
x116 := (u64(fiat.u1(x115)) + (u64(fiat.u1(x107)) + x95))
|
||||
x117, x118 := bits.sub_u64(x110, 0xf3b9cac2fc632551, u64(0x0))
|
||||
x119, x120 := bits.sub_u64(x112, 0xbce6faada7179e84, u64(fiat.u1(x118)))
|
||||
x121, x122 := bits.sub_u64(x114, 0xffffffffffffffff, u64(fiat.u1(x120)))
|
||||
x123, x124 := bits.sub_u64(x116, 0xffffffff00000000, u64(fiat.u1(x122)))
|
||||
_, x126 := bits.sub_u64(u64(0x0), u64(0x0), u64(fiat.u1(x124)))
|
||||
x127 := fiat.cmovznz_u64(fiat.u1(x126), x117, x110)
|
||||
x128 := fiat.cmovznz_u64(fiat.u1(x126), x119, x112)
|
||||
x129 := fiat.cmovznz_u64(fiat.u1(x126), x121, x114)
|
||||
x130 := fiat.cmovznz_u64(fiat.u1(x126), x123, x116)
|
||||
out1[0] = x127
|
||||
out1[1] = x128
|
||||
out1[2] = x129
|
||||
out1[3] = x130
|
||||
}
|
||||
|
||||
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, 0x66e12d94f3d95620)
|
||||
x8, x7 := bits.mul_u64(x4, 0x2845b2392b6bec59)
|
||||
x10, x9 := bits.mul_u64(x4, 0x4699799c49bd6fa6)
|
||||
x12, x11 := bits.mul_u64(x4, 0x83244c95be79eea2)
|
||||
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, 0xccd1c8aaee00bc4f)
|
||||
x22, x21 := bits.mul_u64(x19, 0xffffffff00000000)
|
||||
x24, x23 := bits.mul_u64(x19, 0xffffffffffffffff)
|
||||
x26, x25 := bits.mul_u64(x19, 0xbce6faada7179e84)
|
||||
x28, x27 := bits.mul_u64(x19, 0xf3b9cac2fc632551)
|
||||
x29, x30 := bits.add_u64(x28, x25, u64(0x0))
|
||||
x31, x32 := bits.add_u64(x26, x23, u64(fiat.u1(x30)))
|
||||
x33, x34 := bits.add_u64(x24, x21, u64(fiat.u1(x32)))
|
||||
_, x36 := bits.add_u64(x11, x27, u64(0x0))
|
||||
x37, x38 := bits.add_u64(x13, x29, u64(fiat.u1(x36)))
|
||||
x39, x40 := bits.add_u64(x15, x31, u64(fiat.u1(x38)))
|
||||
x41, x42 := bits.add_u64(x17, x33, u64(fiat.u1(x40)))
|
||||
x43, x44 := bits.add_u64((u64(fiat.u1(x18)) + x6), (u64(fiat.u1(x34)) + x22), u64(fiat.u1(x42)))
|
||||
x46, x45 := bits.mul_u64(x1, 0x66e12d94f3d95620)
|
||||
x48, x47 := bits.mul_u64(x1, 0x2845b2392b6bec59)
|
||||
x50, x49 := bits.mul_u64(x1, 0x4699799c49bd6fa6)
|
||||
x52, x51 := bits.mul_u64(x1, 0x83244c95be79eea2)
|
||||
x53, x54 := bits.add_u64(x52, x49, u64(0x0))
|
||||
x55, x56 := bits.add_u64(x50, x47, u64(fiat.u1(x54)))
|
||||
x57, x58 := bits.add_u64(x48, x45, u64(fiat.u1(x56)))
|
||||
x59, x60 := bits.add_u64(x37, x51, u64(0x0))
|
||||
x61, x62 := bits.add_u64(x39, x53, u64(fiat.u1(x60)))
|
||||
x63, x64 := bits.add_u64(x41, x55, u64(fiat.u1(x62)))
|
||||
x65, x66 := bits.add_u64(x43, x57, u64(fiat.u1(x64)))
|
||||
_, x67 := bits.mul_u64(x59, 0xccd1c8aaee00bc4f)
|
||||
x70, x69 := bits.mul_u64(x67, 0xffffffff00000000)
|
||||
x72, x71 := bits.mul_u64(x67, 0xffffffffffffffff)
|
||||
x74, x73 := bits.mul_u64(x67, 0xbce6faada7179e84)
|
||||
x76, x75 := bits.mul_u64(x67, 0xf3b9cac2fc632551)
|
||||
x77, x78 := bits.add_u64(x76, x73, u64(0x0))
|
||||
x79, x80 := bits.add_u64(x74, x71, u64(fiat.u1(x78)))
|
||||
x81, x82 := bits.add_u64(x72, x69, u64(fiat.u1(x80)))
|
||||
_, x84 := bits.add_u64(x59, x75, u64(0x0))
|
||||
x85, x86 := bits.add_u64(x61, x77, u64(fiat.u1(x84)))
|
||||
x87, x88 := bits.add_u64(x63, x79, u64(fiat.u1(x86)))
|
||||
x89, x90 := bits.add_u64(x65, x81, u64(fiat.u1(x88)))
|
||||
x91, x92 := bits.add_u64(((u64(fiat.u1(x66)) + u64(fiat.u1(x44))) + (u64(fiat.u1(x58)) + x46)), (u64(fiat.u1(x82)) + x70), u64(fiat.u1(x90)))
|
||||
x94, x93 := bits.mul_u64(x2, 0x66e12d94f3d95620)
|
||||
x96, x95 := bits.mul_u64(x2, 0x2845b2392b6bec59)
|
||||
x98, x97 := bits.mul_u64(x2, 0x4699799c49bd6fa6)
|
||||
x100, x99 := bits.mul_u64(x2, 0x83244c95be79eea2)
|
||||
x101, x102 := bits.add_u64(x100, x97, u64(0x0))
|
||||
x103, x104 := bits.add_u64(x98, x95, u64(fiat.u1(x102)))
|
||||
x105, x106 := bits.add_u64(x96, x93, u64(fiat.u1(x104)))
|
||||
x107, x108 := bits.add_u64(x85, x99, u64(0x0))
|
||||
x109, x110 := bits.add_u64(x87, x101, u64(fiat.u1(x108)))
|
||||
x111, x112 := bits.add_u64(x89, x103, u64(fiat.u1(x110)))
|
||||
x113, x114 := bits.add_u64(x91, x105, u64(fiat.u1(x112)))
|
||||
_, x115 := bits.mul_u64(x107, 0xccd1c8aaee00bc4f)
|
||||
x118, x117 := bits.mul_u64(x115, 0xffffffff00000000)
|
||||
x120, x119 := bits.mul_u64(x115, 0xffffffffffffffff)
|
||||
x122, x121 := bits.mul_u64(x115, 0xbce6faada7179e84)
|
||||
x124, x123 := bits.mul_u64(x115, 0xf3b9cac2fc632551)
|
||||
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)))
|
||||
_, x132 := bits.add_u64(x107, x123, u64(0x0))
|
||||
x133, x134 := bits.add_u64(x109, x125, u64(fiat.u1(x132)))
|
||||
x135, x136 := bits.add_u64(x111, x127, u64(fiat.u1(x134)))
|
||||
x137, x138 := bits.add_u64(x113, x129, u64(fiat.u1(x136)))
|
||||
x139, x140 := bits.add_u64(((u64(fiat.u1(x114)) + u64(fiat.u1(x92))) + (u64(fiat.u1(x106)) + x94)), (u64(fiat.u1(x130)) + x118), u64(fiat.u1(x138)))
|
||||
x142, x141 := bits.mul_u64(x3, 0x66e12d94f3d95620)
|
||||
x144, x143 := bits.mul_u64(x3, 0x2845b2392b6bec59)
|
||||
x146, x145 := bits.mul_u64(x3, 0x4699799c49bd6fa6)
|
||||
x148, x147 := bits.mul_u64(x3, 0x83244c95be79eea2)
|
||||
x149, x150 := bits.add_u64(x148, x145, u64(0x0))
|
||||
x151, x152 := bits.add_u64(x146, x143, u64(fiat.u1(x150)))
|
||||
x153, x154 := bits.add_u64(x144, x141, u64(fiat.u1(x152)))
|
||||
x155, x156 := bits.add_u64(x133, x147, u64(0x0))
|
||||
x157, x158 := bits.add_u64(x135, x149, u64(fiat.u1(x156)))
|
||||
x159, x160 := bits.add_u64(x137, x151, u64(fiat.u1(x158)))
|
||||
x161, x162 := bits.add_u64(x139, x153, u64(fiat.u1(x160)))
|
||||
_, x163 := bits.mul_u64(x155, 0xccd1c8aaee00bc4f)
|
||||
x166, x165 := bits.mul_u64(x163, 0xffffffff00000000)
|
||||
x168, x167 := bits.mul_u64(x163, 0xffffffffffffffff)
|
||||
x170, x169 := bits.mul_u64(x163, 0xbce6faada7179e84)
|
||||
x172, x171 := bits.mul_u64(x163, 0xf3b9cac2fc632551)
|
||||
x173, x174 := bits.add_u64(x172, x169, u64(0x0))
|
||||
x175, x176 := bits.add_u64(x170, x167, u64(fiat.u1(x174)))
|
||||
x177, x178 := bits.add_u64(x168, x165, u64(fiat.u1(x176)))
|
||||
_, x180 := bits.add_u64(x155, x171, u64(0x0))
|
||||
x181, x182 := bits.add_u64(x157, x173, u64(fiat.u1(x180)))
|
||||
x183, x184 := bits.add_u64(x159, x175, u64(fiat.u1(x182)))
|
||||
x185, x186 := bits.add_u64(x161, x177, u64(fiat.u1(x184)))
|
||||
x187, x188 := bits.add_u64(((u64(fiat.u1(x162)) + u64(fiat.u1(x140))) + (u64(fiat.u1(x154)) + x142)), (u64(fiat.u1(x178)) + x166), u64(fiat.u1(x186)))
|
||||
x189, x190 := bits.sub_u64(x181, 0xf3b9cac2fc632551, u64(0x0))
|
||||
x191, x192 := bits.sub_u64(x183, 0xbce6faada7179e84, u64(fiat.u1(x190)))
|
||||
x193, x194 := bits.sub_u64(x185, 0xffffffffffffffff, u64(fiat.u1(x192)))
|
||||
x195, x196 := bits.sub_u64(x187, 0xffffffff00000000, u64(fiat.u1(x194)))
|
||||
_, x198 := bits.sub_u64(u64(fiat.u1(x188)), u64(0x0), u64(fiat.u1(x196)))
|
||||
x199 := fiat.cmovznz_u64(fiat.u1(x198), x189, x181)
|
||||
x200 := fiat.cmovznz_u64(fiat.u1(x198), x191, x183)
|
||||
x201 := fiat.cmovznz_u64(fiat.u1(x198), x193, x185)
|
||||
x202 := fiat.cmovznz_u64(fiat.u1(x198), x195, x187)
|
||||
out1[0] = x199
|
||||
out1[1] = x200
|
||||
out1[2] = x201
|
||||
out1[3] = x202
|
||||
}
|
||||
42
core/crypto/_subtle/subtle.odin
Normal file
42
core/crypto/_subtle/subtle.odin
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Various useful bit operations in constant time.
|
||||
*/
|
||||
package _subtle
|
||||
|
||||
import "core:math/bits"
|
||||
|
||||
// byte_eq returns 1 iff a == b, 0 otherwise.
|
||||
@(optimization_mode="none")
|
||||
byte_eq :: proc "contextless" (a, b: byte) -> int {
|
||||
v := a ~ b
|
||||
|
||||
// v == 0 iff a == b. The subtraction will underflow, setting the
|
||||
// sign bit, which will get returned.
|
||||
return int((u32(v)-1) >> 31)
|
||||
}
|
||||
|
||||
// u64_eq returns 1 iff a == b, 0 otherwise.
|
||||
@(optimization_mode="none")
|
||||
u64_eq :: proc "contextless" (a, b: u64) -> u64 {
|
||||
_, borrow := bits.sub_u64(0, a ~ b, 0)
|
||||
return (~borrow) & 1
|
||||
}
|
||||
|
||||
eq :: proc {
|
||||
byte_eq,
|
||||
u64_eq,
|
||||
}
|
||||
|
||||
// u64_is_zero returns 1 iff a == 0, 0 otherwise.
|
||||
@(optimization_mode="none")
|
||||
u64_is_zero :: proc "contextless" (a: u64) -> u64 {
|
||||
_, borrow := bits.sub_u64(a, 1, 0)
|
||||
return borrow
|
||||
}
|
||||
|
||||
// u64_is_non_zero returns 1 iff a != 0, 0 otherwise.
|
||||
@(optimization_mode="none")
|
||||
u64_is_non_zero :: proc "contextless" (a: u64) -> u64 {
|
||||
is_zero := u64_is_zero(a)
|
||||
return (~is_zero) & 1
|
||||
}
|
||||
135
core/crypto/_weierstrass/fe.odin
Normal file
135
core/crypto/_weierstrass/fe.odin
Normal file
@@ -0,0 +1,135 @@
|
||||
package _weierstrass
|
||||
|
||||
import p256r1 "core:crypto/_fiat/field_p256r1"
|
||||
import "core:math/bits"
|
||||
|
||||
Field_Element_p256r1 :: p256r1.Montgomery_Domain_Field_Element
|
||||
|
||||
FE_SIZE_P256R1 :: 32
|
||||
|
||||
fe_clear :: proc {
|
||||
p256r1.fe_clear,
|
||||
}
|
||||
|
||||
fe_clear_vec :: proc {
|
||||
p256r1.fe_clear_vec,
|
||||
}
|
||||
|
||||
fe_set_bytes :: proc {
|
||||
p256r1.fe_from_bytes,
|
||||
}
|
||||
fe_bytes :: proc {
|
||||
p256r1.fe_to_bytes,
|
||||
}
|
||||
|
||||
fe_set :: proc {
|
||||
p256r1.fe_set,
|
||||
}
|
||||
|
||||
fe_zero :: proc {
|
||||
p256r1.fe_zero,
|
||||
}
|
||||
|
||||
fe_a :: proc {
|
||||
fe_a_p256r1,
|
||||
}
|
||||
|
||||
fe_b :: proc {
|
||||
fe_b_p256r1,
|
||||
}
|
||||
|
||||
fe_gen_x :: proc {
|
||||
fe_gen_x_p256r1,
|
||||
}
|
||||
|
||||
fe_gen_y :: proc {
|
||||
fe_gen_y_p256r1,
|
||||
}
|
||||
|
||||
fe_one :: proc {
|
||||
p256r1.fe_one,
|
||||
}
|
||||
|
||||
fe_add :: proc {
|
||||
p256r1.fe_add,
|
||||
}
|
||||
|
||||
fe_sub :: proc {
|
||||
p256r1.fe_sub,
|
||||
}
|
||||
|
||||
fe_negate :: proc {
|
||||
p256r1.fe_opp,
|
||||
}
|
||||
|
||||
fe_mul :: proc {
|
||||
p256r1.fe_mul,
|
||||
}
|
||||
|
||||
fe_square :: proc {
|
||||
p256r1.fe_square,
|
||||
}
|
||||
|
||||
fe_inv :: proc {
|
||||
p256r1.fe_inv,
|
||||
}
|
||||
|
||||
fe_sqrt :: proc {
|
||||
p256r1.fe_sqrt,
|
||||
}
|
||||
|
||||
fe_equal :: proc {
|
||||
p256r1.fe_equal,
|
||||
}
|
||||
|
||||
fe_is_odd :: proc {
|
||||
p256r1.fe_is_odd,
|
||||
}
|
||||
|
||||
fe_is_zero :: proc {
|
||||
fe_is_zero_p256r1,
|
||||
}
|
||||
|
||||
fe_cond_select :: proc {
|
||||
p256r1.fe_cond_select,
|
||||
}
|
||||
|
||||
fe_a_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) {
|
||||
// a = 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc
|
||||
// = -3 mod p
|
||||
fe[0] = 18446744073709551612
|
||||
fe[1] = 17179869183
|
||||
fe[2] = 0
|
||||
fe[3] = 18446744056529682436
|
||||
}
|
||||
|
||||
fe_b_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) {
|
||||
// b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
|
||||
fe[0] = 15608596021259845087
|
||||
fe[1] = 12461466548982526096
|
||||
fe[2] = 16546823903870267094
|
||||
fe[3] = 15866188208926050356
|
||||
}
|
||||
|
||||
fe_gen_x_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) {
|
||||
// G_x = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
|
||||
fe[0] = 8784043285714375740
|
||||
fe[1] = 8483257759279461889
|
||||
fe[2] = 8789745728267363600
|
||||
fe[3] = 1770019616739251654
|
||||
}
|
||||
|
||||
fe_gen_y_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) {
|
||||
// G_y = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5
|
||||
fe[0] = 15992936863339206154
|
||||
fe[1] = 10037038012062884956
|
||||
fe[2] = 15197544864945402661
|
||||
fe[3] = 9615747158586711429
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
fe_is_zero_p256r1 :: proc "contextless" (fe: ^Field_Element_p256r1) -> int {
|
||||
ctrl := p256r1.fe_non_zero(fe)
|
||||
_, borrow := bits.sub_u64(ctrl, 1, 0)
|
||||
return int(borrow)
|
||||
}
|
||||
548
core/crypto/_weierstrass/point.odin
Normal file
548
core/crypto/_weierstrass/point.odin
Normal file
@@ -0,0 +1,548 @@
|
||||
package _weierstrass
|
||||
|
||||
/*
|
||||
This implements prime order short Weierstrass curves defined over a field
|
||||
k with char(k) != 2, 3 (`y^2 = x^3 + ax + b`). for the purpose of
|
||||
implementing ECDH and ECDSA. Use of this package for other purposes is
|
||||
NOT RECOMMENDED.
|
||||
|
||||
As an explicit simplicity/performance tradeoff, projective representation
|
||||
was chosen so that it is possible to use the complete addition
|
||||
formulas.
|
||||
|
||||
See:
|
||||
- https://eprint.iacr.org/2015/1060.pdf
|
||||
- https://hyperelliptic.org/EFD/g1p/auto-shortw-projective.html
|
||||
|
||||
WARNING: The point addition and doubling formulas are specialized for
|
||||
`a = -3`, which covers secp256r1, secp384r1, secp521r1, FRP256v1, SM2,
|
||||
and GOST 34.10. The brainpool curves and secp256k1 are NOT SUPPORTED
|
||||
and would require slightly different formulas.
|
||||
*/
|
||||
|
||||
Point_p256r1 :: struct {
|
||||
x: Field_Element_p256r1,
|
||||
y: Field_Element_p256r1,
|
||||
z: Field_Element_p256r1,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
pt_set_xy_bytes :: proc "contextless" (p: ^$T, x_raw, y_raw: []byte) -> bool {
|
||||
when T == Point_p256r1 {
|
||||
FE_SZ :: FE_SIZE_P256R1
|
||||
x, y: Field_Element_p256r1
|
||||
defer fe_clear_vec([]^Field_Element_p256r1{&x, &y})
|
||||
} else {
|
||||
#panic("weierstrass: invalid curve")
|
||||
}
|
||||
|
||||
if len(x_raw) != FE_SZ || len(y_raw) != FE_SZ {
|
||||
return false
|
||||
}
|
||||
|
||||
if !fe_set_bytes(&x, x_raw) {
|
||||
return false
|
||||
}
|
||||
if !fe_set_bytes(&y, y_raw) {
|
||||
return false
|
||||
}
|
||||
if !is_on_curve(&x, &y) {
|
||||
return false
|
||||
}
|
||||
|
||||
fe_set(&p.x, &x)
|
||||
fe_set(&p.y, &y)
|
||||
fe_one(&p.z)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
pt_set_x_bytes :: proc "contextless" (p: ^$T, x_raw: []byte, y_is_odd: int) -> bool {
|
||||
when T == Point_p256r1 {
|
||||
FE_SZ :: FE_SIZE_P256R1
|
||||
x, y, yy, y_neg: Field_Element_p256r1
|
||||
defer fe_clear_vec([]^Field_Element_p256r1{&x, &y, &yy, &y_neg})
|
||||
} else {
|
||||
#panic("weierstrass: invalid curve")
|
||||
}
|
||||
|
||||
if len(x_raw) != FE_SZ {
|
||||
return false
|
||||
}
|
||||
|
||||
if !fe_set_bytes(&x, x_raw) {
|
||||
return false
|
||||
}
|
||||
set_yy_candidate(&yy, &x)
|
||||
if fe_sqrt(&y, &yy) != 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Pick the correct y-coordinate.
|
||||
fe_negate(&y_neg, &y)
|
||||
parity_neq := (y_is_odd ~ fe_is_odd(&y)) & 1
|
||||
|
||||
fe_set(&p.x, &x)
|
||||
fe_cond_select(&p.y, &y, &y_neg, parity_neq)
|
||||
fe_one(&p.z)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
pt_bytes :: proc "contextless" (x, y: []byte, p: ^$T) -> bool {
|
||||
when T == Point_p256r1 {
|
||||
FE_SZ :: FE_SIZE_P256R1
|
||||
} else {
|
||||
#panic("weierstrass: invalid curve")
|
||||
}
|
||||
|
||||
if pt_is_identity(p) == 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Convert to affine coordinates.
|
||||
pt_rescale(p, p)
|
||||
|
||||
switch len(x) {
|
||||
case 0:
|
||||
case FE_SZ:
|
||||
fe_bytes(x, &p.x)
|
||||
case:
|
||||
panic_contextless("weierstrass: invalid x buffer")
|
||||
}
|
||||
switch len(y) {
|
||||
case 0:
|
||||
case FE_SZ:
|
||||
fe_bytes(y, &p.y)
|
||||
case:
|
||||
panic_contextless("weierstrass: invalid y buffer")
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
pt_set :: proc "contextless" (p, q: ^$T) {
|
||||
fe_set(&p.x, &q.x)
|
||||
fe_set(&p.y, &q.y)
|
||||
fe_set(&p.z, &q.z)
|
||||
}
|
||||
|
||||
pt_identity :: proc "contextless" (p: ^$T) {
|
||||
fe_zero(&p.x)
|
||||
fe_one(&p.y)
|
||||
fe_zero(&p.z)
|
||||
}
|
||||
|
||||
pt_generator :: proc "contextless" (p: ^$T) {
|
||||
fe_gen_x(&p.x)
|
||||
fe_gen_y(&p.y)
|
||||
fe_one(&p.z)
|
||||
}
|
||||
|
||||
pt_clear :: proc "contextless" (p: ^$T) {
|
||||
fe_clear(&p.x)
|
||||
fe_clear(&p.y)
|
||||
fe_clear(&p.z)
|
||||
}
|
||||
|
||||
pt_clear_vec :: proc "contextless" (arg: []^$T) {
|
||||
for p in arg {
|
||||
pt_clear(p)
|
||||
}
|
||||
}
|
||||
|
||||
pt_add :: proc "contextless" (p, a, b: ^$T) {
|
||||
// Algorithm 4 from "Complete addition formulas for prime
|
||||
// order elliptic curves" by Renes, Costello, and Batina.
|
||||
//
|
||||
// The formula is complete in that it is valid for all a and b,
|
||||
// without exceptions or extra assumptions about the inputs.
|
||||
//
|
||||
// The operation costs are `12M + 2mb + 29a`.
|
||||
|
||||
when T == Point_p256r1 {
|
||||
t0, t1, t2, t3, t4, b_fe: Field_Element_p256r1
|
||||
x3, y3, z3: Field_Element_p256r1
|
||||
defer fe_clear_vec([]^Field_Element_p256r1{&t0, &t1, &t2, &t3, &t4, &x3, &y3, &z3})
|
||||
} else {
|
||||
#panic("weierstrass: invalid curve")
|
||||
}
|
||||
|
||||
x1, y1, z1 := &a.x, &a.y, &a.z
|
||||
x2, y2, z2 := &b.x, &b.y, &b.z
|
||||
|
||||
fe_b(&b_fe)
|
||||
|
||||
// t0 := X1 * X2 ; t1 := Y1 * Y2 ; t2 := Z1 * Z2 ;
|
||||
fe_mul(&t0, x1, x2)
|
||||
fe_mul(&t1, y1, y2)
|
||||
fe_mul(&t2, z1, z2)
|
||||
|
||||
// t3 := X1 + Y1 ; t4 := X2 + Y2 ; t3 := t3 * t4 ;
|
||||
fe_add(&t3, x1, y1)
|
||||
fe_add(&t4, x2, y2)
|
||||
fe_mul(&t3, &t3, &t4)
|
||||
|
||||
// t4 := t0 + t1 ; t3 := t3 - t4 ; t4 := Y1 + Z1 ;
|
||||
fe_add(&t4, &t0, &t1)
|
||||
fe_sub(&t3, &t3, &t4)
|
||||
fe_add(&t4, y1, z1)
|
||||
|
||||
// X3 := Y2 + Z2 ; t4 := t4 * X3 ; X3 := t1 + t2 ;
|
||||
fe_add(&x3, y2, z2)
|
||||
fe_mul(&t4, &t4, &x3)
|
||||
fe_add(&x3, &t1, &t2)
|
||||
|
||||
// t4 := t4 - X3 ; X3 := X1 + Z1 ; Y3 := X2 + Z2 ;
|
||||
fe_sub(&t4, &t4, &x3)
|
||||
fe_add(&x3, x1, z1)
|
||||
fe_add(&y3, x2, z2)
|
||||
|
||||
// X3 := X3 * Y3 ; Y3 := t0 + t2 ; Y3 := X3 - Y3 ;
|
||||
fe_mul(&x3, &x3, &y3)
|
||||
fe_add(&y3, &t0, &t2)
|
||||
fe_sub(&y3, &x3, &y3)
|
||||
|
||||
// Z3 := b * t2 ; X3 := Y3 - Z3 ; Z3 := X3 + X3 ;
|
||||
fe_mul(&z3, &b_fe, &t2)
|
||||
fe_sub(&x3, &y3, &z3)
|
||||
fe_add(&z3, &x3, &x3)
|
||||
|
||||
// X3 := X3 + Z3 ; Z3 := t1 - X3 ; X3 := t1 + X3 ;
|
||||
fe_add(&x3, &x3, &z3)
|
||||
fe_sub(&z3, &t1, &x3)
|
||||
fe_add(&x3, &t1, &x3)
|
||||
|
||||
// Y3 := b * Y3 ; t1 := t2 + t2 ; t2 := t1 + t2 ;
|
||||
fe_mul(&y3, &b_fe, &y3)
|
||||
fe_add(&t1, &t2, &t2)
|
||||
fe_add(&t2, &t1, &t2)
|
||||
|
||||
// Y3 := Y3 - t2 ; Y3 := Y3 - t0 ; t1 := Y3 + Y3 ;
|
||||
fe_sub(&y3, &y3, &t2)
|
||||
fe_sub(&y3, &y3, &t0)
|
||||
fe_add(&t1, &y3, &y3)
|
||||
|
||||
// Y3 := t1 + Y3 ; t1 := t0 + t0 ; t0 := t1 + t0 ;
|
||||
fe_add(&y3, &t1, &y3)
|
||||
fe_add(&t1, &t0, &t0)
|
||||
fe_add(&t0, &t1, &t0)
|
||||
|
||||
// t0 := t0 - t2 ; t1 := t4 * Y3 ; t2 := t0 * Y3 ;
|
||||
fe_sub(&t0, &t0, &t2)
|
||||
fe_mul(&t1, &t4, &y3)
|
||||
fe_mul(&t2, &t0, &y3)
|
||||
|
||||
// Y3 := X3 * Z3 ; Y3 := Y3 + t2 ; X3 := t3 * X3 ;
|
||||
fe_mul(&y3, &x3, &z3)
|
||||
fe_add(&y3, &y3, &t2)
|
||||
fe_mul(&x3, &t3, &x3)
|
||||
|
||||
// X3 := X3 - t1 ; Z3 := t4 * Z3 ; t1 := t3 * t0 ;
|
||||
fe_sub(&x3, &x3, &t1)
|
||||
fe_mul(&z3, &t4, &z3)
|
||||
fe_mul(&t1, &t3, &t0)
|
||||
|
||||
// Z3 := Z3 + t1 ;
|
||||
fe_add(&z3, &z3, &t1)
|
||||
|
||||
// return X3 , Y3 , Z3 ;
|
||||
fe_set(&p.x, &x3)
|
||||
fe_set(&p.y, &y3)
|
||||
fe_set(&p.z, &z3)
|
||||
}
|
||||
|
||||
@(private)
|
||||
pt_add_mixed :: proc "contextless" (p, a: ^$T, x2, y2: ^$U) {
|
||||
// Algorithm 5 from "Complete addition formulas for prime
|
||||
// order elliptic curves" by Renes, Costello, and Batina.
|
||||
//
|
||||
// The formula is mixed in that it assumes the z-coordinate
|
||||
// of the addend (`Z2`) is `1`, meaning that it CAN NOT
|
||||
// handle the addend being the point at infinity.
|
||||
//
|
||||
// The operation costs are `11M + 2mb + 23a` saving
|
||||
// `1M + 6a` over `pt_add`.
|
||||
|
||||
when T == Point_p256r1 && U == Field_Element_p256r1 {
|
||||
t0, t1, t2, t3, t4, b_fe: Field_Element_p256r1
|
||||
x3, y3, z3: Field_Element_p256r1
|
||||
defer fe_clear_vec([]^Field_Element_p256r1{&t0, &t1, &t2, &t3, &t4, &x3, &y3, &z3})
|
||||
} else {
|
||||
#panic("weierstrass: invalid curve")
|
||||
}
|
||||
|
||||
x1, y1, z1 := &a.x, &a.y, &a.z
|
||||
|
||||
fe_b(&b_fe)
|
||||
|
||||
// t0 := X1 * X2 ; t1 := Y1 * Y2 ; t3 := X2 + Y2 ;
|
||||
fe_mul(&t0, x1, x2)
|
||||
fe_mul(&t1, y1, y2)
|
||||
fe_add(&t3, x2, y2)
|
||||
|
||||
// t4 := X1 + Y1 ; t3 := t3 * t4 ; t4 := t0 + t1 ;
|
||||
fe_add(&t4, x1, y1)
|
||||
fe_mul(&t3, &t3, &t4)
|
||||
fe_add(&t4, &t0, &t1)
|
||||
|
||||
// t3 := t3 − t4 ; t4 := Y2 * Z1 ; t4 := t4 + Y1 ;
|
||||
fe_sub(&t3, &t3, &t4)
|
||||
fe_mul(&t4, y2, z1)
|
||||
fe_add(&t4, &t4, y1)
|
||||
|
||||
// Y3 := X2 * Z1 ; Y3 := Y3 + X1 ; Z3 := b * Z1 ;
|
||||
fe_mul(&y3, x2, z1)
|
||||
fe_add(&y3, &y3, x1)
|
||||
fe_mul(&z3, &b_fe, z1)
|
||||
|
||||
// X3 := Y3 − Z3 ; Z3 := X3 + X3 ; X3 := X3 + Z3 ;
|
||||
fe_sub(&x3, &y3, &z3)
|
||||
fe_add(&z3, &x3, &x3)
|
||||
fe_add(&x3, &x3, &z3)
|
||||
|
||||
// Z3 := t1 − X3 ; X3 := t1 + X3 ;. Y3 := b * Y3 ;
|
||||
fe_sub(&z3, &t1, &x3)
|
||||
fe_add(&x3, &t1, &x3)
|
||||
fe_mul(&y3, &b_fe, &y3)
|
||||
|
||||
// t1 := Z1 + Z1 ; t2 := t1 + Z1 ; Y3 := Y3 − t2 ;
|
||||
fe_add(&t1, z1, z1)
|
||||
fe_add(&t2, &t1, z1)
|
||||
fe_sub(&y3, &y3, &t2)
|
||||
|
||||
// Y3 := Y3 − t0 ; t1 := Y3 + Y3 ; Y3 := t1 + Y3 ;
|
||||
fe_sub(&y3, &y3, &t0)
|
||||
fe_add(&t1, &y3, &y3)
|
||||
fe_add(&y3, &t1, &y3)
|
||||
|
||||
// t1 := t0 + t0 ; t0 := t1 + t0 ; t0 := t0 − t2 ;
|
||||
fe_add(&t1, &t0, &t0)
|
||||
fe_add(&t0, &t1, &t0)
|
||||
fe_sub(&t0, &t0, &t2)
|
||||
|
||||
// t1 := t4 * Y3 ; t2 := t0 * Y3 ; Y3 := X3 * Z3 ;
|
||||
fe_mul(&t1, &t4, &y3)
|
||||
fe_mul(&t2, &t0, &y3)
|
||||
fe_mul(&y3, &x3, &z3)
|
||||
|
||||
// Y3 := Y3 + t2 ; X3 := t3 * X3 ; X3 := X3 − t1 ;
|
||||
fe_add(&y3, &y3, &t2)
|
||||
fe_mul(&x3, &t3, &x3)
|
||||
fe_sub(&x3, &x3, &t1)
|
||||
|
||||
// Z3 := t4 * Z3 ; t1 := t3 * t0 ; Z3 := Z3 + t1 ;
|
||||
fe_mul(&z3, &t4, &z3)
|
||||
fe_mul(&t1, &t3, &t0)
|
||||
fe_add(&z3, &z3, &t1)
|
||||
|
||||
// return X3 , Y3 , Z3 ;
|
||||
fe_set(&p.x, &x3)
|
||||
fe_set(&p.y, &y3)
|
||||
fe_set(&p.z, &z3)
|
||||
}
|
||||
|
||||
pt_double :: proc "contextless" (p, a: ^$T) {
|
||||
// Algorithm 6 from "Complete addition formulas for prime
|
||||
// order elliptic curves" by Renes, Costello, and Batina.
|
||||
//
|
||||
// The formula is complete in that it is valid for all a,
|
||||
// without exceptions or extra assumptions about the inputs.
|
||||
//
|
||||
// The operation costs are `8M + 3S + 2mb + 21a`.
|
||||
|
||||
when T == Point_p256r1 {
|
||||
t0, t1, t2, t3, b_fe: Field_Element_p256r1
|
||||
x3, y3, z3: Field_Element_p256r1
|
||||
defer fe_clear_vec([]^Field_Element_p256r1{&t0, &t1, &t2, &t3, &x3, &y3, &z3})
|
||||
} else {
|
||||
#panic("weierstrass: invalid curve")
|
||||
}
|
||||
|
||||
x, y, z := &a.x, &a.y, &a.z
|
||||
|
||||
fe_b(&b_fe)
|
||||
|
||||
// t0 := X ^2; t1 := Y ^2; t2 := Z ^2;
|
||||
fe_square(&t0, x)
|
||||
fe_square(&t1, y)
|
||||
fe_square(&t2, z)
|
||||
|
||||
// t3 := X * Y ; t3 := t3 + t3 ; Z3 := X * Z ;
|
||||
fe_mul(&t3, x, y)
|
||||
fe_add(&t3, &t3, &t3)
|
||||
fe_mul(&z3, x, z)
|
||||
|
||||
// Z3 := Z3 + Z3 ; Y3 := b * t2 ; Y3 := Y3 - Z3 ;
|
||||
fe_add(&z3, &z3, &z3)
|
||||
fe_mul(&y3, &b_fe, &t2)
|
||||
fe_sub(&y3, &y3, &z3)
|
||||
|
||||
// X3 := Y3 + Y3 ; Y3 := X3 + Y3 ; X3 := t1 - Y3 ;
|
||||
fe_add(&x3, &y3, &y3)
|
||||
fe_add(&y3, &x3, &y3)
|
||||
fe_sub(&x3, &t1, &y3)
|
||||
|
||||
// Y3 := t1 + Y3 ; Y3 := X3 * Y3 ; X3 := X3 * t3 ;
|
||||
fe_add(&y3, &t1, &y3)
|
||||
fe_mul(&y3, &x3, &y3)
|
||||
fe_mul(&x3, &x3, &t3)
|
||||
|
||||
// t3 := t2 + t2 ; t2 := t2 + t3 ; Z3 := b * Z3 ;
|
||||
fe_add(&t3, &t2, &t2)
|
||||
fe_add(&t2, &t2, &t3)
|
||||
fe_mul(&z3, &b_fe, &z3)
|
||||
|
||||
// Z3 := Z3 - t2 ; Z3 := Z3 - t0 ; t3 := Z3 + Z3 ;
|
||||
fe_sub(&z3, &z3, &t2)
|
||||
fe_sub(&z3, &z3, &t0)
|
||||
fe_add(&t3, &z3, &z3)
|
||||
|
||||
// Z3 := Z3 + t3 ; t3 := t0 + t0 ; t0 := t3 + t0 ;
|
||||
fe_add(&z3, &z3, &t3)
|
||||
fe_add(&t3, &t0, &t0)
|
||||
fe_add(&t0, &t3, &t0)
|
||||
|
||||
// t0 := t0 - t2 ; t0 := t0 * Z3 ; Y3 := Y3 + t0 ;
|
||||
fe_sub(&t0, &t0, &t2)
|
||||
fe_mul(&t0, &t0, &z3)
|
||||
fe_add(&y3, &y3, &t0)
|
||||
|
||||
// t0 := Y * Z ; t0 := t0 + t0 ; Z3 := t0 * Z3 ;
|
||||
fe_mul(&t0, y, z)
|
||||
fe_add(&t0, &t0, &t0)
|
||||
fe_mul(&z3, &t0, &z3)
|
||||
|
||||
// X3 := X3 - Z3 ; Z3 := t0 * t1 ; Z3 := Z3 + Z3 ;
|
||||
fe_sub(&x3, &x3, &z3)
|
||||
fe_mul(&z3, &t0, &t1)
|
||||
fe_add(&z3, &z3, &z3)
|
||||
|
||||
// Z3 := Z3 + Z3 ;
|
||||
fe_add(&z3, &z3, &z3)
|
||||
|
||||
// return X3 , Y3 , Z3 ;
|
||||
fe_set(&p.x, &x3)
|
||||
fe_set(&p.y, &y3)
|
||||
fe_set(&p.z, &z3)
|
||||
}
|
||||
|
||||
pt_sub :: proc "contextless" (p, a, b: ^$T) {
|
||||
b_neg: T
|
||||
pt_negate(&b_neg, b)
|
||||
pt_add(p, a, &b_neg)
|
||||
|
||||
fe_clear(&b_neg)
|
||||
}
|
||||
|
||||
pt_negate :: proc "contextless" (p, a: ^$T) {
|
||||
fe_set(&p.x, &a.x)
|
||||
fe_negate(&p.y, &a.y)
|
||||
fe_set(&p.z, &a.z)
|
||||
}
|
||||
|
||||
pt_rescale :: proc "contextless" (p, a: ^$T) {
|
||||
// A = 1/Z1
|
||||
// X3 = A*X1
|
||||
// Y3 = A*Y1
|
||||
// Z3 = 1
|
||||
//
|
||||
// As per "From A to Z: Projective coordinates leakage in the wild"
|
||||
// leaking the Z-coordinate is bad. The modular inversion algorithm
|
||||
// used in this library is based on Fermat's Little Theorem.
|
||||
//
|
||||
// See: https://eprint.iacr.org/2020/432.pdf
|
||||
|
||||
was_identity := pt_is_identity(a)
|
||||
|
||||
when T == Point_p256r1 {
|
||||
z_inv: Field_Element_p256r1
|
||||
} else {
|
||||
#panic("weierstrass: invalid curve")
|
||||
}
|
||||
|
||||
ident: T
|
||||
fe_inv(&z_inv, &a.z)
|
||||
fe_mul(&p.x, &a.x, &z_inv)
|
||||
fe_mul(&p.y, &a.y, &z_inv)
|
||||
fe_one(&p.z)
|
||||
|
||||
pt_identity(&ident)
|
||||
pt_cond_select(p, p, &ident, was_identity)
|
||||
|
||||
fe_clear(&z_inv)
|
||||
}
|
||||
|
||||
pt_cond_select :: proc "contextless" (p, a, b: ^$T, ctrl: int) {
|
||||
fe_cond_select(&p.x, &a.x, &b.x, ctrl)
|
||||
fe_cond_select(&p.y, &a.y, &b.y, ctrl)
|
||||
fe_cond_select(&p.z, &a.z, &b.z, ctrl)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
pt_equal :: proc "contextless" (a, b: ^$T) -> int {
|
||||
when T == Point_p256r1 {
|
||||
x1z2, x2z1, y1z2, y2z1: Field_Element_p256r1
|
||||
} else {
|
||||
#panic("weierstrass: invalid curve")
|
||||
}
|
||||
|
||||
// Check X1Z2 == X2Z1 && Y1Z2 == Y2Z1
|
||||
fe_mul(&x1z2, &a.x, &b.z)
|
||||
fe_mul(&x2z1, &b.x, &a.z)
|
||||
|
||||
fe_mul(&y1z2, &a.y, &b.z)
|
||||
fe_mul(&y2z1, &b.y, &a.z)
|
||||
|
||||
return fe_equal(&x1z2, &x2z1) & fe_equal(&y1z2, &y2z1)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
pt_is_identity :: proc "contextless" (p: ^$T) -> int {
|
||||
return fe_is_zero(&p.z)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
pt_is_y_odd :: proc "contextless" (p: ^$T) -> int {
|
||||
tmp: T
|
||||
defer pt_clear(&tmp)
|
||||
|
||||
fe_set(&tmp, p)
|
||||
pt_rescale(&tmp)
|
||||
|
||||
return fe_is_odd(&tmp.y)
|
||||
}
|
||||
|
||||
@(private)
|
||||
is_on_curve :: proc "contextless" (x, y: ^$T) -> bool {
|
||||
maybe_yy, yy: T
|
||||
defer fe_clear_vec([]^T{&maybe_yy, &yy})
|
||||
|
||||
// RHS: x^3 + ax + b
|
||||
set_yy_candidate(&maybe_yy, x)
|
||||
|
||||
// LHS: y^2
|
||||
fe_square(&yy, y)
|
||||
|
||||
return fe_equal(&maybe_yy, &yy) == 1
|
||||
}
|
||||
|
||||
@(private)
|
||||
set_yy_candidate :: proc "contextless" (maybe_yy, x: ^$T) {
|
||||
// RHS: x^3 + ax + b
|
||||
rhs, tmp: T
|
||||
|
||||
fe_square(&tmp, x)
|
||||
fe_mul(&rhs, &tmp, x)
|
||||
|
||||
fe_a(&tmp)
|
||||
fe_mul(&tmp, &tmp, x)
|
||||
fe_add(&rhs, &rhs, &tmp)
|
||||
|
||||
fe_b(&tmp)
|
||||
fe_add(maybe_yy, &rhs, &tmp)
|
||||
|
||||
fe_clear(&rhs)
|
||||
}
|
||||
95
core/crypto/_weierstrass/point_s11n_sec.odin
Normal file
95
core/crypto/_weierstrass/point_s11n_sec.odin
Normal file
@@ -0,0 +1,95 @@
|
||||
package _weierstrass
|
||||
|
||||
@(require) import "core:mem"
|
||||
|
||||
@(private)
|
||||
SEC_PREFIX_IDENTITY :: 0x00
|
||||
@(private)
|
||||
SEC_PREFIX_COMPRESSED_EVEN :: 0x02
|
||||
@(private)
|
||||
SEC_PREFIX_COMPRESSED_ODD :: 0x03
|
||||
SEC_PREFIX_UNCOMPRESSED :: 0x04
|
||||
|
||||
@(require_results)
|
||||
pt_set_sec_bytes :: proc "contextless" (p: ^$T, b: []byte) -> bool {
|
||||
when T == Point_p256r1 {
|
||||
FE_SZ :: FE_SIZE_P256R1
|
||||
} else {
|
||||
#panic("weierstrass: invalid curve")
|
||||
}
|
||||
|
||||
b_len := len(b)
|
||||
if b_len < 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
switch b[0] {
|
||||
case SEC_PREFIX_IDENTITY:
|
||||
if b_len != 1 {
|
||||
return false
|
||||
}
|
||||
pt_identity(p)
|
||||
return true
|
||||
case SEC_PREFIX_COMPRESSED_EVEN, SEC_PREFIX_COMPRESSED_ODD:
|
||||
if b_len != 1 + FE_SZ {
|
||||
return false
|
||||
}
|
||||
y_is_odd := b[0] - SEC_PREFIX_COMPRESSED_EVEN
|
||||
return pt_set_x_bytes(p, b[1:], int(y_is_odd))
|
||||
case SEC_PREFIX_UNCOMPRESSED:
|
||||
if b_len != 1 + 2 * FE_SZ {
|
||||
return false
|
||||
}
|
||||
x, y := b[1:1+FE_SZ], b[1+FE_SZ:]
|
||||
return pt_set_xy_bytes(p, x, y)
|
||||
case:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
pt_sec_bytes :: proc "contextless" (b: []byte, p: ^$T, compressed: bool) -> bool {
|
||||
when T == Point_p256r1 {
|
||||
FE_SZ :: FE_SIZE_P256R1
|
||||
} else {
|
||||
#panic("weierstrass: invalid curve")
|
||||
}
|
||||
|
||||
b_len := len(b)
|
||||
if pt_is_identity(p) == 1 {
|
||||
if b_len != 1 {
|
||||
return false
|
||||
}
|
||||
b[0] = SEC_PREFIX_IDENTITY
|
||||
return true
|
||||
}
|
||||
|
||||
x, y: []byte
|
||||
y_: [FE_SZ]byte
|
||||
switch compressed {
|
||||
case true:
|
||||
if b_len != 1 + FE_SZ {
|
||||
return false
|
||||
}
|
||||
x, y = b[1:], y_[:]
|
||||
case false:
|
||||
if b_len != 1 + 2 * FE_SZ {
|
||||
return false
|
||||
}
|
||||
b[0]= SEC_PREFIX_UNCOMPRESSED
|
||||
x, y = b[1:1+FE_SZ], b[1+FE_SZ:]
|
||||
}
|
||||
if !pt_bytes(x, y, p) {
|
||||
return false
|
||||
}
|
||||
if compressed {
|
||||
// Instead of calling pt_is_y_odd, just serializing
|
||||
// y into a temp buffer and checking the parity saves
|
||||
// 1 redundant rescale call.
|
||||
y_is_odd := byte(y[FE_SZ-1] & 1)
|
||||
b[0] = SEC_PREFIX_COMPRESSED_EVEN + y_is_odd
|
||||
mem.zero_explicit(&y_, size_of(y_))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
76
core/crypto/_weierstrass/sc.odin
Normal file
76
core/crypto/_weierstrass/sc.odin
Normal file
@@ -0,0 +1,76 @@
|
||||
package _weierstrass
|
||||
|
||||
import p256r1 "core:crypto/_fiat/field_scalarp256r1"
|
||||
import subtle "core:crypto/_subtle"
|
||||
|
||||
Scalar_p256r1 :: p256r1.Montgomery_Domain_Field_Element
|
||||
|
||||
SC_SIZE_P256R1 :: 32
|
||||
|
||||
sc_clear :: proc {
|
||||
p256r1.fe_clear,
|
||||
}
|
||||
|
||||
sc_clear_vec :: proc {
|
||||
p256r1.fe_clear_vec,
|
||||
}
|
||||
|
||||
sc_set_bytes :: proc {
|
||||
p256r1.fe_from_bytes,
|
||||
}
|
||||
sc_bytes :: proc {
|
||||
p256r1.fe_to_bytes,
|
||||
}
|
||||
|
||||
sc_set :: proc {
|
||||
p256r1.fe_set,
|
||||
}
|
||||
|
||||
sc_zero :: proc {
|
||||
p256r1.fe_zero,
|
||||
}
|
||||
|
||||
sc_one_p256r1 :: proc {
|
||||
p256r1.fe_one,
|
||||
}
|
||||
|
||||
sc_add :: proc {
|
||||
p256r1.fe_add,
|
||||
}
|
||||
|
||||
sc_sub :: proc {
|
||||
p256r1.fe_sub,
|
||||
}
|
||||
|
||||
sc_negate :: proc {
|
||||
p256r1.fe_opp,
|
||||
}
|
||||
|
||||
sc_mul :: proc {
|
||||
p256r1.fe_mul,
|
||||
}
|
||||
|
||||
sc_square :: proc {
|
||||
p256r1.fe_square,
|
||||
}
|
||||
|
||||
sc_cond_assign :: proc {
|
||||
p256r1.fe_cond_assign,
|
||||
}
|
||||
|
||||
sc_equal :: proc {
|
||||
p256r1.fe_equal,
|
||||
}
|
||||
|
||||
sc_is_odd :: proc {
|
||||
p256r1.fe_is_odd,
|
||||
}
|
||||
|
||||
sc_is_zero :: proc {
|
||||
sc_is_zero_p256r1,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
sc_is_zero_p256r1 :: proc "contextless" (fe: ^Scalar_p256r1) -> int {
|
||||
return int(subtle.u64_is_zero(p256r1.fe_non_zero(fe)))
|
||||
}
|
||||
204
core/crypto/_weierstrass/scalar_mul.odin
Normal file
204
core/crypto/_weierstrass/scalar_mul.odin
Normal file
@@ -0,0 +1,204 @@
|
||||
package _weierstrass
|
||||
|
||||
import "core:crypto"
|
||||
import subtle "core:crypto/_subtle"
|
||||
import "core:mem"
|
||||
|
||||
pt_scalar_mul :: proc "contextless" (
|
||||
p, a: ^$T,
|
||||
sc: ^$S,
|
||||
unsafe_is_vartime: bool = false,
|
||||
) {
|
||||
when T == Point_p256r1 && S == Scalar_p256r1 {
|
||||
SC_SZ :: SC_SIZE_P256R1
|
||||
} else {
|
||||
#panic("weierstrass: invalid curve")
|
||||
}
|
||||
|
||||
b: [SC_SZ]byte = ---
|
||||
sc_bytes(b[:], sc)
|
||||
|
||||
pt_scalar_mul_bytes(p, a, b[:], unsafe_is_vartime)
|
||||
|
||||
if !unsafe_is_vartime {
|
||||
mem.zero_explicit(&b, size_of(b))
|
||||
}
|
||||
}
|
||||
|
||||
pt_scalar_mul_bytes :: proc "contextless" (
|
||||
p, a: ^$T,
|
||||
sc: []byte,
|
||||
unsafe_is_vartime: bool = false,
|
||||
) {
|
||||
when T == Point_p256r1 {
|
||||
p_tbl: Multiply_Table_p256r1 = ---
|
||||
q, tmp: Point_p256r1 = ---, ---
|
||||
SC_SZ :: SC_SIZE_P256R1
|
||||
} else {
|
||||
#panic("weierstrass: invalid curve")
|
||||
}
|
||||
|
||||
assert_contextless(len(sc) == SC_SZ, "weierstrass: invalid scalar size")
|
||||
mul_tbl_set(&p_tbl, a, unsafe_is_vartime)
|
||||
|
||||
pt_identity(&q)
|
||||
for limb_byte, i in sc {
|
||||
hi, lo := (limb_byte >> 4) & 0x0f, limb_byte & 0x0f
|
||||
|
||||
if i != 0 {
|
||||
pt_double(&q, &q)
|
||||
pt_double(&q, &q)
|
||||
pt_double(&q, &q)
|
||||
pt_double(&q, &q)
|
||||
}
|
||||
mul_tbl_lookup_add(&q, &tmp, &p_tbl, u64(hi), unsafe_is_vartime)
|
||||
|
||||
pt_double(&q, &q)
|
||||
pt_double(&q, &q)
|
||||
pt_double(&q, &q)
|
||||
pt_double(&q, &q)
|
||||
mul_tbl_lookup_add(&q, &tmp, &p_tbl, u64(lo), unsafe_is_vartime)
|
||||
}
|
||||
|
||||
pt_set(p, &q)
|
||||
|
||||
if !unsafe_is_vartime {
|
||||
mem.zero_explicit(&p_tbl, size_of(p_tbl))
|
||||
pt_clear_vec([]^T{&q, &tmp})
|
||||
}
|
||||
}
|
||||
|
||||
when crypto.COMPACT_IMPLS == true {
|
||||
pt_scalar_mul_generator :: proc "contextless" (
|
||||
p: ^$T,
|
||||
sc: ^$S,
|
||||
unsafe_is_vartime: bool = false,
|
||||
) {
|
||||
g: T
|
||||
pt_generator(&g)
|
||||
|
||||
pt_scalar_mul(p, &g, sc, unsafe_is_vartime)
|
||||
}
|
||||
} else {
|
||||
pt_scalar_mul_generator :: proc "contextless" (
|
||||
p: ^$T,
|
||||
sc: ^$S,
|
||||
unsafe_is_vartime: bool = false,
|
||||
) {
|
||||
when T == Point_p256r1 && S == Scalar_p256r1 {
|
||||
p_tbl_hi := &Gen_Multiply_Table_p256r1_hi
|
||||
p_tbl_lo := &Gen_Multiply_Table_p256r1_lo
|
||||
tmp: Point_p256r1 = ---
|
||||
SC_SZ :: SC_SIZE_P256R1
|
||||
} else {
|
||||
#panic("weierstrass: invalid curve")
|
||||
}
|
||||
|
||||
b: [SC_SZ]byte
|
||||
sc_bytes(b[:], sc)
|
||||
|
||||
pt_identity(p)
|
||||
for limb_byte, i in b {
|
||||
hi, lo := (limb_byte >> 4) & 0x0f, limb_byte & 0x0f
|
||||
mul_affine_tbl_lookup_add(p, &tmp, &p_tbl_hi[i], u64(hi), unsafe_is_vartime)
|
||||
mul_affine_tbl_lookup_add(p, &tmp, &p_tbl_lo[i], u64(lo), unsafe_is_vartime)
|
||||
}
|
||||
|
||||
if !unsafe_is_vartime {
|
||||
mem.zero_explicit(&b, size_of(b))
|
||||
pt_clear(&tmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
Multiply_Table_p256r1 :: [15]Point_p256r1
|
||||
|
||||
@(private="file")
|
||||
mul_tbl_set :: proc "contextless"(
|
||||
tbl: ^$T,
|
||||
point: ^$U,
|
||||
unsafe_is_vartime: bool,
|
||||
) {
|
||||
when T == Multiply_Table_p256r1 && U == Point_p256r1{
|
||||
tmp: Point_p256r1
|
||||
pt_set(&tmp, point)
|
||||
} else {
|
||||
#panic("weierstrass: invalid curve")
|
||||
}
|
||||
|
||||
pt_set(&tbl[0], &tmp)
|
||||
for i in 1 ..<15 {
|
||||
pt_add(&tmp, &tmp, point)
|
||||
pt_set(&tbl[i], &tmp)
|
||||
}
|
||||
|
||||
if !unsafe_is_vartime {
|
||||
pt_clear(&tmp)
|
||||
}
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
mul_tbl_lookup_add :: proc "contextless" (
|
||||
point, tmp: ^$T,
|
||||
tbl: ^$U,
|
||||
idx: u64,
|
||||
unsafe_is_vartime: bool,
|
||||
) {
|
||||
if unsafe_is_vartime {
|
||||
switch idx {
|
||||
case 0:
|
||||
case:
|
||||
pt_add(point, point, &tbl[idx - 1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
pt_identity(tmp)
|
||||
for i in u64(1)..<16 {
|
||||
ctrl := subtle.eq(i, idx)
|
||||
pt_cond_select(tmp, tmp, &tbl[i - 1], int(ctrl))
|
||||
}
|
||||
|
||||
pt_add(point, point, tmp)
|
||||
}
|
||||
|
||||
when crypto.COMPACT_IMPLS == false {
|
||||
@(private)
|
||||
Affine_Point_p256r1 :: struct {
|
||||
x: Field_Element_p256r1,
|
||||
y: Field_Element_p256r1,
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
mul_affine_tbl_lookup_add :: proc "contextless" (
|
||||
point, tmp: ^$T,
|
||||
tbl: ^$U,
|
||||
idx: u64,
|
||||
unsafe_is_vartime: bool,
|
||||
) {
|
||||
if unsafe_is_vartime {
|
||||
switch idx {
|
||||
case 0:
|
||||
case:
|
||||
pt_add_mixed(point, point, &tbl[idx - 1].x, &tbl[idx - 1].y)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
pt_identity(tmp)
|
||||
for i in u64(1)..<16 {
|
||||
ctrl := int(subtle.eq(i, idx))
|
||||
fe_cond_select(&tmp.x, &tmp.x, &tbl[i - 1].x, ctrl)
|
||||
fe_cond_select(&tmp.y, &tmp.y, &tbl[i - 1].y, ctrl)
|
||||
}
|
||||
|
||||
// The mixed addition formula assumes that the addend is not
|
||||
// the neutral element. Do the addition regardless, and then
|
||||
// conditionally select the right result.
|
||||
pt_add_mixed(tmp, point, &tmp.x, &tmp.y)
|
||||
|
||||
ctrl := subtle.u64_is_non_zero(idx)
|
||||
pt_cond_select(point, point, tmp, int(ctrl))
|
||||
}
|
||||
}
|
||||
3985
core/crypto/_weierstrass/secp256r1_table.odin
Normal file
3985
core/crypto/_weierstrass/secp256r1_table.odin
Normal file
File diff suppressed because it is too large
Load Diff
99
core/crypto/_weierstrass/tools/ecc_gen_tables.odin
Normal file
99
core/crypto/_weierstrass/tools/ecc_gen_tables.odin
Normal file
@@ -0,0 +1,99 @@
|
||||
package weistrass_tools
|
||||
|
||||
import secec "core:crypto/_weierstrass"
|
||||
import "core:fmt"
|
||||
import path "core:path/filepath"
|
||||
import "core:os"
|
||||
import "core:strings"
|
||||
|
||||
// Yes this leaks memory, fite me IRL.
|
||||
|
||||
GENERATED :: `/*
|
||||
------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------
|
||||
*/`
|
||||
|
||||
main :: proc() {
|
||||
gen_p256r1_tables()
|
||||
}
|
||||
|
||||
gen_p256r1_tables :: proc() {
|
||||
Affine_Point_p256r1 :: struct {
|
||||
x: secec.Field_Element_p256r1,
|
||||
y: secec.Field_Element_p256r1,
|
||||
}
|
||||
Multiply_Table_p256r1_hi: [32][15]Affine_Point_p256r1
|
||||
Multiply_Table_p256r1_lo: [32][15]Affine_Point_p256r1
|
||||
|
||||
g, p: secec.Point_p256r1
|
||||
secec.pt_generator(&g)
|
||||
|
||||
// Precompute ([1,15] << n) * G multiples of G, MSB->LSB
|
||||
for i in 0..<32 {
|
||||
b: [32]byte
|
||||
for j in 1..<16 {
|
||||
b[i] = u8(j) << 4
|
||||
secec.pt_scalar_mul_bytes(&p, &g, b[:], true)
|
||||
secec.pt_rescale(&p, &p)
|
||||
secec.fe_set(&Multiply_Table_p256r1_hi[i][j-1].x, &p.x)
|
||||
secec.fe_set(&Multiply_Table_p256r1_hi[i][j-1].y, &p.y)
|
||||
|
||||
b[i] = u8(j)
|
||||
secec.pt_scalar_mul_bytes(&p, &g, b[:], true)
|
||||
secec.pt_rescale(&p, &p)
|
||||
secec.fe_set(&Multiply_Table_p256r1_lo[i][j-1].x, &p.x)
|
||||
secec.fe_set(&Multiply_Table_p256r1_lo[i][j-1].y, &p.y)
|
||||
|
||||
b[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
fn := path.join({ODIN_ROOT, "core", "crypto", "_weierstrass", "secp256r1_table.odin"})
|
||||
bld: strings.Builder
|
||||
w := strings.to_writer(&bld)
|
||||
|
||||
fmt.wprintln(w, "package _weierstrass")
|
||||
fmt.wprintln(w, "")
|
||||
fmt.wprintln(w, GENERATED)
|
||||
fmt.wprintln(w, "")
|
||||
fmt.wprintln(w, "import \"core:crypto\"")
|
||||
fmt.wprintln(w, "")
|
||||
fmt.wprintln(w, "when crypto.COMPACT_IMPLS == false {")
|
||||
|
||||
fmt.wprintln(w, "\t@(private,rodata)")
|
||||
fmt.wprintln(w, "\tGen_Multiply_Table_p256r1_hi := [32][15]Affine_Point_p256r1 {")
|
||||
for &v, i in Multiply_Table_p256r1_hi {
|
||||
fmt.wprintln(w, "\t\t{")
|
||||
for &ap, j in v {
|
||||
fmt.wprintln(w, "\t\t\t{")
|
||||
|
||||
x, y := &ap.x, &ap.y
|
||||
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d},\n", x[0], x[1], x[2], x[3])
|
||||
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d},\n", y[0], y[1], y[2], y[3])
|
||||
|
||||
fmt.wprintln(w, "\t\t\t},")
|
||||
}
|
||||
fmt.wprintln(w, "\t\t},")
|
||||
}
|
||||
fmt.wprintln(w, "\t}\n")
|
||||
|
||||
fmt.wprintln(w, "\t@(private,rodata)")
|
||||
fmt.wprintln(w, "\tGen_Multiply_Table_p256r1_lo := [32][15]Affine_Point_p256r1 {")
|
||||
for &v, i in Multiply_Table_p256r1_lo {
|
||||
fmt.wprintln(w, "\t\t{")
|
||||
for &ap, j in v {
|
||||
fmt.wprintln(w, "\t\t\t{")
|
||||
|
||||
x, y := &ap.x, &ap.y
|
||||
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d},\n", x[0], x[1], x[2], x[3])
|
||||
fmt.wprintf(w, "\t\t\t\t{{%d, %d, %d, %d},\n", y[0], y[1], y[2], y[3])
|
||||
|
||||
fmt.wprintln(w, "\t\t\t},")
|
||||
}
|
||||
fmt.wprintln(w, "\t\t},")
|
||||
}
|
||||
fmt.wprintln(w, "\t}")
|
||||
|
||||
fmt.wprintln(w, "}")
|
||||
|
||||
_ = os.write_entire_file(fn, transmute([]byte)(strings.to_string(bld)))
|
||||
}
|
||||
@@ -2,8 +2,12 @@
|
||||
package crypto
|
||||
|
||||
import "base:runtime"
|
||||
import subtle "core:crypto/_subtle"
|
||||
import "core:mem"
|
||||
|
||||
// Omit large precomputed tables, trading off performance for size.
|
||||
COMPACT_IMPLS: bool : #config(ODIN_CRYPTO_COMPACT, false)
|
||||
|
||||
// HAS_RAND_BYTES is true iff the runtime provides a cryptographic
|
||||
// entropy source.
|
||||
HAS_RAND_BYTES :: runtime.HAS_RAND_BYTES
|
||||
@@ -44,7 +48,17 @@ compare_byte_ptrs_constant_time :: proc "contextless" (a, b: ^byte, n: int) -> i
|
||||
|
||||
// After the loop, v == 0 iff a == b. The subtraction will underflow
|
||||
// iff v == 0, setting the sign-bit, which gets returned.
|
||||
return int((u32(v)-1) >> 31)
|
||||
return subtle.eq(0, v)
|
||||
}
|
||||
|
||||
// is_zero_constant_time returns 1 iff b is all 0s, 0 otherwise.
|
||||
is_zero_constant_time :: proc "contextless" (b: []byte) -> int {
|
||||
v: byte
|
||||
for b_ in b {
|
||||
v |= b_
|
||||
}
|
||||
|
||||
return subtle.byte_eq(0, v)
|
||||
}
|
||||
|
||||
// rand_bytes fills the dst buffer with cryptographic entropy taken from
|
||||
|
||||
4
core/crypto/ecdh/doc.odin
Normal file
4
core/crypto/ecdh/doc.odin
Normal file
@@ -0,0 +1,4 @@
|
||||
/*
|
||||
A generic interface to Elliptic Curve Diffie-Hellman key exchange.
|
||||
*/
|
||||
package ecdh
|
||||
404
core/crypto/ecdh/ecdh.odin
Normal file
404
core/crypto/ecdh/ecdh.odin
Normal file
@@ -0,0 +1,404 @@
|
||||
package ecdh
|
||||
|
||||
import "core:crypto"
|
||||
import secec "core:crypto/_weierstrass"
|
||||
import "core:crypto/x25519"
|
||||
import "core:crypto/x448"
|
||||
import "core:mem"
|
||||
import "core:reflect"
|
||||
|
||||
// Note: For these primitives scalar size = point size
|
||||
@(private="file")
|
||||
X25519_Buf :: [x25519.SCALAR_SIZE]byte
|
||||
@(private="file")
|
||||
X448_Buf :: [x448.SCALAR_SIZE]byte
|
||||
|
||||
// Curve the curve identifier associated with a given Private_Key
|
||||
// or Public_Key
|
||||
Curve :: enum {
|
||||
Invalid,
|
||||
SECP256R1,
|
||||
X25519,
|
||||
X448,
|
||||
}
|
||||
|
||||
// CURVE_NAMES is the Curve to curve name string.
|
||||
CURVE_NAMES := [Curve]string {
|
||||
.Invalid = "Invalid",
|
||||
.SECP256R1 = "secp256r1",
|
||||
.X25519 = "X25519",
|
||||
.X448 = "X448",
|
||||
}
|
||||
|
||||
// PRIVATE_KEY_SIZES is the Curve to private key size in bytes.
|
||||
PRIVATE_KEY_SIZES := [Curve]int {
|
||||
.Invalid = 0,
|
||||
.SECP256R1 = secec.SC_SIZE_P256R1,
|
||||
.X25519 = x25519.SCALAR_SIZE,
|
||||
.X448 = x448.SCALAR_SIZE,
|
||||
}
|
||||
|
||||
// PUBLIC_KEY_SIZES is the Curve to public key size in bytes.
|
||||
PUBLIC_KEY_SIZES := [Curve]int {
|
||||
.Invalid = 0,
|
||||
.SECP256R1 = 1 + 2 * secec.FE_SIZE_P256R1,
|
||||
.X25519 = x25519.POINT_SIZE,
|
||||
.X448 = x448.POINT_SIZE,
|
||||
}
|
||||
|
||||
// SHARED_SECRET_SIZES is the Curve to shared secret size in bytes.
|
||||
SHARED_SECRET_SIZES := [Curve]int {
|
||||
.Invalid = 0,
|
||||
.SECP256R1 = secec.FE_SIZE_P256R1,
|
||||
.X25519 = x25519.POINT_SIZE,
|
||||
.X448 = x448.POINT_SIZE,
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
_PRIV_IMPL_IDS := [Curve]typeid {
|
||||
.Invalid = nil,
|
||||
.SECP256R1 = typeid_of(secec.Scalar_p256r1),
|
||||
.X25519 = typeid_of(X25519_Buf),
|
||||
.X448 = typeid_of(X448_Buf),
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
_PUB_IMPL_IDS := [Curve]typeid {
|
||||
.Invalid = nil,
|
||||
.SECP256R1 = typeid_of(secec.Point_p256r1),
|
||||
.X25519 = typeid_of(X25519_Buf),
|
||||
.X448 = typeid_of(X448_Buf),
|
||||
}
|
||||
|
||||
// Private_Key is an ECDH 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).
|
||||
_curve: Curve,
|
||||
_impl: union {
|
||||
secec.Scalar_p256r1,
|
||||
X25519_Buf,
|
||||
X448_Buf,
|
||||
},
|
||||
_pub_key: Public_Key,
|
||||
}
|
||||
|
||||
// Public_Key is an ECDH 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).
|
||||
_curve: Curve,
|
||||
_impl: union {
|
||||
secec.Point_p256r1,
|
||||
X25519_Buf,
|
||||
X448_Buf,
|
||||
},
|
||||
}
|
||||
|
||||
// private_key_generate uses the system entropy source to generate a new
|
||||
// Private_Key. This will only fail iff the system entropy source is
|
||||
// missing or broken.
|
||||
private_key_generate :: proc(priv_key: ^Private_Key, curve: Curve) -> bool {
|
||||
private_key_clear(priv_key)
|
||||
|
||||
if !crypto.HAS_RAND_BYTES {
|
||||
return false
|
||||
}
|
||||
|
||||
reflect.set_union_variant_typeid(
|
||||
priv_key._impl,
|
||||
_PRIV_IMPL_IDS[curve],
|
||||
)
|
||||
|
||||
#partial switch curve {
|
||||
case .SECP256R1:
|
||||
sc := &priv_key._impl.(secec.Scalar_p256r1)
|
||||
|
||||
// 384-bits reduced makes the modulo bias insignificant
|
||||
b: [48]byte = ---
|
||||
defer (mem.zero_explicit(&b, size_of(b)))
|
||||
for {
|
||||
crypto.rand_bytes(b[:])
|
||||
_ = secec.sc_set_bytes(sc, b[:])
|
||||
if secec.sc_is_zero(sc) == 0 { // Likely
|
||||
break
|
||||
}
|
||||
}
|
||||
case .X25519:
|
||||
sc := &priv_key._impl.(X25519_Buf)
|
||||
crypto.rand_bytes(sc[:])
|
||||
case .X448:
|
||||
sc := &priv_key._impl.(X448_Buf)
|
||||
crypto.rand_bytes(sc[:])
|
||||
case:
|
||||
panic("crypto/ecdh: invalid curve")
|
||||
}
|
||||
|
||||
priv_key._curve = curve
|
||||
private_key_generate_public(priv_key)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 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, curve: Curve, b: []byte) -> bool {
|
||||
private_key_clear(priv_key)
|
||||
|
||||
if len(b) != PRIVATE_KEY_SIZES[curve] {
|
||||
return false
|
||||
}
|
||||
|
||||
reflect.set_union_variant_typeid(
|
||||
priv_key._impl,
|
||||
_PRIV_IMPL_IDS[curve],
|
||||
)
|
||||
|
||||
#partial switch curve {
|
||||
case .SECP256R1:
|
||||
sc := &priv_key._impl.(secec.Scalar_p256r1)
|
||||
did_reduce := secec.sc_set_bytes(sc, b)
|
||||
is_zero := secec.sc_is_zero(sc) == 1
|
||||
|
||||
// Reject `0` and scalars that are not less than the
|
||||
// curve order.
|
||||
if did_reduce || is_zero {
|
||||
private_key_clear(priv_key)
|
||||
return false
|
||||
}
|
||||
case .X25519:
|
||||
sc := &priv_key._impl.(X25519_Buf)
|
||||
copy(sc[:], b)
|
||||
case .X448:
|
||||
sc := &priv_key._impl.(X448_Buf)
|
||||
copy(sc[:], b)
|
||||
case:
|
||||
panic("crypto/ecdh: invalid curve")
|
||||
}
|
||||
|
||||
priv_key._curve = curve
|
||||
private_key_generate_public(priv_key)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
private_key_generate_public :: proc(priv_key: ^Private_Key) {
|
||||
switch &sc in priv_key._impl {
|
||||
case secec.Scalar_p256r1:
|
||||
pub_key: secec.Point_p256r1 = ---
|
||||
secec.pt_scalar_mul_generator(&pub_key, &sc)
|
||||
secec.pt_rescale(&pub_key, &pub_key)
|
||||
priv_key._pub_key._impl = pub_key
|
||||
case X25519_Buf:
|
||||
pub_key: X25519_Buf = ---
|
||||
x25519.scalarmult_basepoint(pub_key[:], sc[:])
|
||||
priv_key._pub_key._impl = pub_key
|
||||
case X448_Buf:
|
||||
pub_key: X448_Buf = ---
|
||||
x448.scalarmult_basepoint(pub_key[:], sc[:])
|
||||
priv_key._pub_key._impl = pub_key
|
||||
case:
|
||||
panic("crypto/ecdh: invalid curve")
|
||||
}
|
||||
|
||||
priv_key._pub_key._curve = priv_key._curve
|
||||
}
|
||||
|
||||
// private_key_bytes sets dst to byte-encoding of priv_key.
|
||||
private_key_bytes :: proc(priv_key: ^Private_Key, dst: []byte) {
|
||||
ensure(priv_key._curve != .Invalid, "crypto/ecdh: uninitialized private key")
|
||||
ensure(len(dst) == PRIVATE_KEY_SIZES[priv_key._curve], "crypto/ecdh: invalid destination size")
|
||||
|
||||
#partial switch priv_key._curve {
|
||||
case .SECP256R1:
|
||||
sc := &priv_key._impl.(secec.Scalar_p256r1)
|
||||
secec.sc_bytes(dst, sc)
|
||||
case .X25519:
|
||||
sc := &priv_key._impl.(X25519_Buf)
|
||||
copy(dst, sc[:])
|
||||
case .X448:
|
||||
sc := &priv_key._impl.(X448_Buf)
|
||||
copy(dst, sc[:])
|
||||
case:
|
||||
panic("crypto/ecdh: invalid curve")
|
||||
}
|
||||
}
|
||||
|
||||
// private_key_equal returns true iff the private keys are equal,
|
||||
// in constant time.
|
||||
private_key_equal :: proc(p, q: ^Private_Key) -> bool {
|
||||
if p._curve != q._curve {
|
||||
return false
|
||||
}
|
||||
|
||||
#partial switch p._curve {
|
||||
case .SECP256R1:
|
||||
sc_p, sc_q := &p._impl.(secec.Scalar_p256r1), &q._impl.(secec.Scalar_p256r1)
|
||||
return secec.sc_equal(sc_p, sc_q) == 1
|
||||
case .X25519:
|
||||
b_p, b_q := &p._impl.(X25519_Buf), &q._impl.(X25519_Buf)
|
||||
return crypto.compare_constant_time(b_p[:], b_q[:]) == 1
|
||||
case .X448:
|
||||
b_p, b_q := &p._impl.(X448_Buf), &q._impl.(X448_Buf)
|
||||
return crypto.compare_constant_time(b_p[:], b_q[:]) == 1
|
||||
case:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
|
||||
// public_key_set_bytes decodes a byte-encoded public key, and returns
|
||||
// true iff the operation was successful.
|
||||
public_key_set_bytes :: proc(pub_key: ^Public_Key, curve: Curve, b: []byte) -> bool {
|
||||
public_key_clear(pub_key)
|
||||
|
||||
if len(b) != PUBLIC_KEY_SIZES[curve] {
|
||||
return false
|
||||
}
|
||||
|
||||
reflect.set_union_variant_typeid(
|
||||
pub_key._impl,
|
||||
_PUB_IMPL_IDS[curve],
|
||||
)
|
||||
|
||||
#partial switch curve {
|
||||
case .SECP256R1:
|
||||
if b[0] != secec.SEC_PREFIX_UNCOMPRESSED {
|
||||
return false
|
||||
}
|
||||
|
||||
pt := &pub_key._impl.(secec.Point_p256r1)
|
||||
ok := secec.pt_set_sec_bytes(pt, b)
|
||||
if !ok || secec.pt_is_identity(pt) == 1 {
|
||||
return false
|
||||
}
|
||||
case .X25519:
|
||||
pt := &pub_key._impl.(X25519_Buf)
|
||||
copy(pt[:], b)
|
||||
case .X448:
|
||||
pt := &pub_key._impl.(X448_Buf)
|
||||
copy(pt[:], b)
|
||||
case:
|
||||
panic("crypto/ecdh: invalid curve")
|
||||
}
|
||||
|
||||
pub_key._curve = curve
|
||||
|
||||
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) {
|
||||
ensure(priv_key._curve != .Invalid, "crypto/ecdh: uninitialized private key")
|
||||
public_key_clear(pub_key)
|
||||
pub_key^ = priv_key._pub_key
|
||||
}
|
||||
|
||||
// public_key_bytes sets dst to byte-encoding of pub_key.
|
||||
public_key_bytes :: proc(pub_key: ^Public_Key, dst: []byte) {
|
||||
ensure(pub_key._curve != .Invalid, "crypto/ecdh: uninitialized public key")
|
||||
ensure(len(dst) == PUBLIC_KEY_SIZES[pub_key._curve], "crypto/ecdh: invalid destination size")
|
||||
|
||||
#partial switch pub_key._curve {
|
||||
case .SECP256R1:
|
||||
// Invariant: Unless the caller is manually building pub_key
|
||||
// `Z = 1`, so we can skip the rescale.
|
||||
pt := &pub_key._impl.(secec.Point_p256r1)
|
||||
|
||||
dst[0] = secec.SEC_PREFIX_UNCOMPRESSED
|
||||
secec.fe_bytes(dst[1:1+secec.FE_SIZE_P256R1], &pt.x)
|
||||
secec.fe_bytes(dst[1+secec.FE_SIZE_P256R1:], &pt.y)
|
||||
case .X25519:
|
||||
pt := &pub_key._impl.(X25519_Buf)
|
||||
copy(dst, pt[:])
|
||||
case .X448:
|
||||
pt := &pub_key._impl.(X448_Buf)
|
||||
copy(dst, pt[:])
|
||||
case:
|
||||
panic("crypto/ecdh: invalid curve")
|
||||
}
|
||||
}
|
||||
|
||||
// public_key_equal returns true iff the public keys are equal,
|
||||
// in constant time.
|
||||
public_key_equal :: proc(p, q: ^Public_Key) -> bool {
|
||||
if p._curve != q._curve {
|
||||
return false
|
||||
}
|
||||
|
||||
#partial switch p._curve {
|
||||
case .SECP256R1:
|
||||
pt_p, pt_q := &p._impl.(secec.Point_p256r1), &q._impl.(secec.Point_p256r1)
|
||||
return secec.pt_equal(pt_p, pt_q) == 1
|
||||
case .X25519:
|
||||
b_p, b_q := &p._impl.(X25519_Buf), &q._impl.(X25519_Buf)
|
||||
return crypto.compare_constant_time(b_p[:], b_q[:]) == 1
|
||||
case .X448:
|
||||
b_p, b_q := &p._impl.(X448_Buf), &q._impl.(X448_Buf)
|
||||
return crypto.compare_constant_time(b_p[:], b_q[:]) == 1
|
||||
case:
|
||||
panic("crypto/ecdh: invalid curve")
|
||||
}
|
||||
}
|
||||
|
||||
// public_key_clear clears pub_key to the uninitialized state.
|
||||
public_key_clear :: proc "contextless" (pub_key: ^Public_Key) {
|
||||
mem.zero_explicit(pub_key, size_of(Public_Key))
|
||||
}
|
||||
|
||||
// ecdh performs an Elliptic Curve Diffie-Hellman key exchange betwween
|
||||
// the Private_Key and Public_Key, writing the shared secret to dst.
|
||||
//
|
||||
// The neutral element is rejected as an error.
|
||||
@(require_results)
|
||||
ecdh :: proc(priv_key: ^Private_Key, pub_key: ^Public_Key, dst: []byte) -> bool {
|
||||
ensure(priv_key._curve == pub_key._curve, "crypto/ecdh: curve mismatch")
|
||||
ensure(pub_key._curve != .Invalid, "crypto/ecdh: uninitialized public key")
|
||||
ensure(len(dst) == SHARED_SECRET_SIZES[priv_key._curve], "crypto/ecdh: invalid shared secret size")
|
||||
|
||||
#partial switch priv_key._curve {
|
||||
case .SECP256R1:
|
||||
sc, pt := &priv_key._impl.(secec.Scalar_p256r1), &pub_key._impl.(secec.Point_p256r1)
|
||||
ss: secec.Point_p256r1
|
||||
defer secec.pt_clear(&ss)
|
||||
|
||||
secec.pt_scalar_mul(&ss, pt, sc)
|
||||
return secec.pt_bytes(dst, nil, &ss)
|
||||
case .X25519:
|
||||
sc, pt := &priv_key._impl.(X25519_Buf), &pub_key._impl.(X25519_Buf)
|
||||
x25519.scalarmult(dst, sc[:], pt[:])
|
||||
case .X448:
|
||||
sc, pt := &priv_key._impl.(X448_Buf), &pub_key._impl.(X448_Buf)
|
||||
x448.scalarmult(dst, sc[:], pt[:])
|
||||
case:
|
||||
panic("crypto/ecdh: invalid curve")
|
||||
}
|
||||
|
||||
// X25519/X448 check for all zero digest.
|
||||
return crypto.is_zero_constant_time(dst) == 0
|
||||
}
|
||||
|
||||
// curve returns the Curve used by a Private_Key or Public_Key instance.
|
||||
curve :: proc(k: ^$T) -> Curve where(T == Private_Key || T == Public_Key) {
|
||||
return k._curve
|
||||
}
|
||||
|
||||
// key_size returns the key size of a Private_Key or Public_Key in bytes.
|
||||
key_size :: proc(k: ^$T) -> int where(T == Private_Key || T == Public_Key) {
|
||||
when T == Private_Key {
|
||||
return PRIVATE_KEY_SIZES[k._curve]
|
||||
} else {
|
||||
return PUBLIC_KEY_SIZES[k._curve]
|
||||
}
|
||||
}
|
||||
|
||||
// shared_secret_size returns the shared secret size of a key exchange
|
||||
// in bytes.
|
||||
shared_secret_size :: proc(k: ^$T) -> int where(T == Private_Key || T == Public_Key) {
|
||||
return SHARED_SECRET_SIZES[k._curve]
|
||||
}
|
||||
@@ -170,7 +170,7 @@ public_key_set_bytes :: proc "contextless" (pub_key: ^Public_Key, b: []byte) ->
|
||||
|
||||
// public_key_set_priv sets pub_key to the public component of priv_key.
|
||||
public_key_set_priv :: proc(pub_key: ^Public_Key, priv_key: ^Private_Key) {
|
||||
ensure(priv_key._is_initialized, "crypto/ed25519: uninitialized public key")
|
||||
ensure(priv_key._is_initialized, "crypto/ed25519: uninitialized private key")
|
||||
|
||||
src := &priv_key._pub_key
|
||||
copy(pub_key._b[:], src._b[:])
|
||||
|
||||
@@ -6,6 +6,8 @@ See:
|
||||
*/
|
||||
package x25519
|
||||
|
||||
import "core:crypto"
|
||||
import ed "core:crypto/_edwards25519"
|
||||
import field "core:crypto/_fiat/field_curve25519"
|
||||
import "core:mem"
|
||||
|
||||
@@ -14,8 +16,10 @@ SCALAR_SIZE :: 32
|
||||
// POINT_SIZE is the size of a X25519 point (public key/shared secret) in bytes.
|
||||
POINT_SIZE :: 32
|
||||
|
||||
@(private, rodata)
|
||||
_BASE_POINT: [32]byte = {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
when crypto.COMPACT_IMPLS == true {
|
||||
@(private,rodata)
|
||||
_BASE_POINT: [32]byte = {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
}
|
||||
|
||||
@(private)
|
||||
_scalar_bit :: #force_inline proc "contextless" (s: ^[32]byte, i: int) -> u8 {
|
||||
@@ -111,19 +115,44 @@ scalarmult :: proc(dst, scalar, point: []byte) {
|
||||
e[31] &= 127
|
||||
e[31] |= 64
|
||||
|
||||
p: [32]byte = ---
|
||||
copy_slice(p[:], point)
|
||||
|
||||
d: [32]byte = ---
|
||||
_scalarmult(&d, &e, &p)
|
||||
copy_slice(dst, d[:])
|
||||
p := (^[32]byte)(raw_data(point))
|
||||
d := (^[32]byte)(raw_data(dst))
|
||||
_scalarmult(d, &e, p)
|
||||
|
||||
mem.zero_explicit(&e, size_of(e))
|
||||
mem.zero_explicit(&d, size_of(d))
|
||||
}
|
||||
|
||||
// scalarmult_basepoint "multiplies" the provided scalar with the X25519
|
||||
// base point and writes the resulting point to dst.
|
||||
scalarmult_basepoint :: proc(dst, scalar: []byte) {
|
||||
scalarmult(dst, scalar, _BASE_POINT[:])
|
||||
when crypto.COMPACT_IMPLS == true {
|
||||
scalarmult(dst, scalar, _BASE_POINT[:])
|
||||
} else {
|
||||
ensure(len(scalar) == SCALAR_SIZE, "crypto/x25519: invalid scalar size")
|
||||
ensure(len(dst) == POINT_SIZE, "crypto/x25519: invalid destination point size")
|
||||
|
||||
sc: ed.Scalar = ---
|
||||
ed.sc_set_bytes_rfc8032(&sc, scalar)
|
||||
|
||||
ge: ed.Group_Element = ---
|
||||
ed.ge_scalarmult_basepoint(&ge, &sc)
|
||||
|
||||
// u = (y + z)/(z - y)
|
||||
y_plus_z: field.Loose_Field_Element = ---
|
||||
z_minus_y: field.Loose_Field_Element = ---
|
||||
u: field.Tight_Field_Element = ---
|
||||
|
||||
field.fe_add(&y_plus_z, &ge.y, &ge.z)
|
||||
field.fe_sub(&z_minus_y, &ge.z, &ge.y)
|
||||
field.fe_carry_inv(&u, &z_minus_y)
|
||||
field.fe_carry_mul(&u, &y_plus_z, field.fe_relax_cast(&u))
|
||||
|
||||
dst_ := (^[32]byte)(raw_data(dst))
|
||||
field.fe_to_bytes(dst_, &u)
|
||||
|
||||
field.fe_clear_vec([]^field.Loose_Field_Element{&y_plus_z, &z_minus_y})
|
||||
field.fe_clear(&u)
|
||||
ed.sc_clear(&sc)
|
||||
ed.ge_clear(&ge)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -798,6 +798,7 @@ Struct_Type :: struct {
|
||||
is_raw_union: bool,
|
||||
is_no_copy: bool,
|
||||
is_all_or_none: bool,
|
||||
is_simple: bool,
|
||||
fields: ^Field_List,
|
||||
name_count: int,
|
||||
}
|
||||
|
||||
@@ -2667,6 +2667,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
is_raw_union: bool
|
||||
is_no_copy: bool
|
||||
is_all_or_none: bool
|
||||
is_simple: bool
|
||||
fields: ^ast.Field_List
|
||||
name_count: int
|
||||
|
||||
@@ -2695,6 +2696,11 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
error(p, tag.pos, "duplicate struct tag '#%s'", tag.text)
|
||||
}
|
||||
is_all_or_none = true
|
||||
case "simple":
|
||||
if is_simple {
|
||||
error(p, tag.pos, "duplicate struct tag '#%s'", tag.text)
|
||||
}
|
||||
is_simple = true
|
||||
case "align":
|
||||
if align != nil {
|
||||
error(p, tag.pos, "duplicate struct tag '#%s'", tag.text)
|
||||
@@ -2769,6 +2775,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
st.is_raw_union = is_raw_union
|
||||
st.is_no_copy = is_no_copy
|
||||
st.is_all_or_none = is_all_or_none
|
||||
st.is_simple = is_simple
|
||||
st.fields = fields
|
||||
st.name_count = name_count
|
||||
st.where_token = where_token
|
||||
|
||||
@@ -283,6 +283,10 @@ _is_absolute_path :: proc(path: string) -> bool {
|
||||
if _is_reserved_name(path) {
|
||||
return true
|
||||
}
|
||||
if len(path) > 0 && _is_path_separator(path[0]) {
|
||||
return true
|
||||
}
|
||||
|
||||
l := _volume_name_len(path)
|
||||
if l == 0 {
|
||||
return false
|
||||
|
||||
@@ -49,35 +49,66 @@ volume_name_len :: proc(path: string) -> int {
|
||||
if len(path) < 2 {
|
||||
return 0
|
||||
}
|
||||
c := path[0]
|
||||
|
||||
if path[1] == ':' {
|
||||
switch c {
|
||||
switch path[0] {
|
||||
case 'a'..='z', 'A'..='Z':
|
||||
return 2
|
||||
}
|
||||
}
|
||||
|
||||
// URL: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
|
||||
if l := len(path); l >= 5 && is_slash(path[0]) && is_slash(path[1]) &&
|
||||
!is_slash(path[2]) && path[2] != '.' {
|
||||
for n := 3; n < l-1; n += 1 {
|
||||
if is_slash(path[n]) {
|
||||
n += 1
|
||||
if !is_slash(path[n]) {
|
||||
if path[n] == '.' {
|
||||
break
|
||||
}
|
||||
}
|
||||
for ; n < l; n += 1 {
|
||||
if is_slash(path[n]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return n
|
||||
/*
|
||||
See: URL: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
|
||||
Further allowed paths can be of the form of:
|
||||
- \\server\share or \\server\share\more\path
|
||||
- \\?\C:\...
|
||||
- \\.\PhysicalDriveX
|
||||
*/
|
||||
// Any remaining kind of path has to start with two slashes.
|
||||
if !is_separator(path[0]) || !is_separator(path[1]) {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Device path. The volume name is the whole string
|
||||
if len(path) >= 5 && path[2] == '.' && is_separator(path[3]) {
|
||||
return len(path)
|
||||
}
|
||||
|
||||
// We're a UNC share `\\host\share`, file namespace `\\?\C:` or UNC in file namespace `\\?\\host\share`
|
||||
prefix := 2
|
||||
|
||||
// File namespace.
|
||||
if len(path) >= 5 && path[2] == '?' && is_separator(path[3]) {
|
||||
if is_separator(path[4]) {
|
||||
// `\\?\\` UNC path in file namespace
|
||||
prefix = 5
|
||||
}
|
||||
|
||||
if len(path) >= 6 && path[5] == ':' {
|
||||
switch path[4] {
|
||||
case 'a'..='z', 'A'..='Z':
|
||||
return 6
|
||||
case:
|
||||
return 0
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// UNC path, minimum version of the volume is `\\h\s` for host, share.
|
||||
// Can also contain an IP address in the host position.
|
||||
slash_count := 0
|
||||
for i in prefix..<len(path) {
|
||||
// Host needs to be at least 1 character
|
||||
if is_separator(path[i]) && i > 0 {
|
||||
slash_count += 1
|
||||
|
||||
if slash_count == 2 {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return len(path)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -368,8 +399,8 @@ rel :: proc(base_path, target_path: string, allocator := context.allocator) -> (
|
||||
return strings.clone(".", allocator), .None
|
||||
}
|
||||
|
||||
base_vol := volume_name(base_path)
|
||||
target_vol := volume_name(target_path)
|
||||
base_vol := volume_name(base_clean)
|
||||
target_vol := volume_name(target_clean)
|
||||
base := base_clean [len(base_vol):]
|
||||
target := target_clean[len(target_vol):]
|
||||
if base == "." {
|
||||
|
||||
@@ -36,6 +36,9 @@ is_abs :: proc(path: string) -> bool {
|
||||
if is_reserved_name(path) {
|
||||
return true
|
||||
}
|
||||
if len(path) > 0 && is_slash(path[0]) {
|
||||
return true
|
||||
}
|
||||
l := volume_name_len(path)
|
||||
if l == 0 {
|
||||
return false
|
||||
|
||||
@@ -696,9 +696,10 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt
|
||||
}
|
||||
|
||||
io.write_string(w, "struct ", &n) or_return
|
||||
if .packed in info.flags { io.write_string(w, "#packed ", &n) or_return }
|
||||
if .raw_union in info.flags { io.write_string(w, "#raw_union ", &n) or_return }
|
||||
if .packed in info.flags { io.write_string(w, "#packed ", &n) or_return }
|
||||
if .raw_union in info.flags { io.write_string(w, "#raw_union ", &n) or_return }
|
||||
if .all_or_none in info.flags { io.write_string(w, "#all_or_none ", &n) or_return }
|
||||
if .simple in info.flags { io.write_string(w, "#simple ", &n) or_return }
|
||||
if .align in info.flags {
|
||||
io.write_string(w, "#align(", &n) or_return
|
||||
io.write_i64(w, i64(ti.align), 10, &n) or_return
|
||||
|
||||
@@ -60,6 +60,7 @@ accept_sizes := [256]u8{
|
||||
0xf5..=0xff = 0xf1, // ascii, size 1
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
encode_rune :: proc "contextless" (c: rune) -> ([4]u8, int) {
|
||||
r := c
|
||||
|
||||
@@ -101,9 +102,11 @@ decode_rune :: proc{
|
||||
decode_rune_in_string,
|
||||
decode_rune_in_bytes,
|
||||
}
|
||||
@(require_results)
|
||||
decode_rune_in_string :: #force_inline proc "contextless" (s: string) -> (rune, int) {
|
||||
return decode_rune_in_bytes(transmute([]u8)s)
|
||||
}
|
||||
@(require_results)
|
||||
decode_rune_in_bytes :: proc "contextless" (s: []u8) -> (rune, int) {
|
||||
n := len(s)
|
||||
if n < 1 {
|
||||
@@ -141,6 +144,7 @@ decode_rune_in_bytes :: proc "contextless" (s: []u8) -> (rune, int) {
|
||||
return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
string_to_runes :: proc "odin" (s: string, allocator := context.allocator) -> (runes: []rune) {
|
||||
n := rune_count_in_string(s)
|
||||
|
||||
@@ -153,6 +157,7 @@ string_to_runes :: proc "odin" (s: string, allocator := context.allocator) -> (r
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
runes_to_string :: proc "odin" (runes: []rune, allocator := context.allocator) -> string {
|
||||
byte_count := 0
|
||||
for r in runes {
|
||||
@@ -177,9 +182,11 @@ decode_last_rune :: proc{
|
||||
decode_last_rune_in_bytes,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
decode_last_rune_in_string :: #force_inline proc "contextless" (s: string) -> (rune, int) {
|
||||
return decode_last_rune_in_bytes(transmute([]u8)s)
|
||||
}
|
||||
@(require_results)
|
||||
decode_last_rune_in_bytes :: proc "contextless" (s: []u8) -> (rune, int) {
|
||||
r: rune
|
||||
size: int
|
||||
@@ -212,6 +219,7 @@ decode_last_rune_in_bytes :: proc "contextless" (s: []u8) -> (rune, int) {
|
||||
return r, size
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
rune_at_pos :: proc "contextless" (s: string, pos: int) -> rune {
|
||||
if pos < 0 {
|
||||
return RUNE_ERROR
|
||||
@@ -227,6 +235,7 @@ rune_at_pos :: proc "contextless" (s: string, pos: int) -> rune {
|
||||
return RUNE_ERROR
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
rune_string_at_pos :: proc "contextless" (s: string, pos: int) -> string {
|
||||
if pos < 0 {
|
||||
return ""
|
||||
@@ -243,6 +252,7 @@ rune_string_at_pos :: proc "contextless" (s: string, pos: int) -> string {
|
||||
return ""
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
rune_at :: proc "contextless" (s: string, byte_index: int) -> rune {
|
||||
r, _ := decode_rune_in_string(s[byte_index:])
|
||||
return r
|
||||
@@ -250,6 +260,7 @@ rune_at :: proc "contextless" (s: string, byte_index: int) -> rune {
|
||||
|
||||
// Returns the byte position of rune at position pos in s with an optional start byte position.
|
||||
// Returns -1 if it runs out of the string.
|
||||
@(require_results)
|
||||
rune_offset :: proc "contextless" (s: string, pos: int, start: int = 0) -> int {
|
||||
if pos < 0 {
|
||||
return -1
|
||||
@@ -265,6 +276,7 @@ rune_offset :: proc "contextless" (s: string, pos: int, start: int = 0) -> int {
|
||||
return -1
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
valid_rune :: proc "contextless" (r: rune) -> bool {
|
||||
if r < 0 {
|
||||
return false
|
||||
@@ -276,6 +288,7 @@ valid_rune :: proc "contextless" (r: rune) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
valid_string :: proc "contextless" (s: string) -> bool {
|
||||
n := len(s)
|
||||
for i := 0; i < n; {
|
||||
@@ -309,6 +322,7 @@ valid_string :: proc "contextless" (s: string) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
rune_start :: #force_inline proc "contextless" (b: u8) -> bool {
|
||||
return b&0xc0 != 0x80
|
||||
}
|
||||
@@ -318,9 +332,11 @@ rune_count :: proc{
|
||||
rune_count_in_bytes,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
rune_count_in_string :: #force_inline proc(s: string) -> int {
|
||||
return rune_count_in_bytes(transmute([]u8)s)
|
||||
}
|
||||
@(require_results)
|
||||
rune_count_in_bytes :: proc "contextless" (s: []u8) -> int {
|
||||
count := 0
|
||||
n := len(s)
|
||||
@@ -360,6 +376,7 @@ rune_count_in_bytes :: proc "contextless" (s: []u8) -> int {
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
rune_size :: proc "contextless" (r: rune) -> int {
|
||||
switch {
|
||||
case r < 0: return -1
|
||||
@@ -381,6 +398,7 @@ full_rune :: proc{
|
||||
|
||||
// full_rune_in_bytes reports if the bytes in b begin with a full utf-8 encoding of a rune or not
|
||||
// An invalid encoding is considered a full rune since it will convert as an error rune of width 1 (RUNE_ERROR)
|
||||
@(require_results)
|
||||
full_rune_in_bytes :: proc "contextless" (b: []byte) -> bool {
|
||||
n := len(b)
|
||||
if n == 0 {
|
||||
@@ -401,6 +419,7 @@ full_rune_in_bytes :: proc "contextless" (b: []byte) -> bool {
|
||||
|
||||
// full_rune_in_string reports if the bytes in s begin with a full utf-8 encoding of a rune or not
|
||||
// An invalid encoding is considered a full rune since it will convert as an error rune of width 1 (RUNE_ERROR)
|
||||
@(require_results)
|
||||
full_rune_in_string :: proc "contextless" (s: string) -> bool {
|
||||
return full_rune_in_bytes(transmute([]byte)s)
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ package all
|
||||
@(require) import "core:crypto/chacha20poly1305"
|
||||
@(require) import chash "core:crypto/hash"
|
||||
@(require) import "core:crypto/deoxysii"
|
||||
@(require) import "core:crypto/ecdh"
|
||||
@(require) import "core:crypto/ed25519"
|
||||
@(require) import "core:crypto/hkdf"
|
||||
@(require) import "core:crypto/hmac"
|
||||
|
||||
@@ -17,13 +17,14 @@ package all
|
||||
|
||||
@(require) import "core:container/avl"
|
||||
@(require) import "core:container/bit_array"
|
||||
@(require) import "core:container/handle_map"
|
||||
@(require) import "core:container/intrusive/list"
|
||||
@(require) import "core:container/lru"
|
||||
@(require) import "core:container/pool"
|
||||
@(require) import "core:container/priority_queue"
|
||||
@(require) import "core:container/queue"
|
||||
@(require) import "core:container/small_array"
|
||||
@(require) import "core:container/lru"
|
||||
@(require) import "core:container/intrusive/list"
|
||||
@(require) import "core:container/rbtree"
|
||||
@(require) import "core:container/small_array"
|
||||
@(require) import "core:container/topological_sort"
|
||||
@(require) import "core:container/xar"
|
||||
|
||||
@@ -37,6 +38,7 @@ package all
|
||||
@(require) import "core:crypto/chacha20poly1305"
|
||||
@(require) import chash "core:crypto/hash"
|
||||
@(require) import "core:crypto/deoxysii"
|
||||
@(require) import "core:crypto/ecdh"
|
||||
@(require) import "core:crypto/ed25519"
|
||||
@(require) import "core:crypto/hkdf"
|
||||
@(require) import "core:crypto/hmac"
|
||||
|
||||
@@ -4704,12 +4704,14 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
if (operand->mode == Addressing_Constant) {
|
||||
check_is_expressible(c, operand, t);
|
||||
check_is_expressible(c, operand, target_type);
|
||||
if (operand->mode == Addressing_Invalid) {
|
||||
return;
|
||||
}
|
||||
update_untyped_expr_value(c, operand->expr, operand->value);
|
||||
} else {
|
||||
}
|
||||
|
||||
{
|
||||
switch (operand->type->Basic.kind) {
|
||||
case Basic_UntypedBool:
|
||||
if (!is_type_boolean(target_type)) {
|
||||
@@ -12692,8 +12694,10 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan
|
||||
str = write_expr_to_string(str, st->polymorphic_params, shorthand);
|
||||
str = gb_string_appendc(str, ") ");
|
||||
}
|
||||
if (st->is_packed) str = gb_string_appendc(str, "#packed ");
|
||||
if (st->is_raw_union) str = gb_string_appendc(str, "#raw_union ");
|
||||
if (st->is_packed) str = gb_string_appendc(str, "#packed ");
|
||||
if (st->is_raw_union) str = gb_string_appendc(str, "#raw_union ");
|
||||
if (st->is_all_or_none) str = gb_string_appendc(str, "#all_or_none ");
|
||||
if (st->is_simple) str = gb_string_appendc(str, "#simple ");
|
||||
if (st->align) {
|
||||
str = gb_string_appendc(str, "#align ");
|
||||
str = write_expr_to_string(str, st->align, shorthand);
|
||||
|
||||
@@ -1027,7 +1027,9 @@ gb_internal void check_unroll_range_stmt(CheckerContext *ctx, Ast *node, u32 mod
|
||||
error(operand.expr, "Cannot iterate over '%s' of type '%s' in an '#unroll for' statement", s, t);
|
||||
gb_string_free(t);
|
||||
gb_string_free(s);
|
||||
} else if (operand.mode != Addressing_Constant && unroll_count <= 0) {
|
||||
} else if (operand.mode != Addressing_Constant && (
|
||||
unroll_count <= 0 &&
|
||||
compare_exact_values(Token_CmpEq, inline_for_depth, exact_value_i64(0)))) {
|
||||
error(operand.expr, "An '#unroll for' expression must be known at compile time");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -679,6 +679,21 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
|
||||
gb_unused(where_clause_ok);
|
||||
}
|
||||
check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context);
|
||||
|
||||
if (st->is_simple) {
|
||||
bool success = true;
|
||||
for (Entity *f : struct_type->Struct.fields) {
|
||||
if (!is_type_nearly_simple_compare(f->type)) {
|
||||
gbString s = type_to_string(f->type);
|
||||
error(f->token, "'struct #simple' requires all fields to be at least 'nearly simple compare', got %s", s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
struct_type->Struct.is_simple = true;
|
||||
}
|
||||
}
|
||||
|
||||
wait_signal_set(&struct_type->Struct.fields_wait_signal);
|
||||
}
|
||||
|
||||
|
||||
@@ -1434,12 +1434,13 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt *
|
||||
|
||||
|
||||
if (unroll_count_ev.kind == ExactValue_Invalid) {
|
||||
GB_ASSERT(expr->tav.mode == Addressing_Constant);
|
||||
|
||||
Type *t = base_type(expr->tav.type);
|
||||
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
GB_ASSERT(expr->tav.mode == Addressing_Constant);
|
||||
|
||||
GB_ASSERT(is_type_string(t));
|
||||
{
|
||||
ExactValue value = expr->tav.value;
|
||||
|
||||
@@ -1230,7 +1230,7 @@ gb_internal Ast *ast_dynamic_array_type(AstFile *f, Token token, Ast *elem) {
|
||||
}
|
||||
|
||||
gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, isize field_count,
|
||||
Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_all_or_none,
|
||||
Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_all_or_none, bool is_simple,
|
||||
Ast *align, Ast *min_field_align, Ast *max_field_align,
|
||||
Token where_token, Array<Ast *> const &where_clauses) {
|
||||
Ast *result = alloc_ast_node(f, Ast_StructType);
|
||||
@@ -1241,6 +1241,7 @@ gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, i
|
||||
result->StructType.is_packed = is_packed;
|
||||
result->StructType.is_raw_union = is_raw_union;
|
||||
result->StructType.is_all_or_none = is_all_or_none;
|
||||
result->StructType.is_simple = is_simple;
|
||||
result->StructType.align = align;
|
||||
result->StructType.min_field_align = min_field_align;
|
||||
result->StructType.max_field_align = max_field_align;
|
||||
@@ -2788,6 +2789,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
bool is_packed = false;
|
||||
bool is_all_or_none = false;
|
||||
bool is_raw_union = false;
|
||||
bool is_simple = false;
|
||||
Ast *align = nullptr;
|
||||
Ast *min_field_align = nullptr;
|
||||
Ast *max_field_align = nullptr;
|
||||
@@ -2869,11 +2871,16 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
error_line("\tSuggestion: #max_field_align(%s)", s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
}else if (tag.string == "raw_union") {
|
||||
} else if (tag.string == "raw_union") {
|
||||
if (is_raw_union) {
|
||||
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
is_raw_union = true;
|
||||
} else if (tag.string == "simple") {
|
||||
if (is_simple) {
|
||||
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
is_simple = true;
|
||||
} else {
|
||||
syntax_error(tag, "Invalid struct tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
@@ -2919,7 +2926,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
parser_check_polymorphic_record_parameters(f, polymorphic_params);
|
||||
|
||||
return ast_struct_type(f, token, decls, name_count,
|
||||
polymorphic_params, is_packed, is_raw_union, is_all_or_none,
|
||||
polymorphic_params, is_packed, is_raw_union, is_all_or_none, is_simple,
|
||||
align, min_field_align, max_field_align,
|
||||
where_token, where_clauses);
|
||||
} break;
|
||||
|
||||
@@ -780,6 +780,7 @@ AST_KIND(_TypeBegin, "", bool) \
|
||||
bool is_raw_union; \
|
||||
bool is_no_copy; \
|
||||
bool is_all_or_none; \
|
||||
bool is_simple; \
|
||||
}) \
|
||||
AST_KIND(UnionType, "union type", struct { \
|
||||
Scope *scope; \
|
||||
|
||||
@@ -163,6 +163,7 @@ struct TypeStruct {
|
||||
bool is_packed : 1;
|
||||
bool is_raw_union : 1;
|
||||
bool is_all_or_none : 1;
|
||||
bool is_simple : 1;
|
||||
bool is_poly_specialized : 1;
|
||||
|
||||
std::atomic<bool> are_offsets_being_processed;
|
||||
@@ -2701,12 +2702,16 @@ gb_internal bool is_type_simple_compare(Type *t) {
|
||||
case Type_SoaPointer:
|
||||
case Type_Proc:
|
||||
case Type_BitSet:
|
||||
case Type_BitField:
|
||||
return true;
|
||||
|
||||
case Type_Matrix:
|
||||
return is_type_simple_compare(t->Matrix.elem);
|
||||
|
||||
case Type_Struct:
|
||||
if (t->Struct.is_simple) {
|
||||
return true;
|
||||
}
|
||||
for_array(i, t->Struct.fields) {
|
||||
Entity *f = t->Struct.fields[i];
|
||||
if (!is_type_simple_compare(f->type)) {
|
||||
@@ -2728,6 +2733,16 @@ gb_internal bool is_type_simple_compare(Type *t) {
|
||||
case Type_SimdVector:
|
||||
return is_type_simple_compare(t->SimdVector.elem);
|
||||
|
||||
case Type_Tuple:
|
||||
if (t->Tuple.variables.count == 1) {
|
||||
return is_type_simple_compare(t->Tuple.variables[0]->type);
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Slice:
|
||||
case Type_DynamicArray:
|
||||
case Type_Map:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -2757,12 +2772,16 @@ gb_internal bool is_type_nearly_simple_compare(Type *t) {
|
||||
case Type_SoaPointer:
|
||||
case Type_Proc:
|
||||
case Type_BitSet:
|
||||
case Type_BitField:
|
||||
return true;
|
||||
|
||||
case Type_Matrix:
|
||||
return is_type_nearly_simple_compare(t->Matrix.elem);
|
||||
|
||||
case Type_Struct:
|
||||
if (t->Struct.is_simple) {
|
||||
return true;
|
||||
}
|
||||
for_array(i, t->Struct.fields) {
|
||||
Entity *f = t->Struct.fields[i];
|
||||
if (!is_type_nearly_simple_compare(f->type)) {
|
||||
@@ -2784,6 +2803,17 @@ gb_internal bool is_type_nearly_simple_compare(Type *t) {
|
||||
case Type_SimdVector:
|
||||
return is_type_nearly_simple_compare(t->SimdVector.elem);
|
||||
|
||||
case Type_Tuple:
|
||||
if (t->Tuple.variables.count == 1) {
|
||||
return is_type_nearly_simple_compare(t->Tuple.variables[0]->type);
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Slice:
|
||||
case Type_DynamicArray:
|
||||
case Type_Map:
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -5099,9 +5129,11 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
|
||||
str = gb_string_appendc(str, ")");
|
||||
}
|
||||
|
||||
if (type->Struct.is_packed) str = gb_string_appendc(str, " #packed");
|
||||
if (type->Struct.is_raw_union) str = gb_string_appendc(str, " #raw_union");
|
||||
if (type->Struct.is_packed) str = gb_string_appendc(str, " #packed");
|
||||
if (type->Struct.is_raw_union) str = gb_string_appendc(str, " #raw_union");
|
||||
if (type->Struct.custom_align != 0) str = gb_string_append_fmt(str, " #align %d", cast(int)type->Struct.custom_align);
|
||||
if (type->Struct.is_all_or_none) str = gb_string_appendc(str, " #all_or_none");
|
||||
if (type->Struct.is_simple) str = gb_string_appendc(str, " #simple");
|
||||
|
||||
str = gb_string_appendc(str, " {");
|
||||
|
||||
|
||||
@@ -2,13 +2,14 @@ package benchmark_core_crypto
|
||||
|
||||
import "base:runtime"
|
||||
import "core:encoding/hex"
|
||||
import "core:log"
|
||||
import "core:testing"
|
||||
import "core:text/table"
|
||||
import "core:time"
|
||||
|
||||
import "core:crypto"
|
||||
import "core:crypto/ecdh"
|
||||
import "core:crypto/ed25519"
|
||||
import "core:crypto/x25519"
|
||||
import "core:crypto/x448"
|
||||
|
||||
@(private = "file")
|
||||
ECDH_ITERS :: 10000
|
||||
@@ -25,6 +26,10 @@ benchmark_crypto_ecc :: proc(t: ^testing.T) {
|
||||
|
||||
@(private = "file")
|
||||
bench_ecdh :: proc() {
|
||||
if !crypto.HAS_RAND_BYTES {
|
||||
log.warnf("ECDH benchmarks skipped, no system entropy source")
|
||||
}
|
||||
|
||||
tbl: table.Table
|
||||
table.init(&tbl)
|
||||
defer table.destroy(&tbl)
|
||||
@@ -42,63 +47,37 @@ bench_ecdh :: proc() {
|
||||
)
|
||||
}
|
||||
|
||||
scalar_bp, scalar := bench_x25519()
|
||||
append_tbl(&tbl, "X25519", scalar_bp, scalar)
|
||||
for algo in ecdh.Curve {
|
||||
if algo == .Invalid {
|
||||
continue
|
||||
}
|
||||
algo_name := ecdh.CURVE_NAMES[algo]
|
||||
|
||||
scalar_bp, scalar = bench_x448()
|
||||
append_tbl(&tbl, "X448", scalar_bp, scalar)
|
||||
priv_key_alice: ecdh.Private_Key
|
||||
start := time.tick_now()
|
||||
for _ in 0 ..< ECDH_ITERS {
|
||||
_ = ecdh.private_key_generate(&priv_key_alice, algo)
|
||||
}
|
||||
bp := time.tick_since(start) / ECDH_ITERS
|
||||
|
||||
pub_key_alice: ecdh.Public_Key
|
||||
ecdh.public_key_set_priv(&pub_key_alice, &priv_key_alice)
|
||||
|
||||
priv_key_bob: ecdh.Private_Key
|
||||
_ = ecdh.private_key_generate(&priv_key_bob, algo)
|
||||
ss := make([]byte, ecdh.SHARED_SECRET_SIZES[algo], context.temp_allocator)
|
||||
start = time.tick_now()
|
||||
for _ in 0 ..< ECDH_ITERS {
|
||||
_ = ecdh.ecdh(&priv_key_bob, &pub_key_alice, ss)
|
||||
}
|
||||
sc := time.tick_since(start) / ECDH_ITERS
|
||||
|
||||
append_tbl(&tbl, algo_name, bp, sc)
|
||||
}
|
||||
|
||||
log_table(&tbl)
|
||||
}
|
||||
|
||||
@(private = "file")
|
||||
bench_x25519 :: proc() -> (bp, sc: time.Duration) {
|
||||
point_str := "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
|
||||
scalar_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe"
|
||||
|
||||
point, _ := hex.decode(transmute([]byte)(point_str), context.temp_allocator)
|
||||
scalar, _ := hex.decode(transmute([]byte)(scalar_str), context.temp_allocator)
|
||||
out: [x25519.POINT_SIZE]byte = ---
|
||||
|
||||
start := time.tick_now()
|
||||
for _ in 0 ..< ECDH_ITERS {
|
||||
x25519.scalarmult_basepoint(out[:], scalar[:])
|
||||
}
|
||||
bp = time.tick_since(start) / ECDH_ITERS
|
||||
|
||||
start = time.tick_now()
|
||||
for _ in 0 ..< ECDH_ITERS {
|
||||
x25519.scalarmult(out[:], scalar[:], point[:])
|
||||
}
|
||||
sc = time.tick_since(start) / ECDH_ITERS
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@(private = "file")
|
||||
bench_x448 :: proc() -> (bp, sc: time.Duration) {
|
||||
point_str := "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
|
||||
scalar_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe"
|
||||
|
||||
point, _ := hex.decode(transmute([]byte)(point_str), context.temp_allocator)
|
||||
scalar, _ := hex.decode(transmute([]byte)(scalar_str), context.temp_allocator)
|
||||
out: [x448.POINT_SIZE]byte = ---
|
||||
|
||||
start := time.tick_now()
|
||||
for _ in 0 ..< ECDH_ITERS {
|
||||
x448.scalarmult_basepoint(out[:], scalar[:])
|
||||
}
|
||||
bp = time.tick_since(start) / ECDH_ITERS
|
||||
|
||||
start = time.tick_now()
|
||||
for _ in 0 ..< ECDH_ITERS {
|
||||
x448.scalarmult(out[:], scalar[:], point[:])
|
||||
}
|
||||
sc = time.tick_since(start) / ECDH_ITERS
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@(private = "file")
|
||||
bench_dsa :: proc() {
|
||||
tbl: table.Table
|
||||
|
||||
154
tests/core/crypto/test_core_crypto_ecdh.odin
Normal file
154
tests/core/crypto/test_core_crypto_ecdh.odin
Normal file
@@ -0,0 +1,154 @@
|
||||
package test_core_crypto
|
||||
|
||||
import "core:encoding/hex"
|
||||
import "core:testing"
|
||||
|
||||
import "core:crypto/ecdh"
|
||||
|
||||
@(test)
|
||||
test_ecdh :: proc(t: ^testing.T) {
|
||||
test_vectors := []struct {
|
||||
curve: ecdh.Curve,
|
||||
scalar: string,
|
||||
point: string,
|
||||
product: string,
|
||||
} {
|
||||
// X25519 Test vectors from RFC 7748
|
||||
{
|
||||
.X25519,
|
||||
"a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
|
||||
"e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c",
|
||||
"c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552",
|
||||
},
|
||||
{
|
||||
.X25519,
|
||||
"4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d",
|
||||
"e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493",
|
||||
"95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957",
|
||||
},
|
||||
// X448 Test vectors from RFC 7748
|
||||
{
|
||||
.X448,
|
||||
"3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3",
|
||||
"06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086",
|
||||
"ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f",
|
||||
},
|
||||
{
|
||||
.X448,
|
||||
"203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f",
|
||||
"0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db",
|
||||
"884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d",
|
||||
},
|
||||
// secp256r1 Test vectors (subset) from NIST CAVP
|
||||
{
|
||||
.SECP256R1,
|
||||
"7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534",
|
||||
"04700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac",
|
||||
"46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b",
|
||||
},
|
||||
{
|
||||
.SECP256R1,
|
||||
"38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5",
|
||||
"04809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7aeb29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3",
|
||||
"057d636096cb80b67a8c038c890e887d1adfa4195e9b3ce241c8a778c59cda67",
|
||||
},
|
||||
}
|
||||
|
||||
for v, _ in test_vectors {
|
||||
raw_scalar, _ := hex.decode(transmute([]byte)(v.scalar), context.temp_allocator)
|
||||
raw_point, _ := hex.decode(transmute([]byte)(v.point), context.temp_allocator)
|
||||
|
||||
pub_key: ecdh.Public_Key
|
||||
priv_key: ecdh.Private_Key
|
||||
|
||||
ok := ecdh.private_key_set_bytes(&priv_key, v.curve, raw_scalar)
|
||||
testing.expectf(t, ok, "failed to deserialize private key: %v %x", v.curve, raw_scalar)
|
||||
|
||||
ok = ecdh.public_key_set_bytes(&pub_key, v.curve, raw_point)
|
||||
testing.expectf(t, ok, "failed to deserialize public key: %v %x", v.curve, raw_scalar)
|
||||
|
||||
shared_secret := make([]byte, ecdh.shared_secret_size(&pub_key), context.temp_allocator)
|
||||
ok = ecdh.ecdh(&priv_key, &pub_key, shared_secret)
|
||||
testing.expectf(t, ok, "ecdh failed: %v %v %v", v.curve, &priv_key, &pub_key)
|
||||
|
||||
ss_str := string(hex.encode(shared_secret, context.temp_allocator))
|
||||
testing.expectf(
|
||||
t,
|
||||
ss_str == v.product,
|
||||
"Expected %s for %v %s * %s, but got %s instead",
|
||||
v.product,
|
||||
v.curve,
|
||||
v.scalar,
|
||||
v.point,
|
||||
ss_str,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_ecdh_scalar_basemult :: proc(t: ^testing.T) {
|
||||
test_vectors := []struct {
|
||||
curve: ecdh.Curve,
|
||||
scalar : string,
|
||||
point: string,
|
||||
} {
|
||||
// X25519 from RFC 7748 6.1
|
||||
{
|
||||
.X25519,
|
||||
"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a",
|
||||
"8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a",
|
||||
},
|
||||
{
|
||||
.X25519,
|
||||
"5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb",
|
||||
"de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f",
|
||||
},
|
||||
// X448 from RFC 7748 6.2
|
||||
{
|
||||
.X448,
|
||||
"9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b",
|
||||
"9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0",
|
||||
},
|
||||
{
|
||||
.X448,
|
||||
"1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d",
|
||||
"3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609",
|
||||
},
|
||||
// secp256r1 Test vectors (subset) from NIST CAVP
|
||||
{
|
||||
.SECP256R1,
|
||||
"7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534",
|
||||
"04ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b23028af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141",
|
||||
},
|
||||
{
|
||||
.SECP256R1,
|
||||
"38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5",
|
||||
"04119f2f047902782ab0c9e27a54aff5eb9b964829ca99c06b02ddba95b0a3f6d08f52b726664cac366fc98ac7a012b2682cbd962e5acb544671d41b9445704d1d",
|
||||
},
|
||||
}
|
||||
|
||||
for v, _ in test_vectors {
|
||||
raw_scalar, _ := hex.decode(transmute([]byte)(v.scalar), context.temp_allocator)
|
||||
|
||||
priv_key: ecdh.Private_Key
|
||||
pub_key: ecdh.Public_Key
|
||||
|
||||
ok := ecdh.private_key_set_bytes(&priv_key, v.curve, raw_scalar)
|
||||
testing.expectf(t, ok, "failed to deserialize private key: %v %x", v.curve, raw_scalar)
|
||||
|
||||
ecdh.public_key_set_priv(&pub_key, &priv_key)
|
||||
b := make([]byte, ecdh.key_size(&pub_key), context.temp_allocator)
|
||||
ecdh.public_key_bytes(&pub_key, b)
|
||||
|
||||
pub_str := string(hex.encode(b, context.temp_allocator))
|
||||
testing.expectf(
|
||||
t,
|
||||
pub_str == v.point,
|
||||
"Expected %s for %v %s * G, but got %s instead",
|
||||
v.point,
|
||||
v.curve,
|
||||
v.scalar,
|
||||
pub_str,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -6,11 +6,9 @@ import "core:testing"
|
||||
import field "core:crypto/_fiat/field_curve25519"
|
||||
import "core:crypto/ed25519"
|
||||
import "core:crypto/ristretto255"
|
||||
import "core:crypto/x25519"
|
||||
import "core:crypto/x448"
|
||||
|
||||
@(test)
|
||||
test_sqrt_ratio_m1 :: proc(t: ^testing.T) {
|
||||
test_edwards25519_sqrt_ratio_m1 :: proc(t: ^testing.T) {
|
||||
test_vectors := []struct {
|
||||
u: string,
|
||||
v: string,
|
||||
@@ -625,136 +623,14 @@ test_ed25519 :: proc(t: ^testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_x25519 :: proc(t: ^testing.T) {
|
||||
// Local copy of this so that the base point doesn't need to be exported.
|
||||
_BASE_POINT: [32]byte = {
|
||||
9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
}
|
||||
|
||||
test_vectors := []struct {
|
||||
scalar: string,
|
||||
point: string,
|
||||
product: string,
|
||||
} {
|
||||
// Test vectors from RFC 7748
|
||||
{
|
||||
"a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
|
||||
"e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c",
|
||||
"c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552",
|
||||
},
|
||||
{
|
||||
"4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d",
|
||||
"e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493",
|
||||
"95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957",
|
||||
},
|
||||
}
|
||||
for v, _ in test_vectors {
|
||||
scalar, _ := hex.decode(transmute([]byte)(v.scalar), context.temp_allocator)
|
||||
point, _ := hex.decode(transmute([]byte)(v.point), context.temp_allocator)
|
||||
|
||||
derived_point: [x25519.POINT_SIZE]byte
|
||||
x25519.scalarmult(derived_point[:], scalar[:], point[:])
|
||||
derived_point_str := string(hex.encode(derived_point[:], context.temp_allocator))
|
||||
|
||||
testing.expectf(
|
||||
t,
|
||||
derived_point_str == v.product,
|
||||
"Expected %s for %s * %s, but got %s instead",
|
||||
v.product,
|
||||
v.scalar,
|
||||
v.point,
|
||||
derived_point_str,
|
||||
)
|
||||
|
||||
// Abuse the test vectors to sanity-check the scalar-basepoint multiply.
|
||||
p1, p2: [x25519.POINT_SIZE]byte
|
||||
x25519.scalarmult_basepoint(p1[:], scalar[:])
|
||||
x25519.scalarmult(p2[:], scalar[:], _BASE_POINT[:])
|
||||
p1_str := string(hex.encode(p1[:], context.temp_allocator))
|
||||
p2_str := string(hex.encode(p2[:], context.temp_allocator))
|
||||
testing.expectf(
|
||||
t,
|
||||
p1_str == p2_str,
|
||||
"Expected %s for %s * basepoint, but got %s instead",
|
||||
p2_str,
|
||||
v.scalar,
|
||||
p1_str,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_x448 :: proc(t: ^testing.T) {
|
||||
// Local copy of this so that the base point doesn't need to be exported.
|
||||
_BASE_POINT: [56]byte = {
|
||||
5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
}
|
||||
|
||||
test_vectors := []struct {
|
||||
scalar: string,
|
||||
point: string,
|
||||
product: string,
|
||||
} {
|
||||
// Test vectors from RFC 7748
|
||||
{
|
||||
"3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3",
|
||||
"06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086",
|
||||
"ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f",
|
||||
},
|
||||
{
|
||||
"203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f",
|
||||
"0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db",
|
||||
"884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d",
|
||||
},
|
||||
}
|
||||
for v, _ in test_vectors {
|
||||
scalar, _ := hex.decode(transmute([]byte)(v.scalar), context.temp_allocator)
|
||||
point, _ := hex.decode(transmute([]byte)(v.point), context.temp_allocator)
|
||||
|
||||
derived_point: [x448.POINT_SIZE]byte
|
||||
x448.scalarmult(derived_point[:], scalar[:], point[:])
|
||||
derived_point_str := string(hex.encode(derived_point[:], context.temp_allocator))
|
||||
|
||||
testing.expectf(
|
||||
t,
|
||||
derived_point_str == v.product,
|
||||
"Expected %s for %s * %s, but got %s instead",
|
||||
v.product,
|
||||
v.scalar,
|
||||
v.point,
|
||||
derived_point_str,
|
||||
)
|
||||
|
||||
// Abuse the test vectors to sanity-check the scalar-basepoint multiply.
|
||||
p1, p2: [x448.POINT_SIZE]byte
|
||||
x448.scalarmult_basepoint(p1[:], scalar[:])
|
||||
x448.scalarmult(p2[:], scalar[:], _BASE_POINT[:])
|
||||
p1_str := string(hex.encode(p1[:], context.temp_allocator))
|
||||
p2_str := string(hex.encode(p2[:], context.temp_allocator))
|
||||
testing.expectf(
|
||||
t,
|
||||
p1_str == p2_str,
|
||||
"Expected %s for %s * basepoint, but got %s instead",
|
||||
p2_str,
|
||||
v.scalar,
|
||||
p1_str,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
@(private="file")
|
||||
ge_str :: proc(ge: ^ristretto255.Group_Element) -> string {
|
||||
b: [ristretto255.ELEMENT_SIZE]byte
|
||||
ristretto255.ge_bytes(ge, b[:])
|
||||
return string(hex.encode(b[:], context.temp_allocator))
|
||||
}
|
||||
|
||||
@(private)
|
||||
@(private="file")
|
||||
fe_str :: proc(fe: ^field.Tight_Field_Element) -> string {
|
||||
b: [32]byte
|
||||
field.fe_to_bytes(&b, fe)
|
||||
|
||||
486
tests/core/crypto/test_core_crypto_weierstrass.odin
Normal file
486
tests/core/crypto/test_core_crypto_weierstrass.odin
Normal file
@@ -0,0 +1,486 @@
|
||||
package test_core_crypto
|
||||
|
||||
import ec "core:crypto/_weierstrass"
|
||||
import "core:encoding/hex"
|
||||
import "core:math/big"
|
||||
import "core:testing"
|
||||
|
||||
@(private="file")
|
||||
P256_G_X :: "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"
|
||||
@(private="file")
|
||||
P256_G_Y :: "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"
|
||||
|
||||
@(private="file")
|
||||
P256_G_UNCOMPRESSED :: "04" + P256_G_X + P256_G_Y
|
||||
|
||||
@(test)
|
||||
test_p256_a :: proc(t: ^testing.T) {
|
||||
a_str := "ffffffff00000001000000000000000000000000fffffffffffffffffffffffc"
|
||||
|
||||
fe, a_fe: ec.Field_Element_p256r1
|
||||
ec.fe_a(&fe)
|
||||
ec.fe_a(&a_fe)
|
||||
|
||||
b: [32]byte
|
||||
ec.fe_bytes(b[:], &fe)
|
||||
|
||||
s := (string)(hex.encode(b[:], context.temp_allocator))
|
||||
|
||||
testing.expect(t, s == a_str)
|
||||
|
||||
ec.fe_zero(&fe)
|
||||
ec.fe_set_bytes(&fe, b[:])
|
||||
|
||||
testing.expect(t, ec.fe_equal(&fe, &a_fe) == 1)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_p256_b :: proc(t: ^testing.T) {
|
||||
b_str := "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"
|
||||
|
||||
fe, b_fe: ec.Field_Element_p256r1
|
||||
ec.fe_b(&fe)
|
||||
ec.fe_b(&b_fe)
|
||||
|
||||
b: [32]byte
|
||||
ec.fe_bytes(b[:], &fe)
|
||||
|
||||
s := (string)(hex.encode(b[:], context.temp_allocator))
|
||||
|
||||
testing.expect(t, s == b_str)
|
||||
|
||||
ec.fe_zero(&fe)
|
||||
ec.fe_set_bytes(&fe, b[:])
|
||||
|
||||
testing.expect(t, ec.fe_equal(&fe, &b_fe) == 1)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_p256_g_x :: proc(t: ^testing.T) {
|
||||
fe, x_fe: ec.Field_Element_p256r1
|
||||
ec.fe_gen_x(&fe)
|
||||
ec.fe_gen_x(&x_fe)
|
||||
|
||||
b: [32]byte
|
||||
ec.fe_bytes(b[:], &fe)
|
||||
|
||||
s := (string)(hex.encode(b[:], context.temp_allocator))
|
||||
testing.expect(t, s == P256_G_X)
|
||||
|
||||
ec.fe_zero(&fe)
|
||||
ec.fe_set_bytes(&fe, b[:])
|
||||
|
||||
testing.expect(t, ec.fe_equal(&fe, &x_fe) == 1)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_p256_g_y :: proc(t: ^testing.T) {
|
||||
fe, y_fe: ec.Field_Element_p256r1
|
||||
ec.fe_gen_y(&fe)
|
||||
ec.fe_gen_y(&y_fe)
|
||||
|
||||
b: [32]byte
|
||||
ec.fe_bytes(b[:], &fe)
|
||||
|
||||
s := (string)(hex.encode(b[:], context.temp_allocator))
|
||||
testing.expect(t, s == P256_G_Y)
|
||||
|
||||
ec.fe_zero(&fe)
|
||||
ec.fe_set_bytes(&fe, b[:])
|
||||
|
||||
testing.expect(t, ec.fe_equal(&fe, &y_fe) == 1)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_p256_scalar_reduce :: proc(t: ^testing.T) {
|
||||
test_vectors := []struct {
|
||||
raw: string,
|
||||
reduced: string,
|
||||
} {
|
||||
// n
|
||||
{
|
||||
"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
},
|
||||
// n + 1
|
||||
{
|
||||
"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552",
|
||||
"0000000000000000000000000000000000000000000000000000000000000001",
|
||||
},
|
||||
// 2^384 (Sage)
|
||||
{
|
||||
"01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"431905529c0166ce652e96b7ccca0a99679b73e19ad16947f01cf013fc632551",
|
||||
},
|
||||
// SHA384 odin-linux-amd64-dev-2026-01.tar.gz (Sage)
|
||||
{
|
||||
"87622f79b4b0e76001f9c99b0337b61a0bcd2b5a8e9a3937176825ad75ef0fe8742a348a251dd2682d711f76b33df3e6",
|
||||
"f66db86e28d903033d1e17d818c0eb13fe3d1ae095b4d2ecbcd1a1eccf9f2f8c",
|
||||
},
|
||||
// SHA512 odin-linux-amd64-dev-2026-01.tar.gz (Sage)
|
||||
{
|
||||
"6f85507cec3a35fdb3d4f40d23583681144561e77bc4ea88ab0ea219d5c17b7c9178f5f5a6296a2d18eddd4bdf19e61830fc85d7de23fd4fbde31c4cf6694719",
|
||||
"3217ecbee32c8b0dfcca0f10a884fe43658fbe91458f25d0f1bf2075759c5ebe",
|
||||
},
|
||||
}
|
||||
|
||||
for v, _ in test_vectors {
|
||||
raw_bytes, _ := hex.decode(transmute([]byte)(v.raw), context.temp_allocator)
|
||||
|
||||
sc: ec.Scalar_p256r1
|
||||
_ = ec.sc_set_bytes(&sc, raw_bytes)
|
||||
|
||||
b: [ec.SC_SIZE_P256R1]byte
|
||||
ec.sc_bytes(b[:], &sc)
|
||||
s := (string)(hex.encode(b[:], context.temp_allocator))
|
||||
|
||||
testing.expectf(t, v.reduced == s, "sc: raw %s reduced: %s, expected: %s", v.raw, s, v.reduced)
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_p256_scalar_mul :: proc(t: ^testing.T) {
|
||||
test_vectors := []struct {
|
||||
scalar: string, // NOTE: Base 10
|
||||
x, y: string,
|
||||
} {
|
||||
// Test vectors from http://point-at-infinity.org/ecc/nisttv
|
||||
{
|
||||
"1",
|
||||
"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
|
||||
"4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
|
||||
|
||||
},
|
||||
{
|
||||
"2",
|
||||
"7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC47669978",
|
||||
"07775510DB8ED040293D9AC69F7430DBBA7DADE63CE982299E04B79D227873D1",
|
||||
},
|
||||
{
|
||||
"3",
|
||||
"5ECBE4D1A6330A44C8F7EF951D4BF165E6C6B721EFADA985FB41661BC6E7FD6C",
|
||||
"8734640C4998FF7E374B06CE1A64A2ECD82AB036384FB83D9A79B127A27D5032",
|
||||
},
|
||||
{
|
||||
"4",
|
||||
"E2534A3532D08FBBA02DDE659EE62BD0031FE2DB785596EF509302446B030852",
|
||||
"E0F1575A4C633CC719DFEE5FDA862D764EFC96C3F30EE0055C42C23F184ED8C6",
|
||||
},
|
||||
{
|
||||
"5",
|
||||
"51590B7A515140D2D784C85608668FDFEF8C82FD1F5BE52421554A0DC3D033ED",
|
||||
"E0C17DA8904A727D8AE1BF36BF8A79260D012F00D4D80888D1D0BB44FDA16DA4",
|
||||
},
|
||||
{
|
||||
"6",
|
||||
"B01A172A76A4602C92D3242CB897DDE3024C740DEBB215B4C6B0AAE93C2291A9",
|
||||
"E85C10743237DAD56FEC0E2DFBA703791C00F7701C7E16BDFD7C48538FC77FE2",
|
||||
},
|
||||
{
|
||||
"7",
|
||||
"8E533B6FA0BF7B4625BB30667C01FB607EF9F8B8A80FEF5B300628703187B2A3",
|
||||
"73EB1DBDE03318366D069F83A6F5900053C73633CB041B21C55E1A86C1F400B4",
|
||||
},
|
||||
{
|
||||
"8",
|
||||
"62D9779DBEE9B0534042742D3AB54CADC1D238980FCE97DBB4DD9DC1DB6FB393",
|
||||
"AD5ACCBD91E9D8244FF15D771167CEE0A2ED51F6BBE76A78DA540A6A0F09957E",
|
||||
},
|
||||
{
|
||||
"9",
|
||||
"EA68D7B6FEDF0B71878938D51D71F8729E0ACB8C2C6DF8B3D79E8A4B90949EE0",
|
||||
"2A2744C972C9FCE787014A964A8EA0C84D714FEAA4DE823FE85A224A4DD048FA",
|
||||
},
|
||||
{
|
||||
"10",
|
||||
"CEF66D6B2A3A993E591214D1EA223FB545CA6C471C48306E4C36069404C5723F",
|
||||
"878662A229AAAE906E123CDD9D3B4C10590DED29FE751EEECA34BBAA44AF0773",
|
||||
},
|
||||
{
|
||||
"11",
|
||||
"3ED113B7883B4C590638379DB0C21CDA16742ED0255048BF433391D374BC21D1",
|
||||
"9099209ACCC4C8A224C843AFA4F4C68A090D04DA5E9889DAE2F8EEFCE82A3740",
|
||||
},
|
||||
{
|
||||
"12",
|
||||
"741DD5BDA817D95E4626537320E5D55179983028B2F82C99D500C5EE8624E3C4",
|
||||
"0770B46A9C385FDC567383554887B1548EEB912C35BA5CA71995FF22CD4481D3",
|
||||
},
|
||||
{
|
||||
"13",
|
||||
"177C837AE0AC495A61805DF2D85EE2FC792E284B65EAD58A98E15D9D46072C01",
|
||||
"63BB58CD4EBEA558A24091ADB40F4E7226EE14C3A1FB4DF39C43BBE2EFC7BFD8",
|
||||
},
|
||||
{
|
||||
"14",
|
||||
"54E77A001C3862B97A76647F4336DF3CF126ACBE7A069C5E5709277324D2920B",
|
||||
"F599F1BB29F4317542121F8C05A2E7C37171EA77735090081BA7C82F60D0B375",
|
||||
},
|
||||
{
|
||||
"15",
|
||||
"F0454DC6971ABAE7ADFB378999888265AE03AF92DE3A0EF163668C63E59B9D5F",
|
||||
"B5B93EE3592E2D1F4E6594E51F9643E62A3B21CE75B5FA3F47E59CDE0D034F36",
|
||||
},
|
||||
{
|
||||
"16",
|
||||
"76A94D138A6B41858B821C629836315FCD28392EFF6CA038A5EB4787E1277C6E",
|
||||
"A985FE61341F260E6CB0A1B5E11E87208599A0040FC78BAA0E9DDD724B8C5110",
|
||||
},
|
||||
{
|
||||
"17",
|
||||
"47776904C0F1CC3A9C0984B66F75301A5FA68678F0D64AF8BA1ABCE34738A73E",
|
||||
"AA005EE6B5B957286231856577648E8381B2804428D5733F32F787FF71F1FCDC",
|
||||
},
|
||||
{
|
||||
"18",
|
||||
"1057E0AB5780F470DEFC9378D1C7C87437BB4C6F9EA55C63D936266DBD781FDA",
|
||||
"F6F1645A15CBE5DC9FA9B7DFD96EE5A7DCC11B5C5EF4F1F78D83B3393C6A45A2",
|
||||
},
|
||||
{
|
||||
"19",
|
||||
"CB6D2861102C0C25CE39B7C17108C507782C452257884895C1FC7B74AB03ED83",
|
||||
"58D7614B24D9EF515C35E7100D6D6CE4A496716E30FA3E03E39150752BCECDAA",
|
||||
},
|
||||
{
|
||||
"20",
|
||||
"83A01A9378395BAB9BCD6A0AD03CC56D56E6B19250465A94A234DC4C6B28DA9A",
|
||||
"76E49B6DE2F73234AE6A5EB9D612B75C9F2202BB6923F54FF8240AAA86F640B8",
|
||||
},
|
||||
{
|
||||
"112233445566778899",
|
||||
"339150844EC15234807FE862A86BE77977DBFB3AE3D96F4C22795513AEAAB82F",
|
||||
"B1C14DDFDC8EC1B2583F51E85A5EB3A155840F2034730E9B5ADA38B674336A21",
|
||||
},
|
||||
{
|
||||
"112233445566778899112233445566778899",
|
||||
"1B7E046A076CC25E6D7FA5003F6729F665CC3241B5ADAB12B498CD32F2803264",
|
||||
"BFEA79BE2B666B073DB69A2A241ADAB0738FE9D2DD28B5604EB8C8CF097C457B",
|
||||
},
|
||||
{
|
||||
"029852220098221261079183923314599206100666902414330245206392788703677545185283",
|
||||
"9EACE8F4B071E677C5350B02F2BB2B384AAE89D58AA72CA97A170572E0FB222F",
|
||||
"1BBDAEC2430B09B93F7CB08678636CE12EAAFD58390699B5FD2F6E1188FC2A78",
|
||||
},
|
||||
{
|
||||
"057896042899961394862005778464643882389978449576758748073725983489954366354431",
|
||||
"878F22CC6DB6048D2B767268F22FFAD8E56AB8E2DC615F7BD89F1E350500DD8D",
|
||||
"714A5D7BB901C9C5853400D12341A892EF45D87FC553786756C4F0C9391D763E",
|
||||
},
|
||||
{
|
||||
"57896042899961394862005778464643882389978449576758748073725983489954366354431",
|
||||
"878F22CC6DB6048D2B767268F22FFAD8E56AB8E2DC615F7BD89F1E350500DD8D",
|
||||
"714A5D7BB901C9C5853400D12341A892EF45D87FC553786756C4F0C9391D763E",
|
||||
},
|
||||
{
|
||||
"1766845392945710151501889105729049882997660004824848915955419660366636031",
|
||||
"659A379625AB122F2512B8DADA02C6348D53B54452DFF67AC7ACE4E8856295CA",
|
||||
"49D81AB97B648464D0B4A288BD7818FAB41A16426E943527C4FED8736C53D0F6",
|
||||
},
|
||||
{
|
||||
"28948025760307534517734791687894775804466072615242963443097661355606862201087",
|
||||
"CBCEAAA8A4DD44BBCE58E8DB7740A5510EC2CB7EA8DA8D8F036B3FB04CDA4DE4",
|
||||
"4BD7AA301A80D7F59FD983FEDBE59BB7B2863FE46494935E3745B360E32332FA",
|
||||
},
|
||||
{
|
||||
"113078210460870548944811695960290644973229224625838436424477095834645696384",
|
||||
"F0C4A0576154FF3A33A3460D42EAED806E854DFA37125221D37935124BA462A4",
|
||||
"5B392FA964434D29EEC6C9DBC261CF116796864AA2FAADB984A2DF38D1AEF7A3",
|
||||
},
|
||||
{
|
||||
"12078056106883488161242983286051341125085761470677906721917479268909056",
|
||||
"5E6C8524B6369530B12C62D31EC53E0288173BD662BDF680B53A41ECBCAD00CC",
|
||||
"447FE742C2BFEF4D0DB14B5B83A2682309B5618E0064A94804E9282179FE089F",
|
||||
},
|
||||
{
|
||||
"57782969857385448082319957860328652998540760998293976083718804450708503920639",
|
||||
"03792E541BC209076A3D7920A915021ECD396A6EB5C3960024BE5575F3223484",
|
||||
"FC774AE092403101563B712F68170312304F20C80B40C06282063DB25F268DE4",
|
||||
},
|
||||
{
|
||||
"57896017119460046759583662757090100341435943767777707906455551163257755533312",
|
||||
"2379FF85AB693CDF901D6CE6F2473F39C04A2FE3DCD842CE7AAB0E002095BCF8",
|
||||
"F8B476530A634589D5129E46F322B02FBC610A703D80875EE70D7CE1877436A1",
|
||||
},
|
||||
{
|
||||
"452312848374287284681282171017647412726433684238464212999305864837160993279",
|
||||
"C1E4072C529BF2F44DA769EFC934472848003B3AF2C0F5AA8F8DDBD53E12ED7C",
|
||||
"39A6EE77812BB37E8079CD01ED649D3830FCA46F718C1D3993E4A591824ABCDB",
|
||||
},
|
||||
{
|
||||
"904571339174065134293634407946054000774746055866917729876676367558469746684",
|
||||
"34DFBC09404C21E250A9B40FA8772897AC63A094877DB65862B61BD1507B34F3",
|
||||
"CF6F8A876C6F99CEAEC87148F18C7E1E0DA6E165FFC8ED82ABB65955215F77D3",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044349",
|
||||
"83A01A9378395BAB9BCD6A0AD03CC56D56E6B19250465A94A234DC4C6B28DA9A",
|
||||
"891B64911D08CDCC5195A14629ED48A360DDFD4596DC0AB007DBF5557909BF47",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044350",
|
||||
"CB6D2861102C0C25CE39B7C17108C507782C452257884895C1FC7B74AB03ED83",
|
||||
"A7289EB3DB2610AFA3CA18EFF292931B5B698E92CF05C1FC1C6EAF8AD4313255",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044351",
|
||||
"1057E0AB5780F470DEFC9378D1C7C87437BB4C6F9EA55C63D936266DBD781FDA",
|
||||
"090E9BA4EA341A246056482026911A58233EE4A4A10B0E08727C4CC6C395BA5D",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044352",
|
||||
"47776904C0F1CC3A9C0984B66F75301A5FA68678F0D64AF8BA1ABCE34738A73E",
|
||||
"55FFA1184A46A8D89DCE7A9A889B717C7E4D7FBCD72A8CC0CD0878008E0E0323",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044353",
|
||||
"76A94D138A6B41858B821C629836315FCD28392EFF6CA038A5EB4787E1277C6E",
|
||||
"567A019DCBE0D9F2934F5E4A1EE178DF7A665FFCF0387455F162228DB473AEEF",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044354",
|
||||
"F0454DC6971ABAE7ADFB378999888265AE03AF92DE3A0EF163668C63E59B9D5F",
|
||||
"4A46C11BA6D1D2E1B19A6B1AE069BC19D5C4DE328A4A05C0B81A6321F2FCB0C9",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044355",
|
||||
"54E77A001C3862B97A76647F4336DF3CF126ACBE7A069C5E5709277324D2920B",
|
||||
"0A660E43D60BCE8BBDEDE073FA5D183C8E8E15898CAF6FF7E45837D09F2F4C8A",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044356",
|
||||
"177C837AE0AC495A61805DF2D85EE2FC792E284B65EAD58A98E15D9D46072C01",
|
||||
"9C44A731B1415AA85DBF6E524BF0B18DD911EB3D5E04B20C63BC441D10384027",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044357",
|
||||
"741DD5BDA817D95E4626537320E5D55179983028B2F82C99D500C5EE8624E3C4",
|
||||
"F88F4B9463C7A024A98C7CAAB7784EAB71146ED4CA45A358E66A00DD32BB7E2C",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044358",
|
||||
"3ED113B7883B4C590638379DB0C21CDA16742ED0255048BF433391D374BC21D1",
|
||||
"6F66DF64333B375EDB37BC505B0B3975F6F2FB26A16776251D07110317D5C8BF",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044359",
|
||||
"CEF66D6B2A3A993E591214D1EA223FB545CA6C471C48306E4C36069404C5723F",
|
||||
"78799D5CD655517091EDC32262C4B3EFA6F212D7018AE11135CB4455BB50F88C",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044360",
|
||||
"EA68D7B6FEDF0B71878938D51D71F8729E0ACB8C2C6DF8B3D79E8A4B90949EE0",
|
||||
"D5D8BB358D36031978FEB569B5715F37B28EB0165B217DC017A5DDB5B22FB705",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044361",
|
||||
"62D9779DBEE9B0534042742D3AB54CADC1D238980FCE97DBB4DD9DC1DB6FB393",
|
||||
"52A533416E1627DCB00EA288EE98311F5D12AE0A4418958725ABF595F0F66A81",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044362",
|
||||
"8E533B6FA0BF7B4625BB30667C01FB607EF9F8B8A80FEF5B300628703187B2A3",
|
||||
"8C14E2411FCCE7CA92F9607C590A6FFFAC38C9CD34FBE4DE3AA1E5793E0BFF4B",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044363",
|
||||
"B01A172A76A4602C92D3242CB897DDE3024C740DEBB215B4C6B0AAE93C2291A9",
|
||||
"17A3EF8ACDC8252B9013F1D20458FC86E3FF0890E381E9420283B7AC7038801D",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044364",
|
||||
"51590B7A515140D2D784C85608668FDFEF8C82FD1F5BE52421554A0DC3D033ED",
|
||||
"1F3E82566FB58D83751E40C9407586D9F2FED1002B27F7772E2F44BB025E925B",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044365",
|
||||
"E2534A3532D08FBBA02DDE659EE62BD0031FE2DB785596EF509302446B030852",
|
||||
"1F0EA8A4B39CC339E62011A02579D289B103693D0CF11FFAA3BD3DC0E7B12739",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044366",
|
||||
"5ECBE4D1A6330A44C8F7EF951D4BF165E6C6B721EFADA985FB41661BC6E7FD6C",
|
||||
"78CB9BF2B6670082C8B4F931E59B5D1327D54FCAC7B047C265864ED85D82AFCD",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044367",
|
||||
"7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC47669978",
|
||||
"F888AAEE24712FC0D6C26539608BCF244582521AC3167DD661FB4862DD878C2E",
|
||||
},
|
||||
{
|
||||
"115792089210356248762697446949407573529996955224135760342422259061068512044368",
|
||||
"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
|
||||
"B01CBD1C01E58065711814B583F061E9D431CCA994CEA1313449BF97C840AE0A",
|
||||
},
|
||||
}
|
||||
|
||||
for v, _ in test_vectors {
|
||||
x_bytes, _ := hex.decode(transmute([]byte)(v.x), context.temp_allocator)
|
||||
y_bytes, _ := hex.decode(transmute([]byte)(v.y), context.temp_allocator)
|
||||
|
||||
k_big: big.Int
|
||||
err := big.set(&k_big, v.scalar, 10, context.temp_allocator)
|
||||
testing.expectf(t, err == nil, "failed to parse k", err)
|
||||
|
||||
k_sz: int
|
||||
k_sz, err = big.int_to_bytes_size(&k_big, allocator = context.temp_allocator)
|
||||
testing.expect(t, err == nil)
|
||||
|
||||
k_bytes := make([]byte, k_sz, context.temp_allocator)
|
||||
err = big.int_to_bytes_big(&k_big, k_bytes, allocator = context.temp_allocator)
|
||||
|
||||
p, q, expected, g: ec.Point_p256r1
|
||||
sc: ec.Scalar_p256r1
|
||||
|
||||
_ = ec.sc_set_bytes(&sc, k_bytes)
|
||||
|
||||
ec.pt_generator(&g)
|
||||
ok := ec.pt_set_xy_bytes(&expected, x_bytes, y_bytes)
|
||||
testing.expectf(t, ok, "failed to set point; %s, %s", v.x, v.y)
|
||||
|
||||
ec.pt_scalar_mul(&p, &g, &sc)
|
||||
ec.pt_scalar_mul_generator(&q, &sc)
|
||||
ec.pt_rescale(&p, &p)
|
||||
ec.pt_rescale(&q, &q)
|
||||
|
||||
testing.expect(t, ec.pt_equal(&p, &q) == 1)
|
||||
testing.expectf(t, ec.pt_equal(&p, &expected) == 1, "sc: %s actual: %v expected: %v", v.scalar, &p, &expected)
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_p256_s11n_sec_identity ::proc(t: ^testing.T) {
|
||||
p: ec.Point_p256r1
|
||||
|
||||
ec.pt_generator(&p)
|
||||
ok := ec.pt_set_sec_bytes(&p, []byte{0x00})
|
||||
testing.expect(t, ok)
|
||||
testing.expectf(t, ec.pt_is_identity(&p) == 1, "%v", p)
|
||||
|
||||
b := []byte{0xff}
|
||||
ok = ec.pt_sec_bytes(b, &p, true)
|
||||
testing.expect(t, ok)
|
||||
testing.expect(t, b[0] == 0x00)
|
||||
|
||||
b = []byte{0xff}
|
||||
ok = ec.pt_sec_bytes(b, &p, false)
|
||||
testing.expect(t, ok)
|
||||
testing.expect(t, b[0] == 0x00)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_p256_s11n_sec_generator ::proc(t: ^testing.T) {
|
||||
p, g: ec.Point_p256r1
|
||||
|
||||
ec.pt_generator(&g)
|
||||
ec.pt_identity(&p)
|
||||
|
||||
b: [65]byte
|
||||
ok := ec.pt_sec_bytes(b[:], &g, false)
|
||||
testing.expect(t, ok)
|
||||
s := (string)(hex.encode(b[:], context.temp_allocator))
|
||||
testing.expectf(t, s == P256_G_UNCOMPRESSED, "g: %v bytes: %v, %v", g, P256_G_UNCOMPRESSED, s)
|
||||
|
||||
ok = ec.pt_set_sec_bytes(&p, b[:])
|
||||
testing.expectf(t, ok, "%s", s)
|
||||
testing.expect(t, ec.pt_equal(&g, &p) == 1)
|
||||
}
|
||||
2
vendor/x11/xlib/xlib_keysym.odin
vendored
2
vendor/x11/xlib/xlib_keysym.odin
vendored
@@ -1,7 +1,7 @@
|
||||
#+build linux, freebsd, openbsd
|
||||
package xlib
|
||||
|
||||
KeySym :: enum u32 {
|
||||
KeySym :: enum uint {
|
||||
XK_BackSpace = 0xff08, /* Back space, back char */
|
||||
XK_Tab = 0xff09,
|
||||
XK_Linefeed = 0xff0a, /* Linefeed, LF */
|
||||
|
||||
2
vendor/x11/xlib/xlib_procs.odin
vendored
2
vendor/x11/xlib/xlib_procs.odin
vendored
@@ -2068,7 +2068,7 @@ foreign xlib {
|
||||
Xutf8LookupString :: proc(
|
||||
ic: XIC,
|
||||
event: ^XKeyPressedEvent,
|
||||
buffer_return: ^cstring,
|
||||
buffer_return: cstring,
|
||||
bytes_buffer: i32,
|
||||
keysym_return: ^KeySym,
|
||||
status_return: ^LookupStringStatus,
|
||||
|
||||
Reference in New Issue
Block a user