Compare commits
155 Commits
ci_integra
...
hush
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2cffb3630f | ||
|
|
3b6f5e3d5e | ||
|
|
b65aae9bc1 | ||
|
|
fdb6e208db | ||
|
|
060977fe54 | ||
|
|
9d80be62f9 | ||
|
|
6846ac5f9e | ||
|
|
75bede4bc8 | ||
|
|
d4fce58019 | ||
|
|
23aa869bf4 | ||
|
|
6d03b5c1db | ||
|
|
0ee1e81f5d | ||
|
|
2d97ccb7b8 | ||
|
|
c5642f9f5e | ||
|
|
c2d0a7d048 | ||
|
|
437b66d4ee | ||
|
|
34f762cea2 | ||
|
|
edf7bc144d | ||
|
|
34658c4bd3 | ||
|
|
6dcb4040af | ||
|
|
8c5cd4e4f6 | ||
|
|
e17e4b1346 | ||
|
|
9086dd9afb | ||
|
|
899d852c39 | ||
|
|
566db65a91 | ||
|
|
2b1583d75f | ||
|
|
247f3fb038 | ||
|
|
484330ebd9 | ||
|
|
8e098d4d72 | ||
|
|
6996853168 | ||
|
|
757316d355 | ||
|
|
70caa7d4b0 | ||
|
|
65bbe7daed | ||
|
|
9b455a12cc | ||
|
|
d7ba310294 | ||
|
|
6c99d71d4f | ||
|
|
3501365950 | ||
|
|
663f9d619d | ||
|
|
b856d23069 | ||
|
|
4289843852 | ||
|
|
670bb277e9 | ||
|
|
a1664c6bbc | ||
|
|
20d5cdc571 | ||
|
|
e21be37042 | ||
|
|
e4187f07ff | ||
|
|
3d39706aee | ||
|
|
012d43bc8c | ||
|
|
34ca75cceb | ||
|
|
80db0ae2f9 | ||
|
|
9ae5a9d624 | ||
|
|
2d43e3be7c | ||
|
|
09a20aacfe | ||
|
|
6b43b2d0d6 | ||
|
|
c57a31e82e | ||
|
|
63be3c9470 | ||
|
|
482bef87f0 | ||
|
|
b1ce3905d6 | ||
|
|
af9f9c17ee | ||
|
|
07955092f3 | ||
|
|
00983c48cd | ||
|
|
538de482f3 | ||
|
|
2e408957db | ||
|
|
22ccd1bceb | ||
|
|
76cd0d92bb | ||
|
|
88746e76fa | ||
|
|
794cf79db2 | ||
|
|
9f7e5fa3ce | ||
|
|
fe16e4a412 | ||
|
|
f65c37ea01 | ||
|
|
1a1c77536d | ||
|
|
c03871779a | ||
|
|
4113df4780 | ||
|
|
813cf16ff2 | ||
|
|
e378229bdd | ||
|
|
922ffe6002 | ||
|
|
e1841806c5 | ||
|
|
eb2db2e667 | ||
|
|
8be50c9531 | ||
|
|
c9b23dfdef | ||
|
|
e25b614573 | ||
|
|
7ff32b04d6 | ||
|
|
d707ebd321 | ||
|
|
9b06205ed6 | ||
|
|
61ce4dd3d6 | ||
|
|
9282c7da29 | ||
|
|
2d2e4aad86 | ||
|
|
cc183efda4 | ||
|
|
1f11c404dc | ||
|
|
0c81695731 | ||
|
|
2d8b1fe504 | ||
|
|
06da3b9ac8 | ||
|
|
bbec1b841d | ||
|
|
041671f642 | ||
|
|
e490b79907 | ||
|
|
91ff2c71cf | ||
|
|
0b6bbfb444 | ||
|
|
f5e5cb24e1 | ||
|
|
77ee1d6a8f | ||
|
|
5c16673724 | ||
|
|
4272cfa5b0 | ||
|
|
276e09f1fb | ||
|
|
3e8f2f8202 | ||
|
|
718b25c949 | ||
|
|
3d41ee5aba | ||
|
|
7dfc50e763 | ||
|
|
ef56fabf7b | ||
|
|
2ffa94f714 | ||
|
|
183a64b08e | ||
|
|
fa8103764a | ||
|
|
c5b883f91e | ||
|
|
4752a91781 | ||
|
|
cc5b835102 | ||
|
|
94cacc6152 | ||
|
|
661558e0c8 | ||
|
|
526676ecfc | ||
|
|
2067360930 | ||
|
|
0eb9f5040b | ||
|
|
69ce66ae6c | ||
|
|
002173e187 | ||
|
|
06a152734c | ||
|
|
c49590bab7 | ||
|
|
bb22a167af | ||
|
|
defdf8df52 | ||
|
|
a9d8079c2a | ||
|
|
d9d711ebb7 | ||
|
|
1db099f1cc | ||
|
|
44b601b0a9 | ||
|
|
729138a31e | ||
|
|
f6d9ec8faf | ||
|
|
91a8dc8284 | ||
|
|
4c984595e5 | ||
|
|
623dbd0d74 | ||
|
|
b0b754ba04 | ||
|
|
5a48059a14 | ||
|
|
29a9161981 | ||
|
|
58cb06ee92 | ||
|
|
8201a3933f | ||
|
|
1a3a2bec74 | ||
|
|
428f463555 | ||
|
|
755fc7aba8 | ||
|
|
c7252a43bf | ||
|
|
134b53e812 | ||
|
|
bbc7b44f88 | ||
|
|
02f503c74d | ||
|
|
b1f392ac99 | ||
|
|
9aceb63e7e | ||
|
|
bbbd397b80 | ||
|
|
e6ad371dd7 | ||
|
|
03952704b7 | ||
|
|
13a822f994 | ||
|
|
e97f0df3df | ||
|
|
6402b74741 | ||
|
|
cb0c8f1e07 | ||
|
|
cf7d7e823b | ||
|
|
b11ea2db25 |
8
.travis.yml
Normal file
8
.travis.yml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
language: rust
|
||||||
|
rust:
|
||||||
|
- 1.32.0
|
||||||
|
|
||||||
|
cache: cargo
|
||||||
|
|
||||||
|
script:
|
||||||
|
- cargo test --verbose --release --all
|
||||||
468
Cargo.lock
generated
468
Cargo.lock
generated
@@ -28,22 +28,6 @@ dependencies = [
|
|||||||
"stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aho-corasick"
|
|
||||||
version = "0.6.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ansi_term"
|
|
||||||
version = "0.11.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayvec"
|
name = "arrayvec"
|
||||||
version = "0.4.7"
|
version = "0.4.7"
|
||||||
@@ -52,27 +36,6 @@ dependencies = [
|
|||||||
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "backtrace"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "backtrace-sys"
|
|
||||||
version = "0.1.24"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bellman"
|
name = "bellman"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -80,8 +43,10 @@ dependencies = [
|
|||||||
"bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ff 0.4.0",
|
||||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"group 0.1.0",
|
||||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pairing 0.14.2",
|
"pairing 0.14.2",
|
||||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -92,11 +57,6 @@ name = "bit-vec"
|
|||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "0.9.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@@ -112,6 +72,17 @@ dependencies = [
|
|||||||
"constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-cipher-trait"
|
name = "block-cipher-trait"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
@@ -120,71 +91,29 @@ dependencies = [
|
|||||||
"generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-padding"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byte-tools"
|
name = "byte-tools"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byte-tools"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.2.2"
|
version = "1.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cargo_metadata"
|
|
||||||
version = "0.5.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.0.22"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clippy"
|
|
||||||
version = "0.0.200"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"clippy_lints 0.0.200 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clippy_lints"
|
|
||||||
version = "0.0.200"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "constant_time_eq"
|
name = "constant_time_eq"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
@@ -195,6 +124,19 @@ name = "crossbeam"
|
|||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto_api"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto_api_chachapoly"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"crypto_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.7.2"
|
version = "0.7.2"
|
||||||
@@ -204,16 +146,37 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "digest"
|
||||||
version = "1.5.0"
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fake-simd"
|
||||||
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "error-chain"
|
name = "ff"
|
||||||
version = "0.11.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ff_derive 0.3.0",
|
||||||
|
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ff_derive"
|
||||||
|
version = "0.3.0"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -270,13 +233,26 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getopts"
|
name = "generic-array"
|
||||||
version = "0.2.18"
|
version = "0.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "group"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"ff 0.4.0",
|
||||||
|
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex-literal"
|
name = "hex-literal"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@@ -294,34 +270,6 @@ dependencies = [
|
|||||||
"proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "idna"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "if_chain"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itertools"
|
|
||||||
version = "0.7.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itoa"
|
|
||||||
version = "0.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@@ -339,24 +287,15 @@ dependencies = [
|
|||||||
"bellman 0.1.0",
|
"bellman 0.1.0",
|
||||||
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)",
|
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)",
|
||||||
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ff 0.4.0",
|
||||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pairing 0.14.2",
|
"pairing 0.14.2",
|
||||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"sapling-crypto 0.0.1",
|
"sapling-crypto 0.0.1",
|
||||||
]
|
"zcash_primitives 0.0.0",
|
||||||
|
"zcash_proofs 0.0.0",
|
||||||
[[package]]
|
"zip32 0.0.0",
|
||||||
name = "matches"
|
|
||||||
version = "0.1.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -399,20 +338,21 @@ name = "opaque-debug"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opaque-debug"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pairing"
|
name = "pairing"
|
||||||
version = "0.14.2"
|
version = "0.14.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clippy 0.0.200 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ff 0.4.0",
|
||||||
|
"group 0.1.0",
|
||||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "percent-encoding"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-hack"
|
name = "proc-macro-hack"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -434,20 +374,6 @@ dependencies = [
|
|||||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pulldown-cmark"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quine-mc_cluskey"
|
|
||||||
version = "0.2.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "0.6.8"
|
version = "0.6.8"
|
||||||
@@ -481,26 +407,6 @@ name = "redox_syscall"
|
|||||||
version = "0.1.40"
|
version = "0.1.40"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-syntax"
|
|
||||||
version = "0.6.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-crypto"
|
name = "rust-crypto"
|
||||||
version = "0.2.36"
|
version = "0.2.36"
|
||||||
@@ -513,29 +419,11 @@ dependencies = [
|
|||||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustc-demangle"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-serialize"
|
name = "rustc-serialize"
|
||||||
version = "0.3.24"
|
version = "0.3.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustc_version"
|
|
||||||
version = "0.2.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ryu"
|
|
||||||
version = "0.2.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sapling-crypto"
|
name = "sapling-crypto"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
@@ -544,6 +432,7 @@ dependencies = [
|
|||||||
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)",
|
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)",
|
||||||
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ff 0.4.0",
|
||||||
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pairing 0.14.2",
|
"pairing 0.14.2",
|
||||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -551,42 +440,14 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "sha2"
|
||||||
version = "0.9.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
|
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
"fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
[[package]]
|
|
||||||
name = "semver-parser"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde"
|
|
||||||
version = "1.0.75"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_derive"
|
|
||||||
version = "1.0.75"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_json"
|
|
||||||
version = "1.0.26"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -607,14 +468,6 @@ dependencies = [
|
|||||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thread_local"
|
|
||||||
version = "0.3.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.1.40"
|
version = "0.1.40"
|
||||||
@@ -625,62 +478,16 @@ dependencies = [
|
|||||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "toml"
|
|
||||||
version = "0.4.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.10.0"
|
version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ucd-util"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-bidi"
|
|
||||||
version = "0.3.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-normalization"
|
|
||||||
version = "0.1.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-width"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "url"
|
|
||||||
version = "1.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "utf8-ranges"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.4"
|
version = "0.3.4"
|
||||||
@@ -703,10 +510,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "zcash_primitives"
|
name = "zcash_primitives"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)",
|
||||||
|
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"crypto_api_chachapoly 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ff 0.4.0",
|
||||||
|
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"pairing 0.14.2",
|
||||||
|
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"sapling-crypto 0.0.1",
|
||||||
|
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zcash_proofs"
|
name = "zcash_proofs"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"bellman 0.1.0",
|
||||||
|
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)",
|
||||||
|
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ff 0.4.0",
|
||||||
|
"pairing 0.14.2",
|
||||||
|
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"sapling-crypto 0.0.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zcash_wallet"
|
name = "zcash_wallet"
|
||||||
@@ -719,97 +547,69 @@ dependencies = [
|
|||||||
"aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)",
|
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)",
|
||||||
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ff 0.4.0",
|
||||||
"fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"pairing 0.14.2",
|
"pairing 0.14.2",
|
||||||
"sapling-crypto 0.0.1",
|
"sapling-crypto 0.0.1",
|
||||||
|
"zcash_primitives 0.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e6fb1737cdc8da3db76e90ca817a194249a38fcb500c2e6ecec39b29448aa873"
|
"checksum aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e6fb1737cdc8da3db76e90ca817a194249a38fcb500c2e6ecec39b29448aa873"
|
||||||
"checksum aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67cc03b0a090a05cb01e96998a01905d7ceedce1bc23b756c0bb7faa0682ccb1"
|
"checksum aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67cc03b0a090a05cb01e96998a01905d7ceedce1bc23b756c0bb7faa0682ccb1"
|
||||||
"checksum aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6810b7fb9f2bb4f76f05ac1c170b8dde285b6308955dc3afd89710268c958d9e"
|
"checksum aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6810b7fb9f2bb4f76f05ac1c170b8dde285b6308955dc3afd89710268c958d9e"
|
||||||
"checksum aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "68f56c7353e5a9547cbd76ed90f7bb5ffc3ba09d4ea9bd1d8c06c8b1142eeb5a"
|
|
||||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
|
||||||
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
|
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
|
||||||
"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
|
|
||||||
"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0"
|
|
||||||
"checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f"
|
"checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f"
|
||||||
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
|
||||||
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
|
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
|
||||||
"checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)" = "<none>"
|
"checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)" = "<none>"
|
||||||
|
"checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d"
|
||||||
"checksum block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "370424437b9459f3dfd68428ed9376ddfe03d8b70ede29cc533b3557df186ab4"
|
"checksum block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "370424437b9459f3dfd68428ed9376ddfe03d8b70ede29cc533b3557df186ab4"
|
||||||
|
"checksum block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc4358306e344bf9775d0197fd00d2603e5afb0771bb353538630f022068ea3"
|
||||||
"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
|
"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
|
||||||
|
"checksum byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "980479e6fde23246dfb54d47580d66b4e99202e7579c5eaa9fe10ecb5ebd2182"
|
||||||
"checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87"
|
"checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87"
|
||||||
"checksum cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1efca0b863ca03ed4c109fb1c55e0bc4bbeb221d3e103d86251046b06a526bd0"
|
|
||||||
"checksum cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "4a6007c146fdd28d4512a794b07ffe9d8e89e6bf86e2e0c4ddff2e1fb54a0007"
|
|
||||||
"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
|
|
||||||
"checksum clippy 0.0.200 (registry+https://github.com/rust-lang/crates.io-index)" = "927a1f79af10deb103df108347f23c6b7fa1731c953d6fb24d68be1748a0993f"
|
|
||||||
"checksum clippy_lints 0.0.200 (registry+https://github.com/rust-lang/crates.io-index)" = "d2432663f6bdb90255dcf9df5ca504f99b575bb471281591138f62f9d31f863b"
|
|
||||||
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
|
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
|
||||||
"checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19"
|
"checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19"
|
||||||
|
"checksum crypto_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f855e87e75a4799e18b8529178adcde6fd4f97c1449ff4821e747ff728bb102"
|
||||||
|
"checksum crypto_api_chachapoly 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9ee35dbace0831b5fe7cb9b43eb029aa14a10f594a115025d4628a2baa63ab"
|
||||||
"checksum digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603"
|
"checksum digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603"
|
||||||
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
|
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
|
||||||
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
|
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||||
"checksum fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce3371c82bfbd984f624cab093f55e7336f5a6e589f8518e1258f54f011b89ad"
|
"checksum fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce3371c82bfbd984f624cab093f55e7336f5a6e589f8518e1258f54f011b89ad"
|
||||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||||
"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c"
|
"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c"
|
||||||
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
|
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
|
||||||
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
|
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
|
||||||
|
"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592"
|
||||||
"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
|
"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
|
||||||
"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797"
|
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
|
||||||
"checksum hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4da5f0e01bd8a71a224a4eedecaacfcabda388dbb7a80faf04d3514287572d95"
|
"checksum hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4da5f0e01bd8a71a224a4eedecaacfcabda388dbb7a80faf04d3514287572d95"
|
||||||
"checksum hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d340b6514f232f6db1bd16db65302a5278a04fef9ce867cb932e7e5fa21130a"
|
"checksum hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d340b6514f232f6db1bd16db65302a5278a04fef9ce867cb932e7e5fa21130a"
|
||||||
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
|
|
||||||
"checksum if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4bac95d9aa0624e7b78187d6fb8ab012b41d9f6f54b1bcb61e61c4845f8357ec"
|
|
||||||
"checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450"
|
|
||||||
"checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606"
|
|
||||||
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
|
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
|
||||||
"checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b"
|
"checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b"
|
||||||
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
|
||||||
"checksum memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a3b4142ab8738a78c51896f704f83c11df047ff1bda9a92a661aa6361552d93d"
|
|
||||||
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
|
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
|
||||||
"checksum num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3eceac7784c5dc97c2d6edf30259b4e153e6e2b42b3c85e9a6e9f45d06caef6e"
|
"checksum num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3eceac7784c5dc97c2d6edf30259b4e153e6e2b42b3c85e9a6e9f45d06caef6e"
|
||||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||||
"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe"
|
"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe"
|
||||||
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
|
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
|
||||||
"checksum opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d620c9c26834b34f039489ac0dfdb12c7ac15ccaf818350a64c9b5334a452ad7"
|
"checksum opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d620c9c26834b34f039489ac0dfdb12c7ac15ccaf818350a64c9b5334a452ad7"
|
||||||
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
|
"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409"
|
||||||
"checksum proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ba8d4f9257b85eb6cdf13f055cea3190520aab1409ca2ab43493ea4820c25f0"
|
"checksum proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ba8d4f9257b85eb6cdf13f055cea3190520aab1409ca2ab43493ea4820c25f0"
|
||||||
"checksum proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5cb6f960ad471404618e9817c0e5d10b1ae74cfdf01fab89ea0641fe7fb2892"
|
"checksum proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5cb6f960ad471404618e9817c0e5d10b1ae74cfdf01fab89ea0641fe7fb2892"
|
||||||
"checksum proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b331c6ad3411474cd55540398dc7ad89fc41488e64ec71fdecc9c9b86de96fb0"
|
"checksum proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b331c6ad3411474cd55540398dc7ad89fc41488e64ec71fdecc9c9b86de96fb0"
|
||||||
"checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32"
|
|
||||||
"checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45"
|
|
||||||
"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5"
|
"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5"
|
||||||
"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
|
"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
|
||||||
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
|
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
|
||||||
"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
|
"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
|
||||||
"checksum regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "67d0301b0c6804eca7e3c275119d0b01ff3b7ab9258a65709e608a66312a1025"
|
|
||||||
"checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d"
|
|
||||||
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
|
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
|
||||||
"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395"
|
|
||||||
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
|
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
|
||||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
|
||||||
"checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7"
|
|
||||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
|
||||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|
||||||
"checksum serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)" = "22d340507cea0b7e6632900a176101fea959c7065d93ba555072da90aaaafc87"
|
|
||||||
"checksum serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)" = "234fc8b737737b148ccd625175fc6390f5e4dacfdaa543cb93a3430d984a9119"
|
|
||||||
"checksum serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "44dd2cfde475037451fa99b7e5df77aa3cfd1536575fa8e7a538ab36dcde49ae"
|
|
||||||
"checksum stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "30dc6118470d69ce0fdcf7e6f95e95853f7f4f72f80d835d4519577c323814ab"
|
"checksum stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "30dc6118470d69ce0fdcf7e6f95e95853f7f4f72f80d835d4519577c323814ab"
|
||||||
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
|
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
|
||||||
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
|
||||||
"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
|
"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
|
||||||
"checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9"
|
|
||||||
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
|
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
|
||||||
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
|
|
||||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
|
||||||
"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25"
|
|
||||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
|
||||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||||
"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6"
|
|
||||||
"checksum utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd70f467df6810094968e2fce0ee1bd0e87157aceb026a8c083bcf5e25b9efe4"
|
|
||||||
"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"
|
"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"
|
||||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"bellman",
|
"bellman",
|
||||||
|
"ff",
|
||||||
|
"group",
|
||||||
"librustzcash",
|
"librustzcash",
|
||||||
"pairing",
|
"pairing",
|
||||||
"sapling-crypto",
|
"sapling-crypto",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2017 Zcash Company
|
Copyright (c) 2017-2019 Electric Coin Company
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -11,12 +11,21 @@ version = "0.1.0"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.4"
|
rand = "0.4"
|
||||||
bit-vec = "0.4.4"
|
bit-vec = "0.4.4"
|
||||||
|
ff = { path = "../ff" }
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
futures-cpupool = "0.1"
|
futures-cpupool = { version = "0.1", optional = true }
|
||||||
num_cpus = "1"
|
group = { path = "../group" }
|
||||||
crossbeam = "0.3"
|
num_cpus = { version = "1", optional = true }
|
||||||
pairing = { path = "../pairing" }
|
crossbeam = { version = "0.3", optional = true }
|
||||||
|
pairing = { path = "../pairing", optional = true }
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
groth16 = ["pairing"]
|
||||||
|
multicore = ["futures-cpupool", "crossbeam", "num_cpus"]
|
||||||
|
default = ["groth16", "multicore"]
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "mimc"
|
||||||
|
path = "tests/mimc.rs"
|
||||||
|
required-features = ["groth16"]
|
||||||
|
|||||||
@@ -10,12 +10,8 @@
|
|||||||
//! This allows us to perform polynomial operations in O(n)
|
//! This allows us to perform polynomial operations in O(n)
|
||||||
//! by performing an O(n log n) FFT over such a domain.
|
//! by performing an O(n log n) FFT over such a domain.
|
||||||
|
|
||||||
use pairing::{
|
use ff::{Field, PrimeField, ScalarEngine};
|
||||||
Engine,
|
use group::CurveProjective;
|
||||||
Field,
|
|
||||||
PrimeField,
|
|
||||||
CurveProjective
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
SynthesisError
|
SynthesisError
|
||||||
@@ -23,7 +19,7 @@ use super::{
|
|||||||
|
|
||||||
use super::multicore::Worker;
|
use super::multicore::Worker;
|
||||||
|
|
||||||
pub struct EvaluationDomain<E: Engine, G: Group<E>> {
|
pub struct EvaluationDomain<E: ScalarEngine, G: Group<E>> {
|
||||||
coeffs: Vec<G>,
|
coeffs: Vec<G>,
|
||||||
exp: u32,
|
exp: u32,
|
||||||
omega: E::Fr,
|
omega: E::Fr,
|
||||||
@@ -32,7 +28,7 @@ pub struct EvaluationDomain<E: Engine, G: Group<E>> {
|
|||||||
minv: E::Fr
|
minv: E::Fr
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Engine, G: Group<E>> EvaluationDomain<E, G> {
|
impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
||||||
pub fn as_ref(&self) -> &[G] {
|
pub fn as_ref(&self) -> &[G] {
|
||||||
&self.coeffs
|
&self.coeffs
|
||||||
}
|
}
|
||||||
@@ -189,7 +185,7 @@ impl<E: Engine, G: Group<E>> EvaluationDomain<E, G> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Group<E: Engine>: Sized + Copy + Clone + Send + Sync {
|
pub trait Group<E: ScalarEngine>: Sized + Copy + Clone + Send + Sync {
|
||||||
fn group_zero() -> Self;
|
fn group_zero() -> Self;
|
||||||
fn group_mul_assign(&mut self, by: &E::Fr);
|
fn group_mul_assign(&mut self, by: &E::Fr);
|
||||||
fn group_add_assign(&mut self, other: &Self);
|
fn group_add_assign(&mut self, other: &Self);
|
||||||
@@ -227,23 +223,23 @@ impl<G: CurveProjective> Group<G::Engine> for Point<G> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Scalar<E: Engine>(pub E::Fr);
|
pub struct Scalar<E: ScalarEngine>(pub E::Fr);
|
||||||
|
|
||||||
impl<E: Engine> PartialEq for Scalar<E> {
|
impl<E: ScalarEngine> PartialEq for Scalar<E> {
|
||||||
fn eq(&self, other: &Scalar<E>) -> bool {
|
fn eq(&self, other: &Scalar<E>) -> bool {
|
||||||
self.0 == other.0
|
self.0 == other.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Engine> Copy for Scalar<E> { }
|
impl<E: ScalarEngine> Copy for Scalar<E> { }
|
||||||
|
|
||||||
impl<E: Engine> Clone for Scalar<E> {
|
impl<E: ScalarEngine> Clone for Scalar<E> {
|
||||||
fn clone(&self) -> Scalar<E> {
|
fn clone(&self) -> Scalar<E> {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Engine> Group<E> for Scalar<E> {
|
impl<E: ScalarEngine> Group<E> for Scalar<E> {
|
||||||
fn group_zero() -> Self {
|
fn group_zero() -> Self {
|
||||||
Scalar(E::Fr::zero())
|
Scalar(E::Fr::zero())
|
||||||
}
|
}
|
||||||
@@ -258,7 +254,7 @@ impl<E: Engine> Group<E> for Scalar<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn best_fft<E: Engine, T: Group<E>>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32)
|
fn best_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32)
|
||||||
{
|
{
|
||||||
let log_cpus = worker.log_num_cpus();
|
let log_cpus = worker.log_num_cpus();
|
||||||
|
|
||||||
@@ -269,7 +265,7 @@ fn best_fft<E: Engine, T: Group<E>>(a: &mut [T], worker: &Worker, omega: &E::Fr,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serial_fft<E: Engine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u32)
|
fn serial_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u32)
|
||||||
{
|
{
|
||||||
fn bitreverse(mut n: u32, l: u32) -> u32 {
|
fn bitreverse(mut n: u32, l: u32) -> u32 {
|
||||||
let mut r = 0;
|
let mut r = 0;
|
||||||
@@ -314,7 +310,7 @@ fn serial_fft<E: Engine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u32)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parallel_fft<E: Engine, T: Group<E>>(
|
fn parallel_fft<E: ScalarEngine, T: Group<E>>(
|
||||||
a: &mut [T],
|
a: &mut [T],
|
||||||
worker: &Worker,
|
worker: &Worker,
|
||||||
omega: &E::Fr,
|
omega: &E::Fr,
|
||||||
@@ -375,12 +371,13 @@ fn parallel_fft<E: Engine, T: Group<E>>(
|
|||||||
|
|
||||||
// Test multiplying various (low degree) polynomials together and
|
// Test multiplying various (low degree) polynomials together and
|
||||||
// comparing with naive evaluations.
|
// comparing with naive evaluations.
|
||||||
|
#[cfg(feature = "pairing")]
|
||||||
#[test]
|
#[test]
|
||||||
fn polynomial_arith() {
|
fn polynomial_arith() {
|
||||||
use pairing::bls12_381::Bls12;
|
use pairing::bls12_381::Bls12;
|
||||||
use rand::{self, Rand};
|
use rand::{self, Rand};
|
||||||
|
|
||||||
fn test_mul<E: Engine, R: rand::Rng>(rng: &mut R)
|
fn test_mul<E: ScalarEngine, R: rand::Rng>(rng: &mut R)
|
||||||
{
|
{
|
||||||
let worker = Worker::new();
|
let worker = Worker::new();
|
||||||
|
|
||||||
@@ -422,12 +419,13 @@ fn polynomial_arith() {
|
|||||||
test_mul::<Bls12, _>(rng);
|
test_mul::<Bls12, _>(rng);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "pairing")]
|
||||||
#[test]
|
#[test]
|
||||||
fn fft_composition() {
|
fn fft_composition() {
|
||||||
use pairing::bls12_381::Bls12;
|
use pairing::bls12_381::Bls12;
|
||||||
use rand;
|
use rand;
|
||||||
|
|
||||||
fn test_comp<E: Engine, R: rand::Rng>(rng: &mut R)
|
fn test_comp<E: ScalarEngine, R: rand::Rng>(rng: &mut R)
|
||||||
{
|
{
|
||||||
let worker = Worker::new();
|
let worker = Worker::new();
|
||||||
|
|
||||||
@@ -460,13 +458,14 @@ fn fft_composition() {
|
|||||||
test_comp::<Bls12, _>(rng);
|
test_comp::<Bls12, _>(rng);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "pairing")]
|
||||||
#[test]
|
#[test]
|
||||||
fn parallel_fft_consistency() {
|
fn parallel_fft_consistency() {
|
||||||
use pairing::bls12_381::Bls12;
|
use pairing::bls12_381::Bls12;
|
||||||
use rand::{self, Rand};
|
use rand::{self, Rand};
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
|
||||||
fn test_consistency<E: Engine, R: rand::Rng>(rng: &mut R)
|
fn test_consistency<E: ScalarEngine, R: rand::Rng>(rng: &mut R)
|
||||||
{
|
{
|
||||||
let worker = Worker::new();
|
let worker = Worker::new();
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,9 @@ use rand::Rng;
|
|||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use pairing::{
|
use ff::{Field, PrimeField};
|
||||||
Engine,
|
use group::{CurveAffine, CurveProjective, Wnaf};
|
||||||
PrimeField,
|
use pairing::Engine;
|
||||||
Field,
|
|
||||||
Wnaf,
|
|
||||||
CurveProjective,
|
|
||||||
CurveAffine
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
Parameters,
|
Parameters,
|
||||||
@@ -430,7 +425,7 @@ pub fn generate_parameters<E, C>(
|
|||||||
&worker
|
&worker
|
||||||
);
|
);
|
||||||
|
|
||||||
// Evaluate for auxillary variables.
|
// Evaluate for auxiliary variables.
|
||||||
eval(
|
eval(
|
||||||
&g1_wnaf,
|
&g1_wnaf,
|
||||||
&g2_wnaf,
|
&g2_wnaf,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
use group::{CurveAffine, EncodedPoint};
|
||||||
use pairing::{
|
use pairing::{
|
||||||
Engine,
|
Engine,
|
||||||
CurveAffine,
|
PairingCurveAffine,
|
||||||
EncodedPoint
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use ::{
|
use ::{
|
||||||
@@ -221,7 +221,7 @@ pub struct Parameters<E: Engine> {
|
|||||||
pub h: Arc<Vec<E::G1Affine>>,
|
pub h: Arc<Vec<E::G1Affine>>,
|
||||||
|
|
||||||
// Elements of the form (beta * u_i(tau) + alpha v_i(tau) + w_i(tau)) / delta
|
// Elements of the form (beta * u_i(tau) + alpha v_i(tau) + w_i(tau)) / delta
|
||||||
// for all auxillary inputs. Variables can never be unconstrained, so this
|
// for all auxiliary inputs. Variables can never be unconstrained, so this
|
||||||
// never contains points at infinity.
|
// never contains points at infinity.
|
||||||
pub l: Arc<Vec<E::G1Affine>>,
|
pub l: Arc<Vec<E::G1Affine>>,
|
||||||
|
|
||||||
@@ -385,9 +385,9 @@ pub struct PreparedVerifyingKey<E: Engine> {
|
|||||||
/// Pairing result of alpha*beta
|
/// Pairing result of alpha*beta
|
||||||
alpha_g1_beta_g2: E::Fqk,
|
alpha_g1_beta_g2: E::Fqk,
|
||||||
/// -gamma in G2
|
/// -gamma in G2
|
||||||
neg_gamma_g2: <E::G2Affine as CurveAffine>::Prepared,
|
neg_gamma_g2: <E::G2Affine as PairingCurveAffine>::Prepared,
|
||||||
/// -delta in G2
|
/// -delta in G2
|
||||||
neg_delta_g2: <E::G2Affine as CurveAffine>::Prepared,
|
neg_delta_g2: <E::G2Affine as PairingCurveAffine>::Prepared,
|
||||||
/// Copy of IC from `VerifiyingKey`.
|
/// Copy of IC from `VerifiyingKey`.
|
||||||
ic: Vec<E::G1Affine>
|
ic: Vec<E::G1Affine>
|
||||||
}
|
}
|
||||||
@@ -486,8 +486,8 @@ mod test_with_bls12_381 {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use {Circuit, SynthesisError, ConstraintSystem};
|
use {Circuit, SynthesisError, ConstraintSystem};
|
||||||
|
|
||||||
|
use ff::Field;
|
||||||
use rand::{Rand, thread_rng};
|
use rand::{Rand, thread_rng};
|
||||||
use pairing::{Field};
|
|
||||||
use pairing::bls12_381::{Bls12, Fr};
|
use pairing::bls12_381::{Bls12, Fr};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -4,13 +4,9 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
|
|
||||||
use pairing::{
|
use ff::{Field, PrimeField};
|
||||||
Engine,
|
use group::{CurveAffine, CurveProjective};
|
||||||
PrimeField,
|
use pairing::Engine;
|
||||||
Field,
|
|
||||||
CurveProjective,
|
|
||||||
CurveAffine
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
ParameterSource,
|
ParameterSource,
|
||||||
|
|||||||
@@ -1,16 +1,8 @@
|
|||||||
use pairing::{
|
use ff::{
|
||||||
Engine,
|
Field, LegendreSymbol, PrimeField, PrimeFieldDecodingError,
|
||||||
PrimeField,
|
PrimeFieldRepr, ScalarEngine, SqrtField};
|
||||||
PrimeFieldRepr,
|
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
|
||||||
Field,
|
use pairing::{Engine, PairingCurveAffine};
|
||||||
SqrtField,
|
|
||||||
LegendreSymbol,
|
|
||||||
CurveProjective,
|
|
||||||
CurveAffine,
|
|
||||||
PrimeFieldDecodingError,
|
|
||||||
GroupDecodingError,
|
|
||||||
EncodedPoint
|
|
||||||
};
|
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@@ -263,8 +255,11 @@ impl PrimeField for Fr {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct DummyEngine;
|
pub struct DummyEngine;
|
||||||
|
|
||||||
impl Engine for DummyEngine {
|
impl ScalarEngine for DummyEngine {
|
||||||
type Fr = Fr;
|
type Fr = Fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Engine for DummyEngine {
|
||||||
type G1 = Fr;
|
type G1 = Fr;
|
||||||
type G1Affine = Fr;
|
type G1Affine = Fr;
|
||||||
type G2 = Fr;
|
type G2 = Fr;
|
||||||
@@ -277,8 +272,8 @@ impl Engine for DummyEngine {
|
|||||||
|
|
||||||
fn miller_loop<'a, I>(i: I) -> Self::Fqk
|
fn miller_loop<'a, I>(i: I) -> Self::Fqk
|
||||||
where I: IntoIterator<Item=&'a (
|
where I: IntoIterator<Item=&'a (
|
||||||
&'a <Self::G1Affine as CurveAffine>::Prepared,
|
&'a <Self::G1Affine as PairingCurveAffine>::Prepared,
|
||||||
&'a <Self::G2Affine as CurveAffine>::Prepared
|
&'a <Self::G2Affine as PairingCurveAffine>::Prepared
|
||||||
)>
|
)>
|
||||||
{
|
{
|
||||||
let mut acc = <Fr as Field>::zero();
|
let mut acc = <Fr as Field>::zero();
|
||||||
@@ -401,11 +396,8 @@ impl EncodedPoint for FakePoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CurveAffine for Fr {
|
impl CurveAffine for Fr {
|
||||||
type Pair = Fr;
|
|
||||||
type PairingResult = Fr;
|
|
||||||
type Compressed = FakePoint;
|
type Compressed = FakePoint;
|
||||||
type Uncompressed = FakePoint;
|
type Uncompressed = FakePoint;
|
||||||
type Prepared = Fr;
|
|
||||||
type Projective = Fr;
|
type Projective = Fr;
|
||||||
type Base = Fr;
|
type Base = Fr;
|
||||||
type Scalar = Fr;
|
type Scalar = Fr;
|
||||||
@@ -437,6 +429,16 @@ impl CurveAffine for Fr {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn into_projective(&self) -> Self::Projective {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PairingCurveAffine for Fr {
|
||||||
|
type Prepared = Fr;
|
||||||
|
type Pair = Fr;
|
||||||
|
type PairingResult = Fr;
|
||||||
|
|
||||||
fn prepare(&self) -> Self::Prepared {
|
fn prepare(&self) -> Self::Prepared {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
@@ -444,8 +446,4 @@ impl CurveAffine for Fr {
|
|||||||
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
|
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
|
||||||
self.mul(*other)
|
self.mul(*other)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_projective(&self) -> Self::Projective {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
use pairing::{
|
use ff::{Field, PrimeField};
|
||||||
Engine,
|
use pairing::Engine;
|
||||||
Field,
|
|
||||||
PrimeField
|
|
||||||
};
|
|
||||||
|
|
||||||
mod dummy_engine;
|
mod dummy_engine;
|
||||||
use self::dummy_engine::*;
|
use self::dummy_engine::*;
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
use pairing::{
|
use ff::PrimeField;
|
||||||
Engine,
|
use group::{CurveAffine, CurveProjective};
|
||||||
CurveProjective,
|
use pairing::{Engine, PairingCurveAffine};
|
||||||
CurveAffine,
|
|
||||||
PrimeField
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
Proof,
|
Proof,
|
||||||
|
|||||||
@@ -1,18 +1,27 @@
|
|||||||
|
extern crate ff;
|
||||||
|
extern crate group;
|
||||||
|
#[cfg(feature = "pairing")]
|
||||||
extern crate pairing;
|
extern crate pairing;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate num_cpus;
|
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate futures_cpupool;
|
|
||||||
extern crate bit_vec;
|
extern crate bit_vec;
|
||||||
extern crate crossbeam;
|
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
|
|
||||||
|
#[cfg(feature = "multicore")]
|
||||||
|
extern crate crossbeam;
|
||||||
|
#[cfg(feature = "multicore")]
|
||||||
|
extern crate futures_cpupool;
|
||||||
|
#[cfg(feature = "multicore")]
|
||||||
|
extern crate num_cpus;
|
||||||
|
|
||||||
pub mod multicore;
|
pub mod multicore;
|
||||||
mod multiexp;
|
mod multiexp;
|
||||||
pub mod domain;
|
pub mod domain;
|
||||||
|
#[cfg(feature = "groth16")]
|
||||||
pub mod groth16;
|
pub mod groth16;
|
||||||
|
|
||||||
use pairing::{Engine, Field};
|
use ff::{Field, ScalarEngine};
|
||||||
|
|
||||||
use std::ops::{Add, Sub};
|
use std::ops::{Add, Sub};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@@ -24,7 +33,7 @@ use std::marker::PhantomData;
|
|||||||
/// rank-1 quadratic constraint systems. The `Circuit` trait represents a
|
/// rank-1 quadratic constraint systems. The `Circuit` trait represents a
|
||||||
/// circuit that can be synthesized. The `synthesize` method is called during
|
/// circuit that can be synthesized. The `synthesize` method is called during
|
||||||
/// CRS generation and during proving.
|
/// CRS generation and during proving.
|
||||||
pub trait Circuit<E: Engine> {
|
pub trait Circuit<E: ScalarEngine> {
|
||||||
/// Synthesize the circuit into a rank-1 quadratic constraint system
|
/// Synthesize the circuit into a rank-1 quadratic constraint system
|
||||||
fn synthesize<CS: ConstraintSystem<E>>(
|
fn synthesize<CS: ConstraintSystem<E>>(
|
||||||
self,
|
self,
|
||||||
@@ -51,7 +60,7 @@ impl Variable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the index of either an input variable or
|
/// Represents the index of either an input variable or
|
||||||
/// auxillary variable.
|
/// auxiliary variable.
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
pub enum Index {
|
pub enum Index {
|
||||||
Input(usize),
|
Input(usize),
|
||||||
@@ -61,21 +70,21 @@ pub enum Index {
|
|||||||
/// This represents a linear combination of some variables, with coefficients
|
/// This represents a linear combination of some variables, with coefficients
|
||||||
/// in the scalar field of a pairing-friendly elliptic curve group.
|
/// in the scalar field of a pairing-friendly elliptic curve group.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct LinearCombination<E: Engine>(Vec<(Variable, E::Fr)>);
|
pub struct LinearCombination<E: ScalarEngine>(Vec<(Variable, E::Fr)>);
|
||||||
|
|
||||||
impl<E: Engine> AsRef<[(Variable, E::Fr)]> for LinearCombination<E> {
|
impl<E: ScalarEngine> AsRef<[(Variable, E::Fr)]> for LinearCombination<E> {
|
||||||
fn as_ref(&self) -> &[(Variable, E::Fr)] {
|
fn as_ref(&self) -> &[(Variable, E::Fr)] {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Engine> LinearCombination<E> {
|
impl<E: ScalarEngine> LinearCombination<E> {
|
||||||
pub fn zero() -> LinearCombination<E> {
|
pub fn zero() -> LinearCombination<E> {
|
||||||
LinearCombination(vec![])
|
LinearCombination(vec![])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Engine> Add<(E::Fr, Variable)> for LinearCombination<E> {
|
impl<E: ScalarEngine> Add<(E::Fr, Variable)> for LinearCombination<E> {
|
||||||
type Output = LinearCombination<E>;
|
type Output = LinearCombination<E>;
|
||||||
|
|
||||||
fn add(mut self, (coeff, var): (E::Fr, Variable)) -> LinearCombination<E> {
|
fn add(mut self, (coeff, var): (E::Fr, Variable)) -> LinearCombination<E> {
|
||||||
@@ -85,7 +94,7 @@ impl<E: Engine> Add<(E::Fr, Variable)> for LinearCombination<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Engine> Sub<(E::Fr, Variable)> for LinearCombination<E> {
|
impl<E: ScalarEngine> Sub<(E::Fr, Variable)> for LinearCombination<E> {
|
||||||
type Output = LinearCombination<E>;
|
type Output = LinearCombination<E>;
|
||||||
|
|
||||||
fn sub(self, (mut coeff, var): (E::Fr, Variable)) -> LinearCombination<E> {
|
fn sub(self, (mut coeff, var): (E::Fr, Variable)) -> LinearCombination<E> {
|
||||||
@@ -95,7 +104,7 @@ impl<E: Engine> Sub<(E::Fr, Variable)> for LinearCombination<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Engine> Add<Variable> for LinearCombination<E> {
|
impl<E: ScalarEngine> Add<Variable> for LinearCombination<E> {
|
||||||
type Output = LinearCombination<E>;
|
type Output = LinearCombination<E>;
|
||||||
|
|
||||||
fn add(self, other: Variable) -> LinearCombination<E> {
|
fn add(self, other: Variable) -> LinearCombination<E> {
|
||||||
@@ -103,7 +112,7 @@ impl<E: Engine> Add<Variable> for LinearCombination<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Engine> Sub<Variable> for LinearCombination<E> {
|
impl<E: ScalarEngine> Sub<Variable> for LinearCombination<E> {
|
||||||
type Output = LinearCombination<E>;
|
type Output = LinearCombination<E>;
|
||||||
|
|
||||||
fn sub(self, other: Variable) -> LinearCombination<E> {
|
fn sub(self, other: Variable) -> LinearCombination<E> {
|
||||||
@@ -111,7 +120,7 @@ impl<E: Engine> Sub<Variable> for LinearCombination<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, E: Engine> Add<&'a LinearCombination<E>> for LinearCombination<E> {
|
impl<'a, E: ScalarEngine> Add<&'a LinearCombination<E>> for LinearCombination<E> {
|
||||||
type Output = LinearCombination<E>;
|
type Output = LinearCombination<E>;
|
||||||
|
|
||||||
fn add(mut self, other: &'a LinearCombination<E>) -> LinearCombination<E> {
|
fn add(mut self, other: &'a LinearCombination<E>) -> LinearCombination<E> {
|
||||||
@@ -123,7 +132,7 @@ impl<'a, E: Engine> Add<&'a LinearCombination<E>> for LinearCombination<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, E: Engine> Sub<&'a LinearCombination<E>> for LinearCombination<E> {
|
impl<'a, E: ScalarEngine> Sub<&'a LinearCombination<E>> for LinearCombination<E> {
|
||||||
type Output = LinearCombination<E>;
|
type Output = LinearCombination<E>;
|
||||||
|
|
||||||
fn sub(mut self, other: &'a LinearCombination<E>) -> LinearCombination<E> {
|
fn sub(mut self, other: &'a LinearCombination<E>) -> LinearCombination<E> {
|
||||||
@@ -135,7 +144,7 @@ impl<'a, E: Engine> Sub<&'a LinearCombination<E>> for LinearCombination<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, E: Engine> Add<(E::Fr, &'a LinearCombination<E>)> for LinearCombination<E> {
|
impl<'a, E: ScalarEngine> Add<(E::Fr, &'a LinearCombination<E>)> for LinearCombination<E> {
|
||||||
type Output = LinearCombination<E>;
|
type Output = LinearCombination<E>;
|
||||||
|
|
||||||
fn add(mut self, (coeff, other): (E::Fr, &'a LinearCombination<E>)) -> LinearCombination<E> {
|
fn add(mut self, (coeff, other): (E::Fr, &'a LinearCombination<E>)) -> LinearCombination<E> {
|
||||||
@@ -149,7 +158,7 @@ impl<'a, E: Engine> Add<(E::Fr, &'a LinearCombination<E>)> for LinearCombination
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, E: Engine> Sub<(E::Fr, &'a LinearCombination<E>)> for LinearCombination<E> {
|
impl<'a, E: ScalarEngine> Sub<(E::Fr, &'a LinearCombination<E>)> for LinearCombination<E> {
|
||||||
type Output = LinearCombination<E>;
|
type Output = LinearCombination<E>;
|
||||||
|
|
||||||
fn sub(mut self, (coeff, other): (E::Fr, &'a LinearCombination<E>)) -> LinearCombination<E> {
|
fn sub(mut self, (coeff, other): (E::Fr, &'a LinearCombination<E>)) -> LinearCombination<E> {
|
||||||
@@ -181,7 +190,7 @@ pub enum SynthesisError {
|
|||||||
IoError(io::Error),
|
IoError(io::Error),
|
||||||
/// During verification, our verifying key was malformed.
|
/// During verification, our verifying key was malformed.
|
||||||
MalformedVerifyingKey,
|
MalformedVerifyingKey,
|
||||||
/// During CRS generation, we observed an unconstrained auxillary variable
|
/// During CRS generation, we observed an unconstrained auxiliary variable
|
||||||
UnconstrainedVariable
|
UnconstrainedVariable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +210,7 @@ impl Error for SynthesisError {
|
|||||||
SynthesisError::UnexpectedIdentity => "encountered an identity element in the CRS",
|
SynthesisError::UnexpectedIdentity => "encountered an identity element in the CRS",
|
||||||
SynthesisError::IoError(_) => "encountered an I/O error",
|
SynthesisError::IoError(_) => "encountered an I/O error",
|
||||||
SynthesisError::MalformedVerifyingKey => "malformed verifying key",
|
SynthesisError::MalformedVerifyingKey => "malformed verifying key",
|
||||||
SynthesisError::UnconstrainedVariable => "auxillary variable was unconstrained"
|
SynthesisError::UnconstrainedVariable => "auxiliary variable was unconstrained"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,7 +228,7 @@ impl fmt::Display for SynthesisError {
|
|||||||
|
|
||||||
/// Represents a constraint system which can have new variables
|
/// Represents a constraint system which can have new variables
|
||||||
/// allocated and constrains between them formed.
|
/// allocated and constrains between them formed.
|
||||||
pub trait ConstraintSystem<E: Engine>: Sized {
|
pub trait ConstraintSystem<E: ScalarEngine>: Sized {
|
||||||
/// Represents the type of the "root" of this constraint system
|
/// Represents the type of the "root" of this constraint system
|
||||||
/// so that nested namespaces can minimize indirection.
|
/// so that nested namespaces can minimize indirection.
|
||||||
type Root: ConstraintSystem<E>;
|
type Root: ConstraintSystem<E>;
|
||||||
@@ -291,9 +300,9 @@ pub trait ConstraintSystem<E: Engine>: Sized {
|
|||||||
|
|
||||||
/// This is a "namespaced" constraint system which borrows a constraint system (pushing
|
/// This is a "namespaced" constraint system which borrows a constraint system (pushing
|
||||||
/// a namespace context) and, when dropped, pops out of the namespace context.
|
/// a namespace context) and, when dropped, pops out of the namespace context.
|
||||||
pub struct Namespace<'a, E: Engine, CS: ConstraintSystem<E> + 'a>(&'a mut CS, PhantomData<E>);
|
pub struct Namespace<'a, E: ScalarEngine, CS: ConstraintSystem<E> + 'a>(&'a mut CS, PhantomData<E>);
|
||||||
|
|
||||||
impl<'cs, E: Engine, CS: ConstraintSystem<E>> ConstraintSystem<E> for Namespace<'cs, E, CS> {
|
impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for Namespace<'cs, E, CS> {
|
||||||
type Root = CS::Root;
|
type Root = CS::Root;
|
||||||
|
|
||||||
fn one() -> Variable {
|
fn one() -> Variable {
|
||||||
@@ -356,7 +365,7 @@ impl<'cs, E: Engine, CS: ConstraintSystem<E>> ConstraintSystem<E> for Namespace<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, E: Engine, CS: ConstraintSystem<E>> Drop for Namespace<'a, E, CS> {
|
impl<'a, E: ScalarEngine, CS: ConstraintSystem<E>> Drop for Namespace<'a, E, CS> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.get_root().pop_namespace()
|
self.get_root().pop_namespace()
|
||||||
}
|
}
|
||||||
@@ -364,7 +373,7 @@ impl<'a, E: Engine, CS: ConstraintSystem<E>> Drop for Namespace<'a, E, CS> {
|
|||||||
|
|
||||||
/// Convenience implementation of ConstraintSystem<E> for mutable references to
|
/// Convenience implementation of ConstraintSystem<E> for mutable references to
|
||||||
/// constraint systems.
|
/// constraint systems.
|
||||||
impl<'cs, E: Engine, CS: ConstraintSystem<E>> ConstraintSystem<E> for &'cs mut CS {
|
impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for &'cs mut CS {
|
||||||
type Root = CS::Root;
|
type Root = CS::Root;
|
||||||
|
|
||||||
fn one() -> Variable {
|
fn one() -> Variable {
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
//! crossbeam but may be extended in the future to
|
//! crossbeam but may be extended in the future to
|
||||||
//! allow for various parallelism strategies.
|
//! allow for various parallelism strategies.
|
||||||
|
|
||||||
|
#[cfg(feature = "multicore")]
|
||||||
|
mod implementation {
|
||||||
use num_cpus;
|
use num_cpus;
|
||||||
use futures::{Future, IntoFuture, Poll};
|
use futures::{Future, IntoFuture, Poll};
|
||||||
use futures_cpupool::{CpuPool, CpuFuture};
|
use futures_cpupool::{CpuPool, CpuFuture};
|
||||||
@@ -104,3 +106,63 @@ fn test_log2_floor() {
|
|||||||
assert_eq!(log2_floor(7), 2);
|
assert_eq!(log2_floor(7), 2);
|
||||||
assert_eq!(log2_floor(8), 3);
|
assert_eq!(log2_floor(8), 3);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "multicore"))]
|
||||||
|
mod implementation {
|
||||||
|
use futures::{future, Future, IntoFuture, Poll};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Worker;
|
||||||
|
|
||||||
|
impl Worker {
|
||||||
|
pub fn new() -> Worker {
|
||||||
|
Worker
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn log_num_cpus(&self) -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compute<F, R>(&self, f: F) -> R::Future
|
||||||
|
where
|
||||||
|
F: FnOnce() -> R + Send + 'static,
|
||||||
|
R: IntoFuture + 'static,
|
||||||
|
R::Future: Send + 'static,
|
||||||
|
R::Item: Send + 'static,
|
||||||
|
R::Error: Send + 'static,
|
||||||
|
{
|
||||||
|
f().into_future()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scope<F, R>(&self, elements: usize, f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&DummyScope, usize) -> R,
|
||||||
|
{
|
||||||
|
f(&DummyScope, elements)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WorkerFuture<T, E> {
|
||||||
|
future: future::FutureResult<T, E>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Send + 'static, E: Send + 'static> Future for WorkerFuture<T, E> {
|
||||||
|
type Item = T;
|
||||||
|
type Error = E;
|
||||||
|
|
||||||
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
|
self.future.poll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DummyScope;
|
||||||
|
|
||||||
|
impl DummyScope {
|
||||||
|
pub fn spawn<F: FnOnce()>(&self, f: F) {
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use self::implementation::*;
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
use pairing::{
|
use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine};
|
||||||
CurveAffine,
|
use group::{CurveAffine, CurveProjective};
|
||||||
CurveProjective,
|
|
||||||
Engine,
|
|
||||||
PrimeField,
|
|
||||||
Field,
|
|
||||||
PrimeFieldRepr
|
|
||||||
};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::io;
|
use std::io;
|
||||||
use bit_vec::{self, BitVec};
|
use bit_vec::{self, BitVec};
|
||||||
@@ -141,7 +135,7 @@ fn multiexp_inner<Q, D, G, S>(
|
|||||||
pool: &Worker,
|
pool: &Worker,
|
||||||
bases: S,
|
bases: S,
|
||||||
density_map: D,
|
density_map: D,
|
||||||
exponents: Arc<Vec<<<G::Engine as Engine>::Fr as PrimeField>::Repr>>,
|
exponents: Arc<Vec<<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr>>,
|
||||||
mut skip: u32,
|
mut skip: u32,
|
||||||
c: u32,
|
c: u32,
|
||||||
handle_trivial: bool
|
handle_trivial: bool
|
||||||
@@ -167,8 +161,8 @@ fn multiexp_inner<Q, D, G, S>(
|
|||||||
// Create space for the buckets
|
// Create space for the buckets
|
||||||
let mut buckets = vec![<G as CurveAffine>::Projective::zero(); (1 << c) - 1];
|
let mut buckets = vec![<G as CurveAffine>::Projective::zero(); (1 << c) - 1];
|
||||||
|
|
||||||
let zero = <G::Engine as Engine>::Fr::zero().into_repr();
|
let zero = <G::Engine as ScalarEngine>::Fr::zero().into_repr();
|
||||||
let one = <G::Engine as Engine>::Fr::one().into_repr();
|
let one = <G::Engine as ScalarEngine>::Fr::one().into_repr();
|
||||||
|
|
||||||
// Sort the bases into buckets
|
// Sort the bases into buckets
|
||||||
for (&exp, density) in exponents.iter().zip(density_map.as_ref().iter()) {
|
for (&exp, density) in exponents.iter().zip(density_map.as_ref().iter()) {
|
||||||
@@ -211,7 +205,7 @@ fn multiexp_inner<Q, D, G, S>(
|
|||||||
|
|
||||||
skip += c;
|
skip += c;
|
||||||
|
|
||||||
if skip >= <G::Engine as Engine>::Fr::NUM_BITS {
|
if skip >= <G::Engine as ScalarEngine>::Fr::NUM_BITS {
|
||||||
// There isn't another region.
|
// There isn't another region.
|
||||||
Box::new(this)
|
Box::new(this)
|
||||||
} else {
|
} else {
|
||||||
@@ -238,7 +232,7 @@ pub fn multiexp<Q, D, G, S>(
|
|||||||
pool: &Worker,
|
pool: &Worker,
|
||||||
bases: S,
|
bases: S,
|
||||||
density_map: D,
|
density_map: D,
|
||||||
exponents: Arc<Vec<<<G::Engine as Engine>::Fr as PrimeField>::Repr>>
|
exponents: Arc<Vec<<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr>>
|
||||||
) -> Box<Future<Item=<G as CurveAffine>::Projective, Error=SynthesisError>>
|
) -> Box<Future<Item=<G as CurveAffine>::Projective, Error=SynthesisError>>
|
||||||
where for<'a> &'a Q: QueryDensity,
|
where for<'a> &'a Q: QueryDensity,
|
||||||
D: Send + Sync + 'static + Clone + AsRef<Q>,
|
D: Send + Sync + 'static + Clone + AsRef<Q>,
|
||||||
@@ -261,6 +255,7 @@ pub fn multiexp<Q, D, G, S>(
|
|||||||
multiexp_inner(pool, bases, density_map, exponents, 0, c, true)
|
multiexp_inner(pool, bases, density_map, exponents, 0, c, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "pairing")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_with_bls12() {
|
fn test_with_bls12() {
|
||||||
fn naive_multiexp<G: CurveAffine>(
|
fn naive_multiexp<G: CurveAffine>(
|
||||||
@@ -280,12 +275,12 @@ fn test_with_bls12() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
use rand::{self, Rand};
|
use rand::{self, Rand};
|
||||||
use pairing::bls12_381::Bls12;
|
use pairing::{bls12_381::Bls12, Engine};
|
||||||
|
|
||||||
const SAMPLES: usize = 1 << 14;
|
const SAMPLES: usize = 1 << 14;
|
||||||
|
|
||||||
let rng = &mut rand::thread_rng();
|
let rng = &mut rand::thread_rng();
|
||||||
let v = Arc::new((0..SAMPLES).map(|_| <Bls12 as Engine>::Fr::rand(rng).into_repr()).collect::<Vec<_>>());
|
let v = Arc::new((0..SAMPLES).map(|_| <Bls12 as ScalarEngine>::Fr::rand(rng).into_repr()).collect::<Vec<_>>());
|
||||||
let g = Arc::new((0..SAMPLES).map(|_| <Bls12 as Engine>::G1::rand(rng).into_affine()).collect::<Vec<_>>());
|
let g = Arc::new((0..SAMPLES).map(|_| <Bls12 as Engine>::G1::rand(rng).into_affine()).collect::<Vec<_>>());
|
||||||
|
|
||||||
let naive = naive_multiexp(g.clone(), v.clone());
|
let naive = naive_multiexp(g.clone(), v.clone());
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
extern crate bellman;
|
extern crate bellman;
|
||||||
|
extern crate ff;
|
||||||
extern crate pairing;
|
extern crate pairing;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
|
||||||
@@ -9,10 +10,8 @@ use rand::{thread_rng, Rng};
|
|||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
// Bring in some tools for using pairing-friendly curves
|
// Bring in some tools for using pairing-friendly curves
|
||||||
use pairing::{
|
use ff::Field;
|
||||||
Engine,
|
use pairing::Engine;
|
||||||
Field
|
|
||||||
};
|
|
||||||
|
|
||||||
// We're going to use the BLS12-381 pairing-friendly elliptic curve.
|
// We're going to use the BLS12-381 pairing-friendly elliptic curve.
|
||||||
use pairing::bls12_381::{
|
use pairing::bls12_381::{
|
||||||
|
|||||||
3
ff/.gitignore
vendored
Normal file
3
ff/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
target/
|
||||||
|
**/*.rs.bk
|
||||||
|
Cargo.lock
|
||||||
18
ff/Cargo.toml
Normal file
18
ff/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "ff"
|
||||||
|
version = "0.4.0"
|
||||||
|
authors = ["Sean Bowe <ewillbefull@gmail.com>"]
|
||||||
|
description = "Library for building and interfacing with finite fields"
|
||||||
|
documentation = "https://docs.rs/ff/"
|
||||||
|
homepage = "https://github.com/ebfull/ff"
|
||||||
|
license = "MIT/Apache-2.0"
|
||||||
|
repository = "https://github.com/ebfull/ff"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
byteorder = "1"
|
||||||
|
rand = "0.4"
|
||||||
|
ff_derive = { version = "0.3.0", path = "ff_derive", optional = true }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
derive = ["ff_derive"]
|
||||||
202
ff/LICENSE-APACHE
Normal file
202
ff/LICENSE-APACHE
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
21
ff/LICENSE-MIT
Normal file
21
ff/LICENSE-MIT
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2017 Sean Bowe
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
60
ff/README.md
Normal file
60
ff/README.md
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# ff
|
||||||
|
|
||||||
|
`ff` is a finite field library written in pure Rust, with no `unsafe{}` code.
|
||||||
|
|
||||||
|
## Disclaimers
|
||||||
|
|
||||||
|
* This library does not provide constant-time guarantees.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Add the `ff` crate to your `Cargo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
ff = "0.4"
|
||||||
|
```
|
||||||
|
|
||||||
|
The `ff` crate contains `Field`, `PrimeField`, `PrimeFieldRepr` and `SqrtField` traits. See the **[documentation](https://docs.rs/ff/0.4.0/ff/)** for more.
|
||||||
|
|
||||||
|
### #![derive(PrimeField)]
|
||||||
|
|
||||||
|
If you need an implementation of a prime field, this library also provides a procedural macro that will expand into an efficient implementation of a prime field when supplied with the modulus. `PrimeFieldGenerator` must be an element of Fp of p-1 order, that is also quadratic nonresidue.
|
||||||
|
|
||||||
|
First, enable the `derive` crate feature:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
ff = { version = "0.4", features = ["derive"] }
|
||||||
|
```
|
||||||
|
|
||||||
|
And then use the macro like so:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
extern crate rand;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate ff;
|
||||||
|
|
||||||
|
#[derive(PrimeField)]
|
||||||
|
#[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"]
|
||||||
|
#[PrimeFieldGenerator = "7"]
|
||||||
|
struct Fp(FpRepr);
|
||||||
|
```
|
||||||
|
|
||||||
|
And that's it! `Fp` now implements `Field` and `PrimeField`. `Fp` will also implement `SqrtField` if supported. The library implements `FpRepr` itself and derives `PrimeFieldRepr` for it.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Licensed under either of
|
||||||
|
|
||||||
|
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
at your option.
|
||||||
|
|
||||||
|
### Contribution
|
||||||
|
|
||||||
|
Unless you explicitly state otherwise, any contribution intentionally
|
||||||
|
submitted for inclusion in the work by you, as defined in the Apache-2.0
|
||||||
|
license, shall be dual licensed as above, without any additional terms or
|
||||||
|
conditions.
|
||||||
20
ff/ff_derive/Cargo.toml
Normal file
20
ff/ff_derive/Cargo.toml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "ff_derive"
|
||||||
|
version = "0.3.0"
|
||||||
|
authors = ["Sean Bowe <ewillbefull@gmail.com>"]
|
||||||
|
description = "Procedural macro library used to build custom prime field implementations"
|
||||||
|
documentation = "https://docs.rs/ff/"
|
||||||
|
homepage = "https://github.com/ebfull/ff"
|
||||||
|
license = "MIT/Apache-2.0"
|
||||||
|
repository = "https://github.com/ebfull/ff"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
num-bigint = "0.2"
|
||||||
|
num-traits = "0.2"
|
||||||
|
num-integer = "0.1"
|
||||||
|
proc-macro2 = "0.4"
|
||||||
|
quote = "0.6"
|
||||||
|
syn = "0.14"
|
||||||
1065
ff/ff_derive/src/lib.rs
Normal file
1065
ff/ff_derive/src/lib.rs
Normal file
File diff suppressed because it is too large
Load Diff
393
ff/src/lib.rs
Normal file
393
ff/src/lib.rs
Normal file
@@ -0,0 +1,393 @@
|
|||||||
|
#![allow(unused_imports)]
|
||||||
|
|
||||||
|
extern crate byteorder;
|
||||||
|
extern crate rand;
|
||||||
|
|
||||||
|
#[cfg(feature = "derive")]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate ff_derive;
|
||||||
|
|
||||||
|
#[cfg(feature = "derive")]
|
||||||
|
pub use ff_derive::*;
|
||||||
|
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
|
use std::io::{self, Read, Write};
|
||||||
|
|
||||||
|
/// This trait represents an element of a field.
|
||||||
|
pub trait Field:
|
||||||
|
Sized + Eq + Copy + Clone + Send + Sync + fmt::Debug + fmt::Display + 'static + rand::Rand
|
||||||
|
{
|
||||||
|
/// Returns the zero element of the field, the additive identity.
|
||||||
|
fn zero() -> Self;
|
||||||
|
|
||||||
|
/// Returns the one element of the field, the multiplicative identity.
|
||||||
|
fn one() -> Self;
|
||||||
|
|
||||||
|
/// Returns true iff this element is zero.
|
||||||
|
fn is_zero(&self) -> bool;
|
||||||
|
|
||||||
|
/// Squares this element.
|
||||||
|
fn square(&mut self);
|
||||||
|
|
||||||
|
/// Doubles this element.
|
||||||
|
fn double(&mut self);
|
||||||
|
|
||||||
|
/// Negates this element.
|
||||||
|
fn negate(&mut self);
|
||||||
|
|
||||||
|
/// Adds another element to this element.
|
||||||
|
fn add_assign(&mut self, other: &Self);
|
||||||
|
|
||||||
|
/// Subtracts another element from this element.
|
||||||
|
fn sub_assign(&mut self, other: &Self);
|
||||||
|
|
||||||
|
/// Multiplies another element by this element.
|
||||||
|
fn mul_assign(&mut self, other: &Self);
|
||||||
|
|
||||||
|
/// Computes the multiplicative inverse of this element, if nonzero.
|
||||||
|
fn inverse(&self) -> Option<Self>;
|
||||||
|
|
||||||
|
/// Exponentiates this element by a power of the base prime modulus via
|
||||||
|
/// the Frobenius automorphism.
|
||||||
|
fn frobenius_map(&mut self, power: usize);
|
||||||
|
|
||||||
|
/// Exponentiates this element by a number represented with `u64` limbs,
|
||||||
|
/// least significant digit first.
|
||||||
|
fn pow<S: AsRef<[u64]>>(&self, exp: S) -> Self {
|
||||||
|
let mut res = Self::one();
|
||||||
|
|
||||||
|
let mut found_one = false;
|
||||||
|
|
||||||
|
for i in BitIterator::new(exp) {
|
||||||
|
if found_one {
|
||||||
|
res.square();
|
||||||
|
} else {
|
||||||
|
found_one = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if i {
|
||||||
|
res.mul_assign(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This trait represents an element of a field that has a square root operation described for it.
|
||||||
|
pub trait SqrtField: Field {
|
||||||
|
/// Returns the Legendre symbol of the field element.
|
||||||
|
fn legendre(&self) -> LegendreSymbol;
|
||||||
|
|
||||||
|
/// Returns the square root of the field element, if it is
|
||||||
|
/// quadratic residue.
|
||||||
|
fn sqrt(&self) -> Option<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This trait represents a wrapper around a biginteger which can encode any element of a particular
|
||||||
|
/// prime field. It is a smart wrapper around a sequence of `u64` limbs, least-significant digit
|
||||||
|
/// first.
|
||||||
|
pub trait PrimeFieldRepr:
|
||||||
|
Sized
|
||||||
|
+ Copy
|
||||||
|
+ Clone
|
||||||
|
+ Eq
|
||||||
|
+ Ord
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ Default
|
||||||
|
+ fmt::Debug
|
||||||
|
+ fmt::Display
|
||||||
|
+ 'static
|
||||||
|
+ rand::Rand
|
||||||
|
+ AsRef<[u64]>
|
||||||
|
+ AsMut<[u64]>
|
||||||
|
+ From<u64>
|
||||||
|
{
|
||||||
|
/// Subtract another represetation from this one.
|
||||||
|
fn sub_noborrow(&mut self, other: &Self);
|
||||||
|
|
||||||
|
/// Add another representation to this one.
|
||||||
|
fn add_nocarry(&mut self, other: &Self);
|
||||||
|
|
||||||
|
/// Compute the number of bits needed to encode this number. Always a
|
||||||
|
/// multiple of 64.
|
||||||
|
fn num_bits(&self) -> u32;
|
||||||
|
|
||||||
|
/// Returns true iff this number is zero.
|
||||||
|
fn is_zero(&self) -> bool;
|
||||||
|
|
||||||
|
/// Returns true iff this number is odd.
|
||||||
|
fn is_odd(&self) -> bool;
|
||||||
|
|
||||||
|
/// Returns true iff this number is even.
|
||||||
|
fn is_even(&self) -> bool;
|
||||||
|
|
||||||
|
/// Performs a rightwise bitshift of this number, effectively dividing
|
||||||
|
/// it by 2.
|
||||||
|
fn div2(&mut self);
|
||||||
|
|
||||||
|
/// Performs a rightwise bitshift of this number by some amount.
|
||||||
|
fn shr(&mut self, amt: u32);
|
||||||
|
|
||||||
|
/// Performs a leftwise bitshift of this number, effectively multiplying
|
||||||
|
/// it by 2. Overflow is ignored.
|
||||||
|
fn mul2(&mut self);
|
||||||
|
|
||||||
|
/// Performs a leftwise bitshift of this number by some amount.
|
||||||
|
fn shl(&mut self, amt: u32);
|
||||||
|
|
||||||
|
/// Writes this `PrimeFieldRepr` as a big endian integer.
|
||||||
|
fn write_be<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
|
use byteorder::{BigEndian, WriteBytesExt};
|
||||||
|
|
||||||
|
for digit in self.as_ref().iter().rev() {
|
||||||
|
writer.write_u64::<BigEndian>(*digit)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads a big endian integer into this representation.
|
||||||
|
fn read_be<R: Read>(&mut self, mut reader: R) -> io::Result<()> {
|
||||||
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
|
|
||||||
|
for digit in self.as_mut().iter_mut().rev() {
|
||||||
|
*digit = reader.read_u64::<BigEndian>()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes this `PrimeFieldRepr` as a little endian integer.
|
||||||
|
fn write_le<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
|
use byteorder::{LittleEndian, WriteBytesExt};
|
||||||
|
|
||||||
|
for digit in self.as_ref().iter() {
|
||||||
|
writer.write_u64::<LittleEndian>(*digit)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads a little endian integer into this representation.
|
||||||
|
fn read_le<R: Read>(&mut self, mut reader: R) -> io::Result<()> {
|
||||||
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
|
|
||||||
|
for digit in self.as_mut().iter_mut() {
|
||||||
|
*digit = reader.read_u64::<LittleEndian>()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum LegendreSymbol {
|
||||||
|
Zero = 0,
|
||||||
|
QuadraticResidue = 1,
|
||||||
|
QuadraticNonResidue = -1,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An error that may occur when trying to interpret a `PrimeFieldRepr` as a
|
||||||
|
/// `PrimeField` element.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PrimeFieldDecodingError {
|
||||||
|
/// The encoded value is not in the field
|
||||||
|
NotInField(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for PrimeFieldDecodingError {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
match *self {
|
||||||
|
PrimeFieldDecodingError::NotInField(..) => "not an element of the field",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for PrimeFieldDecodingError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
match *self {
|
||||||
|
PrimeFieldDecodingError::NotInField(ref repr) => {
|
||||||
|
write!(f, "{} is not an element of the field", repr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This represents an element of a prime field.
|
||||||
|
pub trait PrimeField: Field {
|
||||||
|
/// The prime field can be converted back and forth into this biginteger
|
||||||
|
/// representation.
|
||||||
|
type Repr: PrimeFieldRepr + From<Self>;
|
||||||
|
|
||||||
|
/// Interpret a string of numbers as a (congruent) prime field element.
|
||||||
|
/// Does not accept unnecessary leading zeroes or a blank string.
|
||||||
|
fn from_str(s: &str) -> Option<Self> {
|
||||||
|
if s.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if s == "0" {
|
||||||
|
return Some(Self::zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut res = Self::zero();
|
||||||
|
|
||||||
|
let ten = Self::from_repr(Self::Repr::from(10)).unwrap();
|
||||||
|
|
||||||
|
let mut first_digit = true;
|
||||||
|
|
||||||
|
for c in s.chars() {
|
||||||
|
match c.to_digit(10) {
|
||||||
|
Some(c) => {
|
||||||
|
if first_digit {
|
||||||
|
if c == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
first_digit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.mul_assign(&ten);
|
||||||
|
res.add_assign(&Self::from_repr(Self::Repr::from(u64::from(c))).unwrap());
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert this prime field element into a biginteger representation.
|
||||||
|
fn from_repr(Self::Repr) -> Result<Self, PrimeFieldDecodingError>;
|
||||||
|
|
||||||
|
/// Convert a biginteger representation into a prime field element, if
|
||||||
|
/// the number is an element of the field.
|
||||||
|
fn into_repr(&self) -> Self::Repr;
|
||||||
|
|
||||||
|
/// Returns the field characteristic; the modulus.
|
||||||
|
fn char() -> Self::Repr;
|
||||||
|
|
||||||
|
/// How many bits are needed to represent an element of this field.
|
||||||
|
const NUM_BITS: u32;
|
||||||
|
|
||||||
|
/// How many bits of information can be reliably stored in the field element.
|
||||||
|
const CAPACITY: u32;
|
||||||
|
|
||||||
|
/// Returns the multiplicative generator of `char()` - 1 order. This element
|
||||||
|
/// must also be quadratic nonresidue.
|
||||||
|
fn multiplicative_generator() -> Self;
|
||||||
|
|
||||||
|
/// 2^s * t = `char()` - 1 with t odd.
|
||||||
|
const S: u32;
|
||||||
|
|
||||||
|
/// Returns the 2^s root of unity computed by exponentiating the `multiplicative_generator()`
|
||||||
|
/// by t.
|
||||||
|
fn root_of_unity() -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
|
||||||
|
/// with well-defined relationships. Specific relationships (for example, a
|
||||||
|
/// pairing-friendly curve) can be defined in a subtrait.
|
||||||
|
pub trait ScalarEngine: Sized + 'static + Clone {
|
||||||
|
/// This is the scalar field of the engine's groups.
|
||||||
|
type Fr: PrimeField + SqrtField;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BitIterator<E> {
|
||||||
|
t: E,
|
||||||
|
n: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: AsRef<[u64]>> BitIterator<E> {
|
||||||
|
pub fn new(t: E) -> Self {
|
||||||
|
let n = t.as_ref().len() * 64;
|
||||||
|
|
||||||
|
BitIterator { t, n }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: AsRef<[u64]>> Iterator for BitIterator<E> {
|
||||||
|
type Item = bool;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<bool> {
|
||||||
|
if self.n == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
self.n -= 1;
|
||||||
|
let part = self.n / 64;
|
||||||
|
let bit = self.n - (64 * part);
|
||||||
|
|
||||||
|
Some(self.t.as_ref()[part] & (1 << bit) > 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bit_iterator() {
|
||||||
|
let mut a = BitIterator::new([0xa953d79b83f6ab59, 0x6dea2059e200bd39]);
|
||||||
|
let expected = "01101101111010100010000001011001111000100000000010111101001110011010100101010011110101111001101110000011111101101010101101011001";
|
||||||
|
|
||||||
|
for e in expected.chars() {
|
||||||
|
assert!(a.next().unwrap() == (e == '1'));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(a.next().is_none());
|
||||||
|
|
||||||
|
let expected = "1010010101111110101010000101101011101000011101110101001000011001100100100011011010001011011011010001011011101100110100111011010010110001000011110100110001100110011101101000101100011100100100100100001010011101010111110011101011000011101000111011011101011001";
|
||||||
|
|
||||||
|
let mut a = BitIterator::new([
|
||||||
|
0x429d5f3ac3a3b759,
|
||||||
|
0xb10f4c66768b1c92,
|
||||||
|
0x92368b6d16ecd3b4,
|
||||||
|
0xa57ea85ae8775219,
|
||||||
|
]);
|
||||||
|
|
||||||
|
for e in expected.chars() {
|
||||||
|
assert!(a.next().unwrap() == (e == '1'));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(a.next().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use self::arith_impl::*;
|
||||||
|
|
||||||
|
mod arith_impl {
|
||||||
|
/// Calculate a - b - borrow, returning the result and modifying
|
||||||
|
/// the borrow value.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn sbb(a: u64, b: u64, borrow: &mut u64) -> u64 {
|
||||||
|
let tmp = (1u128 << 64) + u128::from(a) - u128::from(b) - u128::from(*borrow);
|
||||||
|
|
||||||
|
*borrow = if tmp >> 64 == 0 { 1 } else { 0 };
|
||||||
|
|
||||||
|
tmp as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate a + b + carry, returning the sum and modifying the
|
||||||
|
/// carry value.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn adc(a: u64, b: u64, carry: &mut u64) -> u64 {
|
||||||
|
let tmp = u128::from(a) + u128::from(b) + u128::from(*carry);
|
||||||
|
|
||||||
|
*carry = (tmp >> 64) as u64;
|
||||||
|
|
||||||
|
tmp as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate a + (b * c) + carry, returning the least significant digit
|
||||||
|
/// and setting carry to the most significant digit.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 {
|
||||||
|
let tmp = (u128::from(a)) + u128::from(b) * u128::from(c) + u128::from(*carry);
|
||||||
|
|
||||||
|
*carry = (tmp >> 64) as u64;
|
||||||
|
|
||||||
|
tmp as u64
|
||||||
|
}
|
||||||
|
}
|
||||||
3
group/.gitignore
vendored
Normal file
3
group/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
/target
|
||||||
|
**/*.rs.bk
|
||||||
|
Cargo.lock
|
||||||
14
group/COPYRIGHT
Normal file
14
group/COPYRIGHT
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
Copyrights in the "group" library are retained by their contributors. No
|
||||||
|
copyright assignment is required to contribute to the "group" library.
|
||||||
|
|
||||||
|
The "group" library is licensed under either of
|
||||||
|
|
||||||
|
* Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
* MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
at your option.
|
||||||
|
|
||||||
|
Unless you explicitly state otherwise, any contribution intentionally
|
||||||
|
submitted for inclusion in the work by you, as defined in the Apache-2.0
|
||||||
|
license, shall be dual licensed as above, without any additional terms or
|
||||||
|
conditions.
|
||||||
17
group/Cargo.toml
Normal file
17
group/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "group"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = [
|
||||||
|
"Sean Bowe <ewillbefull@gmail.com>",
|
||||||
|
"Jack Grigg <jack@z.cash>",
|
||||||
|
]
|
||||||
|
license = "MIT/Apache-2.0"
|
||||||
|
|
||||||
|
description = "Elliptic curve group traits and utilities"
|
||||||
|
documentation = "https://docs.rs/group/"
|
||||||
|
homepage = "https://github.com/ebfull/group"
|
||||||
|
repository = "https://github.com/ebfull/group"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ff = { path = "../ff" }
|
||||||
|
rand = "0.4"
|
||||||
201
group/LICENSE-APACHE
Normal file
201
group/LICENSE-APACHE
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
23
group/LICENSE-MIT
Normal file
23
group/LICENSE-MIT
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
Permission is hereby granted, free of charge, to any
|
||||||
|
person obtaining a copy of this software and associated
|
||||||
|
documentation files (the "Software"), to deal in the
|
||||||
|
Software without restriction, including without
|
||||||
|
limitation the rights to use, copy, modify, merge,
|
||||||
|
publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software
|
||||||
|
is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice
|
||||||
|
shall be included in all copies or substantial portions
|
||||||
|
of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||||
|
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
|
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||||
|
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
17
group/README.md
Normal file
17
group/README.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# group [](https://crates.io/crates/group) #
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Licensed under either of
|
||||||
|
|
||||||
|
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
at your option.
|
||||||
|
|
||||||
|
### Contribution
|
||||||
|
|
||||||
|
Unless you explicitly state otherwise, any contribution intentionally
|
||||||
|
submitted for inclusion in the work by you, as defined in the Apache-2.0
|
||||||
|
license, shall be dual licensed as above, without any additional terms or
|
||||||
|
conditions.
|
||||||
196
group/src/lib.rs
Normal file
196
group/src/lib.rs
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
extern crate ff;
|
||||||
|
extern crate rand;
|
||||||
|
|
||||||
|
use ff::{PrimeField, PrimeFieldDecodingError, ScalarEngine, SqrtField};
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
pub mod tests;
|
||||||
|
|
||||||
|
mod wnaf;
|
||||||
|
pub use self::wnaf::Wnaf;
|
||||||
|
|
||||||
|
/// Projective representation of an elliptic curve point guaranteed to be
|
||||||
|
/// in the correct prime order subgroup.
|
||||||
|
pub trait CurveProjective:
|
||||||
|
PartialEq
|
||||||
|
+ Eq
|
||||||
|
+ Sized
|
||||||
|
+ Copy
|
||||||
|
+ Clone
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ fmt::Debug
|
||||||
|
+ fmt::Display
|
||||||
|
+ rand::Rand
|
||||||
|
+ 'static
|
||||||
|
{
|
||||||
|
type Engine: ScalarEngine<Fr = Self::Scalar>;
|
||||||
|
type Scalar: PrimeField + SqrtField;
|
||||||
|
type Base: SqrtField;
|
||||||
|
type Affine: CurveAffine<Projective = Self, Scalar = Self::Scalar>;
|
||||||
|
|
||||||
|
/// Returns the additive identity.
|
||||||
|
fn zero() -> Self;
|
||||||
|
|
||||||
|
/// Returns a fixed generator of unknown exponent.
|
||||||
|
fn one() -> Self;
|
||||||
|
|
||||||
|
/// Determines if this point is the point at infinity.
|
||||||
|
fn is_zero(&self) -> bool;
|
||||||
|
|
||||||
|
/// Normalizes a slice of projective elements so that
|
||||||
|
/// conversion to affine is cheap.
|
||||||
|
fn batch_normalization(v: &mut [Self]);
|
||||||
|
|
||||||
|
/// Checks if the point is already "normalized" so that
|
||||||
|
/// cheap affine conversion is possible.
|
||||||
|
fn is_normalized(&self) -> bool;
|
||||||
|
|
||||||
|
/// Doubles this element.
|
||||||
|
fn double(&mut self);
|
||||||
|
|
||||||
|
/// Adds another element to this element.
|
||||||
|
fn add_assign(&mut self, other: &Self);
|
||||||
|
|
||||||
|
/// Subtracts another element from this element.
|
||||||
|
fn sub_assign(&mut self, other: &Self) {
|
||||||
|
let mut tmp = *other;
|
||||||
|
tmp.negate();
|
||||||
|
self.add_assign(&tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds an affine element to this element.
|
||||||
|
fn add_assign_mixed(&mut self, other: &Self::Affine);
|
||||||
|
|
||||||
|
/// Negates this element.
|
||||||
|
fn negate(&mut self);
|
||||||
|
|
||||||
|
/// Performs scalar multiplication of this element.
|
||||||
|
fn mul_assign<S: Into<<Self::Scalar as PrimeField>::Repr>>(&mut self, other: S);
|
||||||
|
|
||||||
|
/// Converts this element into its affine representation.
|
||||||
|
fn into_affine(&self) -> Self::Affine;
|
||||||
|
|
||||||
|
/// Recommends a wNAF window table size given a scalar. Always returns a number
|
||||||
|
/// between 2 and 22, inclusive.
|
||||||
|
fn recommended_wnaf_for_scalar(scalar: <Self::Scalar as PrimeField>::Repr) -> usize;
|
||||||
|
|
||||||
|
/// Recommends a wNAF window size given the number of scalars you intend to multiply
|
||||||
|
/// a base by. Always returns a number between 2 and 22, inclusive.
|
||||||
|
fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Affine representation of an elliptic curve point guaranteed to be
|
||||||
|
/// in the correct prime order subgroup.
|
||||||
|
pub trait CurveAffine:
|
||||||
|
Copy + Clone + Sized + Send + Sync + fmt::Debug + fmt::Display + PartialEq + Eq + 'static
|
||||||
|
{
|
||||||
|
type Engine: ScalarEngine<Fr = Self::Scalar>;
|
||||||
|
type Scalar: PrimeField + SqrtField;
|
||||||
|
type Base: SqrtField;
|
||||||
|
type Projective: CurveProjective<Affine = Self, Scalar = Self::Scalar>;
|
||||||
|
type Uncompressed: EncodedPoint<Affine = Self>;
|
||||||
|
type Compressed: EncodedPoint<Affine = Self>;
|
||||||
|
|
||||||
|
/// Returns the additive identity.
|
||||||
|
fn zero() -> Self;
|
||||||
|
|
||||||
|
/// Returns a fixed generator of unknown exponent.
|
||||||
|
fn one() -> Self;
|
||||||
|
|
||||||
|
/// Determines if this point represents the point at infinity; the
|
||||||
|
/// additive identity.
|
||||||
|
fn is_zero(&self) -> bool;
|
||||||
|
|
||||||
|
/// Negates this element.
|
||||||
|
fn negate(&mut self);
|
||||||
|
|
||||||
|
/// Performs scalar multiplication of this element with mixed addition.
|
||||||
|
fn mul<S: Into<<Self::Scalar as PrimeField>::Repr>>(&self, other: S) -> Self::Projective;
|
||||||
|
|
||||||
|
/// Converts this element into its affine representation.
|
||||||
|
fn into_projective(&self) -> Self::Projective;
|
||||||
|
|
||||||
|
/// Converts this element into its compressed encoding, so long as it's not
|
||||||
|
/// the point at infinity.
|
||||||
|
fn into_compressed(&self) -> Self::Compressed {
|
||||||
|
<Self::Compressed as EncodedPoint>::from_affine(*self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts this element into its uncompressed encoding, so long as it's not
|
||||||
|
/// the point at infinity.
|
||||||
|
fn into_uncompressed(&self) -> Self::Uncompressed {
|
||||||
|
<Self::Uncompressed as EncodedPoint>::from_affine(*self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An encoded elliptic curve point, which should essentially wrap a `[u8; N]`.
|
||||||
|
pub trait EncodedPoint:
|
||||||
|
Sized + Send + Sync + AsRef<[u8]> + AsMut<[u8]> + Clone + Copy + 'static
|
||||||
|
{
|
||||||
|
type Affine: CurveAffine;
|
||||||
|
|
||||||
|
/// Creates an empty representation.
|
||||||
|
fn empty() -> Self;
|
||||||
|
|
||||||
|
/// Returns the number of bytes consumed by this representation.
|
||||||
|
fn size() -> usize;
|
||||||
|
|
||||||
|
/// Converts an `EncodedPoint` into a `CurveAffine` element,
|
||||||
|
/// if the encoding represents a valid element.
|
||||||
|
fn into_affine(&self) -> Result<Self::Affine, GroupDecodingError>;
|
||||||
|
|
||||||
|
/// Converts an `EncodedPoint` into a `CurveAffine` element,
|
||||||
|
/// without guaranteeing that the encoding represents a valid
|
||||||
|
/// element. This is useful when the caller knows the encoding is
|
||||||
|
/// valid already.
|
||||||
|
///
|
||||||
|
/// If the encoding is invalid, this can break API invariants,
|
||||||
|
/// so caution is strongly encouraged.
|
||||||
|
fn into_affine_unchecked(&self) -> Result<Self::Affine, GroupDecodingError>;
|
||||||
|
|
||||||
|
/// Creates an `EncodedPoint` from an affine point, as long as the
|
||||||
|
/// point is not the point at infinity.
|
||||||
|
fn from_affine(affine: Self::Affine) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An error that may occur when trying to decode an `EncodedPoint`.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum GroupDecodingError {
|
||||||
|
/// The coordinate(s) do not lie on the curve.
|
||||||
|
NotOnCurve,
|
||||||
|
/// The element is not part of the r-order subgroup.
|
||||||
|
NotInSubgroup,
|
||||||
|
/// One of the coordinates could not be decoded
|
||||||
|
CoordinateDecodingError(&'static str, PrimeFieldDecodingError),
|
||||||
|
/// The compression mode of the encoded element was not as expected
|
||||||
|
UnexpectedCompressionMode,
|
||||||
|
/// The encoding contained bits that should not have been set
|
||||||
|
UnexpectedInformation,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for GroupDecodingError {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
match *self {
|
||||||
|
GroupDecodingError::NotOnCurve => "coordinate(s) do not lie on the curve",
|
||||||
|
GroupDecodingError::NotInSubgroup => "the element is not part of an r-order subgroup",
|
||||||
|
GroupDecodingError::CoordinateDecodingError(..) => "coordinate(s) could not be decoded",
|
||||||
|
GroupDecodingError::UnexpectedCompressionMode => {
|
||||||
|
"encoding has unexpected compression mode"
|
||||||
|
}
|
||||||
|
GroupDecodingError::UnexpectedInformation => "encoding has unexpected information",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for GroupDecodingError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
match *self {
|
||||||
|
GroupDecodingError::CoordinateDecodingError(description, ref err) => {
|
||||||
|
write!(f, "{} decoding error: {}", description, err)
|
||||||
|
}
|
||||||
|
_ => write!(f, "{}", self.description()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use rand::{Rand, Rng, SeedableRng, XorShiftRng};
|
use rand::{Rand, Rng, SeedableRng, XorShiftRng};
|
||||||
|
|
||||||
use {CurveAffine, CurveProjective, EncodedPoint, Field};
|
use {CurveAffine, CurveProjective, EncodedPoint};
|
||||||
|
|
||||||
pub fn curve_tests<G: CurveProjective>() {
|
pub fn curve_tests<G: CurveProjective>() {
|
||||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
@@ -47,8 +47,7 @@ pub fn curve_tests<G: CurveProjective>() {
|
|||||||
{
|
{
|
||||||
let a = G::rand(&mut rng);
|
let a = G::rand(&mut rng);
|
||||||
let b = a.into_affine().into_projective();
|
let b = a.into_affine().into_projective();
|
||||||
let c = a
|
let c = a.into_affine()
|
||||||
.into_affine()
|
|
||||||
.into_projective()
|
.into_projective()
|
||||||
.into_affine()
|
.into_affine()
|
||||||
.into_projective();
|
.into_projective();
|
||||||
@@ -66,8 +65,9 @@ pub fn curve_tests<G: CurveProjective>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn random_wnaf_tests<G: CurveProjective>() {
|
fn random_wnaf_tests<G: CurveProjective>() {
|
||||||
|
use ff::PrimeField;
|
||||||
|
|
||||||
use wnaf::*;
|
use wnaf::*;
|
||||||
use PrimeField;
|
|
||||||
|
|
||||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
|
||||||
@@ -179,6 +179,8 @@ fn random_wnaf_tests<G: CurveProjective>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn random_negation_tests<G: CurveProjective>() {
|
fn random_negation_tests<G: CurveProjective>() {
|
||||||
|
use ff::Field;
|
||||||
|
|
||||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
|
||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
@@ -373,8 +375,7 @@ fn random_transformation_tests<G: CurveProjective>() {
|
|||||||
v[s] = v[s].into_affine().into_projective();
|
v[s] = v[s].into_affine().into_projective();
|
||||||
}
|
}
|
||||||
|
|
||||||
let expected_v = v
|
let expected_v = v.iter()
|
||||||
.iter()
|
|
||||||
.map(|v| v.into_affine().into_projective())
|
.map(|v| v.into_affine().into_projective())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
G::batch_normalization(&mut v);
|
G::batch_normalization(&mut v);
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
use super::{CurveProjective, PrimeField, PrimeFieldRepr};
|
use ff::{PrimeField, PrimeFieldRepr};
|
||||||
|
|
||||||
|
use super::CurveProjective;
|
||||||
|
|
||||||
/// Replaces the contents of `table` with a w-NAF window table for the given window size.
|
/// Replaces the contents of `table` with a w-NAF window table for the given window size.
|
||||||
pub(crate) fn wnaf_table<G: CurveProjective>(table: &mut Vec<G>, mut base: G, window: usize) {
|
pub(crate) fn wnaf_table<G: CurveProjective>(table: &mut Vec<G>, mut base: G, window: usize) {
|
||||||
@@ -15,12 +15,16 @@ crate-type = ["staticlib"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bellman = { path = "../bellman" }
|
bellman = { path = "../bellman" }
|
||||||
|
ff = { path = "../ff" }
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
pairing = { path = "../pairing" }
|
pairing = { path = "../pairing" }
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
rand = "0.4"
|
rand = "0.4"
|
||||||
sapling-crypto = { path = "../sapling-crypto" }
|
sapling-crypto = { path = "../sapling-crypto" }
|
||||||
|
zcash_primitives = { path = "../zcash_primitives" }
|
||||||
|
zcash_proofs = { path = "../zcash_proofs" }
|
||||||
|
zip32 = { path = "../zip32" }
|
||||||
|
|
||||||
[dependencies.blake2-rfc]
|
[dependencies.blake2-rfc]
|
||||||
git = "https://github.com/gtank/blake2-rfc"
|
git = "https://github.com/gtank/blake2-rfc"
|
||||||
|
|||||||
@@ -4,6 +4,12 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
#ifdef WIN32
|
||||||
|
typedef uint16_t codeunit;
|
||||||
|
#else
|
||||||
|
typedef uint8_t codeunit;
|
||||||
|
#endif
|
||||||
|
|
||||||
void librustzcash_to_scalar(const unsigned char *input, unsigned char *result);
|
void librustzcash_to_scalar(const unsigned char *input, unsigned char *result);
|
||||||
|
|
||||||
void librustzcash_ask_to_ak(const unsigned char *ask, unsigned char *result);
|
void librustzcash_ask_to_ak(const unsigned char *ask, unsigned char *result);
|
||||||
@@ -19,11 +25,14 @@ extern "C" {
|
|||||||
/// Loads the zk-SNARK parameters into memory and saves
|
/// Loads the zk-SNARK parameters into memory and saves
|
||||||
/// paths as necessary. Only called once.
|
/// paths as necessary. Only called once.
|
||||||
void librustzcash_init_zksnark_params(
|
void librustzcash_init_zksnark_params(
|
||||||
const char* spend_path,
|
const codeunit* spend_path,
|
||||||
|
size_t spend_path_len,
|
||||||
const char* spend_hash,
|
const char* spend_hash,
|
||||||
const char* output_path,
|
const codeunit* output_path,
|
||||||
|
size_t output_path_len,
|
||||||
const char* output_hash,
|
const char* output_hash,
|
||||||
const char* sprout_path,
|
const codeunit* sprout_path,
|
||||||
|
size_t sprout_path_len,
|
||||||
const char* sprout_hash
|
const char* sprout_hash
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -270,6 +279,35 @@ extern "C" {
|
|||||||
uint64_t vpub_old,
|
uint64_t vpub_old,
|
||||||
uint64_t vpub_new
|
uint64_t vpub_new
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Derive the master ExtendedSpendingKey from a seed.
|
||||||
|
void librustzcash_zip32_xsk_master(
|
||||||
|
const unsigned char *seed,
|
||||||
|
size_t seedlen,
|
||||||
|
unsigned char *xsk_master
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Derive a child ExtendedSpendingKey from a parent.
|
||||||
|
void librustzcash_zip32_xsk_derive(
|
||||||
|
const unsigned char *xsk_parent,
|
||||||
|
uint32_t i,
|
||||||
|
unsigned char *xsk_i
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Derive a child ExtendedFullViewingKey from a parent.
|
||||||
|
bool librustzcash_zip32_xfvk_derive(
|
||||||
|
const unsigned char *xfvk_parent,
|
||||||
|
uint32_t i,
|
||||||
|
unsigned char *xfvk_i
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Derive a PaymentAddress from an ExtendedFullViewingKey.
|
||||||
|
bool librustzcash_zip32_xfvk_address(
|
||||||
|
const unsigned char *xfvk,
|
||||||
|
const unsigned char *j,
|
||||||
|
unsigned char *j_ret,
|
||||||
|
unsigned char *addr_ret
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // LIBRUSTZCASH_INCLUDE_H_
|
#endif // LIBRUSTZCASH_INCLUDE_H_
|
||||||
|
|||||||
@@ -149,8 +149,7 @@ fn expand_array(vin: &[u8], bit_len: usize, byte_pad: usize) -> Vec<u8> {
|
|||||||
vout[j + x] = ((
|
vout[j + x] = ((
|
||||||
// Big-endian
|
// Big-endian
|
||||||
acc_value >> (acc_bits + (8 * (out_width - x - 1)))
|
acc_value >> (acc_bits + (8 * (out_width - x - 1)))
|
||||||
)
|
) & (
|
||||||
& (
|
|
||||||
// Apply bit_len_mask across byte boundaries
|
// Apply bit_len_mask across byte boundaries
|
||||||
(bit_len_mask >> (8 * (out_width - x - 1))) & 0xFF
|
(bit_len_mask >> (8 * (out_width - x - 1))) & 0xFF
|
||||||
)) as u8;
|
)) as u8;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
|
use ff::{PrimeField, PrimeFieldRepr};
|
||||||
use pairing::bls12_381::Bls12;
|
use pairing::bls12_381::Bls12;
|
||||||
use pairing::{PrimeField, PrimeFieldRepr};
|
|
||||||
use rand::{OsRng, Rng};
|
use rand::{OsRng, Rng};
|
||||||
use sapling_crypto::jubjub::{edwards, JubjubBls12};
|
use sapling_crypto::jubjub::{edwards, JubjubBls12};
|
||||||
use sapling_crypto::primitives::{Diversifier, ViewingKey};
|
use sapling_crypto::primitives::{Diversifier, ViewingKey};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use pairing::{bls12_381::Bls12, PrimeField, PrimeFieldRepr};
|
use ff::{PrimeField, PrimeFieldRepr};
|
||||||
|
use pairing::bls12_381::Bls12;
|
||||||
use sapling_crypto::{
|
use sapling_crypto::{
|
||||||
jubjub::{fs::FsRepr, FixedGenerators, JubjubEngine, JubjubParams},
|
jubjub::{fs::FsRepr, FixedGenerators, JubjubEngine, JubjubParams},
|
||||||
primitives::{Diversifier, ProofGenerationKey},
|
primitives::{Diversifier, ProofGenerationKey},
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use pairing::{bls12_381::Bls12, PrimeField, PrimeFieldRepr};
|
use ff::{PrimeField, PrimeFieldRepr};
|
||||||
|
use pairing::bls12_381::Bls12;
|
||||||
use sapling_crypto::{
|
use sapling_crypto::{
|
||||||
jubjub::{FixedGenerators, JubjubEngine}, redjubjub::{PrivateKey, PublicKey, Signature},
|
jubjub::{FixedGenerators, JubjubEngine},
|
||||||
|
redjubjub::{PrivateKey, PublicKey, Signature},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::JUBJUB;
|
use super::JUBJUB;
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ name = "pairing"
|
|||||||
|
|
||||||
# Remember to change version string in README.md.
|
# Remember to change version string in README.md.
|
||||||
version = "0.14.2"
|
version = "0.14.2"
|
||||||
authors = ["Sean Bowe <ewillbefull@gmail.com>"]
|
authors = [
|
||||||
|
"Sean Bowe <ewillbefull@gmail.com>",
|
||||||
|
"Jack Grigg <jack@z.cash>",
|
||||||
|
]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
|
|
||||||
description = "Pairing-friendly elliptic curve library"
|
description = "Pairing-friendly elliptic curve library"
|
||||||
@@ -14,10 +17,10 @@ repository = "https://github.com/ebfull/pairing"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.4"
|
rand = "0.4"
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
clippy = { version = "0.0.200", optional = true }
|
ff = { path = "../ff", features = ["derive"] }
|
||||||
|
group = { path = "../group" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
unstable-features = ["expose-arith"]
|
unstable-features = ["expose-arith"]
|
||||||
expose-arith = []
|
expose-arith = []
|
||||||
u128-support = []
|
|
||||||
default = []
|
default = []
|
||||||
|
|||||||
@@ -6,14 +6,6 @@ This is a Rust crate for using pairing-friendly elliptic curves. Currently, only
|
|||||||
|
|
||||||
Bring the `pairing` crate into your project just as you normally would.
|
Bring the `pairing` crate into your project just as you normally would.
|
||||||
|
|
||||||
If you're using a supported platform and the nightly Rust compiler, you can enable the `u128-support` feature for faster arithmetic.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[dependencies.pairing]
|
|
||||||
version = "0.14"
|
|
||||||
features = ["u128-support"]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Security Warnings
|
## Security Warnings
|
||||||
|
|
||||||
This library does not make any guarantees about constant-time operations, memory access patterns, or resistance to side-channel attacks.
|
This library does not make any guarantees about constant-time operations, memory access patterns, or resistance to side-channel attacks.
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
mod g1 {
|
mod g1 {
|
||||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||||
|
|
||||||
|
use group::CurveProjective;
|
||||||
use pairing::bls12_381::*;
|
use pairing::bls12_381::*;
|
||||||
use pairing::CurveProjective;
|
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_g1_mul_assign(b: &mut ::test::Bencher) {
|
fn bench_g1_mul_assign(b: &mut ::test::Bencher) {
|
||||||
@@ -65,8 +65,8 @@ mod g1 {
|
|||||||
mod g2 {
|
mod g2 {
|
||||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||||
|
|
||||||
|
use group::CurveProjective;
|
||||||
use pairing::bls12_381::*;
|
use pairing::bls12_381::*;
|
||||||
use pairing::CurveProjective;
|
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_g2_mul_assign(b: &mut ::test::Bencher) {
|
fn bench_g2_mul_assign(b: &mut ::test::Bencher) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||||
|
|
||||||
|
use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField};
|
||||||
use pairing::bls12_381::*;
|
use pairing::bls12_381::*;
|
||||||
use pairing::{Field, PrimeField, PrimeFieldRepr, SqrtField};
|
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_fq_repr_add_nocarry(b: &mut ::test::Bencher) {
|
fn bench_fq_repr_add_nocarry(b: &mut ::test::Bencher) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||||
|
|
||||||
|
use ff::Field;
|
||||||
use pairing::bls12_381::*;
|
use pairing::bls12_381::*;
|
||||||
use pairing::Field;
|
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_fq12_add_assign(b: &mut ::test::Bencher) {
|
fn bench_fq12_add_assign(b: &mut ::test::Bencher) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||||
|
|
||||||
|
use ff::{Field, SqrtField};
|
||||||
use pairing::bls12_381::*;
|
use pairing::bls12_381::*;
|
||||||
use pairing::{Field, SqrtField};
|
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_fq2_add_assign(b: &mut ::test::Bencher) {
|
fn bench_fq2_add_assign(b: &mut ::test::Bencher) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||||
|
|
||||||
|
use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField};
|
||||||
use pairing::bls12_381::*;
|
use pairing::bls12_381::*;
|
||||||
use pairing::{Field, PrimeField, PrimeFieldRepr, SqrtField};
|
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_fr_repr_add_nocarry(b: &mut ::test::Bencher) {
|
fn bench_fr_repr_add_nocarry(b: &mut ::test::Bencher) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ mod fr;
|
|||||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||||
|
|
||||||
use pairing::bls12_381::*;
|
use pairing::bls12_381::*;
|
||||||
use pairing::{CurveAffine, Engine};
|
use pairing::{Engine, PairingCurveAffine};
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_pairing_g1_preparation(b: &mut ::test::Bencher) {
|
fn bench_pairing_g1_preparation(b: &mut ::test::Bencher) {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
|
|
||||||
|
extern crate ff;
|
||||||
|
extern crate group;
|
||||||
extern crate pairing;
|
extern crate pairing;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|||||||
@@ -148,12 +148,9 @@ macro_rules! curve_impl {
|
|||||||
type Engine = Bls12;
|
type Engine = Bls12;
|
||||||
type Scalar = $scalarfield;
|
type Scalar = $scalarfield;
|
||||||
type Base = $basefield;
|
type Base = $basefield;
|
||||||
type Prepared = $prepared;
|
|
||||||
type Projective = $projective;
|
type Projective = $projective;
|
||||||
type Uncompressed = $uncompressed;
|
type Uncompressed = $uncompressed;
|
||||||
type Compressed = $compressed;
|
type Compressed = $compressed;
|
||||||
type Pair = $pairing;
|
|
||||||
type PairingResult = Fq12;
|
|
||||||
|
|
||||||
fn zero() -> Self {
|
fn zero() -> Self {
|
||||||
$affine {
|
$affine {
|
||||||
@@ -182,6 +179,17 @@ macro_rules! curve_impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn into_projective(&self) -> $projective {
|
||||||
|
(*self).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PairingCurveAffine for $affine {
|
||||||
|
type Prepared = $prepared;
|
||||||
|
type Pair = $pairing;
|
||||||
|
type PairingResult = Fq12;
|
||||||
|
|
||||||
fn prepare(&self) -> Self::Prepared {
|
fn prepare(&self) -> Self::Prepared {
|
||||||
$prepared::from_affine(*self)
|
$prepared::from_affine(*self)
|
||||||
}
|
}
|
||||||
@@ -190,10 +198,6 @@ macro_rules! curve_impl {
|
|||||||
self.perform_pairing(other)
|
self.perform_pairing(other)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_projective(&self) -> $projective {
|
|
||||||
(*self).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rand for $projective {
|
impl Rand for $projective {
|
||||||
@@ -623,12 +627,11 @@ macro_rules! curve_impl {
|
|||||||
pub mod g1 {
|
pub mod g1 {
|
||||||
use super::super::{Bls12, Fq, Fq12, FqRepr, Fr, FrRepr};
|
use super::super::{Bls12, Fq, Fq12, FqRepr, Fr, FrRepr};
|
||||||
use super::g2::G2Affine;
|
use super::g2::G2Affine;
|
||||||
|
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
|
||||||
|
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
|
||||||
use rand::{Rand, Rng};
|
use rand::{Rand, Rng};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use {
|
use {Engine, PairingCurveAffine};
|
||||||
BitIterator, CurveAffine, CurveProjective, EncodedPoint, Engine, Field, GroupDecodingError,
|
|
||||||
PrimeField, PrimeFieldRepr, SqrtField,
|
|
||||||
};
|
|
||||||
|
|
||||||
curve_impl!(
|
curve_impl!(
|
||||||
"G1",
|
"G1",
|
||||||
@@ -1263,19 +1266,19 @@ pub mod g1 {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn g1_curve_tests() {
|
fn g1_curve_tests() {
|
||||||
::tests::curve::curve_tests::<G1>();
|
use group::tests::curve_tests;
|
||||||
|
curve_tests::<G1>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod g2 {
|
pub mod g2 {
|
||||||
use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr, FrRepr};
|
use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr, FrRepr};
|
||||||
use super::g1::G1Affine;
|
use super::g1::G1Affine;
|
||||||
|
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
|
||||||
|
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
|
||||||
use rand::{Rand, Rng};
|
use rand::{Rand, Rng};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use {
|
use {Engine, PairingCurveAffine};
|
||||||
BitIterator, CurveAffine, CurveProjective, EncodedPoint, Engine, Field, GroupDecodingError,
|
|
||||||
PrimeField, PrimeFieldRepr, SqrtField,
|
|
||||||
};
|
|
||||||
|
|
||||||
curve_impl!(
|
curve_impl!(
|
||||||
"G2",
|
"G2",
|
||||||
@@ -2018,7 +2021,8 @@ pub mod g2 {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn g2_curve_tests() {
|
fn g2_curve_tests() {
|
||||||
::tests::curve::curve_tests::<G2>();
|
use group::tests::curve_tests;
|
||||||
|
curve_tests::<G2>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,69 +1,5 @@
|
|||||||
use super::fq2::Fq2;
|
use super::fq2::Fq2;
|
||||||
use std::cmp::Ordering;
|
use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr};
|
||||||
use {Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, SqrtField};
|
|
||||||
|
|
||||||
// q = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787
|
|
||||||
const MODULUS: FqRepr = FqRepr([
|
|
||||||
0xb9feffffffffaaab,
|
|
||||||
0x1eabfffeb153ffff,
|
|
||||||
0x6730d2a0f6b0f624,
|
|
||||||
0x64774b84f38512bf,
|
|
||||||
0x4b1ba7b6434bacd7,
|
|
||||||
0x1a0111ea397fe69a,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// The number of bits needed to represent the modulus.
|
|
||||||
const MODULUS_BITS: u32 = 381;
|
|
||||||
|
|
||||||
// The number of bits that must be shaved from the beginning of
|
|
||||||
// the representation when randomly sampling.
|
|
||||||
const REPR_SHAVE_BITS: u32 = 3;
|
|
||||||
|
|
||||||
// R = 2**384 % q
|
|
||||||
const R: FqRepr = FqRepr([
|
|
||||||
0x760900000002fffd,
|
|
||||||
0xebf4000bc40c0002,
|
|
||||||
0x5f48985753c758ba,
|
|
||||||
0x77ce585370525745,
|
|
||||||
0x5c071a97a256ec6d,
|
|
||||||
0x15f65ec3fa80e493,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// R2 = R^2 % q
|
|
||||||
const R2: FqRepr = FqRepr([
|
|
||||||
0xf4df1f341c341746,
|
|
||||||
0xa76e6a609d104f1,
|
|
||||||
0x8de5476c4c95b6d5,
|
|
||||||
0x67eb88a9939d83c0,
|
|
||||||
0x9a793e85b519952d,
|
|
||||||
0x11988fe592cae3aa,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// INV = -(q^{-1} mod 2^64) mod 2^64
|
|
||||||
const INV: u64 = 0x89f3fffcfffcfffd;
|
|
||||||
|
|
||||||
// GENERATOR = 2 (multiplicative generator of q-1 order, that is also quadratic nonresidue)
|
|
||||||
const GENERATOR: FqRepr = FqRepr([
|
|
||||||
0x321300000006554f,
|
|
||||||
0xb93c0018d6c40005,
|
|
||||||
0x57605e0db0ddbb51,
|
|
||||||
0x8b256521ed1f9bcb,
|
|
||||||
0x6cf28d7901622c03,
|
|
||||||
0x11ebab9dbb81e28c,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 2^s * t = MODULUS - 1 with t odd
|
|
||||||
const S: u32 = 1;
|
|
||||||
|
|
||||||
// 2^s root of unity computed by GENERATOR^t
|
|
||||||
const ROOT_OF_UNITY: FqRepr = FqRepr([
|
|
||||||
0x43f5fffffffcaaae,
|
|
||||||
0x32b7fff2ed47fffd,
|
|
||||||
0x7e83a49a2e99d69,
|
|
||||||
0xeca8f3318332bb7a,
|
|
||||||
0xef148d1ea0f4c069,
|
|
||||||
0x40ab3263eff0206,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// B coefficient of BLS12-381 curve, 4.
|
// B coefficient of BLS12-381 curve, 4.
|
||||||
pub const B_COEFF: Fq = Fq(FqRepr([
|
pub const B_COEFF: Fq = Fq(FqRepr([
|
||||||
@@ -507,669 +443,11 @@ pub const NEGATIVE_ONE: Fq = Fq(FqRepr([
|
|||||||
0x40ab3263eff0206,
|
0x40ab3263eff0206,
|
||||||
]));
|
]));
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
|
#[derive(PrimeField)]
|
||||||
pub struct FqRepr(pub [u64; 6]);
|
#[PrimeFieldModulus = "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787"]
|
||||||
|
#[PrimeFieldGenerator = "2"]
|
||||||
impl ::rand::Rand for FqRepr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn rand<R: ::rand::Rng>(rng: &mut R) -> Self {
|
|
||||||
FqRepr(rng.gen())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::std::fmt::Display for FqRepr {
|
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
try!(write!(f, "0x"));
|
|
||||||
for i in self.0.iter().rev() {
|
|
||||||
try!(write!(f, "{:016x}", *i));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<[u64]> for FqRepr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn as_ref(&self) -> &[u64] {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsMut<[u64]> for FqRepr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn as_mut(&mut self) -> &mut [u64] {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u64> for FqRepr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn from(val: u64) -> FqRepr {
|
|
||||||
let mut repr = Self::default();
|
|
||||||
repr.0[0] = val;
|
|
||||||
repr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for FqRepr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn cmp(&self, other: &FqRepr) -> Ordering {
|
|
||||||
for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) {
|
|
||||||
if a < b {
|
|
||||||
return Ordering::Less;
|
|
||||||
} else if a > b {
|
|
||||||
return Ordering::Greater;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ordering::Equal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for FqRepr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn partial_cmp(&self, other: &FqRepr) -> Option<Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PrimeFieldRepr for FqRepr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn is_odd(&self) -> bool {
|
|
||||||
self.0[0] & 1 == 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn is_even(&self) -> bool {
|
|
||||||
!self.is_odd()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn is_zero(&self) -> bool {
|
|
||||||
self.0.iter().all(|&e| e == 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn shr(&mut self, mut n: u32) {
|
|
||||||
if n >= 64 * 6 {
|
|
||||||
*self = Self::from(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while n >= 64 {
|
|
||||||
let mut t = 0;
|
|
||||||
for i in self.0.iter_mut().rev() {
|
|
||||||
::std::mem::swap(&mut t, i);
|
|
||||||
}
|
|
||||||
n -= 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
if n > 0 {
|
|
||||||
let mut t = 0;
|
|
||||||
for i in self.0.iter_mut().rev() {
|
|
||||||
let t2 = *i << (64 - n);
|
|
||||||
*i >>= n;
|
|
||||||
*i |= t;
|
|
||||||
t = t2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn div2(&mut self) {
|
|
||||||
let mut t = 0;
|
|
||||||
for i in self.0.iter_mut().rev() {
|
|
||||||
let t2 = *i << 63;
|
|
||||||
*i >>= 1;
|
|
||||||
*i |= t;
|
|
||||||
t = t2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn mul2(&mut self) {
|
|
||||||
let mut last = 0;
|
|
||||||
for i in &mut self.0 {
|
|
||||||
let tmp = *i >> 63;
|
|
||||||
*i <<= 1;
|
|
||||||
*i |= last;
|
|
||||||
last = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn shl(&mut self, mut n: u32) {
|
|
||||||
if n >= 64 * 6 {
|
|
||||||
*self = Self::from(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while n >= 64 {
|
|
||||||
let mut t = 0;
|
|
||||||
for i in &mut self.0 {
|
|
||||||
::std::mem::swap(&mut t, i);
|
|
||||||
}
|
|
||||||
n -= 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
if n > 0 {
|
|
||||||
let mut t = 0;
|
|
||||||
for i in &mut self.0 {
|
|
||||||
let t2 = *i >> (64 - n);
|
|
||||||
*i <<= n;
|
|
||||||
*i |= t;
|
|
||||||
t = t2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn num_bits(&self) -> u32 {
|
|
||||||
let mut ret = (6 as u32) * 64;
|
|
||||||
for i in self.0.iter().rev() {
|
|
||||||
let leading = i.leading_zeros();
|
|
||||||
ret -= leading;
|
|
||||||
if leading != 64 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn add_nocarry(&mut self, other: &FqRepr) {
|
|
||||||
let mut carry = 0;
|
|
||||||
|
|
||||||
for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
|
|
||||||
*a = ::adc(*a, *b, &mut carry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn sub_noborrow(&mut self, other: &FqRepr) {
|
|
||||||
let mut borrow = 0;
|
|
||||||
|
|
||||||
for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
|
|
||||||
*a = ::sbb(*a, *b, &mut borrow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
||||||
pub struct Fq(FqRepr);
|
pub struct Fq(FqRepr);
|
||||||
|
|
||||||
/// `Fq` elements are ordered lexicographically.
|
|
||||||
impl Ord for Fq {
|
|
||||||
#[inline(always)]
|
|
||||||
fn cmp(&self, other: &Fq) -> Ordering {
|
|
||||||
self.into_repr().cmp(&other.into_repr())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for Fq {
|
|
||||||
#[inline(always)]
|
|
||||||
fn partial_cmp(&self, other: &Fq) -> Option<Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::std::fmt::Display for Fq {
|
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
write!(f, "Fq({})", self.into_repr())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::rand::Rand for Fq {
|
|
||||||
fn rand<R: ::rand::Rng>(rng: &mut R) -> Self {
|
|
||||||
loop {
|
|
||||||
let mut tmp = Fq(FqRepr::rand(rng));
|
|
||||||
|
|
||||||
// Mask away the unused bits at the beginning.
|
|
||||||
tmp.0.as_mut()[5] &= 0xffffffffffffffff >> REPR_SHAVE_BITS;
|
|
||||||
|
|
||||||
if tmp.is_valid() {
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Fq> for FqRepr {
|
|
||||||
fn from(e: Fq) -> FqRepr {
|
|
||||||
e.into_repr()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PrimeField for Fq {
|
|
||||||
type Repr = FqRepr;
|
|
||||||
|
|
||||||
fn from_repr(r: FqRepr) -> Result<Fq, PrimeFieldDecodingError> {
|
|
||||||
let mut r = Fq(r);
|
|
||||||
if r.is_valid() {
|
|
||||||
r.mul_assign(&Fq(R2));
|
|
||||||
|
|
||||||
Ok(r)
|
|
||||||
} else {
|
|
||||||
Err(PrimeFieldDecodingError::NotInField(format!("{}", r.0)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_repr(&self) -> FqRepr {
|
|
||||||
let mut r = *self;
|
|
||||||
r.mont_reduce(
|
|
||||||
(self.0).0[0],
|
|
||||||
(self.0).0[1],
|
|
||||||
(self.0).0[2],
|
|
||||||
(self.0).0[3],
|
|
||||||
(self.0).0[4],
|
|
||||||
(self.0).0[5],
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
r.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn char() -> FqRepr {
|
|
||||||
MODULUS
|
|
||||||
}
|
|
||||||
|
|
||||||
const NUM_BITS: u32 = MODULUS_BITS;
|
|
||||||
|
|
||||||
const CAPACITY: u32 = Self::NUM_BITS - 1;
|
|
||||||
|
|
||||||
fn multiplicative_generator() -> Self {
|
|
||||||
Fq(GENERATOR)
|
|
||||||
}
|
|
||||||
|
|
||||||
const S: u32 = S;
|
|
||||||
|
|
||||||
fn root_of_unity() -> Self {
|
|
||||||
Fq(ROOT_OF_UNITY)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Field for Fq {
|
|
||||||
#[inline]
|
|
||||||
fn zero() -> Self {
|
|
||||||
Fq(FqRepr::from(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn one() -> Self {
|
|
||||||
Fq(R)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_zero(&self) -> bool {
|
|
||||||
self.0.is_zero()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn add_assign(&mut self, other: &Fq) {
|
|
||||||
// This cannot exceed the backing capacity.
|
|
||||||
self.0.add_nocarry(&other.0);
|
|
||||||
|
|
||||||
// However, it may need to be reduced.
|
|
||||||
self.reduce();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn double(&mut self) {
|
|
||||||
// This cannot exceed the backing capacity.
|
|
||||||
self.0.mul2();
|
|
||||||
|
|
||||||
// However, it may need to be reduced.
|
|
||||||
self.reduce();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn sub_assign(&mut self, other: &Fq) {
|
|
||||||
// If `other` is larger than `self`, we'll need to add the modulus to self first.
|
|
||||||
if other.0 > self.0 {
|
|
||||||
self.0.add_nocarry(&MODULUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.0.sub_noborrow(&other.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn negate(&mut self) {
|
|
||||||
if !self.is_zero() {
|
|
||||||
let mut tmp = MODULUS;
|
|
||||||
tmp.sub_noborrow(&self.0);
|
|
||||||
self.0 = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn inverse(&self) -> Option<Self> {
|
|
||||||
if self.is_zero() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
// Guajardo Kumar Paar Pelzl
|
|
||||||
// Efficient Software-Implementation of Finite Fields with Applications to Cryptography
|
|
||||||
// Algorithm 16 (BEA for Inversion in Fp)
|
|
||||||
|
|
||||||
let one = FqRepr::from(1);
|
|
||||||
|
|
||||||
let mut u = self.0;
|
|
||||||
let mut v = MODULUS;
|
|
||||||
let mut b = Fq(R2); // Avoids unnecessary reduction step.
|
|
||||||
let mut c = Self::zero();
|
|
||||||
|
|
||||||
while u != one && v != one {
|
|
||||||
while u.is_even() {
|
|
||||||
u.div2();
|
|
||||||
|
|
||||||
if b.0.is_even() {
|
|
||||||
b.0.div2();
|
|
||||||
} else {
|
|
||||||
b.0.add_nocarry(&MODULUS);
|
|
||||||
b.0.div2();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while v.is_even() {
|
|
||||||
v.div2();
|
|
||||||
|
|
||||||
if c.0.is_even() {
|
|
||||||
c.0.div2();
|
|
||||||
} else {
|
|
||||||
c.0.add_nocarry(&MODULUS);
|
|
||||||
c.0.div2();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if v < u {
|
|
||||||
u.sub_noborrow(&v);
|
|
||||||
b.sub_assign(&c);
|
|
||||||
} else {
|
|
||||||
v.sub_noborrow(&u);
|
|
||||||
c.sub_assign(&b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if u == one {
|
|
||||||
Some(b)
|
|
||||||
} else {
|
|
||||||
Some(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn frobenius_map(&mut self, _: usize) {
|
|
||||||
// This has no effect in a prime field.
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn mul_assign(&mut self, other: &Fq) {
|
|
||||||
let mut carry = 0;
|
|
||||||
let r0 = ::mac_with_carry(0, (self.0).0[0], (other.0).0[0], &mut carry);
|
|
||||||
let r1 = ::mac_with_carry(0, (self.0).0[0], (other.0).0[1], &mut carry);
|
|
||||||
let r2 = ::mac_with_carry(0, (self.0).0[0], (other.0).0[2], &mut carry);
|
|
||||||
let r3 = ::mac_with_carry(0, (self.0).0[0], (other.0).0[3], &mut carry);
|
|
||||||
let r4 = ::mac_with_carry(0, (self.0).0[0], (other.0).0[4], &mut carry);
|
|
||||||
let r5 = ::mac_with_carry(0, (self.0).0[0], (other.0).0[5], &mut carry);
|
|
||||||
let r6 = carry;
|
|
||||||
let mut carry = 0;
|
|
||||||
let r1 = ::mac_with_carry(r1, (self.0).0[1], (other.0).0[0], &mut carry);
|
|
||||||
let r2 = ::mac_with_carry(r2, (self.0).0[1], (other.0).0[1], &mut carry);
|
|
||||||
let r3 = ::mac_with_carry(r3, (self.0).0[1], (other.0).0[2], &mut carry);
|
|
||||||
let r4 = ::mac_with_carry(r4, (self.0).0[1], (other.0).0[3], &mut carry);
|
|
||||||
let r5 = ::mac_with_carry(r5, (self.0).0[1], (other.0).0[4], &mut carry);
|
|
||||||
let r6 = ::mac_with_carry(r6, (self.0).0[1], (other.0).0[5], &mut carry);
|
|
||||||
let r7 = carry;
|
|
||||||
let mut carry = 0;
|
|
||||||
let r2 = ::mac_with_carry(r2, (self.0).0[2], (other.0).0[0], &mut carry);
|
|
||||||
let r3 = ::mac_with_carry(r3, (self.0).0[2], (other.0).0[1], &mut carry);
|
|
||||||
let r4 = ::mac_with_carry(r4, (self.0).0[2], (other.0).0[2], &mut carry);
|
|
||||||
let r5 = ::mac_with_carry(r5, (self.0).0[2], (other.0).0[3], &mut carry);
|
|
||||||
let r6 = ::mac_with_carry(r6, (self.0).0[2], (other.0).0[4], &mut carry);
|
|
||||||
let r7 = ::mac_with_carry(r7, (self.0).0[2], (other.0).0[5], &mut carry);
|
|
||||||
let r8 = carry;
|
|
||||||
let mut carry = 0;
|
|
||||||
let r3 = ::mac_with_carry(r3, (self.0).0[3], (other.0).0[0], &mut carry);
|
|
||||||
let r4 = ::mac_with_carry(r4, (self.0).0[3], (other.0).0[1], &mut carry);
|
|
||||||
let r5 = ::mac_with_carry(r5, (self.0).0[3], (other.0).0[2], &mut carry);
|
|
||||||
let r6 = ::mac_with_carry(r6, (self.0).0[3], (other.0).0[3], &mut carry);
|
|
||||||
let r7 = ::mac_with_carry(r7, (self.0).0[3], (other.0).0[4], &mut carry);
|
|
||||||
let r8 = ::mac_with_carry(r8, (self.0).0[3], (other.0).0[5], &mut carry);
|
|
||||||
let r9 = carry;
|
|
||||||
let mut carry = 0;
|
|
||||||
let r4 = ::mac_with_carry(r4, (self.0).0[4], (other.0).0[0], &mut carry);
|
|
||||||
let r5 = ::mac_with_carry(r5, (self.0).0[4], (other.0).0[1], &mut carry);
|
|
||||||
let r6 = ::mac_with_carry(r6, (self.0).0[4], (other.0).0[2], &mut carry);
|
|
||||||
let r7 = ::mac_with_carry(r7, (self.0).0[4], (other.0).0[3], &mut carry);
|
|
||||||
let r8 = ::mac_with_carry(r8, (self.0).0[4], (other.0).0[4], &mut carry);
|
|
||||||
let r9 = ::mac_with_carry(r9, (self.0).0[4], (other.0).0[5], &mut carry);
|
|
||||||
let r10 = carry;
|
|
||||||
let mut carry = 0;
|
|
||||||
let r5 = ::mac_with_carry(r5, (self.0).0[5], (other.0).0[0], &mut carry);
|
|
||||||
let r6 = ::mac_with_carry(r6, (self.0).0[5], (other.0).0[1], &mut carry);
|
|
||||||
let r7 = ::mac_with_carry(r7, (self.0).0[5], (other.0).0[2], &mut carry);
|
|
||||||
let r8 = ::mac_with_carry(r8, (self.0).0[5], (other.0).0[3], &mut carry);
|
|
||||||
let r9 = ::mac_with_carry(r9, (self.0).0[5], (other.0).0[4], &mut carry);
|
|
||||||
let r10 = ::mac_with_carry(r10, (self.0).0[5], (other.0).0[5], &mut carry);
|
|
||||||
let r11 = carry;
|
|
||||||
self.mont_reduce(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn square(&mut self) {
|
|
||||||
let mut carry = 0;
|
|
||||||
let r1 = ::mac_with_carry(0, (self.0).0[0], (self.0).0[1], &mut carry);
|
|
||||||
let r2 = ::mac_with_carry(0, (self.0).0[0], (self.0).0[2], &mut carry);
|
|
||||||
let r3 = ::mac_with_carry(0, (self.0).0[0], (self.0).0[3], &mut carry);
|
|
||||||
let r4 = ::mac_with_carry(0, (self.0).0[0], (self.0).0[4], &mut carry);
|
|
||||||
let r5 = ::mac_with_carry(0, (self.0).0[0], (self.0).0[5], &mut carry);
|
|
||||||
let r6 = carry;
|
|
||||||
let mut carry = 0;
|
|
||||||
let r3 = ::mac_with_carry(r3, (self.0).0[1], (self.0).0[2], &mut carry);
|
|
||||||
let r4 = ::mac_with_carry(r4, (self.0).0[1], (self.0).0[3], &mut carry);
|
|
||||||
let r5 = ::mac_with_carry(r5, (self.0).0[1], (self.0).0[4], &mut carry);
|
|
||||||
let r6 = ::mac_with_carry(r6, (self.0).0[1], (self.0).0[5], &mut carry);
|
|
||||||
let r7 = carry;
|
|
||||||
let mut carry = 0;
|
|
||||||
let r5 = ::mac_with_carry(r5, (self.0).0[2], (self.0).0[3], &mut carry);
|
|
||||||
let r6 = ::mac_with_carry(r6, (self.0).0[2], (self.0).0[4], &mut carry);
|
|
||||||
let r7 = ::mac_with_carry(r7, (self.0).0[2], (self.0).0[5], &mut carry);
|
|
||||||
let r8 = carry;
|
|
||||||
let mut carry = 0;
|
|
||||||
let r7 = ::mac_with_carry(r7, (self.0).0[3], (self.0).0[4], &mut carry);
|
|
||||||
let r8 = ::mac_with_carry(r8, (self.0).0[3], (self.0).0[5], &mut carry);
|
|
||||||
let r9 = carry;
|
|
||||||
let mut carry = 0;
|
|
||||||
let r9 = ::mac_with_carry(r9, (self.0).0[4], (self.0).0[5], &mut carry);
|
|
||||||
let r10 = carry;
|
|
||||||
|
|
||||||
let r11 = r10 >> 63;
|
|
||||||
let r10 = (r10 << 1) | (r9 >> 63);
|
|
||||||
let r9 = (r9 << 1) | (r8 >> 63);
|
|
||||||
let r8 = (r8 << 1) | (r7 >> 63);
|
|
||||||
let r7 = (r7 << 1) | (r6 >> 63);
|
|
||||||
let r6 = (r6 << 1) | (r5 >> 63);
|
|
||||||
let r5 = (r5 << 1) | (r4 >> 63);
|
|
||||||
let r4 = (r4 << 1) | (r3 >> 63);
|
|
||||||
let r3 = (r3 << 1) | (r2 >> 63);
|
|
||||||
let r2 = (r2 << 1) | (r1 >> 63);
|
|
||||||
let r1 = r1 << 1;
|
|
||||||
|
|
||||||
let mut carry = 0;
|
|
||||||
let r0 = ::mac_with_carry(0, (self.0).0[0], (self.0).0[0], &mut carry);
|
|
||||||
let r1 = ::adc(r1, 0, &mut carry);
|
|
||||||
let r2 = ::mac_with_carry(r2, (self.0).0[1], (self.0).0[1], &mut carry);
|
|
||||||
let r3 = ::adc(r3, 0, &mut carry);
|
|
||||||
let r4 = ::mac_with_carry(r4, (self.0).0[2], (self.0).0[2], &mut carry);
|
|
||||||
let r5 = ::adc(r5, 0, &mut carry);
|
|
||||||
let r6 = ::mac_with_carry(r6, (self.0).0[3], (self.0).0[3], &mut carry);
|
|
||||||
let r7 = ::adc(r7, 0, &mut carry);
|
|
||||||
let r8 = ::mac_with_carry(r8, (self.0).0[4], (self.0).0[4], &mut carry);
|
|
||||||
let r9 = ::adc(r9, 0, &mut carry);
|
|
||||||
let r10 = ::mac_with_carry(r10, (self.0).0[5], (self.0).0[5], &mut carry);
|
|
||||||
let r11 = ::adc(r11, 0, &mut carry);
|
|
||||||
self.mont_reduce(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Fq {
|
|
||||||
/// Determines if the element is really in the field. This is only used
|
|
||||||
/// internally.
|
|
||||||
#[inline(always)]
|
|
||||||
fn is_valid(&self) -> bool {
|
|
||||||
self.0 < MODULUS
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Subtracts the modulus from this element if this element is not in the
|
|
||||||
/// field. Only used internally.
|
|
||||||
#[inline(always)]
|
|
||||||
fn reduce(&mut self) {
|
|
||||||
if !self.is_valid() {
|
|
||||||
self.0.sub_noborrow(&MODULUS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn mont_reduce(
|
|
||||||
&mut self,
|
|
||||||
r0: u64,
|
|
||||||
mut r1: u64,
|
|
||||||
mut r2: u64,
|
|
||||||
mut r3: u64,
|
|
||||||
mut r4: u64,
|
|
||||||
mut r5: u64,
|
|
||||||
mut r6: u64,
|
|
||||||
mut r7: u64,
|
|
||||||
mut r8: u64,
|
|
||||||
mut r9: u64,
|
|
||||||
mut r10: u64,
|
|
||||||
mut r11: u64,
|
|
||||||
) {
|
|
||||||
// The Montgomery reduction here is based on Algorithm 14.32 in
|
|
||||||
// Handbook of Applied Cryptography
|
|
||||||
// <http://cacr.uwaterloo.ca/hac/about/chap14.pdf>.
|
|
||||||
|
|
||||||
let k = r0.wrapping_mul(INV);
|
|
||||||
let mut carry = 0;
|
|
||||||
::mac_with_carry(r0, k, MODULUS.0[0], &mut carry);
|
|
||||||
r1 = ::mac_with_carry(r1, k, MODULUS.0[1], &mut carry);
|
|
||||||
r2 = ::mac_with_carry(r2, k, MODULUS.0[2], &mut carry);
|
|
||||||
r3 = ::mac_with_carry(r3, k, MODULUS.0[3], &mut carry);
|
|
||||||
r4 = ::mac_with_carry(r4, k, MODULUS.0[4], &mut carry);
|
|
||||||
r5 = ::mac_with_carry(r5, k, MODULUS.0[5], &mut carry);
|
|
||||||
r6 = ::adc(r6, 0, &mut carry);
|
|
||||||
let carry2 = carry;
|
|
||||||
let k = r1.wrapping_mul(INV);
|
|
||||||
let mut carry = 0;
|
|
||||||
::mac_with_carry(r1, k, MODULUS.0[0], &mut carry);
|
|
||||||
r2 = ::mac_with_carry(r2, k, MODULUS.0[1], &mut carry);
|
|
||||||
r3 = ::mac_with_carry(r3, k, MODULUS.0[2], &mut carry);
|
|
||||||
r4 = ::mac_with_carry(r4, k, MODULUS.0[3], &mut carry);
|
|
||||||
r5 = ::mac_with_carry(r5, k, MODULUS.0[4], &mut carry);
|
|
||||||
r6 = ::mac_with_carry(r6, k, MODULUS.0[5], &mut carry);
|
|
||||||
r7 = ::adc(r7, carry2, &mut carry);
|
|
||||||
let carry2 = carry;
|
|
||||||
let k = r2.wrapping_mul(INV);
|
|
||||||
let mut carry = 0;
|
|
||||||
::mac_with_carry(r2, k, MODULUS.0[0], &mut carry);
|
|
||||||
r3 = ::mac_with_carry(r3, k, MODULUS.0[1], &mut carry);
|
|
||||||
r4 = ::mac_with_carry(r4, k, MODULUS.0[2], &mut carry);
|
|
||||||
r5 = ::mac_with_carry(r5, k, MODULUS.0[3], &mut carry);
|
|
||||||
r6 = ::mac_with_carry(r6, k, MODULUS.0[4], &mut carry);
|
|
||||||
r7 = ::mac_with_carry(r7, k, MODULUS.0[5], &mut carry);
|
|
||||||
r8 = ::adc(r8, carry2, &mut carry);
|
|
||||||
let carry2 = carry;
|
|
||||||
let k = r3.wrapping_mul(INV);
|
|
||||||
let mut carry = 0;
|
|
||||||
::mac_with_carry(r3, k, MODULUS.0[0], &mut carry);
|
|
||||||
r4 = ::mac_with_carry(r4, k, MODULUS.0[1], &mut carry);
|
|
||||||
r5 = ::mac_with_carry(r5, k, MODULUS.0[2], &mut carry);
|
|
||||||
r6 = ::mac_with_carry(r6, k, MODULUS.0[3], &mut carry);
|
|
||||||
r7 = ::mac_with_carry(r7, k, MODULUS.0[4], &mut carry);
|
|
||||||
r8 = ::mac_with_carry(r8, k, MODULUS.0[5], &mut carry);
|
|
||||||
r9 = ::adc(r9, carry2, &mut carry);
|
|
||||||
let carry2 = carry;
|
|
||||||
let k = r4.wrapping_mul(INV);
|
|
||||||
let mut carry = 0;
|
|
||||||
::mac_with_carry(r4, k, MODULUS.0[0], &mut carry);
|
|
||||||
r5 = ::mac_with_carry(r5, k, MODULUS.0[1], &mut carry);
|
|
||||||
r6 = ::mac_with_carry(r6, k, MODULUS.0[2], &mut carry);
|
|
||||||
r7 = ::mac_with_carry(r7, k, MODULUS.0[3], &mut carry);
|
|
||||||
r8 = ::mac_with_carry(r8, k, MODULUS.0[4], &mut carry);
|
|
||||||
r9 = ::mac_with_carry(r9, k, MODULUS.0[5], &mut carry);
|
|
||||||
r10 = ::adc(r10, carry2, &mut carry);
|
|
||||||
let carry2 = carry;
|
|
||||||
let k = r5.wrapping_mul(INV);
|
|
||||||
let mut carry = 0;
|
|
||||||
::mac_with_carry(r5, k, MODULUS.0[0], &mut carry);
|
|
||||||
r6 = ::mac_with_carry(r6, k, MODULUS.0[1], &mut carry);
|
|
||||||
r7 = ::mac_with_carry(r7, k, MODULUS.0[2], &mut carry);
|
|
||||||
r8 = ::mac_with_carry(r8, k, MODULUS.0[3], &mut carry);
|
|
||||||
r9 = ::mac_with_carry(r9, k, MODULUS.0[4], &mut carry);
|
|
||||||
r10 = ::mac_with_carry(r10, k, MODULUS.0[5], &mut carry);
|
|
||||||
r11 = ::adc(r11, carry2, &mut carry);
|
|
||||||
(self.0).0[0] = r6;
|
|
||||||
(self.0).0[1] = r7;
|
|
||||||
(self.0).0[2] = r8;
|
|
||||||
(self.0).0[3] = r9;
|
|
||||||
(self.0).0[4] = r10;
|
|
||||||
(self.0).0[5] = r11;
|
|
||||||
self.reduce();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SqrtField for Fq {
|
|
||||||
fn legendre(&self) -> ::LegendreSymbol {
|
|
||||||
use LegendreSymbol::*;
|
|
||||||
|
|
||||||
// s = self^((q - 1) // 2)
|
|
||||||
let s = self.pow([
|
|
||||||
0xdcff7fffffffd555,
|
|
||||||
0xf55ffff58a9ffff,
|
|
||||||
0xb39869507b587b12,
|
|
||||||
0xb23ba5c279c2895f,
|
|
||||||
0x258dd3db21a5d66b,
|
|
||||||
0xd0088f51cbff34d,
|
|
||||||
]);
|
|
||||||
if s == Fq::zero() {
|
|
||||||
Zero
|
|
||||||
} else if s == Fq::one() {
|
|
||||||
QuadraticResidue
|
|
||||||
} else {
|
|
||||||
QuadraticNonResidue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sqrt(&self) -> Option<Self> {
|
|
||||||
// Shank's algorithm for q mod 4 = 3
|
|
||||||
// https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2)
|
|
||||||
|
|
||||||
// a1 = self^((q - 3) // 4)
|
|
||||||
let mut a1 = self.pow([
|
|
||||||
0xee7fbfffffffeaaa,
|
|
||||||
0x7aaffffac54ffff,
|
|
||||||
0xd9cc34a83dac3d89,
|
|
||||||
0xd91dd2e13ce144af,
|
|
||||||
0x92c6e9ed90d2eb35,
|
|
||||||
0x680447a8e5ff9a6,
|
|
||||||
]);
|
|
||||||
let mut a0 = a1;
|
|
||||||
a0.square();
|
|
||||||
a0.mul_assign(self);
|
|
||||||
|
|
||||||
if a0 == NEGATIVE_ONE {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
a1.mul_assign(self);
|
|
||||||
Some(a1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_b_coeff() {
|
fn test_b_coeff() {
|
||||||
assert_eq!(Fq::from_repr(FqRepr::from(4)).unwrap(), B_COEFF);
|
assert_eq!(Fq::from_repr(FqRepr::from(4)).unwrap(), B_COEFF);
|
||||||
@@ -1899,6 +1177,8 @@ use rand::{Rand, SeedableRng, XorShiftRng};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fq_repr_ordering() {
|
fn test_fq_repr_ordering() {
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
fn assert_equality(a: FqRepr, b: FqRepr) {
|
fn assert_equality(a: FqRepr, b: FqRepr) {
|
||||||
assert_eq!(a, b);
|
assert_eq!(a, b);
|
||||||
assert!(a.cmp(&b) == Ordering::Equal);
|
assert!(a.cmp(&b) == Ordering::Equal);
|
||||||
@@ -2304,14 +1584,16 @@ fn test_fq_is_valid() {
|
|||||||
0x17c8be1800b9f059
|
0x17c8be1800b9f059
|
||||||
])).is_valid()
|
])).is_valid()
|
||||||
);
|
);
|
||||||
assert!(!Fq(FqRepr([
|
assert!(
|
||||||
|
!Fq(FqRepr([
|
||||||
0xffffffffffffffff,
|
0xffffffffffffffff,
|
||||||
0xffffffffffffffff,
|
0xffffffffffffffff,
|
||||||
0xffffffffffffffff,
|
0xffffffffffffffff,
|
||||||
0xffffffffffffffff,
|
0xffffffffffffffff,
|
||||||
0xffffffffffffffff,
|
0xffffffffffffffff,
|
||||||
0xffffffffffffffff
|
0xffffffffffffffff
|
||||||
])).is_valid());
|
])).is_valid()
|
||||||
|
);
|
||||||
|
|
||||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
|
||||||
@@ -2745,6 +2027,8 @@ fn test_fq_pow() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fq_sqrt() {
|
fn test_fq_sqrt() {
|
||||||
|
use ff::SqrtField;
|
||||||
|
|
||||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
|
||||||
assert_eq!(Fq::zero().sqrt().unwrap(), Fq::zero());
|
assert_eq!(Fq::zero().sqrt().unwrap(), Fq::zero());
|
||||||
@@ -2878,6 +2162,8 @@ fn test_fq_num_bits() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fq_root_of_unity() {
|
fn test_fq_root_of_unity() {
|
||||||
|
use ff::SqrtField;
|
||||||
|
|
||||||
assert_eq!(Fq::S, 1);
|
assert_eq!(Fq::S, 1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Fq::multiplicative_generator(),
|
Fq::multiplicative_generator(),
|
||||||
@@ -2924,7 +2210,8 @@ fn fq_repr_tests() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fq_legendre() {
|
fn test_fq_legendre() {
|
||||||
use LegendreSymbol::*;
|
use ff::LegendreSymbol::*;
|
||||||
|
use ff::SqrtField;
|
||||||
|
|
||||||
assert_eq!(QuadraticResidue, Fq::one().legendre());
|
assert_eq!(QuadraticResidue, Fq::one().legendre());
|
||||||
assert_eq!(Zero, Fq::zero().legendre());
|
assert_eq!(Zero, Fq::zero().legendre());
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use super::fq::FROBENIUS_COEFF_FQ12_C1;
|
use super::fq::FROBENIUS_COEFF_FQ12_C1;
|
||||||
use super::fq2::Fq2;
|
use super::fq2::Fq2;
|
||||||
use super::fq6::Fq6;
|
use super::fq6::Fq6;
|
||||||
|
use ff::Field;
|
||||||
use rand::{Rand, Rng};
|
use rand::{Rand, Rng};
|
||||||
use Field;
|
|
||||||
|
|
||||||
/// An element of Fq12, represented by c0 + c1 * w.
|
/// An element of Fq12, represented by c0 + c1 * w.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
@@ -182,7 +182,7 @@ fn test_fq12_mul_by_014() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fq12_field_tests() {
|
fn fq12_field_tests() {
|
||||||
use PrimeField;
|
use ff::PrimeField;
|
||||||
|
|
||||||
::tests::field::random_field_tests::<Fq12>();
|
::tests::field::random_field_tests::<Fq12>();
|
||||||
::tests::field::random_frobenius_tests::<Fq12, _>(super::fq::Fq::char(), 13);
|
::tests::field::random_frobenius_tests::<Fq12, _>(super::fq::Fq::char(), 13);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use super::fq::{FROBENIUS_COEFF_FQ2_C1, Fq, NEGATIVE_ONE};
|
use super::fq::{FROBENIUS_COEFF_FQ2_C1, Fq, NEGATIVE_ONE};
|
||||||
|
use ff::{Field, SqrtField};
|
||||||
use rand::{Rand, Rng};
|
use rand::{Rand, Rng};
|
||||||
use {Field, SqrtField};
|
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ impl Field for Fq2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SqrtField for Fq2 {
|
impl SqrtField for Fq2 {
|
||||||
fn legendre(&self) -> ::LegendreSymbol {
|
fn legendre(&self) -> ::ff::LegendreSymbol {
|
||||||
self.norm().legendre()
|
self.norm().legendre()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,16 +263,18 @@ fn test_fq2_basics() {
|
|||||||
);
|
);
|
||||||
assert!(Fq2::zero().is_zero());
|
assert!(Fq2::zero().is_zero());
|
||||||
assert!(!Fq2::one().is_zero());
|
assert!(!Fq2::one().is_zero());
|
||||||
assert!(!Fq2 {
|
assert!(
|
||||||
|
!Fq2 {
|
||||||
c0: Fq::zero(),
|
c0: Fq::zero(),
|
||||||
c1: Fq::one(),
|
c1: Fq::one(),
|
||||||
}.is_zero());
|
}.is_zero()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fq2_squaring() {
|
fn test_fq2_squaring() {
|
||||||
use super::fq::FqRepr;
|
use super::fq::FqRepr;
|
||||||
use PrimeField;
|
use ff::PrimeField;
|
||||||
|
|
||||||
let mut a = Fq2 {
|
let mut a = Fq2 {
|
||||||
c0: Fq::one(),
|
c0: Fq::one(),
|
||||||
@@ -346,7 +348,7 @@ fn test_fq2_squaring() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fq2_mul() {
|
fn test_fq2_mul() {
|
||||||
use super::fq::FqRepr;
|
use super::fq::FqRepr;
|
||||||
use PrimeField;
|
use ff::PrimeField;
|
||||||
|
|
||||||
let mut a = Fq2 {
|
let mut a = Fq2 {
|
||||||
c0: Fq::from_repr(FqRepr([
|
c0: Fq::from_repr(FqRepr([
|
||||||
@@ -410,7 +412,7 @@ fn test_fq2_mul() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fq2_inverse() {
|
fn test_fq2_inverse() {
|
||||||
use super::fq::FqRepr;
|
use super::fq::FqRepr;
|
||||||
use PrimeField;
|
use ff::PrimeField;
|
||||||
|
|
||||||
assert!(Fq2::zero().inverse().is_none());
|
assert!(Fq2::zero().inverse().is_none());
|
||||||
|
|
||||||
@@ -459,7 +461,7 @@ fn test_fq2_inverse() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fq2_addition() {
|
fn test_fq2_addition() {
|
||||||
use super::fq::FqRepr;
|
use super::fq::FqRepr;
|
||||||
use PrimeField;
|
use ff::PrimeField;
|
||||||
|
|
||||||
let mut a = Fq2 {
|
let mut a = Fq2 {
|
||||||
c0: Fq::from_repr(FqRepr([
|
c0: Fq::from_repr(FqRepr([
|
||||||
@@ -523,7 +525,7 @@ fn test_fq2_addition() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fq2_subtraction() {
|
fn test_fq2_subtraction() {
|
||||||
use super::fq::FqRepr;
|
use super::fq::FqRepr;
|
||||||
use PrimeField;
|
use ff::PrimeField;
|
||||||
|
|
||||||
let mut a = Fq2 {
|
let mut a = Fq2 {
|
||||||
c0: Fq::from_repr(FqRepr([
|
c0: Fq::from_repr(FqRepr([
|
||||||
@@ -587,7 +589,7 @@ fn test_fq2_subtraction() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fq2_negation() {
|
fn test_fq2_negation() {
|
||||||
use super::fq::FqRepr;
|
use super::fq::FqRepr;
|
||||||
use PrimeField;
|
use ff::PrimeField;
|
||||||
|
|
||||||
let mut a = Fq2 {
|
let mut a = Fq2 {
|
||||||
c0: Fq::from_repr(FqRepr([
|
c0: Fq::from_repr(FqRepr([
|
||||||
@@ -634,7 +636,7 @@ fn test_fq2_negation() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fq2_doubling() {
|
fn test_fq2_doubling() {
|
||||||
use super::fq::FqRepr;
|
use super::fq::FqRepr;
|
||||||
use PrimeField;
|
use ff::PrimeField;
|
||||||
|
|
||||||
let mut a = Fq2 {
|
let mut a = Fq2 {
|
||||||
c0: Fq::from_repr(FqRepr([
|
c0: Fq::from_repr(FqRepr([
|
||||||
@@ -681,7 +683,7 @@ fn test_fq2_doubling() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fq2_frobenius_map() {
|
fn test_fq2_frobenius_map() {
|
||||||
use super::fq::FqRepr;
|
use super::fq::FqRepr;
|
||||||
use PrimeField;
|
use ff::PrimeField;
|
||||||
|
|
||||||
let mut a = Fq2 {
|
let mut a = Fq2 {
|
||||||
c0: Fq::from_repr(FqRepr([
|
c0: Fq::from_repr(FqRepr([
|
||||||
@@ -794,7 +796,7 @@ fn test_fq2_frobenius_map() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fq2_sqrt() {
|
fn test_fq2_sqrt() {
|
||||||
use super::fq::FqRepr;
|
use super::fq::FqRepr;
|
||||||
use PrimeField;
|
use ff::PrimeField;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Fq2 {
|
Fq2 {
|
||||||
@@ -865,7 +867,7 @@ fn test_fq2_sqrt() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fq2_legendre() {
|
fn test_fq2_legendre() {
|
||||||
use LegendreSymbol::*;
|
use ff::LegendreSymbol::*;
|
||||||
|
|
||||||
assert_eq!(Zero, Fq2::zero().legendre());
|
assert_eq!(Zero, Fq2::zero().legendre());
|
||||||
// i^2 = -1
|
// i^2 = -1
|
||||||
@@ -900,7 +902,7 @@ fn test_fq2_mul_nonresidue() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fq2_field_tests() {
|
fn fq2_field_tests() {
|
||||||
use PrimeField;
|
use ff::PrimeField;
|
||||||
|
|
||||||
::tests::field::random_field_tests::<Fq2>();
|
::tests::field::random_field_tests::<Fq2>();
|
||||||
::tests::field::random_sqrt_tests::<Fq2>();
|
::tests::field::random_sqrt_tests::<Fq2>();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use super::fq::{FROBENIUS_COEFF_FQ6_C1, FROBENIUS_COEFF_FQ6_C2};
|
use super::fq::{FROBENIUS_COEFF_FQ6_C1, FROBENIUS_COEFF_FQ6_C2};
|
||||||
use super::fq2::Fq2;
|
use super::fq2::Fq2;
|
||||||
|
use ff::Field;
|
||||||
use rand::{Rand, Rng};
|
use rand::{Rand, Rng};
|
||||||
use Field;
|
|
||||||
|
|
||||||
/// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2).
|
/// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2).
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
@@ -367,7 +367,7 @@ fn test_fq6_mul_by_01() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fq6_field_tests() {
|
fn fq6_field_tests() {
|
||||||
use PrimeField;
|
use ff::PrimeField;
|
||||||
|
|
||||||
::tests::field::random_field_tests::<Fq6>();
|
::tests::field::random_field_tests::<Fq6>();
|
||||||
::tests::field::random_frobenius_tests::<Fq6, _>(super::fq::Fq::char(), 13);
|
::tests::field::random_frobenius_tests::<Fq6, _>(super::fq::Fq::char(), 13);
|
||||||
|
|||||||
@@ -1,647 +1,10 @@
|
|||||||
use LegendreSymbol::*;
|
use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr};
|
||||||
use {Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, SqrtField};
|
|
||||||
|
|
||||||
// r = 52435875175126190479447740508185965837690552500527637822603658699938581184513
|
#[derive(PrimeField)]
|
||||||
const MODULUS: FrRepr = FrRepr([
|
#[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"]
|
||||||
0xffffffff00000001,
|
#[PrimeFieldGenerator = "7"]
|
||||||
0x53bda402fffe5bfe,
|
|
||||||
0x3339d80809a1d805,
|
|
||||||
0x73eda753299d7d48,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// The number of bits needed to represent the modulus.
|
|
||||||
const MODULUS_BITS: u32 = 255;
|
|
||||||
|
|
||||||
// The number of bits that must be shaved from the beginning of
|
|
||||||
// the representation when randomly sampling.
|
|
||||||
const REPR_SHAVE_BITS: u32 = 1;
|
|
||||||
|
|
||||||
// R = 2**256 % r
|
|
||||||
const R: FrRepr = FrRepr([
|
|
||||||
0x1fffffffe,
|
|
||||||
0x5884b7fa00034802,
|
|
||||||
0x998c4fefecbc4ff5,
|
|
||||||
0x1824b159acc5056f,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// R2 = R^2 % r
|
|
||||||
const R2: FrRepr = FrRepr([
|
|
||||||
0xc999e990f3f29c6d,
|
|
||||||
0x2b6cedcb87925c23,
|
|
||||||
0x5d314967254398f,
|
|
||||||
0x748d9d99f59ff11,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// INV = -(r^{-1} mod 2^64) mod 2^64
|
|
||||||
const INV: u64 = 0xfffffffeffffffff;
|
|
||||||
|
|
||||||
// GENERATOR = 7 (multiplicative generator of r-1 order, that is also quadratic nonresidue)
|
|
||||||
const GENERATOR: FrRepr = FrRepr([
|
|
||||||
0xefffffff1,
|
|
||||||
0x17e363d300189c0f,
|
|
||||||
0xff9c57876f8457b0,
|
|
||||||
0x351332208fc5a8c4,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 2^s * t = MODULUS - 1 with t odd
|
|
||||||
const S: u32 = 32;
|
|
||||||
|
|
||||||
// 2^s root of unity computed by GENERATOR^t
|
|
||||||
const ROOT_OF_UNITY: FrRepr = FrRepr([
|
|
||||||
0xb9b58d8c5f0e466a,
|
|
||||||
0x5b1b4c801819d7ec,
|
|
||||||
0xaf53ae352a31e64,
|
|
||||||
0x5bf3adda19e9b27b,
|
|
||||||
]);
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
|
|
||||||
pub struct FrRepr(pub [u64; 4]);
|
|
||||||
|
|
||||||
impl ::rand::Rand for FrRepr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn rand<R: ::rand::Rng>(rng: &mut R) -> Self {
|
|
||||||
FrRepr(rng.gen())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::std::fmt::Display for FrRepr {
|
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
try!(write!(f, "0x"));
|
|
||||||
for i in self.0.iter().rev() {
|
|
||||||
try!(write!(f, "{:016x}", *i));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<[u64]> for FrRepr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn as_ref(&self) -> &[u64] {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsMut<[u64]> for FrRepr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn as_mut(&mut self) -> &mut [u64] {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u64> for FrRepr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn from(val: u64) -> FrRepr {
|
|
||||||
let mut repr = Self::default();
|
|
||||||
repr.0[0] = val;
|
|
||||||
repr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for FrRepr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn cmp(&self, other: &FrRepr) -> ::std::cmp::Ordering {
|
|
||||||
for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) {
|
|
||||||
if a < b {
|
|
||||||
return ::std::cmp::Ordering::Less;
|
|
||||||
} else if a > b {
|
|
||||||
return ::std::cmp::Ordering::Greater;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
::std::cmp::Ordering::Equal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for FrRepr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn partial_cmp(&self, other: &FrRepr) -> Option<::std::cmp::Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PrimeFieldRepr for FrRepr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn is_odd(&self) -> bool {
|
|
||||||
self.0[0] & 1 == 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn is_even(&self) -> bool {
|
|
||||||
!self.is_odd()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn is_zero(&self) -> bool {
|
|
||||||
self.0.iter().all(|&e| e == 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn shr(&mut self, mut n: u32) {
|
|
||||||
if n >= 64 * 4 {
|
|
||||||
*self = Self::from(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while n >= 64 {
|
|
||||||
let mut t = 0;
|
|
||||||
for i in self.0.iter_mut().rev() {
|
|
||||||
::std::mem::swap(&mut t, i);
|
|
||||||
}
|
|
||||||
n -= 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
if n > 0 {
|
|
||||||
let mut t = 0;
|
|
||||||
for i in self.0.iter_mut().rev() {
|
|
||||||
let t2 = *i << (64 - n);
|
|
||||||
*i >>= n;
|
|
||||||
*i |= t;
|
|
||||||
t = t2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn div2(&mut self) {
|
|
||||||
let mut t = 0;
|
|
||||||
for i in self.0.iter_mut().rev() {
|
|
||||||
let t2 = *i << 63;
|
|
||||||
*i >>= 1;
|
|
||||||
*i |= t;
|
|
||||||
t = t2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn mul2(&mut self) {
|
|
||||||
let mut last = 0;
|
|
||||||
for i in &mut self.0 {
|
|
||||||
let tmp = *i >> 63;
|
|
||||||
*i <<= 1;
|
|
||||||
*i |= last;
|
|
||||||
last = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn shl(&mut self, mut n: u32) {
|
|
||||||
if n >= 64 * 4 {
|
|
||||||
*self = Self::from(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while n >= 64 {
|
|
||||||
let mut t = 0;
|
|
||||||
for i in &mut self.0 {
|
|
||||||
::std::mem::swap(&mut t, i);
|
|
||||||
}
|
|
||||||
n -= 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
if n > 0 {
|
|
||||||
let mut t = 0;
|
|
||||||
for i in &mut self.0 {
|
|
||||||
let t2 = *i >> (64 - n);
|
|
||||||
*i <<= n;
|
|
||||||
*i |= t;
|
|
||||||
t = t2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn num_bits(&self) -> u32 {
|
|
||||||
let mut ret = (4 as u32) * 64;
|
|
||||||
for i in self.0.iter().rev() {
|
|
||||||
let leading = i.leading_zeros();
|
|
||||||
ret -= leading;
|
|
||||||
if leading != 64 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn add_nocarry(&mut self, other: &FrRepr) {
|
|
||||||
let mut carry = 0;
|
|
||||||
|
|
||||||
for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
|
|
||||||
*a = ::adc(*a, *b, &mut carry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn sub_noborrow(&mut self, other: &FrRepr) {
|
|
||||||
let mut borrow = 0;
|
|
||||||
|
|
||||||
for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
|
|
||||||
*a = ::sbb(*a, *b, &mut borrow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
||||||
pub struct Fr(FrRepr);
|
pub struct Fr(FrRepr);
|
||||||
|
|
||||||
impl ::std::fmt::Display for Fr {
|
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
write!(f, "Fr({})", self.into_repr())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::rand::Rand for Fr {
|
|
||||||
fn rand<R: ::rand::Rng>(rng: &mut R) -> Self {
|
|
||||||
loop {
|
|
||||||
let mut tmp = Fr(FrRepr::rand(rng));
|
|
||||||
|
|
||||||
// Mask away the unused bits at the beginning.
|
|
||||||
tmp.0.as_mut()[3] &= 0xffffffffffffffff >> REPR_SHAVE_BITS;
|
|
||||||
|
|
||||||
if tmp.is_valid() {
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Fr> for FrRepr {
|
|
||||||
fn from(e: Fr) -> FrRepr {
|
|
||||||
e.into_repr()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PrimeField for Fr {
|
|
||||||
type Repr = FrRepr;
|
|
||||||
|
|
||||||
fn from_repr(r: FrRepr) -> Result<Fr, PrimeFieldDecodingError> {
|
|
||||||
let mut r = Fr(r);
|
|
||||||
if r.is_valid() {
|
|
||||||
r.mul_assign(&Fr(R2));
|
|
||||||
|
|
||||||
Ok(r)
|
|
||||||
} else {
|
|
||||||
Err(PrimeFieldDecodingError::NotInField(format!("{}", r.0)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_repr(&self) -> FrRepr {
|
|
||||||
let mut r = *self;
|
|
||||||
r.mont_reduce(
|
|
||||||
(self.0).0[0],
|
|
||||||
(self.0).0[1],
|
|
||||||
(self.0).0[2],
|
|
||||||
(self.0).0[3],
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
r.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn char() -> FrRepr {
|
|
||||||
MODULUS
|
|
||||||
}
|
|
||||||
|
|
||||||
const NUM_BITS: u32 = MODULUS_BITS;
|
|
||||||
|
|
||||||
const CAPACITY: u32 = Self::NUM_BITS - 1;
|
|
||||||
|
|
||||||
fn multiplicative_generator() -> Self {
|
|
||||||
Fr(GENERATOR)
|
|
||||||
}
|
|
||||||
|
|
||||||
const S: u32 = S;
|
|
||||||
|
|
||||||
fn root_of_unity() -> Self {
|
|
||||||
Fr(ROOT_OF_UNITY)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Field for Fr {
|
|
||||||
#[inline]
|
|
||||||
fn zero() -> Self {
|
|
||||||
Fr(FrRepr::from(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn one() -> Self {
|
|
||||||
Fr(R)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_zero(&self) -> bool {
|
|
||||||
self.0.is_zero()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn add_assign(&mut self, other: &Fr) {
|
|
||||||
// This cannot exceed the backing capacity.
|
|
||||||
self.0.add_nocarry(&other.0);
|
|
||||||
|
|
||||||
// However, it may need to be reduced.
|
|
||||||
self.reduce();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn double(&mut self) {
|
|
||||||
// This cannot exceed the backing capacity.
|
|
||||||
self.0.mul2();
|
|
||||||
|
|
||||||
// However, it may need to be reduced.
|
|
||||||
self.reduce();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn sub_assign(&mut self, other: &Fr) {
|
|
||||||
// If `other` is larger than `self`, we'll need to add the modulus to self first.
|
|
||||||
if other.0 > self.0 {
|
|
||||||
self.0.add_nocarry(&MODULUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.0.sub_noborrow(&other.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn negate(&mut self) {
|
|
||||||
if !self.is_zero() {
|
|
||||||
let mut tmp = MODULUS;
|
|
||||||
tmp.sub_noborrow(&self.0);
|
|
||||||
self.0 = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn inverse(&self) -> Option<Self> {
|
|
||||||
if self.is_zero() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
// Guajardo Kumar Paar Pelzl
|
|
||||||
// Efficient Software-Implementation of Finite Fields with Applications to Cryptography
|
|
||||||
// Algorithm 16 (BEA for Inversion in Fp)
|
|
||||||
|
|
||||||
let one = FrRepr::from(1);
|
|
||||||
|
|
||||||
let mut u = self.0;
|
|
||||||
let mut v = MODULUS;
|
|
||||||
let mut b = Fr(R2); // Avoids unnecessary reduction step.
|
|
||||||
let mut c = Self::zero();
|
|
||||||
|
|
||||||
while u != one && v != one {
|
|
||||||
while u.is_even() {
|
|
||||||
u.div2();
|
|
||||||
|
|
||||||
if b.0.is_even() {
|
|
||||||
b.0.div2();
|
|
||||||
} else {
|
|
||||||
b.0.add_nocarry(&MODULUS);
|
|
||||||
b.0.div2();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while v.is_even() {
|
|
||||||
v.div2();
|
|
||||||
|
|
||||||
if c.0.is_even() {
|
|
||||||
c.0.div2();
|
|
||||||
} else {
|
|
||||||
c.0.add_nocarry(&MODULUS);
|
|
||||||
c.0.div2();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if v < u {
|
|
||||||
u.sub_noborrow(&v);
|
|
||||||
b.sub_assign(&c);
|
|
||||||
} else {
|
|
||||||
v.sub_noborrow(&u);
|
|
||||||
c.sub_assign(&b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if u == one {
|
|
||||||
Some(b)
|
|
||||||
} else {
|
|
||||||
Some(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn frobenius_map(&mut self, _: usize) {
|
|
||||||
// This has no effect in a prime field.
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn mul_assign(&mut self, other: &Fr) {
|
|
||||||
let mut carry = 0;
|
|
||||||
let r0 = ::mac_with_carry(0, (self.0).0[0], (other.0).0[0], &mut carry);
|
|
||||||
let r1 = ::mac_with_carry(0, (self.0).0[0], (other.0).0[1], &mut carry);
|
|
||||||
let r2 = ::mac_with_carry(0, (self.0).0[0], (other.0).0[2], &mut carry);
|
|
||||||
let r3 = ::mac_with_carry(0, (self.0).0[0], (other.0).0[3], &mut carry);
|
|
||||||
let r4 = carry;
|
|
||||||
let mut carry = 0;
|
|
||||||
let r1 = ::mac_with_carry(r1, (self.0).0[1], (other.0).0[0], &mut carry);
|
|
||||||
let r2 = ::mac_with_carry(r2, (self.0).0[1], (other.0).0[1], &mut carry);
|
|
||||||
let r3 = ::mac_with_carry(r3, (self.0).0[1], (other.0).0[2], &mut carry);
|
|
||||||
let r4 = ::mac_with_carry(r4, (self.0).0[1], (other.0).0[3], &mut carry);
|
|
||||||
let r5 = carry;
|
|
||||||
let mut carry = 0;
|
|
||||||
let r2 = ::mac_with_carry(r2, (self.0).0[2], (other.0).0[0], &mut carry);
|
|
||||||
let r3 = ::mac_with_carry(r3, (self.0).0[2], (other.0).0[1], &mut carry);
|
|
||||||
let r4 = ::mac_with_carry(r4, (self.0).0[2], (other.0).0[2], &mut carry);
|
|
||||||
let r5 = ::mac_with_carry(r5, (self.0).0[2], (other.0).0[3], &mut carry);
|
|
||||||
let r6 = carry;
|
|
||||||
let mut carry = 0;
|
|
||||||
let r3 = ::mac_with_carry(r3, (self.0).0[3], (other.0).0[0], &mut carry);
|
|
||||||
let r4 = ::mac_with_carry(r4, (self.0).0[3], (other.0).0[1], &mut carry);
|
|
||||||
let r5 = ::mac_with_carry(r5, (self.0).0[3], (other.0).0[2], &mut carry);
|
|
||||||
let r6 = ::mac_with_carry(r6, (self.0).0[3], (other.0).0[3], &mut carry);
|
|
||||||
let r7 = carry;
|
|
||||||
self.mont_reduce(r0, r1, r2, r3, r4, r5, r6, r7);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn square(&mut self) {
|
|
||||||
let mut carry = 0;
|
|
||||||
let r1 = ::mac_with_carry(0, (self.0).0[0], (self.0).0[1], &mut carry);
|
|
||||||
let r2 = ::mac_with_carry(0, (self.0).0[0], (self.0).0[2], &mut carry);
|
|
||||||
let r3 = ::mac_with_carry(0, (self.0).0[0], (self.0).0[3], &mut carry);
|
|
||||||
let r4 = carry;
|
|
||||||
let mut carry = 0;
|
|
||||||
let r3 = ::mac_with_carry(r3, (self.0).0[1], (self.0).0[2], &mut carry);
|
|
||||||
let r4 = ::mac_with_carry(r4, (self.0).0[1], (self.0).0[3], &mut carry);
|
|
||||||
let r5 = carry;
|
|
||||||
let mut carry = 0;
|
|
||||||
let r5 = ::mac_with_carry(r5, (self.0).0[2], (self.0).0[3], &mut carry);
|
|
||||||
let r6 = carry;
|
|
||||||
|
|
||||||
let r7 = r6 >> 63;
|
|
||||||
let r6 = (r6 << 1) | (r5 >> 63);
|
|
||||||
let r5 = (r5 << 1) | (r4 >> 63);
|
|
||||||
let r4 = (r4 << 1) | (r3 >> 63);
|
|
||||||
let r3 = (r3 << 1) | (r2 >> 63);
|
|
||||||
let r2 = (r2 << 1) | (r1 >> 63);
|
|
||||||
let r1 = r1 << 1;
|
|
||||||
|
|
||||||
let mut carry = 0;
|
|
||||||
let r0 = ::mac_with_carry(0, (self.0).0[0], (self.0).0[0], &mut carry);
|
|
||||||
let r1 = ::adc(r1, 0, &mut carry);
|
|
||||||
let r2 = ::mac_with_carry(r2, (self.0).0[1], (self.0).0[1], &mut carry);
|
|
||||||
let r3 = ::adc(r3, 0, &mut carry);
|
|
||||||
let r4 = ::mac_with_carry(r4, (self.0).0[2], (self.0).0[2], &mut carry);
|
|
||||||
let r5 = ::adc(r5, 0, &mut carry);
|
|
||||||
let r6 = ::mac_with_carry(r6, (self.0).0[3], (self.0).0[3], &mut carry);
|
|
||||||
let r7 = ::adc(r7, 0, &mut carry);
|
|
||||||
self.mont_reduce(r0, r1, r2, r3, r4, r5, r6, r7);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Fr {
|
|
||||||
/// Determines if the element is really in the field. This is only used
|
|
||||||
/// internally.
|
|
||||||
#[inline(always)]
|
|
||||||
fn is_valid(&self) -> bool {
|
|
||||||
self.0 < MODULUS
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Subtracts the modulus from this element if this element is not in the
|
|
||||||
/// field. Only used internally.
|
|
||||||
#[inline(always)]
|
|
||||||
fn reduce(&mut self) {
|
|
||||||
if !self.is_valid() {
|
|
||||||
self.0.sub_noborrow(&MODULUS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn mont_reduce(
|
|
||||||
&mut self,
|
|
||||||
r0: u64,
|
|
||||||
mut r1: u64,
|
|
||||||
mut r2: u64,
|
|
||||||
mut r3: u64,
|
|
||||||
mut r4: u64,
|
|
||||||
mut r5: u64,
|
|
||||||
mut r6: u64,
|
|
||||||
mut r7: u64,
|
|
||||||
) {
|
|
||||||
// The Montgomery reduction here is based on Algorithm 14.32 in
|
|
||||||
// Handbook of Applied Cryptography
|
|
||||||
// <http://cacr.uwaterloo.ca/hac/about/chap14.pdf>.
|
|
||||||
|
|
||||||
let k = r0.wrapping_mul(INV);
|
|
||||||
let mut carry = 0;
|
|
||||||
::mac_with_carry(r0, k, MODULUS.0[0], &mut carry);
|
|
||||||
r1 = ::mac_with_carry(r1, k, MODULUS.0[1], &mut carry);
|
|
||||||
r2 = ::mac_with_carry(r2, k, MODULUS.0[2], &mut carry);
|
|
||||||
r3 = ::mac_with_carry(r3, k, MODULUS.0[3], &mut carry);
|
|
||||||
r4 = ::adc(r4, 0, &mut carry);
|
|
||||||
let carry2 = carry;
|
|
||||||
let k = r1.wrapping_mul(INV);
|
|
||||||
let mut carry = 0;
|
|
||||||
::mac_with_carry(r1, k, MODULUS.0[0], &mut carry);
|
|
||||||
r2 = ::mac_with_carry(r2, k, MODULUS.0[1], &mut carry);
|
|
||||||
r3 = ::mac_with_carry(r3, k, MODULUS.0[2], &mut carry);
|
|
||||||
r4 = ::mac_with_carry(r4, k, MODULUS.0[3], &mut carry);
|
|
||||||
r5 = ::adc(r5, carry2, &mut carry);
|
|
||||||
let carry2 = carry;
|
|
||||||
let k = r2.wrapping_mul(INV);
|
|
||||||
let mut carry = 0;
|
|
||||||
::mac_with_carry(r2, k, MODULUS.0[0], &mut carry);
|
|
||||||
r3 = ::mac_with_carry(r3, k, MODULUS.0[1], &mut carry);
|
|
||||||
r4 = ::mac_with_carry(r4, k, MODULUS.0[2], &mut carry);
|
|
||||||
r5 = ::mac_with_carry(r5, k, MODULUS.0[3], &mut carry);
|
|
||||||
r6 = ::adc(r6, carry2, &mut carry);
|
|
||||||
let carry2 = carry;
|
|
||||||
let k = r3.wrapping_mul(INV);
|
|
||||||
let mut carry = 0;
|
|
||||||
::mac_with_carry(r3, k, MODULUS.0[0], &mut carry);
|
|
||||||
r4 = ::mac_with_carry(r4, k, MODULUS.0[1], &mut carry);
|
|
||||||
r5 = ::mac_with_carry(r5, k, MODULUS.0[2], &mut carry);
|
|
||||||
r6 = ::mac_with_carry(r6, k, MODULUS.0[3], &mut carry);
|
|
||||||
r7 = ::adc(r7, carry2, &mut carry);
|
|
||||||
(self.0).0[0] = r4;
|
|
||||||
(self.0).0[1] = r5;
|
|
||||||
(self.0).0[2] = r6;
|
|
||||||
(self.0).0[3] = r7;
|
|
||||||
self.reduce();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SqrtField for Fr {
|
|
||||||
fn legendre(&self) -> ::LegendreSymbol {
|
|
||||||
// s = self^((r - 1) // 2)
|
|
||||||
let s = self.pow([
|
|
||||||
0x7fffffff80000000,
|
|
||||||
0xa9ded2017fff2dff,
|
|
||||||
0x199cec0404d0ec02,
|
|
||||||
0x39f6d3a994cebea4,
|
|
||||||
]);
|
|
||||||
if s == Self::zero() {
|
|
||||||
Zero
|
|
||||||
} else if s == Self::one() {
|
|
||||||
QuadraticResidue
|
|
||||||
} else {
|
|
||||||
QuadraticNonResidue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sqrt(&self) -> Option<Self> {
|
|
||||||
// Tonelli-Shank's algorithm for q mod 16 = 1
|
|
||||||
// https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5)
|
|
||||||
match self.legendre() {
|
|
||||||
Zero => Some(*self),
|
|
||||||
QuadraticNonResidue => None,
|
|
||||||
QuadraticResidue => {
|
|
||||||
let mut c = Fr(ROOT_OF_UNITY);
|
|
||||||
// r = self^((t + 1) // 2)
|
|
||||||
let mut r = self.pow([
|
|
||||||
0x7fff2dff80000000,
|
|
||||||
0x4d0ec02a9ded201,
|
|
||||||
0x94cebea4199cec04,
|
|
||||||
0x39f6d3a9,
|
|
||||||
]);
|
|
||||||
// t = self^t
|
|
||||||
let mut t = self.pow([
|
|
||||||
0xfffe5bfeffffffff,
|
|
||||||
0x9a1d80553bda402,
|
|
||||||
0x299d7d483339d808,
|
|
||||||
0x73eda753,
|
|
||||||
]);
|
|
||||||
let mut m = S;
|
|
||||||
|
|
||||||
while t != Self::one() {
|
|
||||||
let mut i = 1;
|
|
||||||
{
|
|
||||||
let mut t2i = t;
|
|
||||||
t2i.square();
|
|
||||||
loop {
|
|
||||||
if t2i == Self::one() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
t2i.square();
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _ in 0..(m - i - 1) {
|
|
||||||
c.square();
|
|
||||||
}
|
|
||||||
r.mul_assign(&c);
|
|
||||||
c.square();
|
|
||||||
t.mul_assign(&c);
|
|
||||||
m = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||||
|
|
||||||
@@ -909,6 +272,9 @@ fn test_fr_repr_sub_noborrow() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fr_legendre() {
|
fn test_fr_legendre() {
|
||||||
|
use ff::LegendreSymbol::*;
|
||||||
|
use ff::SqrtField;
|
||||||
|
|
||||||
assert_eq!(QuadraticResidue, Fr::one().legendre());
|
assert_eq!(QuadraticResidue, Fr::one().legendre());
|
||||||
assert_eq!(Zero, Fr::zero().legendre());
|
assert_eq!(Zero, Fr::zero().legendre());
|
||||||
|
|
||||||
@@ -1022,12 +388,14 @@ fn test_fr_is_valid() {
|
|||||||
0x73eda753299d7d48
|
0x73eda753299d7d48
|
||||||
])).is_valid()
|
])).is_valid()
|
||||||
);
|
);
|
||||||
assert!(!Fr(FrRepr([
|
assert!(
|
||||||
|
!Fr(FrRepr([
|
||||||
0xffffffffffffffff,
|
0xffffffffffffffff,
|
||||||
0xffffffffffffffff,
|
0xffffffffffffffff,
|
||||||
0xffffffffffffffff,
|
0xffffffffffffffff,
|
||||||
0xffffffffffffffff
|
0xffffffffffffffff
|
||||||
])).is_valid());
|
])).is_valid()
|
||||||
|
);
|
||||||
|
|
||||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
|
||||||
@@ -1417,6 +785,8 @@ fn test_fr_pow() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fr_sqrt() {
|
fn test_fr_sqrt() {
|
||||||
|
use ff::SqrtField;
|
||||||
|
|
||||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
|
||||||
assert_eq!(Fr::zero().sqrt().unwrap(), Fr::zero());
|
assert_eq!(Fr::zero().sqrt().unwrap(), Fr::zero());
|
||||||
@@ -1582,6 +952,8 @@ fn test_fr_num_bits() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fr_root_of_unity() {
|
fn test_fr_root_of_unity() {
|
||||||
|
use ff::SqrtField;
|
||||||
|
|
||||||
assert_eq!(Fr::S, 32);
|
assert_eq!(Fr::S, 32);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Fr::multiplicative_generator(),
|
Fr::multiplicative_generator(),
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ pub use self::fq2::Fq2;
|
|||||||
pub use self::fq6::Fq6;
|
pub use self::fq6::Fq6;
|
||||||
pub use self::fr::{Fr, FrRepr};
|
pub use self::fr::{Fr, FrRepr};
|
||||||
|
|
||||||
use super::{BitIterator, CurveAffine, Engine, Field};
|
use super::{Engine, PairingCurveAffine};
|
||||||
|
|
||||||
|
use ff::{BitIterator, Field, ScalarEngine};
|
||||||
|
use group::CurveAffine;
|
||||||
|
|
||||||
// The BLS parameter x for BLS12-381 is -0xd201000000010000
|
// The BLS parameter x for BLS12-381 is -0xd201000000010000
|
||||||
const BLS_X: u64 = 0xd201000000010000;
|
const BLS_X: u64 = 0xd201000000010000;
|
||||||
@@ -27,8 +30,11 @@ const BLS_X_IS_NEGATIVE: bool = true;
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Bls12;
|
pub struct Bls12;
|
||||||
|
|
||||||
impl Engine for Bls12 {
|
impl ScalarEngine for Bls12 {
|
||||||
type Fr = Fr;
|
type Fr = Fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Engine for Bls12 {
|
||||||
type G1 = G1;
|
type G1 = G1;
|
||||||
type G1Affine = G1Affine;
|
type G1Affine = G1Affine;
|
||||||
type G2 = G2;
|
type G2 = G2;
|
||||||
@@ -41,8 +47,8 @@ impl Engine for Bls12 {
|
|||||||
where
|
where
|
||||||
I: IntoIterator<
|
I: IntoIterator<
|
||||||
Item = &'a (
|
Item = &'a (
|
||||||
&'a <Self::G1Affine as CurveAffine>::Prepared,
|
&'a <Self::G1Affine as PairingCurveAffine>::Prepared,
|
||||||
&'a <Self::G2Affine as CurveAffine>::Prepared,
|
&'a <Self::G2Affine as PairingCurveAffine>::Prepared,
|
||||||
),
|
),
|
||||||
>,
|
>,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
use ff::PrimeFieldRepr;
|
||||||
|
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use *;
|
use *;
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
// `clippy` is a code linting tool for improving code quality by catching
|
// `clippy` is a code linting tool for improving code quality by catching
|
||||||
// common mistakes or strange code patterns. If the `clippy` feature is
|
// common mistakes or strange code patterns. If the `cargo-clippy` feature
|
||||||
// provided, it is enabled and all compiler warnings are prohibited.
|
// is provided, all compiler warnings are prohibited.
|
||||||
#![cfg_attr(feature = "clippy", deny(warnings))]
|
#![cfg_attr(feature = "cargo-clippy", deny(warnings))]
|
||||||
#![cfg_attr(feature = "clippy", feature(plugin))]
|
#![cfg_attr(feature = "cargo-clippy", allow(inline_always))]
|
||||||
#![cfg_attr(feature = "clippy", plugin(clippy))]
|
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
||||||
#![cfg_attr(feature = "clippy", allow(inline_always))]
|
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]
|
||||||
#![cfg_attr(feature = "clippy", allow(too_many_arguments))]
|
#![cfg_attr(feature = "cargo-clippy", allow(many_single_char_names))]
|
||||||
#![cfg_attr(feature = "clippy", allow(unreadable_literal))]
|
#![cfg_attr(feature = "cargo-clippy", allow(new_without_default_derive))]
|
||||||
#![cfg_attr(feature = "clippy", allow(many_single_char_names))]
|
#![cfg_attr(feature = "cargo-clippy", allow(write_literal))]
|
||||||
#![cfg_attr(feature = "clippy", allow(new_without_default_derive))]
|
|
||||||
#![cfg_attr(feature = "clippy", allow(write_literal))]
|
|
||||||
// Force public structures to implement Debug
|
// Force public structures to implement Debug
|
||||||
#![deny(missing_debug_implementations)]
|
#![deny(missing_debug_implementations)]
|
||||||
|
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
|
extern crate ff;
|
||||||
|
extern crate group;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -21,20 +21,13 @@ pub mod tests;
|
|||||||
|
|
||||||
pub mod bls12_381;
|
pub mod bls12_381;
|
||||||
|
|
||||||
mod wnaf;
|
use ff::{Field, PrimeField, ScalarEngine, SqrtField};
|
||||||
pub use self::wnaf::Wnaf;
|
use group::{CurveAffine, CurveProjective};
|
||||||
|
|
||||||
use std::error::Error;
|
|
||||||
use std::fmt;
|
|
||||||
use std::io::{self, Read, Write};
|
|
||||||
|
|
||||||
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
|
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
|
||||||
/// with well-defined relationships. In particular, the G1/G2 curve groups are
|
/// with well-defined relationships. In particular, the G1/G2 curve groups are
|
||||||
/// of prime order `r`, and are equipped with a bilinear pairing function.
|
/// of prime order `r`, and are equipped with a bilinear pairing function.
|
||||||
pub trait Engine: Sized + 'static + Clone {
|
pub trait Engine: ScalarEngine {
|
||||||
/// This is the scalar field of the G1/G2 groups.
|
|
||||||
type Fr: PrimeField + SqrtField;
|
|
||||||
|
|
||||||
/// The projective representation of an element in G1.
|
/// The projective representation of an element in G1.
|
||||||
type G1: CurveProjective<
|
type G1: CurveProjective<
|
||||||
Engine = Self,
|
Engine = Self,
|
||||||
@@ -45,7 +38,7 @@ pub trait Engine: Sized + 'static + Clone {
|
|||||||
+ From<Self::G1Affine>;
|
+ From<Self::G1Affine>;
|
||||||
|
|
||||||
/// The affine representation of an element in G1.
|
/// The affine representation of an element in G1.
|
||||||
type G1Affine: CurveAffine<
|
type G1Affine: PairingCurveAffine<
|
||||||
Engine = Self,
|
Engine = Self,
|
||||||
Base = Self::Fq,
|
Base = Self::Fq,
|
||||||
Scalar = Self::Fr,
|
Scalar = Self::Fr,
|
||||||
@@ -65,7 +58,7 @@ pub trait Engine: Sized + 'static + Clone {
|
|||||||
+ From<Self::G2Affine>;
|
+ From<Self::G2Affine>;
|
||||||
|
|
||||||
/// The affine representation of an element in G2.
|
/// The affine representation of an element in G2.
|
||||||
type G2Affine: CurveAffine<
|
type G2Affine: PairingCurveAffine<
|
||||||
Engine = Self,
|
Engine = Self,
|
||||||
Base = Self::Fqe,
|
Base = Self::Fqe,
|
||||||
Scalar = Self::Fr,
|
Scalar = Self::Fr,
|
||||||
@@ -89,8 +82,8 @@ pub trait Engine: Sized + 'static + Clone {
|
|||||||
where
|
where
|
||||||
I: IntoIterator<
|
I: IntoIterator<
|
||||||
Item = &'a (
|
Item = &'a (
|
||||||
&'a <Self::G1Affine as CurveAffine>::Prepared,
|
&'a <Self::G1Affine as PairingCurveAffine>::Prepared,
|
||||||
&'a <Self::G2Affine as CurveAffine>::Prepared,
|
&'a <Self::G2Affine as PairingCurveAffine>::Prepared,
|
||||||
),
|
),
|
||||||
>;
|
>;
|
||||||
|
|
||||||
@@ -109,650 +102,16 @@ pub trait Engine: Sized + 'static + Clone {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Projective representation of an elliptic curve point guaranteed to be
|
/// Affine representation of an elliptic curve point that can be used
|
||||||
/// in the correct prime order subgroup.
|
/// to perform pairings.
|
||||||
pub trait CurveProjective:
|
pub trait PairingCurveAffine: CurveAffine {
|
||||||
PartialEq
|
|
||||||
+ Eq
|
|
||||||
+ Sized
|
|
||||||
+ Copy
|
|
||||||
+ Clone
|
|
||||||
+ Send
|
|
||||||
+ Sync
|
|
||||||
+ fmt::Debug
|
|
||||||
+ fmt::Display
|
|
||||||
+ rand::Rand
|
|
||||||
+ 'static
|
|
||||||
{
|
|
||||||
type Engine: Engine<Fr = Self::Scalar>;
|
|
||||||
type Scalar: PrimeField + SqrtField;
|
|
||||||
type Base: SqrtField;
|
|
||||||
type Affine: CurveAffine<Projective = Self, Scalar = Self::Scalar>;
|
|
||||||
|
|
||||||
/// Returns the additive identity.
|
|
||||||
fn zero() -> Self;
|
|
||||||
|
|
||||||
/// Returns a fixed generator of unknown exponent.
|
|
||||||
fn one() -> Self;
|
|
||||||
|
|
||||||
/// Determines if this point is the point at infinity.
|
|
||||||
fn is_zero(&self) -> bool;
|
|
||||||
|
|
||||||
/// Normalizes a slice of projective elements so that
|
|
||||||
/// conversion to affine is cheap.
|
|
||||||
fn batch_normalization(v: &mut [Self]);
|
|
||||||
|
|
||||||
/// Checks if the point is already "normalized" so that
|
|
||||||
/// cheap affine conversion is possible.
|
|
||||||
fn is_normalized(&self) -> bool;
|
|
||||||
|
|
||||||
/// Doubles this element.
|
|
||||||
fn double(&mut self);
|
|
||||||
|
|
||||||
/// Adds another element to this element.
|
|
||||||
fn add_assign(&mut self, other: &Self);
|
|
||||||
|
|
||||||
/// Subtracts another element from this element.
|
|
||||||
fn sub_assign(&mut self, other: &Self) {
|
|
||||||
let mut tmp = *other;
|
|
||||||
tmp.negate();
|
|
||||||
self.add_assign(&tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds an affine element to this element.
|
|
||||||
fn add_assign_mixed(&mut self, other: &Self::Affine);
|
|
||||||
|
|
||||||
/// Negates this element.
|
|
||||||
fn negate(&mut self);
|
|
||||||
|
|
||||||
/// Performs scalar multiplication of this element.
|
|
||||||
fn mul_assign<S: Into<<Self::Scalar as PrimeField>::Repr>>(&mut self, other: S);
|
|
||||||
|
|
||||||
/// Converts this element into its affine representation.
|
|
||||||
fn into_affine(&self) -> Self::Affine;
|
|
||||||
|
|
||||||
/// Recommends a wNAF window table size given a scalar. Always returns a number
|
|
||||||
/// between 2 and 22, inclusive.
|
|
||||||
fn recommended_wnaf_for_scalar(scalar: <Self::Scalar as PrimeField>::Repr) -> usize;
|
|
||||||
|
|
||||||
/// Recommends a wNAF window size given the number of scalars you intend to multiply
|
|
||||||
/// a base by. Always returns a number between 2 and 22, inclusive.
|
|
||||||
fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Affine representation of an elliptic curve point guaranteed to be
|
|
||||||
/// in the correct prime order subgroup.
|
|
||||||
pub trait CurveAffine:
|
|
||||||
Copy + Clone + Sized + Send + Sync + fmt::Debug + fmt::Display + PartialEq + Eq + 'static
|
|
||||||
{
|
|
||||||
type Engine: Engine<Fr = Self::Scalar>;
|
|
||||||
type Scalar: PrimeField + SqrtField;
|
|
||||||
type Base: SqrtField;
|
|
||||||
type Projective: CurveProjective<Affine = Self, Scalar = Self::Scalar>;
|
|
||||||
type Prepared: Clone + Send + Sync + 'static;
|
type Prepared: Clone + Send + Sync + 'static;
|
||||||
type Uncompressed: EncodedPoint<Affine = Self>;
|
type Pair: PairingCurveAffine<Pair = Self>;
|
||||||
type Compressed: EncodedPoint<Affine = Self>;
|
|
||||||
type Pair: CurveAffine<Pair = Self>;
|
|
||||||
type PairingResult: Field;
|
type PairingResult: Field;
|
||||||
|
|
||||||
/// Returns the additive identity.
|
|
||||||
fn zero() -> Self;
|
|
||||||
|
|
||||||
/// Returns a fixed generator of unknown exponent.
|
|
||||||
fn one() -> Self;
|
|
||||||
|
|
||||||
/// Determines if this point represents the point at infinity; the
|
|
||||||
/// additive identity.
|
|
||||||
fn is_zero(&self) -> bool;
|
|
||||||
|
|
||||||
/// Negates this element.
|
|
||||||
fn negate(&mut self);
|
|
||||||
|
|
||||||
/// Performs scalar multiplication of this element with mixed addition.
|
|
||||||
fn mul<S: Into<<Self::Scalar as PrimeField>::Repr>>(&self, other: S) -> Self::Projective;
|
|
||||||
|
|
||||||
/// Prepares this element for pairing purposes.
|
/// Prepares this element for pairing purposes.
|
||||||
fn prepare(&self) -> Self::Prepared;
|
fn prepare(&self) -> Self::Prepared;
|
||||||
|
|
||||||
/// Perform a pairing
|
/// Perform a pairing
|
||||||
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult;
|
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult;
|
||||||
|
|
||||||
/// Converts this element into its affine representation.
|
|
||||||
fn into_projective(&self) -> Self::Projective;
|
|
||||||
|
|
||||||
/// Converts this element into its compressed encoding, so long as it's not
|
|
||||||
/// the point at infinity.
|
|
||||||
fn into_compressed(&self) -> Self::Compressed {
|
|
||||||
<Self::Compressed as EncodedPoint>::from_affine(*self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts this element into its uncompressed encoding, so long as it's not
|
|
||||||
/// the point at infinity.
|
|
||||||
fn into_uncompressed(&self) -> Self::Uncompressed {
|
|
||||||
<Self::Uncompressed as EncodedPoint>::from_affine(*self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An encoded elliptic curve point, which should essentially wrap a `[u8; N]`.
|
|
||||||
pub trait EncodedPoint:
|
|
||||||
Sized + Send + Sync + AsRef<[u8]> + AsMut<[u8]> + Clone + Copy + 'static
|
|
||||||
{
|
|
||||||
type Affine: CurveAffine;
|
|
||||||
|
|
||||||
/// Creates an empty representation.
|
|
||||||
fn empty() -> Self;
|
|
||||||
|
|
||||||
/// Returns the number of bytes consumed by this representation.
|
|
||||||
fn size() -> usize;
|
|
||||||
|
|
||||||
/// Converts an `EncodedPoint` into a `CurveAffine` element,
|
|
||||||
/// if the encoding represents a valid element.
|
|
||||||
fn into_affine(&self) -> Result<Self::Affine, GroupDecodingError>;
|
|
||||||
|
|
||||||
/// Converts an `EncodedPoint` into a `CurveAffine` element,
|
|
||||||
/// without guaranteeing that the encoding represents a valid
|
|
||||||
/// element. This is useful when the caller knows the encoding is
|
|
||||||
/// valid already.
|
|
||||||
///
|
|
||||||
/// If the encoding is invalid, this can break API invariants,
|
|
||||||
/// so caution is strongly encouraged.
|
|
||||||
fn into_affine_unchecked(&self) -> Result<Self::Affine, GroupDecodingError>;
|
|
||||||
|
|
||||||
/// Creates an `EncodedPoint` from an affine point, as long as the
|
|
||||||
/// point is not the point at infinity.
|
|
||||||
fn from_affine(affine: Self::Affine) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This trait represents an element of a field.
|
|
||||||
pub trait Field:
|
|
||||||
Sized + Eq + Copy + Clone + Send + Sync + fmt::Debug + fmt::Display + 'static + rand::Rand
|
|
||||||
{
|
|
||||||
/// Returns the zero element of the field, the additive identity.
|
|
||||||
fn zero() -> Self;
|
|
||||||
|
|
||||||
/// Returns the one element of the field, the multiplicative identity.
|
|
||||||
fn one() -> Self;
|
|
||||||
|
|
||||||
/// Returns true iff this element is zero.
|
|
||||||
fn is_zero(&self) -> bool;
|
|
||||||
|
|
||||||
/// Squares this element.
|
|
||||||
fn square(&mut self);
|
|
||||||
|
|
||||||
/// Doubles this element.
|
|
||||||
fn double(&mut self);
|
|
||||||
|
|
||||||
/// Negates this element.
|
|
||||||
fn negate(&mut self);
|
|
||||||
|
|
||||||
/// Adds another element to this element.
|
|
||||||
fn add_assign(&mut self, other: &Self);
|
|
||||||
|
|
||||||
/// Subtracts another element from this element.
|
|
||||||
fn sub_assign(&mut self, other: &Self);
|
|
||||||
|
|
||||||
/// Multiplies another element by this element.
|
|
||||||
fn mul_assign(&mut self, other: &Self);
|
|
||||||
|
|
||||||
/// Computes the multiplicative inverse of this element, if nonzero.
|
|
||||||
fn inverse(&self) -> Option<Self>;
|
|
||||||
|
|
||||||
/// Exponentiates this element by a power of the base prime modulus via
|
|
||||||
/// the Frobenius automorphism.
|
|
||||||
fn frobenius_map(&mut self, power: usize);
|
|
||||||
|
|
||||||
/// Exponentiates this element by a number represented with `u64` limbs,
|
|
||||||
/// least significant digit first.
|
|
||||||
fn pow<S: AsRef<[u64]>>(&self, exp: S) -> Self {
|
|
||||||
let mut res = Self::one();
|
|
||||||
|
|
||||||
let mut found_one = false;
|
|
||||||
|
|
||||||
for i in BitIterator::new(exp) {
|
|
||||||
if found_one {
|
|
||||||
res.square();
|
|
||||||
} else {
|
|
||||||
found_one = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if i {
|
|
||||||
res.mul_assign(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This trait represents an element of a field that has a square root operation described for it.
|
|
||||||
pub trait SqrtField: Field {
|
|
||||||
/// Returns the Legendre symbol of the field element.
|
|
||||||
fn legendre(&self) -> LegendreSymbol;
|
|
||||||
|
|
||||||
/// Returns the square root of the field element, if it is
|
|
||||||
/// quadratic residue.
|
|
||||||
fn sqrt(&self) -> Option<Self>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This trait represents a wrapper around a biginteger which can encode any element of a particular
|
|
||||||
/// prime field. It is a smart wrapper around a sequence of `u64` limbs, least-significant digit
|
|
||||||
/// first.
|
|
||||||
pub trait PrimeFieldRepr:
|
|
||||||
Sized
|
|
||||||
+ Copy
|
|
||||||
+ Clone
|
|
||||||
+ Eq
|
|
||||||
+ Ord
|
|
||||||
+ Send
|
|
||||||
+ Sync
|
|
||||||
+ Default
|
|
||||||
+ fmt::Debug
|
|
||||||
+ fmt::Display
|
|
||||||
+ 'static
|
|
||||||
+ rand::Rand
|
|
||||||
+ AsRef<[u64]>
|
|
||||||
+ AsMut<[u64]>
|
|
||||||
+ From<u64>
|
|
||||||
{
|
|
||||||
/// Subtract another represetation from this one.
|
|
||||||
fn sub_noborrow(&mut self, other: &Self);
|
|
||||||
|
|
||||||
/// Add another representation to this one.
|
|
||||||
fn add_nocarry(&mut self, other: &Self);
|
|
||||||
|
|
||||||
/// Compute the number of bits needed to encode this number. Always a
|
|
||||||
/// multiple of 64.
|
|
||||||
fn num_bits(&self) -> u32;
|
|
||||||
|
|
||||||
/// Returns true iff this number is zero.
|
|
||||||
fn is_zero(&self) -> bool;
|
|
||||||
|
|
||||||
/// Returns true iff this number is odd.
|
|
||||||
fn is_odd(&self) -> bool;
|
|
||||||
|
|
||||||
/// Returns true iff this number is even.
|
|
||||||
fn is_even(&self) -> bool;
|
|
||||||
|
|
||||||
/// Performs a rightwise bitshift of this number, effectively dividing
|
|
||||||
/// it by 2.
|
|
||||||
fn div2(&mut self);
|
|
||||||
|
|
||||||
/// Performs a rightwise bitshift of this number by some amount.
|
|
||||||
fn shr(&mut self, amt: u32);
|
|
||||||
|
|
||||||
/// Performs a leftwise bitshift of this number, effectively multiplying
|
|
||||||
/// it by 2. Overflow is ignored.
|
|
||||||
fn mul2(&mut self);
|
|
||||||
|
|
||||||
/// Performs a leftwise bitshift of this number by some amount.
|
|
||||||
fn shl(&mut self, amt: u32);
|
|
||||||
|
|
||||||
/// Writes this `PrimeFieldRepr` as a big endian integer.
|
|
||||||
fn write_be<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
|
||||||
use byteorder::{BigEndian, WriteBytesExt};
|
|
||||||
|
|
||||||
for digit in self.as_ref().iter().rev() {
|
|
||||||
writer.write_u64::<BigEndian>(*digit)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reads a big endian integer into this representation.
|
|
||||||
fn read_be<R: Read>(&mut self, mut reader: R) -> io::Result<()> {
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
|
||||||
|
|
||||||
for digit in self.as_mut().iter_mut().rev() {
|
|
||||||
*digit = reader.read_u64::<BigEndian>()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes this `PrimeFieldRepr` as a little endian integer.
|
|
||||||
fn write_le<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
|
||||||
use byteorder::{LittleEndian, WriteBytesExt};
|
|
||||||
|
|
||||||
for digit in self.as_ref().iter() {
|
|
||||||
writer.write_u64::<LittleEndian>(*digit)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reads a little endian integer into this representation.
|
|
||||||
fn read_le<R: Read>(&mut self, mut reader: R) -> io::Result<()> {
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt};
|
|
||||||
|
|
||||||
for digit in self.as_mut().iter_mut() {
|
|
||||||
*digit = reader.read_u64::<LittleEndian>()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum LegendreSymbol {
|
|
||||||
Zero = 0,
|
|
||||||
QuadraticResidue = 1,
|
|
||||||
QuadraticNonResidue = -1,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An error that may occur when trying to interpret a `PrimeFieldRepr` as a
|
|
||||||
/// `PrimeField` element.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum PrimeFieldDecodingError {
|
|
||||||
/// The encoded value is not in the field
|
|
||||||
NotInField(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for PrimeFieldDecodingError {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match *self {
|
|
||||||
PrimeFieldDecodingError::NotInField(..) => "not an element of the field",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for PrimeFieldDecodingError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
||||||
match *self {
|
|
||||||
PrimeFieldDecodingError::NotInField(ref repr) => {
|
|
||||||
write!(f, "{} is not an element of the field", repr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An error that may occur when trying to decode an `EncodedPoint`.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum GroupDecodingError {
|
|
||||||
/// The coordinate(s) do not lie on the curve.
|
|
||||||
NotOnCurve,
|
|
||||||
/// The element is not part of the r-order subgroup.
|
|
||||||
NotInSubgroup,
|
|
||||||
/// One of the coordinates could not be decoded
|
|
||||||
CoordinateDecodingError(&'static str, PrimeFieldDecodingError),
|
|
||||||
/// The compression mode of the encoded element was not as expected
|
|
||||||
UnexpectedCompressionMode,
|
|
||||||
/// The encoding contained bits that should not have been set
|
|
||||||
UnexpectedInformation,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for GroupDecodingError {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match *self {
|
|
||||||
GroupDecodingError::NotOnCurve => "coordinate(s) do not lie on the curve",
|
|
||||||
GroupDecodingError::NotInSubgroup => "the element is not part of an r-order subgroup",
|
|
||||||
GroupDecodingError::CoordinateDecodingError(..) => "coordinate(s) could not be decoded",
|
|
||||||
GroupDecodingError::UnexpectedCompressionMode => {
|
|
||||||
"encoding has unexpected compression mode"
|
|
||||||
}
|
|
||||||
GroupDecodingError::UnexpectedInformation => "encoding has unexpected information",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for GroupDecodingError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
||||||
match *self {
|
|
||||||
GroupDecodingError::CoordinateDecodingError(description, ref err) => {
|
|
||||||
write!(f, "{} decoding error: {}", description, err)
|
|
||||||
}
|
|
||||||
_ => write!(f, "{}", self.description()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This represents an element of a prime field.
|
|
||||||
pub trait PrimeField: Field {
|
|
||||||
/// The prime field can be converted back and forth into this biginteger
|
|
||||||
/// representation.
|
|
||||||
type Repr: PrimeFieldRepr + From<Self>;
|
|
||||||
|
|
||||||
/// Interpret a string of numbers as a (congruent) prime field element.
|
|
||||||
/// Does not accept unnecessary leading zeroes or a blank string.
|
|
||||||
fn from_str(s: &str) -> Option<Self> {
|
|
||||||
if s.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if s == "0" {
|
|
||||||
return Some(Self::zero());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut res = Self::zero();
|
|
||||||
|
|
||||||
let ten = Self::from_repr(Self::Repr::from(10)).unwrap();
|
|
||||||
|
|
||||||
let mut first_digit = true;
|
|
||||||
|
|
||||||
for c in s.chars() {
|
|
||||||
match c.to_digit(10) {
|
|
||||||
Some(c) => {
|
|
||||||
if first_digit {
|
|
||||||
if c == 0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
first_digit = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.mul_assign(&ten);
|
|
||||||
res.add_assign(&Self::from_repr(Self::Repr::from(u64::from(c))).unwrap());
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert this prime field element into a biginteger representation.
|
|
||||||
fn from_repr(Self::Repr) -> Result<Self, PrimeFieldDecodingError>;
|
|
||||||
|
|
||||||
/// Convert a biginteger representation into a prime field element, if
|
|
||||||
/// the number is an element of the field.
|
|
||||||
fn into_repr(&self) -> Self::Repr;
|
|
||||||
|
|
||||||
/// Returns the field characteristic; the modulus.
|
|
||||||
fn char() -> Self::Repr;
|
|
||||||
|
|
||||||
/// How many bits are needed to represent an element of this field.
|
|
||||||
const NUM_BITS: u32;
|
|
||||||
|
|
||||||
/// How many bits of information can be reliably stored in the field element.
|
|
||||||
const CAPACITY: u32;
|
|
||||||
|
|
||||||
/// Returns the multiplicative generator of `char()` - 1 order. This element
|
|
||||||
/// must also be quadratic nonresidue.
|
|
||||||
fn multiplicative_generator() -> Self;
|
|
||||||
|
|
||||||
/// 2^s * t = `char()` - 1 with t odd.
|
|
||||||
const S: u32;
|
|
||||||
|
|
||||||
/// Returns the 2^s root of unity computed by exponentiating the `multiplicative_generator()`
|
|
||||||
/// by t.
|
|
||||||
fn root_of_unity() -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct BitIterator<E> {
|
|
||||||
t: E,
|
|
||||||
n: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: AsRef<[u64]>> BitIterator<E> {
|
|
||||||
pub fn new(t: E) -> Self {
|
|
||||||
let n = t.as_ref().len() * 64;
|
|
||||||
|
|
||||||
BitIterator { t, n }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: AsRef<[u64]>> Iterator for BitIterator<E> {
|
|
||||||
type Item = bool;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<bool> {
|
|
||||||
if self.n == 0 {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
self.n -= 1;
|
|
||||||
let part = self.n / 64;
|
|
||||||
let bit = self.n - (64 * part);
|
|
||||||
|
|
||||||
Some(self.t.as_ref()[part] & (1 << bit) > 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bit_iterator() {
|
|
||||||
let mut a = BitIterator::new([0xa953d79b83f6ab59, 0x6dea2059e200bd39]);
|
|
||||||
let expected = "01101101111010100010000001011001111000100000000010111101001110011010100101010011110101111001101110000011111101101010101101011001";
|
|
||||||
|
|
||||||
for e in expected.chars() {
|
|
||||||
assert!(a.next().unwrap() == (e == '1'));
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(a.next().is_none());
|
|
||||||
|
|
||||||
let expected = "1010010101111110101010000101101011101000011101110101001000011001100100100011011010001011011011010001011011101100110100111011010010110001000011110100110001100110011101101000101100011100100100100100001010011101010111110011101011000011101000111011011101011001";
|
|
||||||
|
|
||||||
let mut a = BitIterator::new([
|
|
||||||
0x429d5f3ac3a3b759,
|
|
||||||
0xb10f4c66768b1c92,
|
|
||||||
0x92368b6d16ecd3b4,
|
|
||||||
0xa57ea85ae8775219,
|
|
||||||
]);
|
|
||||||
|
|
||||||
for e in expected.chars() {
|
|
||||||
assert!(a.next().unwrap() == (e == '1'));
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(a.next().is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "expose-arith"))]
|
|
||||||
use self::arith_impl::*;
|
|
||||||
|
|
||||||
#[cfg(feature = "expose-arith")]
|
|
||||||
pub use self::arith_impl::*;
|
|
||||||
|
|
||||||
#[cfg(feature = "u128-support")]
|
|
||||||
mod arith_impl {
|
|
||||||
/// Calculate a - b - borrow, returning the result and modifying
|
|
||||||
/// the borrow value.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn sbb(a: u64, b: u64, borrow: &mut u64) -> u64 {
|
|
||||||
let tmp = (1u128 << 64) + u128::from(a) - u128::from(b) - u128::from(*borrow);
|
|
||||||
|
|
||||||
*borrow = if tmp >> 64 == 0 { 1 } else { 0 };
|
|
||||||
|
|
||||||
tmp as u64
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate a + b + carry, returning the sum and modifying the
|
|
||||||
/// carry value.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn adc(a: u64, b: u64, carry: &mut u64) -> u64 {
|
|
||||||
let tmp = u128::from(a) + u128::from(b) + u128::from(*carry);
|
|
||||||
|
|
||||||
*carry = (tmp >> 64) as u64;
|
|
||||||
|
|
||||||
tmp as u64
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate a + (b * c) + carry, returning the least significant digit
|
|
||||||
/// and setting carry to the most significant digit.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 {
|
|
||||||
let tmp = (u128::from(a)) + u128::from(b) * u128::from(c) + u128::from(*carry);
|
|
||||||
|
|
||||||
*carry = (tmp >> 64) as u64;
|
|
||||||
|
|
||||||
tmp as u64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "u128-support"))]
|
|
||||||
mod arith_impl {
|
|
||||||
#[inline(always)]
|
|
||||||
fn split_u64(i: u64) -> (u64, u64) {
|
|
||||||
(i >> 32, i & 0xFFFFFFFF)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn combine_u64(hi: u64, lo: u64) -> u64 {
|
|
||||||
(hi << 32) | lo
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate a - b - borrow, returning the result and modifying
|
|
||||||
/// the borrow value.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn sbb(a: u64, b: u64, borrow: &mut u64) -> u64 {
|
|
||||||
let (a_hi, a_lo) = split_u64(a);
|
|
||||||
let (b_hi, b_lo) = split_u64(b);
|
|
||||||
let (b, r0) = split_u64((1 << 32) + a_lo - b_lo - *borrow);
|
|
||||||
let (b, r1) = split_u64((1 << 32) + a_hi - b_hi - ((b == 0) as u64));
|
|
||||||
|
|
||||||
*borrow = (b == 0) as u64;
|
|
||||||
|
|
||||||
combine_u64(r1, r0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate a + b + carry, returning the sum and modifying the
|
|
||||||
/// carry value.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn adc(a: u64, b: u64, carry: &mut u64) -> u64 {
|
|
||||||
let (a_hi, a_lo) = split_u64(a);
|
|
||||||
let (b_hi, b_lo) = split_u64(b);
|
|
||||||
let (carry_hi, carry_lo) = split_u64(*carry);
|
|
||||||
|
|
||||||
let (t, r0) = split_u64(a_lo + b_lo + carry_lo);
|
|
||||||
let (t, r1) = split_u64(t + a_hi + b_hi + carry_hi);
|
|
||||||
|
|
||||||
*carry = t;
|
|
||||||
|
|
||||||
combine_u64(r1, r0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate a + (b * c) + carry, returning the least significant digit
|
|
||||||
/// and setting carry to the most significant digit.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 {
|
|
||||||
/*
|
|
||||||
[ b_hi | b_lo ]
|
|
||||||
[ c_hi | c_lo ] *
|
|
||||||
-------------------------------------------
|
|
||||||
[ b_lo * c_lo ] <-- w
|
|
||||||
[ b_hi * c_lo ] <-- x
|
|
||||||
[ b_lo * c_hi ] <-- y
|
|
||||||
[ b_hi * c_lo ] <-- z
|
|
||||||
[ a_hi | a_lo ]
|
|
||||||
[ C_hi | C_lo ]
|
|
||||||
*/
|
|
||||||
|
|
||||||
let (a_hi, a_lo) = split_u64(a);
|
|
||||||
let (b_hi, b_lo) = split_u64(b);
|
|
||||||
let (c_hi, c_lo) = split_u64(c);
|
|
||||||
let (carry_hi, carry_lo) = split_u64(*carry);
|
|
||||||
|
|
||||||
let (w_hi, w_lo) = split_u64(b_lo * c_lo);
|
|
||||||
let (x_hi, x_lo) = split_u64(b_hi * c_lo);
|
|
||||||
let (y_hi, y_lo) = split_u64(b_lo * c_hi);
|
|
||||||
let (z_hi, z_lo) = split_u64(b_hi * c_hi);
|
|
||||||
|
|
||||||
let (t, r0) = split_u64(w_lo + a_lo + carry_lo);
|
|
||||||
let (t, r1) = split_u64(t + w_hi + x_lo + y_lo + a_hi + carry_hi);
|
|
||||||
let (t, r2) = split_u64(t + x_hi + y_hi + z_lo);
|
|
||||||
let (_, r3) = split_u64(t + z_hi);
|
|
||||||
|
|
||||||
*carry = combine_u64(r3, r2);
|
|
||||||
|
|
||||||
combine_u64(r1, r0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
use group::{CurveAffine, CurveProjective};
|
||||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||||
|
|
||||||
use {CurveAffine, CurveProjective, Engine, Field, PrimeField};
|
use {Engine, Field, PairingCurveAffine, PrimeField};
|
||||||
|
|
||||||
pub fn engine_tests<E: Engine>() {
|
pub fn engine_tests<E: Engine>() {
|
||||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
use ff::{Field, LegendreSymbol, PrimeField, SqrtField};
|
||||||
use rand::{Rng, SeedableRng, XorShiftRng};
|
use rand::{Rng, SeedableRng, XorShiftRng};
|
||||||
use {Field, LegendreSymbol, PrimeField, SqrtField};
|
|
||||||
|
|
||||||
pub fn random_frobenius_tests<F: Field, C: AsRef<[u64]>>(characteristic: C, maxpower: usize) {
|
pub fn random_frobenius_tests<F: Field, C: AsRef<[u64]>>(characteristic: C, maxpower: usize) {
|
||||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
pub mod curve;
|
|
||||||
pub mod engine;
|
pub mod engine;
|
||||||
pub mod field;
|
pub mod field;
|
||||||
pub mod repr;
|
pub mod repr;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
use ff::PrimeFieldRepr;
|
||||||
use rand::{SeedableRng, XorShiftRng};
|
use rand::{SeedableRng, XorShiftRng};
|
||||||
use PrimeFieldRepr;
|
|
||||||
|
|
||||||
pub fn random_repr_tests<R: PrimeFieldRepr>() {
|
pub fn random_repr_tests<R: PrimeFieldRepr>() {
|
||||||
random_encoding_tests::<R>();
|
random_encoding_tests::<R>();
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ features = ["expose-arith"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bellman = { path = "../bellman" }
|
bellman = { path = "../bellman" }
|
||||||
|
ff = { path = "../ff" }
|
||||||
rand = "0.4"
|
rand = "0.4"
|
||||||
digest = "0.7"
|
digest = "0.7"
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
@@ -25,7 +26,3 @@ rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex-literal = "0.1"
|
hex-literal = "0.1"
|
||||||
rust-crypto = "0.2"
|
rust-crypto = "0.2"
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["u128-support"]
|
|
||||||
u128-support = ["pairing/u128-support"]
|
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
use pairing::{
|
use ff::{BitIterator, Field, PrimeField};
|
||||||
Engine,
|
use pairing::Engine;
|
||||||
Field,
|
|
||||||
PrimeField,
|
|
||||||
BitIterator
|
|
||||||
};
|
|
||||||
|
|
||||||
use bellman::{
|
use bellman::{
|
||||||
ConstraintSystem,
|
ConstraintSystem,
|
||||||
@@ -806,8 +802,8 @@ impl From<AllocatedBit> for Boolean {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use bellman::{ConstraintSystem};
|
use bellman::{ConstraintSystem};
|
||||||
|
use ff::{Field, PrimeField};
|
||||||
use pairing::bls12_381::{Bls12, Fr};
|
use pairing::bls12_381::{Bls12, Fr};
|
||||||
use pairing::{Field, PrimeField};
|
|
||||||
use ::circuit::test::*;
|
use ::circuit::test::*;
|
||||||
use super::{
|
use super::{
|
||||||
AllocatedBit,
|
AllocatedBit,
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
use pairing::{
|
use ff::Field;
|
||||||
Engine,
|
use pairing::Engine;
|
||||||
Field
|
|
||||||
};
|
|
||||||
|
|
||||||
use bellman::{
|
use bellman::{
|
||||||
SynthesisError,
|
SynthesisError,
|
||||||
@@ -751,8 +749,8 @@ impl<E: JubjubEngine> MontgomeryPoint<E> {
|
|||||||
mod test {
|
mod test {
|
||||||
use bellman::{ConstraintSystem};
|
use bellman::{ConstraintSystem};
|
||||||
use rand::{XorShiftRng, SeedableRng, Rand, Rng};
|
use rand::{XorShiftRng, SeedableRng, Rand, Rng};
|
||||||
|
use ff::{BitIterator, Field, PrimeField};
|
||||||
use pairing::bls12_381::{Bls12, Fr};
|
use pairing::bls12_381::{Bls12, Fr};
|
||||||
use pairing::{BitIterator, Field, PrimeField};
|
|
||||||
use ::circuit::test::*;
|
use ::circuit::test::*;
|
||||||
use ::jubjub::{
|
use ::jubjub::{
|
||||||
montgomery,
|
montgomery,
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
use pairing::{Engine, Field};
|
use ff::Field;
|
||||||
|
use pairing::Engine;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use super::num::{
|
use super::num::{
|
||||||
AllocatedNum,
|
AllocatedNum,
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
use pairing::{
|
use ff::{Field, PrimeField};
|
||||||
Engine,
|
use pairing::Engine;
|
||||||
Field,
|
|
||||||
PrimeField
|
|
||||||
};
|
|
||||||
|
|
||||||
use bellman::{
|
use bellman::{
|
||||||
SynthesisError,
|
SynthesisError,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use pairing::{Engine, Field, PrimeField};
|
use ff::{Field, PrimeField};
|
||||||
|
use pairing::Engine;
|
||||||
use bellman::{ConstraintSystem, SynthesisError};
|
use bellman::{ConstraintSystem, SynthesisError};
|
||||||
use super::boolean::{Boolean};
|
use super::boolean::{Boolean};
|
||||||
use super::num::Num;
|
use super::num::Num;
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
use pairing::{
|
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr};
|
||||||
Engine,
|
use pairing::Engine;
|
||||||
Field,
|
|
||||||
PrimeField,
|
|
||||||
PrimeFieldRepr,
|
|
||||||
BitIterator
|
|
||||||
};
|
|
||||||
|
|
||||||
use bellman::{
|
use bellman::{
|
||||||
SynthesisError,
|
SynthesisError,
|
||||||
@@ -462,8 +457,8 @@ impl<E: Engine> Num<E> {
|
|||||||
mod test {
|
mod test {
|
||||||
use rand::{SeedableRng, Rand, Rng, XorShiftRng};
|
use rand::{SeedableRng, Rand, Rng, XorShiftRng};
|
||||||
use bellman::{ConstraintSystem};
|
use bellman::{ConstraintSystem};
|
||||||
|
use ff::{BitIterator, Field, PrimeField};
|
||||||
use pairing::bls12_381::{Bls12, Fr};
|
use pairing::bls12_381::{Bls12, Fr};
|
||||||
use pairing::{Field, PrimeField, BitIterator};
|
|
||||||
use ::circuit::test::*;
|
use ::circuit::test::*;
|
||||||
use super::{AllocatedNum, Boolean};
|
use super::{AllocatedNum, Boolean};
|
||||||
|
|
||||||
|
|||||||
@@ -116,8 +116,8 @@ mod test {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use ::circuit::test::*;
|
use ::circuit::test::*;
|
||||||
use ::circuit::boolean::{Boolean, AllocatedBit};
|
use ::circuit::boolean::{Boolean, AllocatedBit};
|
||||||
|
use ff::PrimeField;
|
||||||
use pairing::bls12_381::{Bls12, Fr};
|
use pairing::bls12_381::{Bls12, Fr};
|
||||||
use pairing::PrimeField;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_pedersen_hash_constraints() {
|
fn test_pedersen_hash_constraints() {
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
use pairing::{
|
use ff::{Field, PrimeField, PrimeFieldRepr};
|
||||||
PrimeField,
|
|
||||||
PrimeFieldRepr,
|
|
||||||
Field,
|
|
||||||
};
|
|
||||||
|
|
||||||
use bellman::{
|
use bellman::{
|
||||||
SynthesisError,
|
SynthesisError,
|
||||||
@@ -31,6 +27,8 @@ use super::blake2s;
|
|||||||
use super::num;
|
use super::num;
|
||||||
use super::multipack;
|
use super::multipack;
|
||||||
|
|
||||||
|
pub const TREE_DEPTH: usize = 32;
|
||||||
|
|
||||||
/// This is an instance of the `Spend` circuit.
|
/// This is an instance of the `Spend` circuit.
|
||||||
pub struct Spend<'a, E: JubjubEngine> {
|
pub struct Spend<'a, E: JubjubEngine> {
|
||||||
pub params: &'a E::Params,
|
pub params: &'a E::Params,
|
||||||
@@ -600,7 +598,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_input_circuit_with_bls12_381() {
|
fn test_input_circuit_with_bls12_381() {
|
||||||
use pairing::{Field, BitIterator};
|
use ff::{BitIterator, Field};
|
||||||
use pairing::bls12_381::*;
|
use pairing::bls12_381::*;
|
||||||
use rand::{SeedableRng, Rng, XorShiftRng};
|
use rand::{SeedableRng, Rng, XorShiftRng};
|
||||||
use ::circuit::test::*;
|
use ::circuit::test::*;
|
||||||
@@ -732,7 +730,7 @@ fn test_input_circuit_with_bls12_381() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_output_circuit_with_bls12_381() {
|
fn test_output_circuit_with_bls12_381() {
|
||||||
use pairing::{Field};
|
use ff::Field;
|
||||||
use pairing::bls12_381::*;
|
use pairing::bls12_381::*;
|
||||||
use rand::{SeedableRng, Rng, XorShiftRng};
|
use rand::{SeedableRng, Rng, XorShiftRng};
|
||||||
use ::circuit::test::*;
|
use ::circuit::test::*;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use pairing::{Engine, Field};
|
use ff::Field;
|
||||||
|
use pairing::Engine;
|
||||||
use bellman::{ConstraintSystem, SynthesisError, Circuit, LinearCombination};
|
use bellman::{ConstraintSystem, SynthesisError, Circuit, LinearCombination};
|
||||||
use circuit::boolean::{
|
use circuit::boolean::{
|
||||||
AllocatedBit,
|
AllocatedBit,
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
use pairing::{
|
use ff::{Field, PrimeField, PrimeFieldRepr};
|
||||||
Engine,
|
use pairing::Engine;
|
||||||
Field,
|
|
||||||
PrimeField,
|
|
||||||
PrimeFieldRepr
|
|
||||||
};
|
|
||||||
|
|
||||||
use bellman::{
|
use bellman::{
|
||||||
LinearCombination,
|
LinearCombination,
|
||||||
@@ -445,8 +441,8 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cs() {
|
fn test_cs() {
|
||||||
|
use ff::PrimeField;
|
||||||
use pairing::bls12_381::{Bls12, Fr};
|
use pairing::bls12_381::{Bls12, Fr};
|
||||||
use pairing::PrimeField;
|
|
||||||
|
|
||||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||||
assert!(cs.is_satisfied());
|
assert!(cs.is_satisfied());
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
use pairing::{
|
use ff::{Field, PrimeField};
|
||||||
Engine,
|
use pairing::Engine;
|
||||||
Field,
|
|
||||||
PrimeField
|
|
||||||
};
|
|
||||||
|
|
||||||
use bellman::{
|
use bellman::{
|
||||||
SynthesisError,
|
SynthesisError,
|
||||||
@@ -415,8 +412,8 @@ mod test {
|
|||||||
use rand::{XorShiftRng, SeedableRng, Rng};
|
use rand::{XorShiftRng, SeedableRng, Rng};
|
||||||
use ::circuit::boolean::{Boolean};
|
use ::circuit::boolean::{Boolean};
|
||||||
use super::{UInt32};
|
use super::{UInt32};
|
||||||
|
use ff::Field;
|
||||||
use pairing::bls12_381::{Bls12};
|
use pairing::bls12_381::{Bls12};
|
||||||
use pairing::{Field};
|
|
||||||
use ::circuit::test::*;
|
use ::circuit::test::*;
|
||||||
use bellman::{ConstraintSystem};
|
use bellman::{ConstraintSystem};
|
||||||
use circuit::multieq::MultiEq;
|
use circuit::multieq::MultiEq;
|
||||||
@@ -659,9 +656,9 @@ mod test {
|
|||||||
for i in 0..60 {
|
for i in 0..60 {
|
||||||
let num = rng.gen();
|
let num = rng.gen();
|
||||||
let a = UInt32::constant(num).shr(i);
|
let a = UInt32::constant(num).shr(i);
|
||||||
let b = UInt32::constant(num >> i);
|
let b = UInt32::constant(num.wrapping_shr(i as u32));
|
||||||
|
|
||||||
assert_eq!(a.value.unwrap(), num >> i);
|
assert_eq!(a.value.unwrap(), num.wrapping_shr(i as u32));
|
||||||
|
|
||||||
assert_eq!(a.bits.len(), b.bits.len());
|
assert_eq!(a.bits.len(), b.bits.len());
|
||||||
for (a, b) in a.bits.iter().zip(b.bits.iter()) {
|
for (a, b) in a.bits.iter().zip(b.bits.iter()) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use jubjub::{
|
|||||||
edwards
|
edwards
|
||||||
};
|
};
|
||||||
|
|
||||||
use pairing::{
|
use ff::{
|
||||||
PrimeField
|
PrimeField
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,4 @@
|
|||||||
use pairing::{
|
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
|
||||||
Field,
|
|
||||||
SqrtField,
|
|
||||||
PrimeField,
|
|
||||||
PrimeFieldRepr,
|
|
||||||
BitIterator
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
JubjubEngine,
|
JubjubEngine,
|
||||||
@@ -31,6 +25,7 @@ use std::io::{
|
|||||||
//
|
//
|
||||||
// See "Twisted Edwards Curves Revisited"
|
// See "Twisted Edwards Curves Revisited"
|
||||||
// Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson
|
// Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Point<E: JubjubEngine, Subgroup> {
|
pub struct Point<E: JubjubEngine, Subgroup> {
|
||||||
x: E::Fr,
|
x: E::Fr,
|
||||||
y: E::Fr,
|
y: E::Fr,
|
||||||
@@ -50,6 +45,14 @@ fn convert_subgroup<E: JubjubEngine, S1, S2>(from: &Point<E, S1>) -> Point<E, S2
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E: JubjubEngine> From<&Point<E, Unknown>> for Point<E, Unknown>
|
||||||
|
{
|
||||||
|
fn from(p: &Point<E, Unknown>) -> Point<E, Unknown>
|
||||||
|
{
|
||||||
|
p.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<E: JubjubEngine> From<Point<E, PrimeOrder>> for Point<E, Unknown>
|
impl<E: JubjubEngine> From<Point<E, PrimeOrder>> for Point<E, Unknown>
|
||||||
{
|
{
|
||||||
fn from(p: Point<E, PrimeOrder>) -> Point<E, Unknown>
|
fn from(p: Point<E, PrimeOrder>) -> Point<E, Unknown>
|
||||||
@@ -58,6 +61,14 @@ impl<E: JubjubEngine> From<Point<E, PrimeOrder>> for Point<E, Unknown>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E: JubjubEngine> From<&Point<E, PrimeOrder>> for Point<E, Unknown>
|
||||||
|
{
|
||||||
|
fn from(p: &Point<E, PrimeOrder>) -> Point<E, Unknown>
|
||||||
|
{
|
||||||
|
convert_subgroup(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<E: JubjubEngine, Subgroup> Clone for Point<E, Subgroup>
|
impl<E: JubjubEngine, Subgroup> Clone for Point<E, Subgroup>
|
||||||
{
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
use pairing::{BitIterator, Field, PrimeField, SqrtField, PrimeFieldRepr, PrimeFieldDecodingError, LegendreSymbol};
|
use ff::{
|
||||||
use pairing::LegendreSymbol::*;
|
adc, mac_with_carry, sbb, BitIterator, Field,
|
||||||
use pairing::{adc, sbb, mac_with_carry};
|
LegendreSymbol::{self, *},
|
||||||
|
PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, SqrtField,
|
||||||
|
};
|
||||||
|
|
||||||
use super::ToUniform;
|
use super::ToUniform;
|
||||||
|
|
||||||
|
|||||||
@@ -17,12 +17,8 @@
|
|||||||
//! the Montgomery curve forms a group isomorphism, allowing points
|
//! the Montgomery curve forms a group isomorphism, allowing points
|
||||||
//! to be freely converted between the two forms.
|
//! to be freely converted between the two forms.
|
||||||
|
|
||||||
use pairing::{
|
use ff::{Field, PrimeField, SqrtField};
|
||||||
Engine,
|
use pairing::Engine;
|
||||||
Field,
|
|
||||||
PrimeField,
|
|
||||||
SqrtField
|
|
||||||
};
|
|
||||||
|
|
||||||
use group_hash::group_hash;
|
use group_hash::group_hash;
|
||||||
|
|
||||||
@@ -47,9 +43,11 @@ pub mod fs;
|
|||||||
pub mod tests;
|
pub mod tests;
|
||||||
|
|
||||||
/// Point of unknown order.
|
/// Point of unknown order.
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Unknown { }
|
pub enum Unknown { }
|
||||||
|
|
||||||
/// Point of prime order.
|
/// Point of prime order.
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum PrimeOrder { }
|
pub enum PrimeOrder { }
|
||||||
|
|
||||||
/// Fixed generators of the Jubjub curve of unknown
|
/// Fixed generators of the Jubjub curve of unknown
|
||||||
|
|||||||
@@ -1,10 +1,4 @@
|
|||||||
use pairing::{
|
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
|
||||||
Field,
|
|
||||||
SqrtField,
|
|
||||||
PrimeField,
|
|
||||||
PrimeFieldRepr,
|
|
||||||
BitIterator
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
JubjubEngine,
|
JubjubEngine,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use super::{
|
|||||||
edwards
|
edwards
|
||||||
};
|
};
|
||||||
|
|
||||||
use pairing::{
|
use ff::{
|
||||||
Field,
|
Field,
|
||||||
PrimeField,
|
PrimeField,
|
||||||
PrimeFieldRepr,
|
PrimeFieldRepr,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ extern crate pairing;
|
|||||||
extern crate bellman;
|
extern crate bellman;
|
||||||
extern crate blake2_rfc;
|
extern crate blake2_rfc;
|
||||||
extern crate digest;
|
extern crate digest;
|
||||||
|
extern crate ff;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
use ff::{Field, PrimeField, PrimeFieldRepr};
|
||||||
use jubjub::*;
|
use jubjub::*;
|
||||||
use pairing::*;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum Personalization {
|
pub enum Personalization {
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
use pairing::{
|
use ff::{Field, PrimeField, PrimeFieldRepr};
|
||||||
Field,
|
|
||||||
PrimeField,
|
|
||||||
PrimeFieldRepr
|
|
||||||
};
|
|
||||||
|
|
||||||
use constants;
|
use constants;
|
||||||
|
|
||||||
@@ -66,6 +62,7 @@ impl<E: JubjubEngine> ProofGenerationKey<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ViewingKey<E: JubjubEngine> {
|
pub struct ViewingKey<E: JubjubEngine> {
|
||||||
pub ak: edwards::Point<E, PrimeOrder>,
|
pub ak: edwards::Point<E, PrimeOrder>,
|
||||||
pub nk: edwards::Point<E, PrimeOrder>
|
pub nk: edwards::Point<E, PrimeOrder>
|
||||||
@@ -120,7 +117,7 @@ impl<E: JubjubEngine> ViewingKey<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub struct Diversifier(pub [u8; 11]);
|
pub struct Diversifier(pub [u8; 11]);
|
||||||
|
|
||||||
impl Diversifier {
|
impl Diversifier {
|
||||||
@@ -133,12 +130,18 @@ impl Diversifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PaymentAddress<E: JubjubEngine> {
|
pub struct PaymentAddress<E: JubjubEngine> {
|
||||||
pub pk_d: edwards::Point<E, PrimeOrder>,
|
pub pk_d: edwards::Point<E, PrimeOrder>,
|
||||||
pub diversifier: Diversifier
|
pub diversifier: Diversifier
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E: JubjubEngine> PartialEq for PaymentAddress<E> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.pk_d == other.pk_d && self.diversifier == other.diversifier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<E: JubjubEngine> PaymentAddress<E> {
|
impl<E: JubjubEngine> PaymentAddress<E> {
|
||||||
pub fn g_d(
|
pub fn g_d(
|
||||||
&self,
|
&self,
|
||||||
@@ -166,6 +169,7 @@ impl<E: JubjubEngine> PaymentAddress<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct Note<E: JubjubEngine> {
|
pub struct Note<E: JubjubEngine> {
|
||||||
/// The value of the note
|
/// The value of the note
|
||||||
pub value: u64,
|
pub value: u64,
|
||||||
@@ -177,6 +181,15 @@ pub struct Note<E: JubjubEngine> {
|
|||||||
pub r: E::Fs
|
pub r: E::Fs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E: JubjubEngine> PartialEq for Note<E> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.value == other.value
|
||||||
|
&& self.g_d == other.g_d
|
||||||
|
&& self.pk_d == other.pk_d
|
||||||
|
&& self.r == other.r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<E: JubjubEngine> Note<E> {
|
impl<E: JubjubEngine> Note<E> {
|
||||||
pub fn uncommitted() -> E::Fr {
|
pub fn uncommitted() -> E::Fr {
|
||||||
// The smallest u-coordinate that is not on the curve
|
// The smallest u-coordinate that is not on the curve
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//! Implementation of RedJubjub, a specialization of RedDSA to the Jubjub curve.
|
//! Implementation of RedJubjub, a specialization of RedDSA to the Jubjub curve.
|
||||||
//! See section 5.4.6 of the Sapling protocol specification.
|
//! See section 5.4.6 of the Sapling protocol specification.
|
||||||
|
|
||||||
use pairing::{Field, PrimeField, PrimeFieldRepr};
|
use ff::{Field, PrimeField, PrimeFieldRepr};
|
||||||
use rand::{Rng, Rand};
|
use rand::{Rng, Rand};
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ fn h_star<E: JubjubEngine>(a: &[u8], b: &[u8]) -> E::Fs {
|
|||||||
hash_to_scalar::<E>(b"Zcash_RedJubjubH", a, b)
|
hash_to_scalar::<E>(b"Zcash_RedJubjubH", a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Signature {
|
pub struct Signature {
|
||||||
rbar: [u8; 32],
|
rbar: [u8; 32],
|
||||||
sbar: [u8; 32],
|
sbar: [u8; 32],
|
||||||
@@ -37,6 +37,7 @@ pub struct Signature {
|
|||||||
|
|
||||||
pub struct PrivateKey<E: JubjubEngine>(pub E::Fs);
|
pub struct PrivateKey<E: JubjubEngine>(pub E::Fs);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct PublicKey<E: JubjubEngine>(pub Point<E, Unknown>);
|
pub struct PublicKey<E: JubjubEngine>(pub Point<E, Unknown>);
|
||||||
|
|
||||||
impl Signature {
|
impl Signature {
|
||||||
|
|||||||
@@ -6,3 +6,16 @@ authors = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
byteorder = "1"
|
||||||
|
crypto_api_chachapoly = "0.1"
|
||||||
|
ff = { path = "../ff" }
|
||||||
|
hex = "0.3"
|
||||||
|
lazy_static = "1"
|
||||||
|
pairing = { path = "../pairing" }
|
||||||
|
rand = "0.4"
|
||||||
|
sapling-crypto = { path = "../sapling-crypto" }
|
||||||
|
sha2 = "0.8"
|
||||||
|
|
||||||
|
[dependencies.blake2-rfc]
|
||||||
|
git = "https://github.com/gtank/blake2-rfc"
|
||||||
|
rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2017 Zcash Company
|
Copyright (c) 2017-2019 Electric Coin Company
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
209
zcash_primitives/src/block.rs
Normal file
209
zcash_primitives/src/block.rs
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
use hex;
|
||||||
|
use std::fmt;
|
||||||
|
use std::io::{self, Read, Write};
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use serialize::Vector;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct BlockHash(pub [u8; 32]);
|
||||||
|
|
||||||
|
impl fmt::Display for BlockHash {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let mut data = self.0.clone();
|
||||||
|
data.reverse();
|
||||||
|
formatter.write_str(&hex::encode(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A Zcash block header.
|
||||||
|
pub struct BlockHeader(BlockHeaderData);
|
||||||
|
|
||||||
|
impl Deref for BlockHeader {
|
||||||
|
type Target = BlockHeaderData;
|
||||||
|
|
||||||
|
fn deref(&self) -> &BlockHeaderData {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BlockHeaderData {
|
||||||
|
pub version: i32,
|
||||||
|
pub prev_block: BlockHash,
|
||||||
|
pub merkle_root: [u8; 32],
|
||||||
|
pub final_sapling_root: [u8; 32],
|
||||||
|
pub time: u32,
|
||||||
|
pub bits: u32,
|
||||||
|
pub nonce: [u8; 32],
|
||||||
|
pub solution: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockHeaderData {
|
||||||
|
pub fn freeze(self) -> BlockHeader {
|
||||||
|
BlockHeader(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockHeader {
|
||||||
|
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||||
|
let version = reader.read_i32::<LittleEndian>()?;
|
||||||
|
|
||||||
|
let mut prev_block = BlockHash([0; 32]);
|
||||||
|
reader.read_exact(&mut prev_block.0)?;
|
||||||
|
|
||||||
|
let mut merkle_root = [0; 32];
|
||||||
|
reader.read_exact(&mut merkle_root)?;
|
||||||
|
|
||||||
|
let mut final_sapling_root = [0; 32];
|
||||||
|
reader.read_exact(&mut final_sapling_root)?;
|
||||||
|
|
||||||
|
let time = reader.read_u32::<LittleEndian>()?;
|
||||||
|
let bits = reader.read_u32::<LittleEndian>()?;
|
||||||
|
|
||||||
|
let mut nonce = [0; 32];
|
||||||
|
reader.read_exact(&mut nonce)?;
|
||||||
|
|
||||||
|
let solution = Vector::read(&mut reader, |r| r.read_u8())?;
|
||||||
|
|
||||||
|
Ok(BlockHeader(BlockHeaderData {
|
||||||
|
version,
|
||||||
|
prev_block,
|
||||||
|
merkle_root,
|
||||||
|
final_sapling_root,
|
||||||
|
time,
|
||||||
|
bits,
|
||||||
|
nonce,
|
||||||
|
solution,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
|
writer.write_i32::<LittleEndian>(self.version)?;
|
||||||
|
writer.write_all(&self.prev_block.0)?;
|
||||||
|
writer.write_all(&self.merkle_root)?;
|
||||||
|
writer.write_all(&self.final_sapling_root)?;
|
||||||
|
writer.write_u32::<LittleEndian>(self.time)?;
|
||||||
|
writer.write_u32::<LittleEndian>(self.bits)?;
|
||||||
|
writer.write_all(&self.nonce)?;
|
||||||
|
Vector::write(&mut writer, &self.solution, |w, b| w.write_u8(*b))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::BlockHeader;
|
||||||
|
|
||||||
|
const HEADER_MAINNET_415000: [u8; 1487] = [
|
||||||
|
0x04, 0x00, 0x00, 0x00, 0x52, 0x74, 0xb4, 0x3b, 0x9e, 0x4a, 0xd8, 0xf4, 0x3e, 0x93, 0xf7,
|
||||||
|
0x84, 0x63, 0xd2, 0x4d, 0xcf, 0xe5, 0x31, 0xae, 0xb4, 0x71, 0x98, 0x19, 0xf4, 0xf9, 0x7f,
|
||||||
|
0x7e, 0x03, 0x00, 0x00, 0x00, 0x00, 0x66, 0x30, 0x73, 0xbc, 0x4b, 0xfa, 0x95, 0xc9, 0xbe,
|
||||||
|
0xc3, 0x6a, 0xad, 0x72, 0x68, 0xa5, 0x73, 0x04, 0x97, 0x97, 0xbd, 0xfc, 0x5a, 0xa4, 0xc7,
|
||||||
|
0x43, 0xfb, 0xe4, 0x82, 0x0a, 0xa3, 0x93, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xbe, 0xcc, 0x5b, 0xe1,
|
||||||
|
0xab, 0x03, 0x1c, 0xc2, 0xfd, 0x60, 0x7c, 0x77, 0x6a, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x3e, 0xb2, 0x18, 0x19, 0xfd, 0x40, 0x05, 0x00, 0x94, 0x9d, 0x55, 0xde, 0x0c, 0xc6,
|
||||||
|
0x33, 0xe0, 0xcc, 0xe4, 0x1e, 0x46, 0x49, 0xef, 0x4a, 0xa3, 0x34, 0x9f, 0x01, 0x00, 0x29,
|
||||||
|
0x0f, 0xfe, 0x28, 0x1b, 0x94, 0x7b, 0x3b, 0x53, 0xfb, 0xd2, 0xf3, 0x5b, 0x1c, 0xe2, 0x92,
|
||||||
|
0x64, 0x9b, 0x96, 0xac, 0x6e, 0x08, 0x83, 0xaf, 0x3a, 0x68, 0x44, 0xb9, 0x55, 0x92, 0xe7,
|
||||||
|
0x45, 0x56, 0xda, 0x34, 0x4b, 0x47, 0x01, 0x96, 0x1c, 0xd4, 0x13, 0x0c, 0x68, 0x21, 0x9c,
|
||||||
|
0xfa, 0x13, 0x41, 0xd5, 0xaf, 0xb5, 0x04, 0x9e, 0xb0, 0xe8, 0xbe, 0x4a, 0x2d, 0x92, 0xd6,
|
||||||
|
0x78, 0xc4, 0x07, 0x85, 0xe3, 0x37, 0x05, 0x54, 0x8b, 0x5f, 0x3a, 0x54, 0xf0, 0xa4, 0xc3,
|
||||||
|
0x9a, 0x2f, 0x58, 0xee, 0x78, 0x4a, 0x24, 0x16, 0x3c, 0xd8, 0x6f, 0x54, 0x81, 0x23, 0x27,
|
||||||
|
0xdf, 0x55, 0xe1, 0xd5, 0x5c, 0xa8, 0x4b, 0x6e, 0x7b, 0x88, 0x7a, 0x7c, 0xbf, 0xb9, 0x09,
|
||||||
|
0x1a, 0x58, 0x5b, 0xdb, 0x8e, 0xa4, 0x75, 0x93, 0x07, 0xc5, 0x6c, 0x1b, 0x3d, 0xaf, 0xc6,
|
||||||
|
0x69, 0x24, 0x5a, 0x6f, 0x65, 0x4b, 0x6f, 0x73, 0x00, 0x52, 0x26, 0x6a, 0x01, 0xad, 0x4f,
|
||||||
|
0x9c, 0x0b, 0x59, 0xed, 0x4e, 0x17, 0x71, 0x2b, 0x3e, 0x72, 0xdf, 0x04, 0x98, 0xaa, 0x8d,
|
||||||
|
0xe4, 0x88, 0x8f, 0x99, 0x35, 0x31, 0xc6, 0x0a, 0xcd, 0xed, 0x1d, 0x4b, 0x66, 0xe8, 0x9d,
|
||||||
|
0xe0, 0xb6, 0x48, 0x2c, 0xcc, 0xd4, 0xa7, 0x12, 0xf5, 0xcf, 0x9d, 0x4c, 0xa8, 0x3b, 0xe0,
|
||||||
|
0xf9, 0x22, 0xde, 0x2c, 0x1d, 0xbb, 0x3a, 0x14, 0x07, 0x48, 0x0d, 0xbe, 0x87, 0x95, 0x99,
|
||||||
|
0x3d, 0x8b, 0xe6, 0x40, 0x98, 0x8a, 0xbf, 0xe7, 0xa8, 0xa1, 0xb3, 0x3a, 0x12, 0x13, 0x1c,
|
||||||
|
0x45, 0x1e, 0x1a, 0xbc, 0x0d, 0x83, 0xfb, 0x85, 0x18, 0x62, 0xc6, 0x37, 0xce, 0x72, 0x4d,
|
||||||
|
0x5f, 0xe9, 0x7a, 0xa9, 0xa8, 0x06, 0xcf, 0x34, 0xba, 0xb5, 0x09, 0xf4, 0x55, 0x4b, 0x0c,
|
||||||
|
0xd1, 0x0a, 0x7d, 0xdf, 0xd5, 0x82, 0x1b, 0x09, 0x1a, 0xd2, 0xc9, 0x0c, 0x1a, 0xa1, 0xd8,
|
||||||
|
0x1e, 0xb3, 0xd7, 0x2d, 0xb4, 0x19, 0x93, 0xb6, 0x48, 0xf4, 0x1e, 0x21, 0x38, 0xff, 0x95,
|
||||||
|
0x31, 0xa3, 0x0f, 0xf7, 0x3b, 0x22, 0x14, 0x0e, 0x4e, 0xbd, 0x7b, 0xaa, 0x33, 0x84, 0x8e,
|
||||||
|
0x51, 0x2d, 0x99, 0x30, 0x0c, 0x5c, 0x13, 0x1c, 0x6e, 0x75, 0xf5, 0x71, 0x4a, 0x5c, 0x6d,
|
||||||
|
0xcb, 0x17, 0x8b, 0x4a, 0x49, 0x78, 0xda, 0xc8, 0x3a, 0xd4, 0x12, 0xfb, 0xd6, 0x92, 0x01,
|
||||||
|
0x92, 0x50, 0xc5, 0x53, 0x04, 0x9a, 0xad, 0x45, 0x79, 0x84, 0xbe, 0xdf, 0xc9, 0x6a, 0xe7,
|
||||||
|
0x01, 0xc6, 0x59, 0xbc, 0x70, 0x07, 0xa9, 0x7d, 0x0a, 0x90, 0x02, 0xb9, 0x45, 0xbd, 0xec,
|
||||||
|
0x45, 0xa9, 0x45, 0xef, 0x62, 0x85, 0xb2, 0xcd, 0x55, 0x3b, 0x4c, 0x09, 0xd9, 0x07, 0xc6,
|
||||||
|
0x27, 0x86, 0x3f, 0x03, 0x99, 0xe8, 0x72, 0x5b, 0x4f, 0xf7, 0xfc, 0x59, 0x79, 0xe3, 0xcf,
|
||||||
|
0xf2, 0x28, 0x14, 0x50, 0x84, 0x48, 0xef, 0x8b, 0x98, 0x31, 0xc2, 0x85, 0x95, 0x93, 0x33,
|
||||||
|
0x39, 0x6a, 0xa3, 0x62, 0xa5, 0x1c, 0xf2, 0x05, 0x09, 0x7a, 0xfa, 0xbe, 0xc1, 0x5e, 0x41,
|
||||||
|
0xfb, 0x6e, 0x30, 0xb6, 0x22, 0x37, 0x4b, 0xf5, 0x8b, 0x37, 0xef, 0x9d, 0x1b, 0x24, 0x1e,
|
||||||
|
0xad, 0x5a, 0x68, 0x2b, 0x98, 0xb6, 0x57, 0x49, 0xa5, 0x75, 0x68, 0xe2, 0x38, 0xd5, 0x0a,
|
||||||
|
0xfd, 0x41, 0x7e, 0x1e, 0x96, 0x0e, 0x7b, 0x5a, 0x06, 0x4f, 0xd9, 0xf6, 0x94, 0xd7, 0x83,
|
||||||
|
0xa2, 0xcb, 0xcd, 0x58, 0x55, 0x2d, 0xed, 0xbb, 0x9e, 0x5e, 0x11, 0x23, 0x67, 0x4e, 0xf7,
|
||||||
|
0x3a, 0x52, 0x41, 0x96, 0xcf, 0x05, 0xd3, 0xe5, 0x24, 0x66, 0x05, 0x49, 0xff, 0xe7, 0xbd,
|
||||||
|
0x65, 0x68, 0x05, 0x71, 0x35, 0xff, 0xd5, 0xaf, 0xd9, 0x43, 0xf6, 0xda, 0x11, 0xcb, 0xb5,
|
||||||
|
0x97, 0xe8, 0xcc, 0xec, 0xd7, 0x7e, 0xcb, 0xe9, 0x09, 0xde, 0x06, 0x31, 0xbf, 0xa2, 0x9c,
|
||||||
|
0xd3, 0xe3, 0xd5, 0x54, 0x46, 0x71, 0xba, 0x80, 0x25, 0x61, 0x53, 0xd6, 0xe9, 0x99, 0x0b,
|
||||||
|
0x88, 0xad, 0x8e, 0x0c, 0xf4, 0x98, 0x9b, 0xef, 0x4b, 0xe4, 0x57, 0xf9, 0xc7, 0xb0, 0xf1,
|
||||||
|
0xaa, 0xcd, 0x6e, 0x0e, 0xf3, 0x20, 0x60, 0x5c, 0x29, 0xed, 0x0c, 0xd2, 0xeb, 0x6c, 0xfc,
|
||||||
|
0xe2, 0x16, 0xc5, 0x2a, 0x31, 0x75, 0x80, 0x20, 0x1c, 0xad, 0x7a, 0x09, 0x43, 0xd2, 0x4b,
|
||||||
|
0x7b, 0x06, 0xd5, 0xbf, 0x75, 0x87, 0x61, 0xdd, 0x96, 0xe1, 0x19, 0x70, 0xb5, 0xde, 0xd6,
|
||||||
|
0x97, 0x22, 0x2b, 0x2c, 0x77, 0xe7, 0xf2, 0x56, 0xa6, 0x05, 0xac, 0x75, 0x55, 0x49, 0xc1,
|
||||||
|
0x65, 0x1f, 0x25, 0xad, 0xfc, 0x9d, 0x53, 0xd9, 0x11, 0x7e, 0x3a, 0x0b, 0xb4, 0x09, 0xee,
|
||||||
|
0xe4, 0xa6, 0x00, 0x12, 0x04, 0x72, 0x94, 0x9c, 0x7d, 0xda, 0x1c, 0x2e, 0xdb, 0x3c, 0x33,
|
||||||
|
0x0c, 0x7f, 0x96, 0x17, 0x99, 0x82, 0x91, 0x64, 0x57, 0xd3, 0x31, 0xe9, 0x63, 0x09, 0xdd,
|
||||||
|
0x24, 0xdf, 0x74, 0xee, 0xdd, 0x00, 0xe7, 0xdb, 0x49, 0x7e, 0xe1, 0x30, 0xf7, 0x7d, 0xe6,
|
||||||
|
0x66, 0xeb, 0x55, 0x7f, 0xb3, 0x16, 0xe8, 0x7a, 0xda, 0xf1, 0x81, 0x3c, 0xe4, 0x26, 0xa4,
|
||||||
|
0x58, 0xa6, 0xee, 0xe3, 0xa8, 0x5b, 0x2a, 0xb8, 0x8f, 0x65, 0x53, 0xaa, 0xda, 0xe8, 0xde,
|
||||||
|
0x65, 0x2e, 0x21, 0x1a, 0x1d, 0x9f, 0x33, 0x4d, 0x59, 0x6b, 0x5e, 0xb6, 0x17, 0x34, 0x07,
|
||||||
|
0xef, 0xcc, 0x2e, 0x81, 0x54, 0xbb, 0x9c, 0xa1, 0x21, 0x2a, 0xa9, 0xa1, 0xa1, 0x12, 0x1d,
|
||||||
|
0x2f, 0x5a, 0x77, 0x12, 0xcf, 0x25, 0xcc, 0x81, 0x48, 0xb8, 0x05, 0x2e, 0x0d, 0x2e, 0x09,
|
||||||
|
0xf2, 0x0e, 0x5b, 0xa2, 0xa9, 0x82, 0x77, 0xe9, 0x75, 0xb0, 0xee, 0xd9, 0xa8, 0x92, 0x06,
|
||||||
|
0x96, 0x63, 0x37, 0x16, 0x3f, 0x21, 0x5c, 0x9d, 0x04, 0xa6, 0x59, 0x8b, 0x09, 0x58, 0xd3,
|
||||||
|
0x33, 0xd8, 0x46, 0x77, 0x3c, 0x69, 0xe5, 0xab, 0xfd, 0x0a, 0x04, 0x27, 0xf3, 0x66, 0x06,
|
||||||
|
0x14, 0xdd, 0x82, 0xb7, 0x9a, 0xdb, 0x85, 0x1a, 0x0d, 0x58, 0xb6, 0x2d, 0xf5, 0xf0, 0xb3,
|
||||||
|
0xac, 0x83, 0x6e, 0x6e, 0x25, 0xf3, 0xa5, 0x1f, 0x49, 0xa9, 0x9a, 0xde, 0x57, 0x79, 0x6f,
|
||||||
|
0xe9, 0xfc, 0xc2, 0x6f, 0x0a, 0x1f, 0x94, 0xff, 0x08, 0x19, 0xfe, 0x52, 0xb7, 0x50, 0x87,
|
||||||
|
0xed, 0xbe, 0xd3, 0xa8, 0x16, 0x26, 0xeb, 0x54, 0x16, 0xc6, 0x65, 0x57, 0xf1, 0x1c, 0x0f,
|
||||||
|
0xce, 0xdf, 0xf2, 0x23, 0xd6, 0xaa, 0x8c, 0xd5, 0xc3, 0x53, 0x86, 0xe5, 0xb4, 0xb9, 0x5a,
|
||||||
|
0x0f, 0x03, 0x92, 0xca, 0x30, 0x1a, 0x38, 0xb3, 0x68, 0x7d, 0x09, 0x44, 0x93, 0xb9, 0xe9,
|
||||||
|
0xd2, 0x64, 0xd0, 0x7a, 0x19, 0x0c, 0xe5, 0x7d, 0x11, 0x68, 0x04, 0x38, 0x2a, 0x3f, 0xab,
|
||||||
|
0xe1, 0x5a, 0xf4, 0xdf, 0x4f, 0xa0, 0x43, 0xf0, 0x28, 0x7a, 0xa1, 0xed, 0x55, 0x68, 0xd9,
|
||||||
|
0xef, 0x5d, 0x12, 0x51, 0x0d, 0x01, 0x0c, 0xcd, 0xab, 0x4e, 0xb6, 0x16, 0xf6, 0xdf, 0x13,
|
||||||
|
0xbb, 0x31, 0x26, 0xef, 0x43, 0xd9, 0xd6, 0x57, 0x35, 0xe4, 0xe4, 0xc0, 0x4b, 0x57, 0x63,
|
||||||
|
0x48, 0xd0, 0x40, 0xb5, 0x35, 0x05, 0x5a, 0x3d, 0x5a, 0xe1, 0x91, 0xb7, 0x5f, 0x06, 0x12,
|
||||||
|
0xf3, 0xb2, 0x40, 0x66, 0xa0, 0x52, 0x45, 0xf2, 0x7f, 0xe5, 0x7b, 0xda, 0x66, 0xbd, 0x6d,
|
||||||
|
0xec, 0x7e, 0x4f, 0xc9, 0xcb, 0x23, 0x68, 0x02, 0x06, 0x2a, 0xdd, 0xe3, 0xcd, 0x0e, 0x31,
|
||||||
|
0x34, 0x82, 0xc9, 0x2a, 0x0c, 0x72, 0x11, 0x02, 0xb1, 0xf3, 0x8b, 0x01, 0x5a, 0xb8, 0xd0,
|
||||||
|
0x15, 0x59, 0xcb, 0xcb, 0x40, 0xf6, 0x74, 0xe9, 0xef, 0xad, 0x5e, 0xe9, 0xc2, 0xfe, 0x13,
|
||||||
|
0x3f, 0xaa, 0x55, 0xca, 0x1d, 0xd0, 0xff, 0x26, 0x71, 0x0f, 0x9d, 0xa8, 0x19, 0xcc, 0x14,
|
||||||
|
0x59, 0xcb, 0x7e, 0xd2, 0x60, 0xda, 0xd3, 0xdb, 0x05, 0x96, 0x25, 0x8d, 0x47, 0xc7, 0x4c,
|
||||||
|
0x32, 0xa8, 0xb8, 0x52, 0xb6, 0x71, 0xc5, 0xa0, 0xca, 0xa2, 0x00, 0x16, 0x03, 0xd9, 0x0c,
|
||||||
|
0x91, 0xa7, 0xdf, 0x2e, 0x2d, 0x4e, 0xe9, 0xae, 0x9b, 0xf1, 0xa6, 0xb1, 0xec, 0x88, 0x15,
|
||||||
|
0x1c, 0x62, 0x36, 0x0d, 0x03, 0x02, 0x4d, 0x2e, 0x2d, 0x01, 0x14, 0x08, 0x4f, 0x6b, 0x88,
|
||||||
|
0xc5, 0xbb, 0xa2, 0x4a, 0xa7, 0xce, 0xcf, 0xac, 0x16, 0xe9, 0x1e, 0x0b, 0xaf, 0x3d, 0x86,
|
||||||
|
0x53, 0xe2, 0x18, 0x09, 0x3e, 0x81, 0xd2, 0xa6, 0x3c, 0x32, 0xef, 0xf1, 0xd9, 0x03, 0x0f,
|
||||||
|
0x9e, 0x14, 0x14, 0xec, 0xe4, 0x20, 0xda, 0xa2, 0x4e, 0x0d, 0xd5, 0xb8, 0x45, 0xb3, 0x27,
|
||||||
|
0x4b, 0xb8, 0x39, 0xca, 0x1c, 0x53, 0xbc, 0xc0, 0x19, 0x42, 0x42, 0xd7, 0x4b, 0x26, 0x31,
|
||||||
|
0xb9, 0x49, 0x5a, 0x65, 0x4f, 0xbb, 0xdc, 0xbf, 0xad, 0x77, 0x9f, 0x73, 0x22, 0xb6, 0x07,
|
||||||
|
0x36, 0x24, 0x98, 0x80, 0x60, 0x48, 0x21, 0xd9, 0x69, 0x24, 0xe3, 0xfa, 0x39, 0x7f, 0x35,
|
||||||
|
0x4a, 0x5e, 0xcc, 0xa3, 0x4f, 0x61, 0x4d, 0xa5, 0x45, 0x6f, 0x9b, 0x36, 0x33, 0x8c, 0x37,
|
||||||
|
0xd8, 0xf6, 0xfb, 0xf6, 0x26, 0xbe, 0x98, 0x34, 0x77, 0x76, 0x60, 0x22, 0x87, 0x27, 0x46,
|
||||||
|
0xda, 0x10, 0xa1, 0x77, 0x1c, 0xeb, 0x02, 0xdd, 0x8a, 0xac, 0x01, 0xba, 0x18, 0x6b, 0xf1,
|
||||||
|
0x48, 0x86, 0x30, 0x47, 0x9e, 0x12, 0x84, 0xda, 0x01, 0x90, 0xfc, 0xe8, 0xb5, 0x9a, 0xc6,
|
||||||
|
0xb0, 0xfd, 0x41, 0x6b, 0xee, 0x56, 0xb7, 0x2f, 0x0a, 0x58, 0x45, 0x15, 0x35, 0x57, 0xff,
|
||||||
|
0x0f, 0x49, 0x50, 0xa0, 0xdc, 0x5b, 0xe6, 0x5c, 0xe9, 0x42, 0xd2, 0x2e, 0x18, 0x53, 0x4c,
|
||||||
|
0x4e, 0x0e, 0xfa, 0xbb, 0x2d, 0x15, 0x25, 0xdc, 0x48, 0x58, 0xb9, 0xb0, 0xf7, 0x7d, 0x47,
|
||||||
|
0x4a, 0x12, 0x5e, 0xbc, 0x25, 0x0e, 0x08, 0xfe, 0xdb, 0xfa, 0xa6, 0x6f, 0x45, 0x3d, 0x90,
|
||||||
|
0x93, 0x2c, 0xab, 0x3f, 0xf4, 0x52, 0x21, 0x90, 0x99, 0x68, 0xe5, 0x1e, 0x6b, 0xc2, 0x54,
|
||||||
|
0xd5, 0x09, 0xad, 0xeb, 0x75, 0xcb, 0xa7, 0x6d, 0x48, 0xfe, 0x02, 0x4e, 0x3e, 0x66, 0xd8,
|
||||||
|
0xdf, 0x5e,
|
||||||
|
];
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn header_read_write() {
|
||||||
|
let header = BlockHeader::read(&HEADER_MAINNET_415000[..]).unwrap();
|
||||||
|
let mut encoded = Vec::with_capacity(HEADER_MAINNET_415000.len());
|
||||||
|
header.write(&mut encoded).unwrap();
|
||||||
|
assert_eq!(&HEADER_MAINNET_415000[..], &encoded[..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
218
zcash_primitives/src/keys.rs
Normal file
218
zcash_primitives/src/keys.rs
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
//! Sapling key components.
|
||||||
|
//!
|
||||||
|
//! Implements section 4.2.2 of the Zcash Protocol Specification.
|
||||||
|
|
||||||
|
use blake2_rfc::blake2b::{Blake2b, Blake2bResult};
|
||||||
|
use ff::{PrimeField, PrimeFieldRepr};
|
||||||
|
use sapling_crypto::{
|
||||||
|
jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, ToUniform, Unknown},
|
||||||
|
primitives::{ProofGenerationKey, ViewingKey},
|
||||||
|
};
|
||||||
|
use std::io::{self, Read, Write};
|
||||||
|
|
||||||
|
pub const PRF_EXPAND_PERSONALIZATION: &'static [u8; 16] = b"Zcash_ExpandSeed";
|
||||||
|
|
||||||
|
/// PRF^expand(sk, t) := BLAKE2b-512("Zcash_ExpandSeed", sk || t)
|
||||||
|
pub fn prf_expand(sk: &[u8], t: &[u8]) -> Blake2bResult {
|
||||||
|
prf_expand_vec(sk, &[t])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prf_expand_vec(sk: &[u8], ts: &[&[u8]]) -> Blake2bResult {
|
||||||
|
let mut h = Blake2b::with_params(64, &[], &[], PRF_EXPAND_PERSONALIZATION);
|
||||||
|
h.update(sk);
|
||||||
|
for t in ts {
|
||||||
|
h.update(t);
|
||||||
|
}
|
||||||
|
h.finalize()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An outgoing viewing key
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct OutgoingViewingKey(pub [u8; 32]);
|
||||||
|
|
||||||
|
/// A Sapling expanded spending key
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ExpandedSpendingKey<E: JubjubEngine> {
|
||||||
|
pub ask: E::Fs,
|
||||||
|
pub nsk: E::Fs,
|
||||||
|
pub ovk: OutgoingViewingKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A Sapling full viewing key
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FullViewingKey<E: JubjubEngine> {
|
||||||
|
pub vk: ViewingKey<E>,
|
||||||
|
pub ovk: OutgoingViewingKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: JubjubEngine> ExpandedSpendingKey<E> {
|
||||||
|
pub fn from_spending_key(sk: &[u8]) -> Self {
|
||||||
|
let ask = E::Fs::to_uniform(prf_expand(sk, &[0x00]).as_bytes());
|
||||||
|
let nsk = E::Fs::to_uniform(prf_expand(sk, &[0x01]).as_bytes());
|
||||||
|
let mut ovk = OutgoingViewingKey([0u8; 32]);
|
||||||
|
ovk.0
|
||||||
|
.copy_from_slice(&prf_expand(sk, &[0x02]).as_bytes()[..32]);
|
||||||
|
ExpandedSpendingKey { ask, nsk, ovk }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proof_generation_key(&self, params: &E::Params) -> ProofGenerationKey<E> {
|
||||||
|
ProofGenerationKey {
|
||||||
|
ak: params
|
||||||
|
.generator(FixedGenerators::SpendingKeyGenerator)
|
||||||
|
.mul(self.ask, params),
|
||||||
|
nsk: self.nsk,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||||
|
let mut ask_repr = <E::Fs as PrimeField>::Repr::default();
|
||||||
|
ask_repr.read_le(&mut reader)?;
|
||||||
|
let ask = E::Fs::from_repr(ask_repr)
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||||
|
|
||||||
|
let mut nsk_repr = <E::Fs as PrimeField>::Repr::default();
|
||||||
|
nsk_repr.read_le(&mut reader)?;
|
||||||
|
let nsk = E::Fs::from_repr(nsk_repr)
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||||
|
|
||||||
|
let mut ovk = [0; 32];
|
||||||
|
reader.read_exact(&mut ovk)?;
|
||||||
|
|
||||||
|
Ok(ExpandedSpendingKey {
|
||||||
|
ask,
|
||||||
|
nsk,
|
||||||
|
ovk: OutgoingViewingKey(ovk),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
|
self.ask.into_repr().write_le(&mut writer)?;
|
||||||
|
self.nsk.into_repr().write_le(&mut writer)?;
|
||||||
|
writer.write_all(&self.ovk.0)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(&self) -> [u8; 96] {
|
||||||
|
let mut result = [0u8; 96];
|
||||||
|
self.write(&mut result[..])
|
||||||
|
.expect("should be able to serialize an ExpandedSpendingKey");
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: JubjubEngine> Clone for FullViewingKey<E> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
FullViewingKey {
|
||||||
|
vk: ViewingKey {
|
||||||
|
ak: self.vk.ak.clone(),
|
||||||
|
nk: self.vk.nk.clone(),
|
||||||
|
},
|
||||||
|
ovk: self.ovk.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: JubjubEngine> FullViewingKey<E> {
|
||||||
|
pub fn from_expanded_spending_key(expsk: &ExpandedSpendingKey<E>, params: &E::Params) -> Self {
|
||||||
|
FullViewingKey {
|
||||||
|
vk: ViewingKey {
|
||||||
|
ak: params
|
||||||
|
.generator(FixedGenerators::SpendingKeyGenerator)
|
||||||
|
.mul(expsk.ask, params),
|
||||||
|
nk: params
|
||||||
|
.generator(FixedGenerators::ProofGenerationKey)
|
||||||
|
.mul(expsk.nsk, params),
|
||||||
|
},
|
||||||
|
ovk: expsk.ovk,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read<R: Read>(mut reader: R, params: &E::Params) -> io::Result<Self> {
|
||||||
|
let ak = edwards::Point::<E, Unknown>::read(&mut reader, params)?;
|
||||||
|
let ak = match ak.as_prime_order(params) {
|
||||||
|
Some(p) => p,
|
||||||
|
None => {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidData,
|
||||||
|
"ak not in prime-order subgroup",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if ak == edwards::Point::zero() {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidData,
|
||||||
|
"ak not of prime order",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let nk = edwards::Point::<E, Unknown>::read(&mut reader, params)?;
|
||||||
|
let nk = match nk.as_prime_order(params) {
|
||||||
|
Some(p) => p,
|
||||||
|
None => {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidData,
|
||||||
|
"nk not in prime-order subgroup",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut ovk = [0; 32];
|
||||||
|
reader.read_exact(&mut ovk)?;
|
||||||
|
|
||||||
|
Ok(FullViewingKey {
|
||||||
|
vk: ViewingKey { ak, nk },
|
||||||
|
ovk: OutgoingViewingKey(ovk),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
|
self.vk.ak.write(&mut writer)?;
|
||||||
|
self.vk.nk.write(&mut writer)?;
|
||||||
|
writer.write_all(&self.ovk.0)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(&self) -> [u8; 96] {
|
||||||
|
let mut result = [0u8; 96];
|
||||||
|
self.write(&mut result[..])
|
||||||
|
.expect("should be able to serialize a FullViewingKey");
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use pairing::bls12_381::Bls12;
|
||||||
|
use sapling_crypto::jubjub::{edwards, FixedGenerators, JubjubParams, PrimeOrder};
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use super::FullViewingKey;
|
||||||
|
use crate::JUBJUB;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ak_must_be_prime_order() {
|
||||||
|
let mut buf = [0; 96];
|
||||||
|
let identity = edwards::Point::<Bls12, PrimeOrder>::zero();
|
||||||
|
|
||||||
|
// Set both ak and nk to the identity.
|
||||||
|
identity.write(&mut buf[0..32]).unwrap();
|
||||||
|
identity.write(&mut buf[32..64]).unwrap();
|
||||||
|
|
||||||
|
// ak is not allowed to be the identity.
|
||||||
|
assert_eq!(
|
||||||
|
FullViewingKey::<Bls12>::read(&buf[..], &JUBJUB)
|
||||||
|
.unwrap_err()
|
||||||
|
.description(),
|
||||||
|
"ak not of prime order"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set ak to a basepoint.
|
||||||
|
let basepoint = JUBJUB.generator(FixedGenerators::SpendingKeyGenerator);
|
||||||
|
basepoint.write(&mut buf[0..32]).unwrap();
|
||||||
|
|
||||||
|
// nk is allowed to be the identity.
|
||||||
|
assert!(FullViewingKey::<Bls12>::read(&buf[..], &JUBJUB).is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,28 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
|
||||||
|
extern crate blake2_rfc;
|
||||||
|
extern crate byteorder;
|
||||||
|
extern crate crypto_api_chachapoly;
|
||||||
|
extern crate ff;
|
||||||
|
extern crate hex;
|
||||||
|
extern crate pairing;
|
||||||
|
extern crate rand;
|
||||||
|
extern crate sapling_crypto;
|
||||||
|
extern crate sha2;
|
||||||
|
|
||||||
|
use sapling_crypto::jubjub::JubjubBls12;
|
||||||
|
|
||||||
|
pub mod block;
|
||||||
|
pub mod keys;
|
||||||
|
pub mod note_encryption;
|
||||||
|
pub mod sapling;
|
||||||
|
mod serialize;
|
||||||
|
pub mod transaction;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod test_vectors;
|
||||||
#[test]
|
|
||||||
fn it_works() {
|
lazy_static! {
|
||||||
assert_eq!(2 + 2, 4);
|
pub static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() };
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
1377
zcash_primitives/src/note_encryption.rs
Normal file
1377
zcash_primitives/src/note_encryption.rs
Normal file
File diff suppressed because it is too large
Load Diff
37
zcash_primitives/src/sapling.rs
Normal file
37
zcash_primitives/src/sapling.rs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
use pairing::bls12_381::Bls12;
|
||||||
|
use rand::OsRng;
|
||||||
|
use sapling_crypto::{
|
||||||
|
jubjub::{fs::Fs, FixedGenerators, JubjubBls12},
|
||||||
|
redjubjub::{PrivateKey, PublicKey, Signature},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Create the spendAuthSig for a Sapling SpendDescription.
|
||||||
|
pub fn spend_sig(
|
||||||
|
ask: PrivateKey<Bls12>,
|
||||||
|
ar: Fs,
|
||||||
|
sighash: &[u8; 32],
|
||||||
|
params: &JubjubBls12,
|
||||||
|
) -> Signature {
|
||||||
|
// Initialize secure RNG
|
||||||
|
let mut rng = OsRng::new().expect("should be able to construct RNG");
|
||||||
|
|
||||||
|
// We compute `rsk`...
|
||||||
|
let rsk = ask.randomize(ar);
|
||||||
|
|
||||||
|
// We compute `rk` from there (needed for key prefixing)
|
||||||
|
let rk = PublicKey::from_private(&rsk, FixedGenerators::SpendingKeyGenerator, params);
|
||||||
|
|
||||||
|
// Compute the signature's message for rk/spend_auth_sig
|
||||||
|
let mut data_to_be_signed = [0u8; 64];
|
||||||
|
rk.0.write(&mut data_to_be_signed[0..32])
|
||||||
|
.expect("message buffer should be 32 bytes");
|
||||||
|
(&mut data_to_be_signed[32..64]).copy_from_slice(&sighash[..]);
|
||||||
|
|
||||||
|
// Do the signing
|
||||||
|
rsk.sign(
|
||||||
|
&data_to_be_signed,
|
||||||
|
&mut rng,
|
||||||
|
FixedGenerators::SpendingKeyGenerator,
|
||||||
|
params,
|
||||||
|
)
|
||||||
|
}
|
||||||
156
zcash_primitives/src/serialize.rs
Normal file
156
zcash_primitives/src/serialize.rs
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
use std::io::{self, Read, Write};
|
||||||
|
|
||||||
|
const MAX_SIZE: usize = 0x02000000;
|
||||||
|
|
||||||
|
struct CompactSize;
|
||||||
|
|
||||||
|
impl CompactSize {
|
||||||
|
fn read<R: Read>(mut reader: R) -> io::Result<usize> {
|
||||||
|
let flag = reader.read_u8()?;
|
||||||
|
match if flag < 253 {
|
||||||
|
Ok(flag as usize)
|
||||||
|
} else if flag == 253 {
|
||||||
|
match reader.read_u16::<LittleEndian>()? {
|
||||||
|
n if n < 253 => Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"non-canonical CompactSize",
|
||||||
|
)),
|
||||||
|
n => Ok(n as usize),
|
||||||
|
}
|
||||||
|
} else if flag == 254 {
|
||||||
|
match reader.read_u32::<LittleEndian>()? {
|
||||||
|
n if n < 0x10000 => Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"non-canonical CompactSize",
|
||||||
|
)),
|
||||||
|
n => Ok(n as usize),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match reader.read_u64::<LittleEndian>()? {
|
||||||
|
n if n < 0x100000000 => Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"non-canonical CompactSize",
|
||||||
|
)),
|
||||||
|
n => Ok(n as usize),
|
||||||
|
}
|
||||||
|
}? {
|
||||||
|
s if s > MAX_SIZE => Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"CompactSize too large",
|
||||||
|
)),
|
||||||
|
s => Ok(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write<W: Write>(mut writer: W, size: usize) -> io::Result<()> {
|
||||||
|
match size {
|
||||||
|
s if s < 253 => writer.write_u8(s as u8),
|
||||||
|
s if s <= 0xFFFF => {
|
||||||
|
writer.write_u8(253)?;
|
||||||
|
writer.write_u16::<LittleEndian>(s as u16)
|
||||||
|
}
|
||||||
|
s if s <= 0xFFFFFFFF => {
|
||||||
|
writer.write_u8(254)?;
|
||||||
|
writer.write_u32::<LittleEndian>(s as u32)
|
||||||
|
}
|
||||||
|
s => {
|
||||||
|
writer.write_u8(255)?;
|
||||||
|
writer.write_u64::<LittleEndian>(s as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Vector;
|
||||||
|
|
||||||
|
impl Vector {
|
||||||
|
pub fn read<R: Read, E, F>(mut reader: R, func: F) -> io::Result<Vec<E>>
|
||||||
|
where
|
||||||
|
F: Fn(&mut R) -> io::Result<E>,
|
||||||
|
{
|
||||||
|
let count = CompactSize::read(&mut reader)?;
|
||||||
|
(0..count).into_iter().map(|_| func(&mut reader)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<W: Write, E, F>(mut writer: W, vec: &[E], func: F) -> io::Result<()>
|
||||||
|
where
|
||||||
|
F: Fn(&mut W, &E) -> io::Result<()>,
|
||||||
|
{
|
||||||
|
CompactSize::write(&mut writer, vec.len())?;
|
||||||
|
vec.iter().map(|e| func(&mut writer, e)).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn compact_size() {
|
||||||
|
macro_rules! eval {
|
||||||
|
($value:expr, $expected:expr) => {
|
||||||
|
let mut data = vec![];
|
||||||
|
CompactSize::write(&mut data, $value).unwrap();
|
||||||
|
assert_eq!(&data[..], &$expected[..]);
|
||||||
|
match CompactSize::read(&data[..]) {
|
||||||
|
Ok(n) => assert_eq!(n, $value),
|
||||||
|
Err(e) => panic!("Unexpected error: {:?}", e),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
eval!(0, [0]);
|
||||||
|
eval!(1, [1]);
|
||||||
|
eval!(252, [252]);
|
||||||
|
eval!(253, [253, 253, 0]);
|
||||||
|
eval!(254, [253, 254, 0]);
|
||||||
|
eval!(255, [253, 255, 0]);
|
||||||
|
eval!(256, [253, 0, 1]);
|
||||||
|
eval!(256, [253, 0, 1]);
|
||||||
|
eval!(65535, [253, 255, 255]);
|
||||||
|
eval!(65536, [254, 0, 0, 1, 0]);
|
||||||
|
eval!(65537, [254, 1, 0, 1, 0]);
|
||||||
|
|
||||||
|
eval!(33554432, [254, 0, 0, 0, 2]);
|
||||||
|
|
||||||
|
{
|
||||||
|
let value = 33554433;
|
||||||
|
let encoded = &[254, 1, 0, 0, 2][..];
|
||||||
|
let mut data = vec![];
|
||||||
|
CompactSize::write(&mut data, value).unwrap();
|
||||||
|
assert_eq!(&data[..], encoded);
|
||||||
|
assert!(CompactSize::read(encoded).is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn vector() {
|
||||||
|
macro_rules! eval {
|
||||||
|
($value:expr, $expected:expr) => {
|
||||||
|
let mut data = vec![];
|
||||||
|
Vector::write(&mut data, &$value, |w, e| w.write_u8(*e)).unwrap();
|
||||||
|
assert_eq!(&data[..], &$expected[..]);
|
||||||
|
match Vector::read(&data[..], |r| r.read_u8()) {
|
||||||
|
Ok(v) => assert_eq!(v, $value),
|
||||||
|
Err(e) => panic!("Unexpected error: {:?}", e),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
eval!(vec![], [0]);
|
||||||
|
eval!(vec![0], [1, 0]);
|
||||||
|
eval!(vec![1], [1, 1]);
|
||||||
|
eval!(vec![5; 8], [8, 5, 5, 5, 5, 5, 5, 5, 5]);
|
||||||
|
|
||||||
|
{
|
||||||
|
// expected = [253, 4, 1, 7, 7, 7, ...]
|
||||||
|
let mut expected = vec![7; 263];
|
||||||
|
expected[0] = 253;
|
||||||
|
expected[1] = 4;
|
||||||
|
expected[2] = 1;
|
||||||
|
|
||||||
|
eval!(vec![7; 260], expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
zcash_primitives/src/test_vectors.rs
Normal file
1
zcash_primitives/src/test_vectors.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub(crate) mod note_encryption;
|
||||||
2046
zcash_primitives/src/test_vectors/note_encryption.rs
Normal file
2046
zcash_primitives/src/test_vectors/note_encryption.rs
Normal file
File diff suppressed because it is too large
Load Diff
495
zcash_primitives/src/transaction/components.rs
Normal file
495
zcash_primitives/src/transaction/components.rs
Normal file
@@ -0,0 +1,495 @@
|
|||||||
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
use ff::{PrimeField, PrimeFieldRepr};
|
||||||
|
use pairing::bls12_381::{Bls12, Fr, FrRepr};
|
||||||
|
use sapling_crypto::{
|
||||||
|
jubjub::{edwards, Unknown},
|
||||||
|
redjubjub::{PublicKey, Signature},
|
||||||
|
};
|
||||||
|
use std::io::{self, Read, Write};
|
||||||
|
|
||||||
|
use serialize::Vector;
|
||||||
|
use JUBJUB;
|
||||||
|
|
||||||
|
// π_A + π_B + π_C
|
||||||
|
const GROTH_PROOF_SIZE: usize = (48 + 96 + 48);
|
||||||
|
// π_A + π_A' + π_B + π_B' + π_C + π_C' + π_K + π_H
|
||||||
|
const PHGR_PROOF_SIZE: usize = (33 + 33 + 65 + 33 + 33 + 33 + 33 + 33);
|
||||||
|
|
||||||
|
const ZC_NUM_JS_INPUTS: usize = 2;
|
||||||
|
const ZC_NUM_JS_OUTPUTS: usize = 2;
|
||||||
|
|
||||||
|
const COIN: i64 = 1_0000_0000;
|
||||||
|
const MAX_MONEY: i64 = 21_000_000 * COIN;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct Amount(pub i64);
|
||||||
|
|
||||||
|
impl Amount {
|
||||||
|
// Read an Amount from a signed 64-bit little-endian integer.
|
||||||
|
pub fn read_i64<R: Read>(mut reader: R, allow_negative: bool) -> io::Result<Self> {
|
||||||
|
let amount = reader.read_i64::<LittleEndian>()?;
|
||||||
|
if 0 <= amount && amount <= MAX_MONEY {
|
||||||
|
Ok(Amount(amount))
|
||||||
|
} else if allow_negative && -MAX_MONEY <= amount && amount < 0 {
|
||||||
|
Ok(Amount(amount))
|
||||||
|
} else {
|
||||||
|
Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidData,
|
||||||
|
if allow_negative {
|
||||||
|
"Amount not in {-MAX_MONEY..MAX_MONEY}"
|
||||||
|
} else {
|
||||||
|
"Amount not in {0..MAX_MONEY}"
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read an Amount from an unsigned 64-bit little-endian integer.
|
||||||
|
pub fn read_u64<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||||
|
let amount = reader.read_u64::<LittleEndian>()?;
|
||||||
|
if amount <= MAX_MONEY as u64 {
|
||||||
|
Ok(Amount(amount as i64))
|
||||||
|
} else {
|
||||||
|
Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidData,
|
||||||
|
"Amount not in {0..MAX_MONEY}",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Script(pub Vec<u8>);
|
||||||
|
|
||||||
|
impl Script {
|
||||||
|
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||||
|
let script = Vector::read(&mut reader, |r| r.read_u8())?;
|
||||||
|
Ok(Script(script))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
|
Vector::write(&mut writer, &self.0, |w, e| w.write_u8(*e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct OutPoint {
|
||||||
|
hash: [u8; 32],
|
||||||
|
n: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OutPoint {
|
||||||
|
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||||
|
let mut hash = [0; 32];
|
||||||
|
reader.read_exact(&mut hash)?;
|
||||||
|
let n = reader.read_u32::<LittleEndian>()?;
|
||||||
|
Ok(OutPoint { hash, n })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
|
writer.write_all(&self.hash)?;
|
||||||
|
writer.write_u32::<LittleEndian>(self.n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TxIn {
|
||||||
|
pub prevout: OutPoint,
|
||||||
|
script_sig: Script,
|
||||||
|
pub sequence: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TxIn {
|
||||||
|
pub fn read<R: Read>(mut reader: &mut R) -> io::Result<Self> {
|
||||||
|
let prevout = OutPoint::read(&mut reader)?;
|
||||||
|
let script_sig = Script::read(&mut reader)?;
|
||||||
|
let sequence = reader.read_u32::<LittleEndian>()?;
|
||||||
|
|
||||||
|
Ok(TxIn {
|
||||||
|
prevout,
|
||||||
|
script_sig,
|
||||||
|
sequence,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
|
self.prevout.write(&mut writer)?;
|
||||||
|
self.script_sig.write(&mut writer)?;
|
||||||
|
writer.write_u32::<LittleEndian>(self.sequence)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TxOut {
|
||||||
|
value: Amount,
|
||||||
|
script_pubkey: Script,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TxOut {
|
||||||
|
pub fn read<R: Read>(mut reader: &mut R) -> io::Result<Self> {
|
||||||
|
let value = Amount::read_i64(&mut reader, false)?;
|
||||||
|
let script_pubkey = Script::read(&mut reader)?;
|
||||||
|
|
||||||
|
Ok(TxOut {
|
||||||
|
value,
|
||||||
|
script_pubkey,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
|
writer.write_i64::<LittleEndian>(self.value.0)?;
|
||||||
|
self.script_pubkey.write(&mut writer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SpendDescription {
|
||||||
|
pub cv: edwards::Point<Bls12, Unknown>,
|
||||||
|
pub anchor: Fr,
|
||||||
|
pub nullifier: [u8; 32],
|
||||||
|
pub rk: PublicKey<Bls12>,
|
||||||
|
pub zkproof: [u8; GROTH_PROOF_SIZE],
|
||||||
|
pub spend_auth_sig: Option<Signature>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for SpendDescription {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"SpendDescription(cv = {:?}, anchor = {:?}, nullifier = {:?}, rk = {:?}, spend_auth_sig = {:?})",
|
||||||
|
self.cv, self.anchor, self.nullifier, self.rk, self.spend_auth_sig
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpendDescription {
|
||||||
|
pub fn read<R: Read>(mut reader: &mut R) -> io::Result<Self> {
|
||||||
|
// Consensus rules (§4.4):
|
||||||
|
// - Canonical encoding is enforced here.
|
||||||
|
// - "Not small order" is enforced in SaplingVerificationContext::check_spend()
|
||||||
|
// (located in zcash_proofs::sapling::verifier).
|
||||||
|
let cv = edwards::Point::<Bls12, Unknown>::read(&mut reader, &JUBJUB)?;
|
||||||
|
|
||||||
|
// Consensus rule (§7.3): Canonical encoding is enforced here
|
||||||
|
let anchor = {
|
||||||
|
let mut f = FrRepr::default();
|
||||||
|
f.read_le(&mut reader)?;
|
||||||
|
Fr::from_repr(f).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut nullifier = [0; 32];
|
||||||
|
reader.read_exact(&mut nullifier)?;
|
||||||
|
|
||||||
|
// Consensus rules (§4.4):
|
||||||
|
// - Canonical encoding is enforced here.
|
||||||
|
// - "Not small order" is enforced in SaplingVerificationContext::check_spend()
|
||||||
|
let rk = PublicKey::<Bls12>::read(&mut reader, &JUBJUB)?;
|
||||||
|
|
||||||
|
// Consensus rules (§4.4):
|
||||||
|
// - Canonical encoding is enforced by the API of SaplingVerificationContext::check_spend()
|
||||||
|
// due to the need to parse this into a bellman::groth16::Proof.
|
||||||
|
// - Proof validity is enforced in SaplingVerificationContext::check_spend()
|
||||||
|
let mut zkproof = [0; GROTH_PROOF_SIZE];
|
||||||
|
reader.read_exact(&mut zkproof)?;
|
||||||
|
|
||||||
|
// Consensus rules (§4.4):
|
||||||
|
// - Canonical encoding is enforced here.
|
||||||
|
// - Signature validity is enforced in SaplingVerificationContext::check_spend()
|
||||||
|
let spend_auth_sig = Some(Signature::read(&mut reader)?);
|
||||||
|
|
||||||
|
Ok(SpendDescription {
|
||||||
|
cv,
|
||||||
|
anchor,
|
||||||
|
nullifier,
|
||||||
|
rk,
|
||||||
|
zkproof,
|
||||||
|
spend_auth_sig,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
|
self.cv.write(&mut writer)?;
|
||||||
|
self.anchor.into_repr().write_le(&mut writer)?;
|
||||||
|
writer.write_all(&self.nullifier)?;
|
||||||
|
self.rk.write(&mut writer)?;
|
||||||
|
writer.write_all(&self.zkproof)?;
|
||||||
|
match self.spend_auth_sig {
|
||||||
|
Some(sig) => sig.write(&mut writer),
|
||||||
|
None => {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"Missing spend auth signature",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OutputDescription {
|
||||||
|
pub cv: edwards::Point<Bls12, Unknown>,
|
||||||
|
pub cmu: Fr,
|
||||||
|
pub ephemeral_key: edwards::Point<Bls12, Unknown>,
|
||||||
|
pub enc_ciphertext: [u8; 580],
|
||||||
|
pub out_ciphertext: [u8; 80],
|
||||||
|
pub zkproof: [u8; GROTH_PROOF_SIZE],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for OutputDescription {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"OutputDescription(cv = {:?}, cmu = {:?}, ephemeral_key = {:?})",
|
||||||
|
self.cv, self.cmu, self.ephemeral_key
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OutputDescription {
|
||||||
|
pub fn read<R: Read>(mut reader: &mut R) -> io::Result<Self> {
|
||||||
|
// Consensus rules (§4.5):
|
||||||
|
// - Canonical encoding is enforced here.
|
||||||
|
// - "Not small order" is enforced in SaplingVerificationContext::check_output()
|
||||||
|
// (located in zcash_proofs::sapling::verifier).
|
||||||
|
let cv = edwards::Point::<Bls12, Unknown>::read(&mut reader, &JUBJUB)?;
|
||||||
|
|
||||||
|
// Consensus rule (§7.4): Canonical encoding is enforced here
|
||||||
|
let cmu = {
|
||||||
|
let mut f = FrRepr::default();
|
||||||
|
f.read_le(&mut reader)?;
|
||||||
|
Fr::from_repr(f).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?
|
||||||
|
};
|
||||||
|
|
||||||
|
// Consensus rules (§4.5):
|
||||||
|
// - Canonical encoding is enforced here.
|
||||||
|
// - "Not small order" is enforced in SaplingVerificationContext::check_output()
|
||||||
|
let ephemeral_key = edwards::Point::<Bls12, Unknown>::read(&mut reader, &JUBJUB)?;
|
||||||
|
|
||||||
|
let mut enc_ciphertext = [0; 580];
|
||||||
|
let mut out_ciphertext = [0; 80];
|
||||||
|
reader.read_exact(&mut enc_ciphertext)?;
|
||||||
|
reader.read_exact(&mut out_ciphertext)?;
|
||||||
|
|
||||||
|
// Consensus rules (§4.5):
|
||||||
|
// - Canonical encoding is enforced by the API of SaplingVerificationContext::check_output()
|
||||||
|
// due to the need to parse this into a bellman::groth16::Proof.
|
||||||
|
// - Proof validity is enforced in SaplingVerificationContext::check_output()
|
||||||
|
let mut zkproof = [0; GROTH_PROOF_SIZE];
|
||||||
|
reader.read_exact(&mut zkproof)?;
|
||||||
|
|
||||||
|
Ok(OutputDescription {
|
||||||
|
cv,
|
||||||
|
cmu,
|
||||||
|
ephemeral_key,
|
||||||
|
enc_ciphertext,
|
||||||
|
out_ciphertext,
|
||||||
|
zkproof,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
|
self.cv.write(&mut writer)?;
|
||||||
|
self.cmu.into_repr().write_le(&mut writer)?;
|
||||||
|
self.ephemeral_key.write(&mut writer)?;
|
||||||
|
writer.write_all(&self.enc_ciphertext)?;
|
||||||
|
writer.write_all(&self.out_ciphertext)?;
|
||||||
|
writer.write_all(&self.zkproof)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SproutProof {
|
||||||
|
Groth([u8; GROTH_PROOF_SIZE]),
|
||||||
|
PHGR([u8; PHGR_PROOF_SIZE]),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for SproutProof {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||||
|
match self {
|
||||||
|
SproutProof::Groth(_) => write!(f, "SproutProof::Groth"),
|
||||||
|
SproutProof::PHGR(_) => write!(f, "SproutProof::PHGR"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct JSDescription {
|
||||||
|
vpub_old: Amount,
|
||||||
|
vpub_new: Amount,
|
||||||
|
anchor: [u8; 32],
|
||||||
|
nullifiers: [[u8; 32]; ZC_NUM_JS_INPUTS],
|
||||||
|
commitments: [[u8; 32]; ZC_NUM_JS_OUTPUTS],
|
||||||
|
ephemeral_key: [u8; 32],
|
||||||
|
random_seed: [u8; 32],
|
||||||
|
macs: [[u8; 32]; ZC_NUM_JS_INPUTS],
|
||||||
|
proof: SproutProof,
|
||||||
|
ciphertexts: [[u8; 601]; ZC_NUM_JS_OUTPUTS],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for JSDescription {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"JSDescription(
|
||||||
|
vpub_old = {:?}, vpub_new = {:?},
|
||||||
|
anchor = {:?},
|
||||||
|
nullifiers = {:?},
|
||||||
|
commitments = {:?},
|
||||||
|
ephemeral_key = {:?},
|
||||||
|
random_seed = {:?},
|
||||||
|
macs = {:?})",
|
||||||
|
self.vpub_old,
|
||||||
|
self.vpub_new,
|
||||||
|
self.anchor,
|
||||||
|
self.nullifiers,
|
||||||
|
self.commitments,
|
||||||
|
self.ephemeral_key,
|
||||||
|
self.random_seed,
|
||||||
|
self.macs
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JSDescription {
|
||||||
|
pub fn read<R: Read>(mut reader: R, use_groth: bool) -> io::Result<Self> {
|
||||||
|
// Consensus rule (§4.3): Canonical encoding is enforced here
|
||||||
|
let vpub_old = Amount::read_u64(&mut reader)?;
|
||||||
|
|
||||||
|
// Consensus rule (§4.3): Canonical encoding is enforced here
|
||||||
|
let vpub_new = Amount::read_u64(&mut reader)?;
|
||||||
|
|
||||||
|
// Consensus rule (§4.3): One of vpub_old and vpub_new being zero is
|
||||||
|
// enforced by CheckTransactionWithoutProofVerification() in zcashd.
|
||||||
|
|
||||||
|
let mut anchor = [0; 32];
|
||||||
|
reader.read_exact(&mut anchor)?;
|
||||||
|
|
||||||
|
let mut nullifiers = [[0; 32]; ZC_NUM_JS_INPUTS];
|
||||||
|
nullifiers
|
||||||
|
.iter_mut()
|
||||||
|
.map(|nf| reader.read_exact(nf))
|
||||||
|
.collect::<io::Result<()>>()?;
|
||||||
|
|
||||||
|
let mut commitments = [[0; 32]; ZC_NUM_JS_OUTPUTS];
|
||||||
|
commitments
|
||||||
|
.iter_mut()
|
||||||
|
.map(|cm| reader.read_exact(cm))
|
||||||
|
.collect::<io::Result<()>>()?;
|
||||||
|
|
||||||
|
// Consensus rule (§4.3): Canonical encoding is enforced by
|
||||||
|
// ZCNoteDecryption::decrypt() in zcashd
|
||||||
|
let mut ephemeral_key = [0; 32];
|
||||||
|
reader.read_exact(&mut ephemeral_key)?;
|
||||||
|
|
||||||
|
let mut random_seed = [0; 32];
|
||||||
|
reader.read_exact(&mut random_seed)?;
|
||||||
|
|
||||||
|
let mut macs = [[0; 32]; ZC_NUM_JS_INPUTS];
|
||||||
|
macs.iter_mut()
|
||||||
|
.map(|mac| reader.read_exact(mac))
|
||||||
|
.collect::<io::Result<()>>()?;
|
||||||
|
|
||||||
|
let proof = match use_groth {
|
||||||
|
true => {
|
||||||
|
// Consensus rules (§4.3):
|
||||||
|
// - Canonical encoding is enforced in librustzcash_sprout_verify()
|
||||||
|
// - Proof validity is enforced in librustzcash_sprout_verify()
|
||||||
|
let mut proof = [0; GROTH_PROOF_SIZE];
|
||||||
|
reader.read_exact(&mut proof)?;
|
||||||
|
SproutProof::Groth(proof)
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
// Consensus rules (§4.3):
|
||||||
|
// - Canonical encoding is enforced by PHGRProof in zcashd
|
||||||
|
// - Proof validity is enforced by JSDescription::Verify() in zcashd
|
||||||
|
let mut proof = [0; PHGR_PROOF_SIZE];
|
||||||
|
reader.read_exact(&mut proof)?;
|
||||||
|
SproutProof::PHGR(proof)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut ciphertexts = [[0; 601]; ZC_NUM_JS_OUTPUTS];
|
||||||
|
ciphertexts
|
||||||
|
.iter_mut()
|
||||||
|
.map(|ct| reader.read_exact(ct))
|
||||||
|
.collect::<io::Result<()>>()?;
|
||||||
|
|
||||||
|
Ok(JSDescription {
|
||||||
|
vpub_old,
|
||||||
|
vpub_new,
|
||||||
|
anchor,
|
||||||
|
nullifiers,
|
||||||
|
commitments,
|
||||||
|
ephemeral_key,
|
||||||
|
random_seed,
|
||||||
|
macs,
|
||||||
|
proof,
|
||||||
|
ciphertexts,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
|
writer.write_i64::<LittleEndian>(self.vpub_old.0)?;
|
||||||
|
writer.write_i64::<LittleEndian>(self.vpub_new.0)?;
|
||||||
|
writer.write_all(&self.anchor)?;
|
||||||
|
writer.write_all(&self.nullifiers[0])?;
|
||||||
|
writer.write_all(&self.nullifiers[1])?;
|
||||||
|
writer.write_all(&self.commitments[0])?;
|
||||||
|
writer.write_all(&self.commitments[1])?;
|
||||||
|
writer.write_all(&self.ephemeral_key)?;
|
||||||
|
writer.write_all(&self.random_seed)?;
|
||||||
|
writer.write_all(&self.macs[0])?;
|
||||||
|
writer.write_all(&self.macs[1])?;
|
||||||
|
|
||||||
|
match &self.proof {
|
||||||
|
SproutProof::Groth(p) => writer.write_all(p)?,
|
||||||
|
SproutProof::PHGR(p) => writer.write_all(p)?,
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.write_all(&self.ciphertexts[0])?;
|
||||||
|
writer.write_all(&self.ciphertexts[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::{Amount, MAX_MONEY};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn amount_in_range() {
|
||||||
|
let zero = b"\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||||
|
assert_eq!(Amount::read_u64(&zero[..]).unwrap(), Amount(0));
|
||||||
|
assert_eq!(Amount::read_i64(&zero[..], false).unwrap(), Amount(0));
|
||||||
|
assert_eq!(Amount::read_i64(&zero[..], true).unwrap(), Amount(0));
|
||||||
|
|
||||||
|
let neg_one = b"\xff\xff\xff\xff\xff\xff\xff\xff";
|
||||||
|
assert!(Amount::read_u64(&neg_one[..]).is_err());
|
||||||
|
assert!(Amount::read_i64(&neg_one[..], false).is_err());
|
||||||
|
assert_eq!(Amount::read_i64(&neg_one[..], true).unwrap(), Amount(-1));
|
||||||
|
|
||||||
|
let max_money = b"\x00\x40\x07\x5a\xf0\x75\x07\x00";
|
||||||
|
assert_eq!(Amount::read_u64(&max_money[..]).unwrap(), Amount(MAX_MONEY));
|
||||||
|
assert_eq!(
|
||||||
|
Amount::read_i64(&max_money[..], false).unwrap(),
|
||||||
|
Amount(MAX_MONEY)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Amount::read_i64(&max_money[..], true).unwrap(),
|
||||||
|
Amount(MAX_MONEY)
|
||||||
|
);
|
||||||
|
|
||||||
|
let max_money_p1 = b"\x01\x40\x07\x5a\xf0\x75\x07\x00";
|
||||||
|
assert!(Amount::read_u64(&max_money_p1[..]).is_err());
|
||||||
|
assert!(Amount::read_i64(&max_money_p1[..], false).is_err());
|
||||||
|
assert!(Amount::read_i64(&max_money_p1[..], true).is_err());
|
||||||
|
|
||||||
|
let neg_max_money = b"\x00\xc0\xf8\xa5\x0f\x8a\xf8\xff";
|
||||||
|
assert!(Amount::read_u64(&neg_max_money[..]).is_err());
|
||||||
|
assert!(Amount::read_i64(&neg_max_money[..], false).is_err());
|
||||||
|
assert_eq!(
|
||||||
|
Amount::read_i64(&neg_max_money[..], true).unwrap(),
|
||||||
|
Amount(-MAX_MONEY)
|
||||||
|
);
|
||||||
|
|
||||||
|
let neg_max_money_m1 = b"\xff\xbf\xf8\xa5\x0f\x8a\xf8\xff";
|
||||||
|
assert!(Amount::read_u64(&neg_max_money_m1[..]).is_err());
|
||||||
|
assert!(Amount::read_i64(&neg_max_money_m1[..], false).is_err());
|
||||||
|
assert!(Amount::read_i64(&neg_max_money_m1[..], true).is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
327
zcash_primitives/src/transaction/mod.rs
Normal file
327
zcash_primitives/src/transaction/mod.rs
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
use hex;
|
||||||
|
use sapling_crypto::redjubjub::Signature;
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
|
use std::fmt;
|
||||||
|
use std::io::{self, Read, Write};
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use serialize::Vector;
|
||||||
|
|
||||||
|
pub mod components;
|
||||||
|
mod sighash;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
|
pub use self::sighash::{signature_hash, signature_hash_data, SIGHASH_ALL};
|
||||||
|
|
||||||
|
use self::components::{Amount, JSDescription, OutputDescription, SpendDescription, TxIn, TxOut};
|
||||||
|
|
||||||
|
const OVERWINTER_VERSION_GROUP_ID: u32 = 0x03C48270;
|
||||||
|
const OVERWINTER_TX_VERSION: u32 = 3;
|
||||||
|
const SAPLING_VERSION_GROUP_ID: u32 = 0x892F2085;
|
||||||
|
const SAPLING_TX_VERSION: u32 = 4;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct TxId(pub [u8; 32]);
|
||||||
|
|
||||||
|
impl fmt::Display for TxId {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let mut data = self.0.clone();
|
||||||
|
data.reverse();
|
||||||
|
formatter.write_str(&hex::encode(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A Zcash transaction.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Transaction {
|
||||||
|
txid: TxId,
|
||||||
|
data: TransactionData,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Transaction {
|
||||||
|
type Target = TransactionData;
|
||||||
|
|
||||||
|
fn deref(&self) -> &TransactionData {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TransactionData {
|
||||||
|
pub overwintered: bool,
|
||||||
|
pub version: u32,
|
||||||
|
pub version_group_id: u32,
|
||||||
|
pub vin: Vec<TxIn>,
|
||||||
|
pub vout: Vec<TxOut>,
|
||||||
|
pub lock_time: u32,
|
||||||
|
pub expiry_height: u32,
|
||||||
|
pub value_balance: Amount,
|
||||||
|
pub shielded_spends: Vec<SpendDescription>,
|
||||||
|
pub shielded_outputs: Vec<OutputDescription>,
|
||||||
|
pub joinsplits: Vec<JSDescription>,
|
||||||
|
pub joinsplit_pubkey: Option<[u8; 32]>,
|
||||||
|
pub joinsplit_sig: Option<[u8; 64]>,
|
||||||
|
pub binding_sig: Option<Signature>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for TransactionData {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"TransactionData(
|
||||||
|
overwintered = {:?},
|
||||||
|
version = {:?},
|
||||||
|
version_group_id = {:?},
|
||||||
|
vin = {:?},
|
||||||
|
vout = {:?},
|
||||||
|
lock_time = {:?},
|
||||||
|
expiry_height = {:?},
|
||||||
|
value_balance = {:?},
|
||||||
|
shielded_spends = {:?},
|
||||||
|
shielded_outputs = {:?},
|
||||||
|
joinsplits = {:?},
|
||||||
|
joinsplit_pubkey = {:?},
|
||||||
|
binding_sig = {:?})",
|
||||||
|
self.overwintered,
|
||||||
|
self.version,
|
||||||
|
self.version_group_id,
|
||||||
|
self.vin,
|
||||||
|
self.vout,
|
||||||
|
self.lock_time,
|
||||||
|
self.expiry_height,
|
||||||
|
self.value_balance,
|
||||||
|
self.shielded_spends,
|
||||||
|
self.shielded_outputs,
|
||||||
|
self.joinsplits,
|
||||||
|
self.joinsplit_pubkey,
|
||||||
|
self.binding_sig
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TransactionData {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
TransactionData {
|
||||||
|
overwintered: true,
|
||||||
|
version: SAPLING_TX_VERSION,
|
||||||
|
version_group_id: SAPLING_VERSION_GROUP_ID,
|
||||||
|
vin: vec![],
|
||||||
|
vout: vec![],
|
||||||
|
lock_time: 0,
|
||||||
|
expiry_height: 0,
|
||||||
|
value_balance: Amount(0),
|
||||||
|
shielded_spends: vec![],
|
||||||
|
shielded_outputs: vec![],
|
||||||
|
joinsplits: vec![],
|
||||||
|
joinsplit_pubkey: None,
|
||||||
|
joinsplit_sig: None,
|
||||||
|
binding_sig: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn header(&self) -> u32 {
|
||||||
|
let mut header = self.version;
|
||||||
|
if self.overwintered {
|
||||||
|
header |= 1 << 31;
|
||||||
|
}
|
||||||
|
header
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn freeze(self) -> io::Result<Transaction> {
|
||||||
|
Transaction::from_data(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Transaction {
|
||||||
|
fn from_data(data: TransactionData) -> io::Result<Self> {
|
||||||
|
let mut tx = Transaction {
|
||||||
|
txid: TxId([0; 32]),
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
let mut raw = vec![];
|
||||||
|
tx.write(&mut raw)?;
|
||||||
|
tx.txid
|
||||||
|
.0
|
||||||
|
.copy_from_slice(&Sha256::digest(&Sha256::digest(&raw)));
|
||||||
|
Ok(tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn txid(&self) -> TxId {
|
||||||
|
self.txid
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||||
|
let header = reader.read_u32::<LittleEndian>()?;
|
||||||
|
let overwintered = (header >> 31) == 1;
|
||||||
|
let version = header & 0x7FFFFFFF;
|
||||||
|
|
||||||
|
let version_group_id = match overwintered {
|
||||||
|
true => reader.read_u32::<LittleEndian>()?,
|
||||||
|
false => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let is_overwinter_v3 = overwintered
|
||||||
|
&& version_group_id == OVERWINTER_VERSION_GROUP_ID
|
||||||
|
&& version == OVERWINTER_TX_VERSION;
|
||||||
|
let is_sapling_v4 = overwintered
|
||||||
|
&& version_group_id == SAPLING_VERSION_GROUP_ID
|
||||||
|
&& version == SAPLING_TX_VERSION;
|
||||||
|
if overwintered && !(is_overwinter_v3 || is_sapling_v4) {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"Unknown transaction format",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let vin = Vector::read(&mut reader, TxIn::read)?;
|
||||||
|
let vout = Vector::read(&mut reader, TxOut::read)?;
|
||||||
|
let lock_time = reader.read_u32::<LittleEndian>()?;
|
||||||
|
let expiry_height = match is_overwinter_v3 || is_sapling_v4 {
|
||||||
|
true => reader.read_u32::<LittleEndian>()?,
|
||||||
|
false => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let (value_balance, shielded_spends, shielded_outputs) = if is_sapling_v4 {
|
||||||
|
let vb = Amount::read_i64(&mut reader, true)?;
|
||||||
|
let ss = Vector::read(&mut reader, SpendDescription::read)?;
|
||||||
|
let so = Vector::read(&mut reader, OutputDescription::read)?;
|
||||||
|
(vb, ss, so)
|
||||||
|
} else {
|
||||||
|
(Amount(0), vec![], vec![])
|
||||||
|
};
|
||||||
|
|
||||||
|
let (joinsplits, joinsplit_pubkey, joinsplit_sig) = if version >= 2 {
|
||||||
|
let jss = Vector::read(&mut reader, |r| {
|
||||||
|
JSDescription::read(r, overwintered && version >= SAPLING_TX_VERSION)
|
||||||
|
})?;
|
||||||
|
let (pubkey, sig) = if !jss.is_empty() {
|
||||||
|
let mut joinsplit_pubkey = [0; 32];
|
||||||
|
let mut joinsplit_sig = [0; 64];
|
||||||
|
reader.read_exact(&mut joinsplit_pubkey)?;
|
||||||
|
reader.read_exact(&mut joinsplit_sig)?;
|
||||||
|
(Some(joinsplit_pubkey), Some(joinsplit_sig))
|
||||||
|
} else {
|
||||||
|
(None, None)
|
||||||
|
};
|
||||||
|
(jss, pubkey, sig)
|
||||||
|
} else {
|
||||||
|
(vec![], None, None)
|
||||||
|
};
|
||||||
|
|
||||||
|
let binding_sig =
|
||||||
|
match is_sapling_v4 && !(shielded_spends.is_empty() && shielded_outputs.is_empty()) {
|
||||||
|
true => Some(Signature::read(&mut reader)?),
|
||||||
|
false => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Transaction::from_data(TransactionData {
|
||||||
|
overwintered,
|
||||||
|
version,
|
||||||
|
version_group_id,
|
||||||
|
vin,
|
||||||
|
vout,
|
||||||
|
lock_time,
|
||||||
|
expiry_height,
|
||||||
|
value_balance,
|
||||||
|
shielded_spends,
|
||||||
|
shielded_outputs,
|
||||||
|
joinsplits,
|
||||||
|
joinsplit_pubkey,
|
||||||
|
joinsplit_sig,
|
||||||
|
binding_sig,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
|
writer.write_u32::<LittleEndian>(self.header())?;
|
||||||
|
if self.overwintered {
|
||||||
|
writer.write_u32::<LittleEndian>(self.version_group_id)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_overwinter_v3 = self.overwintered
|
||||||
|
&& self.version_group_id == OVERWINTER_VERSION_GROUP_ID
|
||||||
|
&& self.version == OVERWINTER_TX_VERSION;
|
||||||
|
let is_sapling_v4 = self.overwintered
|
||||||
|
&& self.version_group_id == SAPLING_VERSION_GROUP_ID
|
||||||
|
&& self.version == SAPLING_TX_VERSION;
|
||||||
|
if self.overwintered && !(is_overwinter_v3 || is_sapling_v4) {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"Unknown transaction format",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector::write(&mut writer, &self.vin, |w, e| e.write(w))?;
|
||||||
|
Vector::write(&mut writer, &self.vout, |w, e| e.write(w))?;
|
||||||
|
writer.write_u32::<LittleEndian>(self.lock_time)?;
|
||||||
|
if is_overwinter_v3 || is_sapling_v4 {
|
||||||
|
writer.write_u32::<LittleEndian>(self.expiry_height)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_sapling_v4 {
|
||||||
|
writer.write_i64::<LittleEndian>(self.value_balance.0)?;
|
||||||
|
Vector::write(&mut writer, &self.shielded_spends, |w, e| e.write(w))?;
|
||||||
|
Vector::write(&mut writer, &self.shielded_outputs, |w, e| e.write(w))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.version >= 2 {
|
||||||
|
Vector::write(&mut writer, &self.joinsplits, |w, e| e.write(w))?;
|
||||||
|
if !self.joinsplits.is_empty() {
|
||||||
|
match self.joinsplit_pubkey {
|
||||||
|
Some(pubkey) => writer.write_all(&pubkey)?,
|
||||||
|
None => {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"Missing JoinSplit pubkey",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match self.joinsplit_sig {
|
||||||
|
Some(sig) => writer.write_all(&sig)?,
|
||||||
|
None => {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"Missing JoinSplit signature",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.version < 2 || self.joinsplits.is_empty() {
|
||||||
|
if self.joinsplit_pubkey.is_some() {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"JoinSplit pubkey should not be present",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if self.joinsplit_sig.is_some() {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"JoinSplit signature should not be present",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_sapling_v4 && !(self.shielded_spends.is_empty() && self.shielded_outputs.is_empty()) {
|
||||||
|
match self.binding_sig {
|
||||||
|
Some(sig) => sig.write(&mut writer)?,
|
||||||
|
None => {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"Missing binding signature",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if self.binding_sig.is_some() {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"Binding signature should not be present",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
234
zcash_primitives/src/transaction/sighash.rs
Normal file
234
zcash_primitives/src/transaction/sighash.rs
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
use blake2_rfc::blake2b::Blake2b;
|
||||||
|
use byteorder::{LittleEndian, WriteBytesExt};
|
||||||
|
use ff::{PrimeField, PrimeFieldRepr};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
components::{Amount, Script, TxOut},
|
||||||
|
Transaction, TransactionData, OVERWINTER_VERSION_GROUP_ID, SAPLING_TX_VERSION,
|
||||||
|
SAPLING_VERSION_GROUP_ID,
|
||||||
|
};
|
||||||
|
|
||||||
|
const ZCASH_SIGHASH_PERSONALIZATION_PREFIX: &'static [u8; 12] = b"ZcashSigHash";
|
||||||
|
const ZCASH_PREVOUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashPrevoutHash";
|
||||||
|
const ZCASH_SEQUENCE_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSequencHash";
|
||||||
|
const ZCASH_OUTPUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashOutputsHash";
|
||||||
|
const ZCASH_JOINSPLITS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashJSplitsHash";
|
||||||
|
const ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSSpendsHash";
|
||||||
|
const ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSOutputHash";
|
||||||
|
|
||||||
|
pub const SIGHASH_ALL: u32 = 1;
|
||||||
|
const SIGHASH_NONE: u32 = 2;
|
||||||
|
const SIGHASH_SINGLE: u32 = 3;
|
||||||
|
const SIGHASH_MASK: u32 = 0x1f;
|
||||||
|
const SIGHASH_ANYONECANPAY: u32 = 0x80;
|
||||||
|
|
||||||
|
macro_rules! update_u32 {
|
||||||
|
($h:expr, $value:expr, $tmp:expr) => {
|
||||||
|
(&mut $tmp[..4]).write_u32::<LittleEndian>($value).unwrap();
|
||||||
|
$h.update(&$tmp[..4]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! update_i64 {
|
||||||
|
($h:expr, $value:expr, $tmp:expr) => {
|
||||||
|
(&mut $tmp[..8]).write_i64::<LittleEndian>($value).unwrap();
|
||||||
|
$h.update(&$tmp[..8]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! update_hash {
|
||||||
|
($h:expr, $cond:expr, $value:expr) => {
|
||||||
|
if $cond {
|
||||||
|
$h.update(&$value);
|
||||||
|
} else {
|
||||||
|
$h.update(&[0; 32]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
enum SigHashVersion {
|
||||||
|
Sprout,
|
||||||
|
Overwinter,
|
||||||
|
Sapling,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SigHashVersion {
|
||||||
|
fn from_tx(tx: &TransactionData) -> Self {
|
||||||
|
if tx.overwintered {
|
||||||
|
match tx.version_group_id {
|
||||||
|
OVERWINTER_VERSION_GROUP_ID => SigHashVersion::Overwinter,
|
||||||
|
SAPLING_VERSION_GROUP_ID => SigHashVersion::Sapling,
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SigHashVersion::Sprout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prevout_hash(tx: &TransactionData) -> Vec<u8> {
|
||||||
|
let mut data = Vec::with_capacity(tx.vin.len() * 36);
|
||||||
|
for t_in in &tx.vin {
|
||||||
|
t_in.prevout.write(&mut data).unwrap();
|
||||||
|
}
|
||||||
|
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_PREVOUTS_HASH_PERSONALIZATION);
|
||||||
|
h.update(&data);
|
||||||
|
h.finalize().as_ref().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sequence_hash(tx: &TransactionData) -> Vec<u8> {
|
||||||
|
let mut data = Vec::with_capacity(tx.vin.len() * 4);
|
||||||
|
for t_in in &tx.vin {
|
||||||
|
(&mut data)
|
||||||
|
.write_u32::<LittleEndian>(t_in.sequence)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SEQUENCE_HASH_PERSONALIZATION);
|
||||||
|
h.update(&data);
|
||||||
|
h.finalize().as_ref().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn outputs_hash(tx: &TransactionData) -> Vec<u8> {
|
||||||
|
let mut data = Vec::with_capacity(tx.vout.len() * (4 + 1));
|
||||||
|
for t_out in &tx.vout {
|
||||||
|
t_out.write(&mut data).unwrap();
|
||||||
|
}
|
||||||
|
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_OUTPUTS_HASH_PERSONALIZATION);
|
||||||
|
h.update(&data);
|
||||||
|
h.finalize().as_ref().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn single_output_hash(tx_out: &TxOut) -> Vec<u8> {
|
||||||
|
let mut data = vec![];
|
||||||
|
tx_out.write(&mut data).unwrap();
|
||||||
|
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_OUTPUTS_HASH_PERSONALIZATION);
|
||||||
|
h.update(&data);
|
||||||
|
h.finalize().as_ref().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn joinsplits_hash(tx: &TransactionData) -> Vec<u8> {
|
||||||
|
let mut data = Vec::with_capacity(
|
||||||
|
tx.joinsplits.len()
|
||||||
|
* if tx.version < SAPLING_TX_VERSION {
|
||||||
|
1802 // JSDescription with PHGR13 proof
|
||||||
|
} else {
|
||||||
|
1698 // JSDescription with Groth16 proof
|
||||||
|
},
|
||||||
|
);
|
||||||
|
for js in &tx.joinsplits {
|
||||||
|
js.write(&mut data).unwrap();
|
||||||
|
}
|
||||||
|
data.extend_from_slice(&tx.joinsplit_pubkey.unwrap());
|
||||||
|
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_JOINSPLITS_HASH_PERSONALIZATION);
|
||||||
|
h.update(&data);
|
||||||
|
h.finalize().as_ref().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shielded_spends_hash(tx: &TransactionData) -> Vec<u8> {
|
||||||
|
let mut data = Vec::with_capacity(tx.shielded_spends.len() * 384);
|
||||||
|
for s_spend in &tx.shielded_spends {
|
||||||
|
s_spend.cv.write(&mut data).unwrap();
|
||||||
|
s_spend.anchor.into_repr().write_le(&mut data).unwrap();
|
||||||
|
data.extend_from_slice(&s_spend.nullifier);
|
||||||
|
s_spend.rk.write(&mut data).unwrap();
|
||||||
|
data.extend_from_slice(&s_spend.zkproof);
|
||||||
|
}
|
||||||
|
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION);
|
||||||
|
h.update(&data);
|
||||||
|
h.finalize().as_ref().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shielded_outputs_hash(tx: &TransactionData) -> Vec<u8> {
|
||||||
|
let mut data = Vec::with_capacity(tx.shielded_outputs.len() * 948);
|
||||||
|
for s_out in &tx.shielded_outputs {
|
||||||
|
s_out.write(&mut data).unwrap();
|
||||||
|
}
|
||||||
|
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION);
|
||||||
|
h.update(&data);
|
||||||
|
h.finalize().as_ref().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signature_hash_data(
|
||||||
|
tx: &TransactionData,
|
||||||
|
consensus_branch_id: u32,
|
||||||
|
hash_type: u32,
|
||||||
|
transparent_input: Option<(usize, Script, Amount)>,
|
||||||
|
) -> Vec<u8> {
|
||||||
|
let sigversion = SigHashVersion::from_tx(tx);
|
||||||
|
match sigversion {
|
||||||
|
SigHashVersion::Overwinter | SigHashVersion::Sapling => {
|
||||||
|
let hash_outputs = if (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE
|
||||||
|
&& (hash_type & SIGHASH_MASK) != SIGHASH_NONE
|
||||||
|
{
|
||||||
|
outputs_hash(tx)
|
||||||
|
} else if (hash_type & SIGHASH_MASK) == SIGHASH_SINGLE
|
||||||
|
&& transparent_input.is_some()
|
||||||
|
&& transparent_input.as_ref().unwrap().0 < tx.vout.len()
|
||||||
|
{
|
||||||
|
single_output_hash(&tx.vout[transparent_input.as_ref().unwrap().0])
|
||||||
|
} else {
|
||||||
|
vec![0; 32]
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut personal = [0; 16];
|
||||||
|
(&mut personal[..12]).copy_from_slice(ZCASH_SIGHASH_PERSONALIZATION_PREFIX);
|
||||||
|
(&mut personal[12..])
|
||||||
|
.write_u32::<LittleEndian>(consensus_branch_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut h = Blake2b::with_params(32, &[], &[], &personal);
|
||||||
|
let mut tmp = [0; 8];
|
||||||
|
|
||||||
|
update_u32!(h, tx.header(), tmp);
|
||||||
|
update_u32!(h, tx.version_group_id, tmp);
|
||||||
|
update_hash!(h, hash_type & SIGHASH_ANYONECANPAY == 0, prevout_hash(tx));
|
||||||
|
update_hash!(
|
||||||
|
h,
|
||||||
|
hash_type & SIGHASH_ANYONECANPAY == 0
|
||||||
|
&& (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE
|
||||||
|
&& (hash_type & SIGHASH_MASK) != SIGHASH_NONE,
|
||||||
|
sequence_hash(tx)
|
||||||
|
);
|
||||||
|
h.update(&hash_outputs);
|
||||||
|
update_hash!(h, !tx.joinsplits.is_empty(), joinsplits_hash(tx));
|
||||||
|
if sigversion == SigHashVersion::Sapling {
|
||||||
|
update_hash!(h, !tx.shielded_spends.is_empty(), shielded_spends_hash(tx));
|
||||||
|
update_hash!(
|
||||||
|
h,
|
||||||
|
!tx.shielded_outputs.is_empty(),
|
||||||
|
shielded_outputs_hash(tx)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
update_u32!(h, tx.lock_time, tmp);
|
||||||
|
update_u32!(h, tx.expiry_height, tmp);
|
||||||
|
if sigversion == SigHashVersion::Sapling {
|
||||||
|
update_i64!(h, tx.value_balance.0, tmp);
|
||||||
|
}
|
||||||
|
update_u32!(h, hash_type, tmp);
|
||||||
|
|
||||||
|
if let Some((n, script_code, amount)) = transparent_input {
|
||||||
|
let mut data = vec![];
|
||||||
|
tx.vin[n].prevout.write(&mut data).unwrap();
|
||||||
|
script_code.write(&mut data).unwrap();
|
||||||
|
(&mut data).write_i64::<LittleEndian>(amount.0).unwrap();
|
||||||
|
(&mut data)
|
||||||
|
.write_u32::<LittleEndian>(tx.vin[n].sequence)
|
||||||
|
.unwrap();
|
||||||
|
h.update(&data);
|
||||||
|
}
|
||||||
|
|
||||||
|
h.finalize().as_ref().to_vec()
|
||||||
|
}
|
||||||
|
SigHashVersion::Sprout => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signature_hash(
|
||||||
|
tx: &Transaction,
|
||||||
|
consensus_branch_id: u32,
|
||||||
|
hash_type: u32,
|
||||||
|
transparent_input: Option<(usize, Script, Amount)>,
|
||||||
|
) -> Vec<u8> {
|
||||||
|
signature_hash_data(tx, consensus_branch_id, hash_type, transparent_input)
|
||||||
|
}
|
||||||
5405
zcash_primitives/src/transaction/tests.rs
Normal file
5405
zcash_primitives/src/transaction/tests.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,3 +6,13 @@ authors = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bellman = { path = "../bellman" }
|
||||||
|
byteorder = "1"
|
||||||
|
ff = { path = "../ff" }
|
||||||
|
pairing = { path = "../pairing" }
|
||||||
|
rand = "0.4"
|
||||||
|
sapling-crypto = { path = "../sapling-crypto" }
|
||||||
|
|
||||||
|
[dependencies.blake2-rfc]
|
||||||
|
git = "https://github.com/gtank/blake2-rfc"
|
||||||
|
rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2017 Zcash Company
|
Copyright (c) 2017-2019 Electric Coin Company
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user