Cleanup and unit tests

This commit is contained in:
Elliot Glaysher 2019-06-21 11:30:12 -07:00
parent 2f8d36c485
commit 6b05abd5ad
3 changed files with 205 additions and 36 deletions

View File

@ -5,17 +5,19 @@
:: +raw is the raw internal ring signature implementation. +raw does not deal
:: with urbit ship identities and is low level.
::
:: This raw interface is vaguely modeled on the haskell aos-signature package,
:: but is written in terms of ed25519 primitives instead of general ECC and
:: changes how linkage tags are computed so that how linkage occurs is a
:: client decision instead of hard coding the set of public keys as the
:: linkage scope.
::
++ raw
|%
:: +oracle: deterministic random response on input
::
++ oracle
|= input=*
:: l:ed is ecc-n
(mod (shaz (jam input)) l:ed:crypto)
::
::::
::
:: +generate-public-linkage: generate public linkage information
::
++ generate-public-linkage
@ -25,8 +27,7 @@
=/ data=@ (oracle link-scope)
=/ h=@udpoint (scalarmult-base:ed:crypto data)
[data h]
:: +generate-linkage: generates linkage information from scope and private key
:: +generate-linkage: linkage information from scope and private key
::
:: data: deterministically picked data point based off scope
:: h: h = [data] * g
@ -44,8 +45,8 @@
:: +generate-challenge: generate challenge from a given message
::
:: When :link-scope is ~ (ie, we're not building a linked ring signature),
:: calculates just the hash of `[message g]`. Otherwise, weaves the linkage
:: state into the challenge.
:: calculates just the hash of `[message g]`. Otherwise, weaves the
:: linkage state into the challenge.
::
++ generate-challenge
|= $: :: common to both linked and unlinked
@ -114,8 +115,8 @@
:: +scalarmult-h: maybe multiply u by h in linkage
::
:: Since linkage tags are optional, we need to be able to just do the math
:: in case :linkage is set and fall through otherwise. +scalarmult-h is used
:: to generate the (unit point) consumed by +generate-challenge.
:: in case :linkage is set and fall through otherwise. +scalarmult-h is
:: used to generate the (unit point) consumed by +generate-challenge.
::
++ scalarmult-h
|= [u=@ linkage=(unit [data=@ h=@udpoint y=@udpoint])]
@ -132,8 +133,6 @@
(scag i l)
:: +sign: creates a ring signature on an ed25519 curve
::
:: Creates an optionally linkable ring signature on
::
++ sign
|= $: message=*
link-scope=(unit *)
@ -236,7 +235,14 @@
signature=raw-ring-signature
==
^- ?
:: TODO: if our signature has a linking y, we must have a link-scope and
:: if there's a linkage scope but no tag, fail
::
?: &(?=(^ link-scope) ?=(~ y.signature))
%.n
:: if there's no linkage scope but a tag, fail
::
?: &(?=(~ link-scope) ?=(^ y.signature))
%.n
:: vice versa.
::
:: decompose the signature into [s0 s1 s2....]
@ -260,7 +266,8 @@
(head anonymity-list)
s0
==
:: generate the linkage using public data, and the y point from the signature
:: generate the linkage using public data, and the y point from the
:: signature
::
=/ linkage=(unit [data=@ h=@udpoint y=@udpoint])
?~ link-scope
@ -299,9 +306,19 @@
::
=(ch0.signature (head challenges))
--
:: +detail: non-public details about figuring out keys
:: +detail: details about getting keys from Azimuth
::
++ detail
|%
:: +seed-to-private-key-scalar: keyfile form to scalar we can multiply with
::
++ seed-to-private-key-scalar
|= sk/@I ^- @udscalar
?: (gth (met 3 sk) 32) !!
=+ h=(shal (rsh 0 3 b:ed:crypto) sk)
%+ add
(bex (sub b:ed:crypto 2))
(lsh 0 3 (cut 0 [3 (sub b:ed:crypto 5)] h))
:: +get-public-key-from-pass: decode the raw @ public key structure
::
++ get-public-key-from-pass
@ -328,8 +345,8 @@
::
=/ d=deed:ames
.^(deed:ames j+/(scot %p our)/deed/(scot %da now)/(scot %p ship)/(scot %ud life))
:: we have the deed which has pass, which is several numbers +cat-ed together;
:: pull out the keys
:: we have the deed which has pass, which is several numbers +cat-ed
:: together; pull out the keys
::
=/ x=[crypt=@ auth=@] (get-public-key-from-pass pass.d)
::
@ -378,17 +395,10 @@
$(invited t.invited)
--
--
|%
:: +qfix is otherwise equivalent to +puck? +puck is jetted. is there a jet divergence?
:: public interface
::
++ seed-to-private-key-scalar
|= sk/@I ^- @udscalar
?: (gth (met 3 sk) 32) !!
=+ h=(shal (rsh 0 3 b:ed:crypto) sk)
=/ x (bex (sub b:ed:crypto 2))
=/ y (lsh 0 3 (cut 0 [3 (sub b:ed:crypto 5)] h))
(add x y)
:: signs a message on the current ship
|%
:: +sign: ring-signs a message using the current ship
::
++ sign
|= $: our=@p
@ -411,14 +421,14 @@
::
=/ our-life=life
.^(life %j /(scot %p our)/life/(scot %da now)/(scot %p our))
:: get our ships' secret key
:: get our ships' secret keyfile ring
::
=/ secret-ring=ring
.^(ring %j /(scot %p our)/vein/(scot %da now)/(scot %ud our-life))
:: fetch the encoded auth seedd from the ring
::
::
=/ secrets=[encrypt=@ auth=@]
(get-private-key-from-ring:detail secret-ring)
=/ secret-auth-seed=@
+:(get-private-key-from-ring:detail secret-ring)
:: get our ships' public key
::
=/ public-key=@udpoint
@ -426,15 +436,23 @@
::
:- participants.p
:- link-scope
(sign:raw message link-scope keys.p public-key (seed-to-private-key-scalar auth.secrets) eny)
:: verifies a message
%- sign:raw :*
message
link-scope
keys.p
public-key
(seed-to-private-key-scalar:detail secret-auth-seed)
eny
==
:: +verify: verifies a message against a ring signature
::
++ verify
|= [our=@p now=@da message=* =ring-signature]
^- ?
::
=/ keys=(set @udpoint)
(build-verifying-participants:detail our now ~(tap in participants.ring-signature))
%^ build-verifying-participants:detail our now
~(tap in participants.ring-signature)
::
(verify:raw message link-scope.ring-signature keys raw.ring-signature)
--

View File

@ -3127,8 +3127,8 @@
~% %ed + ~
|%
::
++ add
~/ %add
++ point-add
~/ %point-add
|= [a-point=@udpoint b-point=@udpoint]
^- @udpoint
::

151
tests/lib/ring.hoon Normal file
View File

@ -0,0 +1,151 @@
/+ *test, ring
::
=/ eny=@uvJ `@`0xdead.beef
::
=/ hello-world "Hello World"
=/ not-hello-world "Goodbye World"
::
=/ empty-scope ~
=/ test-scope `[%scope 5]
=/ test-scope-2 `[%scope 6]
::
=/ our-privkey=@udscalar 3
=/ our-pubkey=@udpoint (scalarmult-base:ed:crypto our-privkey)
::
=/ two-privkey=@udscalar 2
=/ two-pubkey=@udpoint (scalarmult-base:ed:crypto two-privkey)
::
=/ public-key-set (sy (turn (gulf 1 5) scalarmult-base:ed:crypto))
|%
++ test-basic-unlinked
=/ unlinked
%- sign:raw:ring :*
hello-world
empty-scope
public-key-set
our-pubkey
our-privkey
eny
==
::
%+ expect-eq
!> %.y
!> (verify:raw:ring hello-world empty-scope public-key-set unlinked)
::
++ test-linked-different-message-same-key-same-scope
=/ linked-hello-world
%- sign:raw:ring :*
hello-world
test-scope
public-key-set
our-pubkey
our-privkey
eny
==
::
=/ linked-not-hello-world
%- sign:raw:ring :*
not-hello-world
test-scope
public-key-set
our-pubkey
our-privkey
eny
==
::
;: weld
%+ expect-eq
!> %.y
!> (verify:raw:ring hello-world test-scope public-key-set linked-hello-world)
::
%+ expect-eq
!> %.y
!> (verify:raw:ring not-hello-world test-scope public-key-set linked-not-hello-world)
::
(expect-eq !>(%.y) !>(?=(^ y.linked-hello-world)))
(expect-eq !>(%.y) !>(?=(^ y.linked-not-hello-world)))
::
%+ expect-eq
!> y.linked-hello-world
!> y.linked-not-hello-world
==
:: if we use the same key to sign the same message in two different scopes, we
:: must have different resulting linkage tags.
::
++ test-linked-same-message-same-key-different-scope
=/ scope-one-hello-world
%- sign:raw:ring :*
hello-world
test-scope
public-key-set
our-pubkey
our-privkey
eny
==
::
=/ scope-two-hello-world
%- sign:raw:ring :*
hello-world
test-scope-2
public-key-set
our-pubkey
our-privkey
eny
==
::
;: weld
%+ expect-eq
!> %.y
!> (verify:raw:ring hello-world test-scope public-key-set scope-one-hello-world)
::
%+ expect-eq
!> %.y
!> (verify:raw:ring hello-world test-scope-2 public-key-set scope-two-hello-world)
::
(expect-eq !>(%.y) !>(?=(^ y.scope-one-hello-world)))
(expect-eq !>(%.y) !>(?=(^ y.scope-two-hello-world)))
::
%+ expect-eq
!> %.n
!> =(y.scope-one-hello-world y.scope-two-hello-world)
==
:: the same message signed by two different keys should have different linkage
::
++ test-linked-same-message-different-key
=/ our-hello-world
%- sign:raw:ring :*
hello-world
test-scope
public-key-set
our-pubkey
our-privkey
eny
==
::
=/ two-hello-world
%- sign:raw:ring :*
hello-world
test-scope
public-key-set
two-pubkey
two-privkey
eny
==
::
;: weld
%+ expect-eq
!> %.y
!> (verify:raw:ring hello-world test-scope public-key-set our-hello-world)
::
%+ expect-eq
!> %.y
!> (verify:raw:ring hello-world test-scope public-key-set two-hello-world)
::
(expect-eq !>(%.y) !>(?=(^ y.our-hello-world)))
(expect-eq !>(%.y) !>(?=(^ y.two-hello-world)))
::
%+ expect-eq
!> %.n
!> =(y.our-hello-world y.two-hello-world)
==
--