core/crypto/_edwards25519: Support crypto.COMPACT_IMPLS

This commit is contained in:
Yawning Angel
2026-01-21 00:43:10 +09:00
parent c35b49bf60
commit f5b7274a77
6 changed files with 5288 additions and 126 deletions

View File

@@ -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
}

View File

@@ -1,130 +1,24 @@
package _edwards25519
import "core:crypto"
import field "core:crypto/_fiat/field_scalar25519"
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,rodata)
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,

View 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)
}
}

File diff suppressed because it is too large Load Diff

View 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)))
}

View File

@@ -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)
}
}