►
Description
Using empty asm!() directives and empty functions, this talk will show how we can circumvent LLVM's optimizations, and make our binaries secure again. However, these tricks are ugly and unsupported on the stable channel. We need something bigger to solve this issue. We need secret types.
More at https://rustfest.global/session/8-rfc-secret-types-in-rust/
B
Hello,
everybody
I'm
dan
spankles
and
I'm
with
here
with
diane
hosfelt,
and
we
will
be
talking
about
secret
types
in
rust.
So
the
main
gist
of
this
talk
will
be
that
there
that,
like
some
of
you,
may
know
that
cryptographic
engineers
tend
to
like
write
a
lot
of
their
code
in
assembly,
and
there
is
a
good
reason
for
that,
and
I
will
explain
why
that
is.
But
as
a
cryptographic
engineer
or
an
aspiring
cryptographic
engineer,
I'd
like
to
write
my
code
in
rust.
B
B
While
this
talk
is
pre-recorded.
Both
diane
and
me
are
here
in
the
at
the
conference
and
in
the
chat
so
feel
free
to
ask
any
questions
either
at
the
end
of
the
talk
or
just
put
them
in
the
chat
during
the
talk,
and
we
will
take
care
of
them.
C
B
Okay,
so
I
will
explain
a
couple
of
things
and
then
diane
will
take
over
first
we'll
talk
about
how
timing
side
channels
work,
what
what
are
timing
side
channels?
Why
are
they
dangerous
and
then
we'll
talk
about
how
rust
is
not
suitable
to
write
code?
That
is
actually
that
actually
prevents
these
timing
channels.
C
C
These
attacks
are
a
particular
threat
in
the
post
spectre.
World
they're
primarily
used
to
attack
secrets
that
are
long
lived
that
are
extremely
valuable
if
compromised,
where
each
bit
compromised
provides
incremental
value
and
where
the
confidentiality
of
compromise
is
desirable,
the
fix
is
constant
time
code
or
to
be
more
precise
data
invariant
code,
where
the
time
it
takes
to
execute
the
code
doesn't
depend
on
the
input.
B
Let
me
explain
to
you
why
at
this
point,
it's
really
hard
for
us
to
to
guarantee
that
the
compiler
is
constant
time.
So
this
is,
this
story
will
be
true
for
basically
any
programming
language
that
is
compiled.
There
are
some
exceptions,
but
we're
at
the
rest
conference.
So,
let's,
let's
focus
on
rust.
B
So
the
main
problem
here
is
that
compilers
are,
in
some
sense
problematic,
so
compilers
are
allowed
to
optimize
anything
that
they
feel
does
not
change
the
program
and
the
the
the
behavior
like
or
the
run
time
of
a
program
and
stuff
like
that
is
not
it's
not
considered
to
change
the
program
in
the
view
of
a
compiler,
so
so
the
compiler
might
actually
optimize
stuff
that
we
don't
think
would
be,
would
should
be
possible,
and
so,
for
example,
there
is
there
is
this
thing
that
lvm
could
do,
which
is
eliminating
conditional
moves
that
may
load,
and
let
me
show
you
an
example
of
this.
B
Okay,
so
what
you
see
here
on
the
left
is,
I
have
written
this
nice
little
c-mop
function
and
what
this
c-mo
malfunction
is
meant
to
do.
Is
it
should
so?
If
this
conditional
value
is
true,
what
it
should
do
is
it
should
move
the
value
in
b
into
a,
and
if
this
conditional
value
is
false,
then
then
a
should
just
remain.
The
same.
Value
and
b
should
just
be
dropped
and
thrown
away,
but
the
important
thing
here
is
that
that
conditional
value
is
secret.
B
We
don't
want
to
leak
any
information
about
this
secret
value,
so
the
runtime
of
this
function
should
be
always
the
same
time.
The
same
length,
the
same
duration
like
depending
on
the
value
of
this
conditional
value.
So
what
we
do
first,
is
we
generate
a
mask
from
this
conditional
value,
and
the
value
that
will
come
out
of
this
mask
will
be
something
like
either
only
only
once
or
if
the
conditional
value
is
true.
Sorry,
if
the
conditional
value
was
false,
it
will
be
a
mask
of
only
zeros.
B
B
B
This
behavior
of
this
function
completely
depends
on
this
conditional
value.
So,
first,
what
it
does
is
it
checks.
Is
this
conditional
value?
Is
it
actually
zero?
So
is
it
false?
And
if
it's,
if
it
sees
that
this
conditional
value
is
true,
it
jumps
to
this
instruction.
So
it
skips
this
complete
instruction,
and
if
this
this,
this
conditional
value
was
false,
then
it
just
does
this
instruction
then
moves
the
under
instruction
and
that's
it.
So,
basically,
in
one
of
the
two
cases,
it
skipped
this
instruction
and.
B
The
important
thing
to
see
here
is
that,
depending
on
this
value,
depending
on
the
value
of
the
conditional,
the
runtime
of
the
algorithm
changes-
and
so
here
we
have
a
case
where
the
compiler
introduced
a
side
channel
which
could
be
a
side
channel
vulnerability.
B
And
the
the
interesting
thing
is
that
if
we,
if
we
only
look
at
the
source
code
in
rust,
it
looks
like
something
that,
like
it
looks
like
code
that
that
that
feels
completely
like
this
could
should
be
implemented.
In
constant
time
like
we
have
this,
this
bitwise
and
operation
this
bit
wide
end
and
operation,
and
then
these
claw
operations-
and
you
don't
even
see
them
in
the
in
the
new
implement
in
the
compiled
code,
because
lvm
is
smart
enough
to
see
that
they
are
not
needed,
and
this
is
actually
a
pretty
big
danger
for
us.
C
Obviously
we're
at
rust
fest,
so
we've
all
bought
into
rust,
but
the
question
remains:
if
we
can
do
secret
invariant
programming
with
assembly,
why
do
we
need
to
do
it
in
rest?
At
all?
Writing
cryptographic
and
other
security.
Critical
code
in
high-level
languages
like
rest
is
attractive
for
numerous
reasons:
first,
they're
generally
more
readable
and
accessible
to
developers
and
reviewers,
leading
to
higher
quality
more
secure
code.
C
B
So
then,
why
do
we
focus
on
rust?
Why
don't
we
just
like?
If
we
cannot
write
secure
code?
Why
do
we
want
to
use
rust
in
the
first
place?
And
that's
that's?
Well.
Obviously,
everybody
here
has
their
idea
of
why
they
reuse
rust
and
in
our
case
it's
kind
of
the
same.
So
we
want
to
use
rust.
The
reason
that
we
want
that
we
want
to
use
rust
is
because
we
have
all
these
types
and
all
these
nice
nice
checks
in
the
compiler
that
allow
us
to
make
our
code.
B
That's
that's
easier
to
write,
secure
code
and
we
want
to
utilize
these
checks
and
these
tools
as
much
as
possible,
because
writing
just
plain
assembly
is
really
hard
and
super
error
prone
and
then
there's
the
other
thing
that
if
we
only
write
assembly
well,
then
you
have
written
an
assembly
for
an
intel
processor.
B
When
you
run
want
to
run
the
same
code
on
an
arm
processor,
you
you
have
to
rewrite
the
whole
code
and
we
don't.
We
don't
want
to
do
that,
because
it
also
allows
you
to
make
more
mistakes
and
we
want
our
crypto
code
to
be
really
secure.
B
So
we
would
like
to
use
a
high-level
language
if
that
is
at
all
possible,
so
it's
not
at
all
bad,
so
there
is
some
way
how
rust
can
be
in
a
way
side,
channel
resistant,
and
this
this,
like
a
couple
of
these
these
so
so
in
rust,
we
can
like
make
these
new
type
style
wrappers
around
integer,
so
a
struct
that
only
has
some
integer
type
and
implement
some
operations
on
that
that
are
presumably
in
constant
time
and
there's
two
main
examples
in
the
world
in
the
wild.
B
B
This
is
probably
what
you
should
use
and
we
don't
have
anything
better
at
the
moment
and
the
other.
The
other
example
that
I'd
like
to
mention
is
the
secret
integers
great.
The
secret
engine
just
creates
a
bit
more
academic
of
nature
and
what
it
does
it
looks
at
like
what
if
we
would
replace
all
of
the
integer
types
with
some
kind
of
constant
time,
integer
type
would
that
work
and
and
and
and
what
the
secret
interest
create.
B
The
solo
crate
does
that,
and
that
is
why
I
recommend
that
great,
but
both
of
those
crates.
They
are
only
a
best
effort,
their
only
only
best
effort,
and
they
don't
guarantee
all
of
the
all
of
the
like.
They
don't
fix.
All
of
the
compiler
optimization
issues.
B
B
So
it
turns
out
that
the
problem
here
is
that
lvm
seems
to
be
able
to
to
completely
eliminate
this
mask
variable.
So
this
mask
variable
is
secret
because
the
because
it
it
directly
depends
on
this
conditional
value
which,
which
we
said
was
secret
and
then
because,
because
lvm
can
just
analyze
through
this
mask
variable,
it
can
do
this
really
nice
optimization
of
adding
a
branch
and
then
just
just
eliminating
all
these
bitwise
operations.
B
B
So
what
we
do
here
is
we
we
construct
an
assembly
directive
which
takes
this
mask
value
as
an
input
and
always
also
takes
this
mask
value
as
an
output,
and
then
lvm
is
not
not
able
to
reason
about
what
happens
inside
of
that
assembly
directive
like
we
know
that
nothing
happens
inside
assembly
directive,
but
lvm
cannot
reason
about
that
and
because
it
can't
the
it
will
actually
keep
this
mask
value
completely
intact
and
it
will
not
be
able
to
optimize
through
that
variable
and
at
the
other
trick.
B
So
so
so
the
assembly
directive
doesn't
work
on
stable
rust,
because
it's
because
for
the
assembly
directive,
you
need
to
have
a
nightly
rust
version
to
compile.
So
that's
not
really
optimal,
and
so
the
other
trick
that
we
can
use
is
to
to
do
a
volatile
read
of
secret
data,
and
what
this
does.
B
Is
it
guarantees
that,
at
some
point,
this
mask
value
would
have
existed
on
the
stack
and
because
of
that,
lvm
is
also
not
able
to
optimize
through
this
this,
this
volatile
read
both
tricks
kind
of
work
in
90
of
the
cases
they
don't.
They
don't
not
have
like
a
hundred
percent
success
rate
for
all
for
all
for
our
cases.
B
I
won't
go
into
why
that
is
at
this
moment,
but
but
it's
important
to
know
that
they
don't
always
work.
They
are
best
effort
tricks
and
the
most
important
part
is
that,
although
these
tricks
might
work
at
the
moment,
they
are
not
guarantees
and
the
compiler
might
change
in
the
future.
B
So
perhaps
in
five
years
the
compiler
is
actually
able
to
look
into
this
assembly
directive
and
see
that
nothing
happens
and
it
might
eliminate
that
assembly
directive
completely
and
we
don't
know
we
don't
have
any
guarantee
that
this
kind
of
stuff
won't
happen
in
the
future.
So
it
might
be
that
in
in
a
couple
of
years
a
completely
secure
version
of
some
software
now
might
actually
be
insecure
with
a
new
compiler
version,
which
I
find
very
scary.
C
It
turns
out
that
the
general
purpose
instructions
on
various
platforms
take
a
variable
number
of
cycles,
so
for
us
to
truly
have
secret
independent
run
times,
we
need
to
completely
eliminate
the
problematic
instructions.
This
can't
be
done
at
a
language
level.
Only
at
a
compiler
level
enter
rfc
number
2859.
C
C
Using
these
integer
types,
we
can
build
more
complex
types.
For
example,
a
secret
key
may
be
an
array
of
secret
u8
bytes.
These
types
keep
us
secure
by
disallowing
any
rust
code
that
would
result
in
insecure
binary
code.
So,
for
example,
we
don't
allow
indexing
based
on
secrets.
We
don't
allow
using
secret
bool
in
an
if
statement.
We
don't
allow
division,
which
is
a
non-constant
time
algorithm.
C
In
this
case,
the
compiler
should
give
us
an
error
because
that's
not
allowed.
Now
there
are
two
parts
to
this
problem.
There
is
an
llvm
part
and
a
rust
part
which
I've
already
described,
there's
been
some
work
in
the
allovm
realm
to
propose
a
similar
rfc
to
this
one
which
we've
worked
together
on
at
hax
2020.,
we're
not
entirely
sure
what
the
status
of
that
work
is
at
the
moment.
But
what
llvm
needs
to
do
is
make
sure
that
our
constant
time
rest
code
is
also
compiled
safely.
C
So
llvm
needs
to
make
sure
to
guarantee
that
what
we
wrote
down
in
the
code
is
still
safe
in
the
emitted
binary.
That
means
no
branching
on
secret,
no
indexing
with
secret
indices
and
no
variable
time
instructions.
At
the
moment.
Zeroing
memory
is
out
of
scope,
but
when
we
have
this
information
about
public
and
secret
values,
then
we've
laid
the
groundwork
to
support
that
as
well.
C
D
All
right,
thank
you.
So
much
don
and
diane
we're
lucky
enough
to
have
you
both
here
for
a
q,
a
all
right,
so
you've
been
joined
by
your
friend
too.
D
Entirely
too
ignored
during
the
day
right
people
looking
at
their
screens
all
day,
how
dare
they
so
we
do
have
a
couple
of
questions
from
the
audience
which
is
great.
The
first
one
we've
got
is
that
this
is
all
very
complex.
D
C
There
are,
there
are
tools
that
you
can
use
formal
verification
tools
that
can
determine
if
on
different
inputs,
there
are
different
runtimes.
So
that's
one
of
the
ways
that
you
can
determine
if
a
program
has
non-secret
independent
runtimes
for
part
of
it,
dan.
B
So
yeah,
so
the
way
we
discover
these
kinds
of
issues
is
like
at
some
point.
Sometimes
I
write
a
piece
of
assembly
and
the
first
thing
I
do
before
I
write.
Some
piece
of
assembly
is
actually
just
program
it
in
c
or
rust,
and
then
see
what
the
compiler
tells
me
to
do.
And
then
then
these
are
the
moments
that
I
that
I
stumble
on
these
hey
wait,
but
if
I
would
do
this,
that
would
this
would
not
be
secure
and
that's
that's
when
I
first
discovered
this
for
myself
so
yeah.
D
Cool,
I
mean
it's
really
cool
that
you
like,
like
you
said
that
you
gave
us
kind
of
an
insight
on
you,
try
and
see
what
the
compiler
tells
you
first
and
that's
how
you
can
discover
it
yeah.
I
guess
just
be
curious
about
what
the
compiler
actually
tells
you
not
just
like
all
right.
D
Someone
is
asked
if
there's
a
working
group
working
on
it
on
a
solution.
I
suppose.
C
D
C
Yeah,
that
would
be
great
because
you
know
one
of
the
things
that
needs
to
happen
is
on
the
on
the
rest
side
and
on
the
all
of
them
side
we're
going
to
have
to
eventually
do
some
implementation
work.
You
know
it's
not
enough
to
just
define
what
has
to
happen.
We
also
have
to
implement
these
instructions
on
the
secret
types.
So
that'll
actually
be
a
lot
of
work.
D
Yeah
so
we
actually
seem
to
have
very
little
time
left,
but
there
was
a
lot
of
a
lot
of
chatter
in
the
chat
room.
So
I
guess
people
can
find
you
in
there
and
we
can
get
a
few
more
questions.
There
were
lots
of
questions
and
we
just
didn't
have
enough
time,
but
thank
you
so
much
for
joining
us.
It
was
really
great
to
to
have
you
here
and
oh
batman.
Let
me
see
if
I
can
get
she's
asleep,
she's
melted
into
a
puddle
say.