mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-01-30 07:22:15 +00:00
Squashed 'bellman/' changes from 4272cfa..2279da4
2279da4 Merge pull request #38 from debris/docs 2e57190 Remove documentation entry from Cargo.toml 346d540 bellman 0.2.0 8d79665 Merge pull request #93 from defuse/qed-it-lrz f50079f Crate docs 701cb2b Update READMEs ccf1ee9 CI: Check intra-doc links ddd390a Add READMEs to Cargo.toml files 54d3122 Add missing cs.is_satisfied() to bellman test 52bf23c Fix build warnings 581ad35 boolean: adds tests for alloc_conditionally 0403396 blake2s: adds test vectors from go-jubjub 9f24e47 Fix blake2s test data length assertion. 42d5b3b Add blake2s test vectors for varying sizes from go-jubjub b2597de pedersen_hash: removes debug prints c903fad pedersen hashes: example of size limit bug bc697c1 bellman: Fix compile errors without multicore feature a4e5df9 Upgrade to hex-literal 0.2 c063509 Migrate bellman to crossbeam 0.7 1775843 Take self directly in into_* functions 614d784 Rename into_ -> to_ where &self is used. 08664b1 Address various clippy warnings/errors in bellman bb11ef2 cargo fmt cff2e2f cargo fix --edition-idioms for bellman dc2a280 Add edition = 2018 1a2bc19 cargo fmt ad37878 cargo fix --edition for bellman e73d1a2 cargo fmt bellman dfb86fc Move generic circuit gadgets into bellman 9b3d766 Migrate to rand 0.7 055280f Migrate ff, group, pairing, and bellman to rand 0.6 533d586 Migrate bellman to rand 0.5 bfa9aaf Merge pull request #61 from rex4539/fix-typos 3dd8490 Place bellman multicore operations behind a (default) feature flag 955e679 Merge pull request #46 from str4d/ff-traits d4ddaa9 Fix typos 12f93f2 Add ff and group crates to Cargo workspace 2e35a32 Update sapling-crypto crate to use ff crate 2019e63 Update workspace after pulling in external crates git-subtree-dir: bellman git-subtree-split: 2279da422ca9d7b83e84cb85018c713976b873e5
This commit is contained in:
parent
76cd0d92bb
commit
f337eb1f5c
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
||||
target
|
||||
Cargo.lock
|
||||
|
@ -1,66 +0,0 @@
|
||||
|
||||
# /************************************************************************
|
||||
# File: .gitlab-ci.yml
|
||||
# Author: mdr0id
|
||||
# Date: 9/10/2018
|
||||
# Description: Used to setup runners/jobs for librustzcash
|
||||
# Usage: Commit source and the pipeline will trigger the according jobs.
|
||||
# For now the build and test are done in the same jobs.
|
||||
#
|
||||
# Known bugs/missing features:
|
||||
#
|
||||
# ************************************************************************/
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
- deploy
|
||||
|
||||
rust-latest:
|
||||
stage: build
|
||||
image: rust:latest
|
||||
script:
|
||||
- cargo --verbose --version
|
||||
- time cargo build --verbose
|
||||
|
||||
rust-nightly:
|
||||
stage: build
|
||||
image: rustlang/rust:nightly
|
||||
script:
|
||||
- cargo --verbose --version
|
||||
- cargo build --verbose
|
||||
allow_failure: true
|
||||
|
||||
librustzcash-test-latest:
|
||||
stage: test
|
||||
image: rust:latest
|
||||
script:
|
||||
- cargo --verbose --version
|
||||
- time cargo test --release --verbose
|
||||
|
||||
librustzcash-test-rust-nightly:
|
||||
stage: test
|
||||
image: rustlang/rust:nightly
|
||||
script:
|
||||
- cargo --verbose --version
|
||||
- cargo test --release --verbose
|
||||
allow_failure: true
|
||||
|
||||
#used to manually deploy a given release
|
||||
librustzcash-rust-rc:
|
||||
stage: deploy
|
||||
image: rust:latest
|
||||
script:
|
||||
- cargo --verbose --version
|
||||
- time cargo build --release --verbose
|
||||
when: manual
|
||||
|
||||
#used to manually deploy a given release
|
||||
librustzcash-rust-nightly-rc:
|
||||
stage: deploy
|
||||
image: rustlang/rust:nightly
|
||||
script:
|
||||
- cargo --verbose --version
|
||||
- cargo build --release --verbose
|
||||
allow_failure: true
|
||||
when: manual
|
@ -1,8 +0,0 @@
|
||||
language: rust
|
||||
rust:
|
||||
- 1.31.0
|
||||
|
||||
cache: cargo
|
||||
|
||||
script:
|
||||
- cargo test --verbose --release --all
|
521
Cargo.lock
generated
521
Cargo.lock
generated
@ -1,521 +0,0 @@
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes-soft"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aesni"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"opaque-debug 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 = "arrayvec"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bellman"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ff 0.4.0 (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)",
|
||||
"group 0.1.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",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "blake2-rfc"
|
||||
version = "0.2.18"
|
||||
source = "git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9#7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.2.2 (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-cipher-trait"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ff"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ff_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ff_derive"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "fpe"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "futures-cpupool"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "group"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ff 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex-literal"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hex-literal-impl 0.1.1 (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 = "hex-literal-impl"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "librustzcash"
|
||||
version = "0.1.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)",
|
||||
"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)",
|
||||
"pairing 0.14.2",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sapling-crypto 0.0.1",
|
||||
"zcash_proofs 0.0.0",
|
||||
"zip32 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodrop"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"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)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.8.0"
|
||||
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]]
|
||||
name = "opaque-debug"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "pairing"
|
||||
version = "0.14.2"
|
||||
dependencies = [
|
||||
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ff 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"group 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack-impl"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.8"
|
||||
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)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rust-crypto"
|
||||
version = "0.2.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.24 (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-serialize"
|
||||
version = "0.3.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "sapling-crypto"
|
||||
version = "0.0.1"
|
||||
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)",
|
||||
"digest 0.7.2 (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",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stream-cipher"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.14.9"
|
||||
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)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "zcash_primitives"
|
||||
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)",
|
||||
"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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_proofs"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bellman 0.1.0",
|
||||
"byteorder 1.2.2 (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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_wallet"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "zip32"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"byteorder 1.2.2 (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",
|
||||
"sapling-crypto 0.0.1",
|
||||
]
|
||||
|
||||
[metadata]
|
||||
"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 aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6810b7fb9f2bb4f76f05ac1c170b8dde285b6308955dc3afd89710268c958d9e"
|
||||
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
|
||||
"checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f"
|
||||
"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 block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "370424437b9459f3dfd68428ed9376ddfe03d8b70ede29cc533b3557df186ab4"
|
||||
"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
|
||||
"checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87"
|
||||
"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 digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603"
|
||||
"checksum ff 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eec81e2e423086589b224dbcfbab70e3732913de25479d05165b20d4aaed05f4"
|
||||
"checksum ff_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70335090ee115d5716416ca38980cce7752f40923f41d22cf5a69a6269f9e2a2"
|
||||
"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-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-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 generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
|
||||
"checksum group 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5fa874cb11ddaf7cf45b511138f24169985d61d8760779426016230d11101d1a"
|
||||
"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 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 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-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_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 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-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b331c6ad3411474cd55540398dc7ad89fc41488e64ec71fdecc9c9b86de96fb0"
|
||||
"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.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 rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
|
||||
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
|
||||
"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 time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
|
||||
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"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-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
56
Cargo.toml
56
Cargo.toml
@ -1,16 +1,42 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"bellman",
|
||||
"librustzcash",
|
||||
"pairing",
|
||||
"sapling-crypto",
|
||||
"zcash_primitives",
|
||||
"zcash_proofs",
|
||||
"zcash_wallet",
|
||||
"zip32",
|
||||
]
|
||||
[package]
|
||||
authors = ["Sean Bowe <ewillbefull@gmail.com>"]
|
||||
description = "zk-SNARK library"
|
||||
readme = "README.md"
|
||||
homepage = "https://github.com/ebfull/bellman"
|
||||
license = "MIT/Apache-2.0"
|
||||
name = "bellman"
|
||||
repository = "https://github.com/ebfull/bellman"
|
||||
version = "0.2.0"
|
||||
edition = "2018"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
panic = 'abort'
|
||||
codegen-units = 1
|
||||
[dependencies]
|
||||
bit-vec = "0.4.4"
|
||||
blake2s_simd = "0.5"
|
||||
ff = { version = "0.5.0", path = "../ff" }
|
||||
futures = "0.1"
|
||||
futures-cpupool = { version = "0.1", optional = true }
|
||||
group = { version = "0.2.0", path = "../group" }
|
||||
num_cpus = { version = "1", optional = true }
|
||||
crossbeam = { version = "0.7", optional = true }
|
||||
pairing = { version = "0.15.0", path = "../pairing", optional = true }
|
||||
rand_core = "0.5"
|
||||
byteorder = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
hex-literal = "0.2"
|
||||
rand = "0.7"
|
||||
rand_xorshift = "0.2"
|
||||
sha2 = "0.8"
|
||||
|
||||
[features]
|
||||
groth16 = ["pairing"]
|
||||
multicore = ["futures-cpupool", "crossbeam", "num_cpus"]
|
||||
default = ["groth16", "multicore"]
|
||||
|
||||
[[test]]
|
||||
name = "mimc"
|
||||
path = "tests/mimc.rs"
|
||||
required-features = ["groth16"]
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "actively-developed" }
|
||||
|
@ -199,4 +199,3 @@ 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.
|
||||
|
||||
|
40
LICENSE-MIT
40
LICENSE-MIT
@ -1,21 +1,23 @@
|
||||
The MIT License (MIT)
|
||||
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:
|
||||
|
||||
Copyright (c) 2017 Zcash Company
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
20
README.md
20
README.md
@ -1,17 +1,23 @@
|
||||
# Zcash Rust crates
|
||||
# bellman [![Crates.io](https://img.shields.io/crates/v/bellman.svg)](https://crates.io/crates/bellman) #
|
||||
|
||||
This repository contains a (work-in-progress) set of Rust crates for
|
||||
working with Zcash.
|
||||
`bellman` is a crate for building zk-SNARK circuits. It provides circuit traits
|
||||
and primitive structures, as well as basic gadget implementations such as
|
||||
booleans and number abstractions.
|
||||
|
||||
## Security Warnings
|
||||
## Roadmap
|
||||
|
||||
These libraries are currently under development and have not been fully-reviewed.
|
||||
`bellman` is being refactored into a generic proving library. Currently it is
|
||||
pairing-specific, and different types of proving systems need to be implemented
|
||||
as sub-modules. After the refactor, `bellman` will be generic using the `ff` and
|
||||
`group` crates, while specific proving systems will be separate crates that pull
|
||||
in the dependencies they require.
|
||||
|
||||
## License
|
||||
|
||||
All code in this workspace is licensed under either of
|
||||
Licensed under either of
|
||||
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* 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.
|
||||
|
2
bellman/.gitignore
vendored
2
bellman/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
target
|
||||
Cargo.lock
|
@ -1,30 +0,0 @@
|
||||
[package]
|
||||
authors = ["Sean Bowe <ewillbefull@gmail.com>"]
|
||||
description = "zk-SNARK library"
|
||||
documentation = "https://github.com/ebfull/bellman"
|
||||
homepage = "https://github.com/ebfull/bellman"
|
||||
license = "MIT/Apache-2.0"
|
||||
name = "bellman"
|
||||
repository = "https://github.com/ebfull/bellman"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.4"
|
||||
bit-vec = "0.4.4"
|
||||
ff = "0.4"
|
||||
futures = "0.1"
|
||||
futures-cpupool = "0.1"
|
||||
group = "0.1"
|
||||
num_cpus = "1"
|
||||
crossbeam = "0.3"
|
||||
pairing = { path = "../pairing", optional = true }
|
||||
byteorder = "1"
|
||||
|
||||
[features]
|
||||
groth16 = ["pairing"]
|
||||
default = ["groth16"]
|
||||
|
||||
[[test]]
|
||||
name = "mimc"
|
||||
path = "tests/mimc.rs"
|
||||
required-features = ["groth16"]
|
@ -1,201 +0,0 @@
|
||||
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.
|
@ -1,23 +0,0 @@
|
||||
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.
|
@ -1,19 +0,0 @@
|
||||
# bellman [![Crates.io](https://img.shields.io/crates/v/bellman.svg)](https://crates.io/crates/bellman) #
|
||||
|
||||
This is a research project being built for [Zcash](https://z.cash/).
|
||||
|
||||
## 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.
|
@ -1,106 +0,0 @@
|
||||
//! This is an interface for dealing with the kinds of
|
||||
//! parallel computations involved in bellman. It's
|
||||
//! currently just a thin wrapper around CpuPool and
|
||||
//! crossbeam but may be extended in the future to
|
||||
//! allow for various parallelism strategies.
|
||||
|
||||
use num_cpus;
|
||||
use futures::{Future, IntoFuture, Poll};
|
||||
use futures_cpupool::{CpuPool, CpuFuture};
|
||||
use crossbeam::{self, Scope};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Worker {
|
||||
cpus: usize,
|
||||
pool: CpuPool
|
||||
}
|
||||
|
||||
impl Worker {
|
||||
// We don't expose this outside the library so that
|
||||
// all `Worker` instances have the same number of
|
||||
// CPUs configured.
|
||||
pub(crate) fn new_with_cpus(cpus: usize) -> Worker {
|
||||
Worker {
|
||||
cpus: cpus,
|
||||
pool: CpuPool::new(cpus)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new() -> Worker {
|
||||
Self::new_with_cpus(num_cpus::get())
|
||||
}
|
||||
|
||||
pub fn log_num_cpus(&self) -> u32 {
|
||||
log2_floor(self.cpus)
|
||||
}
|
||||
|
||||
pub fn compute<F, R>(
|
||||
&self, f: F
|
||||
) -> WorkerFuture<R::Item, R::Error>
|
||||
where F: FnOnce() -> R + Send + 'static,
|
||||
R: IntoFuture + 'static,
|
||||
R::Future: Send + 'static,
|
||||
R::Item: Send + 'static,
|
||||
R::Error: Send + 'static
|
||||
{
|
||||
WorkerFuture {
|
||||
future: self.pool.spawn_fn(f)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scope<'a, F, R>(
|
||||
&self,
|
||||
elements: usize,
|
||||
f: F
|
||||
) -> R
|
||||
where F: FnOnce(&Scope<'a>, usize) -> R
|
||||
{
|
||||
let chunk_size = if elements < self.cpus {
|
||||
1
|
||||
} else {
|
||||
elements / self.cpus
|
||||
};
|
||||
|
||||
crossbeam::scope(|scope| {
|
||||
f(scope, chunk_size)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WorkerFuture<T, E> {
|
||||
future: CpuFuture<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()
|
||||
}
|
||||
}
|
||||
|
||||
fn log2_floor(num: usize) -> u32 {
|
||||
assert!(num > 0);
|
||||
|
||||
let mut pow = 0;
|
||||
|
||||
while (1 << (pow+1)) <= num {
|
||||
pow += 1;
|
||||
}
|
||||
|
||||
pow
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_log2_floor() {
|
||||
assert_eq!(log2_floor(1), 0);
|
||||
assert_eq!(log2_floor(2), 1);
|
||||
assert_eq!(log2_floor(3), 1);
|
||||
assert_eq!(log2_floor(4), 2);
|
||||
assert_eq!(log2_floor(5), 2);
|
||||
assert_eq!(log2_floor(6), 2);
|
||||
assert_eq!(log2_floor(7), 2);
|
||||
assert_eq!(log2_floor(8), 3);
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
[package]
|
||||
name = "librustzcash"
|
||||
version = "0.1.0"
|
||||
authors = [
|
||||
"Sean Bowe <ewillbefull@gmail.com>",
|
||||
"Jack Grigg <jack@z.cash>",
|
||||
"Jay Graber <jay@z.cash>",
|
||||
"Simon Liu <simon@z.cash>"
|
||||
]
|
||||
|
||||
[lib]
|
||||
name = "rustzcash"
|
||||
path = "src/rustzcash.rs"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
bellman = { path = "../bellman" }
|
||||
libc = "0.2"
|
||||
pairing = { path = "../pairing" }
|
||||
lazy_static = "1"
|
||||
byteorder = "1"
|
||||
rand = "0.4"
|
||||
sapling-crypto = { path = "../sapling-crypto" }
|
||||
zcash_proofs = { path = "../zcash_proofs" }
|
||||
zip32 = { path = "../zip32" }
|
||||
|
||||
[dependencies.blake2-rfc]
|
||||
git = "https://github.com/gtank/blake2-rfc"
|
||||
rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
|
@ -1,20 +0,0 @@
|
||||
# librustzcash
|
||||
|
||||
This repository contains librustzcash, a static library for Zcash code assets written in Rust.
|
||||
|
||||
## 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.
|
||||
|
@ -1,313 +0,0 @@
|
||||
#ifndef LIBRUSTZCASH_INCLUDE_H_
|
||||
#define LIBRUSTZCASH_INCLUDE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
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_ask_to_ak(const unsigned char *ask, unsigned char *result);
|
||||
|
||||
void librustzcash_nsk_to_nk(const unsigned char *nsk, unsigned char *result);
|
||||
|
||||
void librustzcash_crh_ivk(const unsigned char *ak, const unsigned char *nk, unsigned char *result);
|
||||
|
||||
bool librustzcash_check_diversifier(const unsigned char *diversifier);
|
||||
|
||||
bool librustzcash_ivk_to_pkd(const unsigned char *ivk, const unsigned char *diversifier, unsigned char *result);
|
||||
|
||||
/// Loads the zk-SNARK parameters into memory and saves
|
||||
/// paths as necessary. Only called once.
|
||||
void librustzcash_init_zksnark_params(
|
||||
const codeunit* spend_path,
|
||||
size_t spend_path_len,
|
||||
const char* spend_hash,
|
||||
const codeunit* output_path,
|
||||
size_t output_path_len,
|
||||
const char* output_hash,
|
||||
const codeunit* sprout_path,
|
||||
size_t sprout_path_len,
|
||||
const char* sprout_hash
|
||||
);
|
||||
|
||||
/// Validates the provided Equihash solution against
|
||||
/// the given parameters, input and nonce.
|
||||
bool librustzcash_eh_isvalid(
|
||||
uint32_t n,
|
||||
uint32_t k,
|
||||
const unsigned char* input,
|
||||
size_t input_len,
|
||||
const unsigned char* nonce,
|
||||
size_t nonce_len,
|
||||
const unsigned char* soln,
|
||||
size_t soln_len
|
||||
);
|
||||
|
||||
/// Writes the "uncommitted" note value for empty leaves
|
||||
/// of the merkle tree. `result` must be a valid pointer
|
||||
/// to 32 bytes which will be written.
|
||||
void librustzcash_tree_uncommitted(
|
||||
unsigned char *result
|
||||
);
|
||||
|
||||
/// Computes a merkle tree hash for a given depth.
|
||||
/// The `depth` parameter should not be larger than
|
||||
/// 62.
|
||||
///
|
||||
/// `a` and `b` each must be of length 32, and must each
|
||||
/// be scalars of BLS12-381.
|
||||
///
|
||||
/// The result of the merkle tree hash is placed in
|
||||
/// `result`, which must also be of length 32.
|
||||
void librustzcash_merkle_hash(
|
||||
size_t depth,
|
||||
const unsigned char *a,
|
||||
const unsigned char *b,
|
||||
unsigned char *result
|
||||
);
|
||||
|
||||
/// Computes the signature for each Spend description, given the key
|
||||
/// `ask`, the re-randomization `ar`, the 32-byte sighash `sighash`,
|
||||
/// and an output `result` buffer of 64-bytes for the signature.
|
||||
///
|
||||
/// This function will fail if the provided `ask` or `ar` are invalid.
|
||||
bool librustzcash_sapling_spend_sig(
|
||||
const unsigned char *ask,
|
||||
const unsigned char *ar,
|
||||
const unsigned char *sighash,
|
||||
unsigned char *result
|
||||
);
|
||||
|
||||
/// Creates a Sapling proving context. Please free this when you're done.
|
||||
void * librustzcash_sapling_proving_ctx_init();
|
||||
|
||||
/// This function (using the proving context) constructs a Spend proof
|
||||
/// given the necessary witness information. It outputs `cv` (the value
|
||||
/// commitment) and `rk` (so that you don't have to compute it) along
|
||||
/// with the proof.
|
||||
bool librustzcash_sapling_spend_proof(
|
||||
void *ctx,
|
||||
const unsigned char *ak,
|
||||
const unsigned char *nsk,
|
||||
const unsigned char *diversifier,
|
||||
const unsigned char *rcm,
|
||||
const unsigned char *ar,
|
||||
const uint64_t value,
|
||||
const unsigned char *anchor,
|
||||
const unsigned char *witness,
|
||||
unsigned char *cv,
|
||||
unsigned char *rk,
|
||||
unsigned char *zkproof
|
||||
);
|
||||
|
||||
/// This function (using the proving context) constructs an Output
|
||||
/// proof given the necessary witness information. It outputs `cv`
|
||||
/// and the `zkproof`.
|
||||
bool librustzcash_sapling_output_proof(
|
||||
void *ctx,
|
||||
const unsigned char *esk,
|
||||
const unsigned char *diversifier,
|
||||
const unsigned char *pk_d,
|
||||
const unsigned char *rcm,
|
||||
const uint64_t value,
|
||||
unsigned char *cv,
|
||||
unsigned char *zkproof
|
||||
);
|
||||
|
||||
/// This function (using the proving context) constructs a binding
|
||||
/// signature. You must provide the intended valueBalance so that
|
||||
/// we can internally check consistency.
|
||||
bool librustzcash_sapling_binding_sig(
|
||||
const void *ctx,
|
||||
int64_t valueBalance,
|
||||
const unsigned char *sighash,
|
||||
unsigned char *result
|
||||
);
|
||||
|
||||
/// Frees a Sapling proving context returned from
|
||||
/// `librustzcash_sapling_proving_ctx_init`.
|
||||
void librustzcash_sapling_proving_ctx_free(void *);
|
||||
|
||||
/// Creates a Sapling verification context. Please free this
|
||||
/// when you're done.
|
||||
void * librustzcash_sapling_verification_ctx_init();
|
||||
|
||||
/// Check the validity of a Sapling Spend description,
|
||||
/// accumulating the value commitment into the context.
|
||||
bool librustzcash_sapling_check_spend(
|
||||
void *ctx,
|
||||
const unsigned char *cv,
|
||||
const unsigned char *anchor,
|
||||
const unsigned char *nullifier,
|
||||
const unsigned char *rk,
|
||||
const unsigned char *zkproof,
|
||||
const unsigned char *spendAuthSig,
|
||||
const unsigned char *sighashValue
|
||||
);
|
||||
|
||||
/// Check the validity of a Sapling Output description,
|
||||
/// accumulating the value commitment into the context.
|
||||
bool librustzcash_sapling_check_output(
|
||||
void *ctx,
|
||||
const unsigned char *cv,
|
||||
const unsigned char *cm,
|
||||
const unsigned char *ephemeralKey,
|
||||
const unsigned char *zkproof
|
||||
);
|
||||
|
||||
/// Finally checks the validity of the entire Sapling
|
||||
/// transaction given valueBalance and the binding signature.
|
||||
bool librustzcash_sapling_final_check(
|
||||
void *ctx,
|
||||
int64_t valueBalance,
|
||||
const unsigned char *bindingSig,
|
||||
const unsigned char *sighashValue
|
||||
);
|
||||
|
||||
/// Frees a Sapling verification context returned from
|
||||
/// `librustzcash_sapling_verification_ctx_init`.
|
||||
void librustzcash_sapling_verification_ctx_free(void *);
|
||||
|
||||
/// Compute a Sapling nullifier.
|
||||
///
|
||||
/// The `diversifier` parameter must be 11 bytes in length.
|
||||
/// The `pk_d`, `r`, `ak` and `nk` parameters must be of length 32.
|
||||
/// The result is also of length 32 and placed in `result`.
|
||||
/// Returns false if the diversifier or pk_d is not valid
|
||||
bool librustzcash_sapling_compute_nf(
|
||||
const unsigned char *diversifier,
|
||||
const unsigned char *pk_d,
|
||||
const uint64_t value,
|
||||
const unsigned char *r,
|
||||
const unsigned char *ak,
|
||||
const unsigned char *nk,
|
||||
const uint64_t position,
|
||||
unsigned char *result
|
||||
);
|
||||
|
||||
/// Compute a Sapling commitment.
|
||||
///
|
||||
/// The `diversifier` parameter must be 11 bytes in length.
|
||||
/// The `pk_d` and `r` parameters must be of length 32.
|
||||
/// The result is also of length 32 and placed in `result`.
|
||||
/// Returns false if the diversifier or pk_d is not valid
|
||||
bool librustzcash_sapling_compute_cm(
|
||||
const unsigned char *diversifier,
|
||||
const unsigned char *pk_d,
|
||||
const uint64_t value,
|
||||
const unsigned char *r,
|
||||
unsigned char *result
|
||||
);
|
||||
|
||||
/// Compute [sk] [8] P for some 32-byte
|
||||
/// point P, and 32-byte Fs. If P or sk
|
||||
/// are invalid, returns false. Otherwise,
|
||||
/// the result is written to the 32-byte
|
||||
/// `result` buffer.
|
||||
bool librustzcash_sapling_ka_agree(
|
||||
const unsigned char *p,
|
||||
const unsigned char *sk,
|
||||
unsigned char *result
|
||||
);
|
||||
|
||||
/// Compute g_d = GH(diversifier) and returns
|
||||
/// false if the diversifier is invalid.
|
||||
/// Computes [esk] g_d and writes the result
|
||||
/// to the 32-byte `result` buffer. Returns
|
||||
/// false if `esk` is not a valid scalar.
|
||||
bool librustzcash_sapling_ka_derivepublic(
|
||||
const unsigned char *diversifier,
|
||||
const unsigned char *esk,
|
||||
unsigned char *result
|
||||
);
|
||||
|
||||
/// Generate uniformly random scalar in Jubjub.
|
||||
/// The result is of length 32.
|
||||
void librustzcash_sapling_generate_r(
|
||||
unsigned char *result
|
||||
);
|
||||
|
||||
/// Sprout JoinSplit proof generation.
|
||||
void librustzcash_sprout_prove(
|
||||
unsigned char *proof_out,
|
||||
|
||||
const unsigned char *phi,
|
||||
const unsigned char *rt,
|
||||
const unsigned char *h_sig,
|
||||
|
||||
const unsigned char *in_sk1,
|
||||
uint64_t in_value1,
|
||||
const unsigned char *in_rho1,
|
||||
const unsigned char *in_r1,
|
||||
const unsigned char *in_auth1,
|
||||
|
||||
const unsigned char *in_sk2,
|
||||
uint64_t in_value2,
|
||||
const unsigned char *in_rho2,
|
||||
const unsigned char *in_r2,
|
||||
const unsigned char *in_auth2,
|
||||
|
||||
const unsigned char *out_pk1,
|
||||
uint64_t out_value1,
|
||||
const unsigned char *out_r1,
|
||||
|
||||
const unsigned char *out_pk2,
|
||||
uint64_t out_value2,
|
||||
const unsigned char *out_r2,
|
||||
|
||||
uint64_t vpub_old,
|
||||
uint64_t vpub_new
|
||||
);
|
||||
|
||||
/// Sprout JoinSplit proof verification.
|
||||
bool librustzcash_sprout_verify(
|
||||
const unsigned char *proof,
|
||||
const unsigned char *rt,
|
||||
const unsigned char *h_sig,
|
||||
const unsigned char *mac1,
|
||||
const unsigned char *mac2,
|
||||
const unsigned char *nf1,
|
||||
const unsigned char *nf2,
|
||||
const unsigned char *cm1,
|
||||
const unsigned char *cm2,
|
||||
uint64_t vpub_old,
|
||||
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_
|
@ -1,467 +0,0 @@
|
||||
use blake2_rfc::blake2b::{Blake2b, Blake2bResult};
|
||||
use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use std::io::Cursor;
|
||||
use std::mem::size_of;
|
||||
|
||||
struct Params {
|
||||
n: u32,
|
||||
k: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Node {
|
||||
hash: Vec<u8>,
|
||||
indices: Vec<u32>,
|
||||
}
|
||||
|
||||
impl Params {
|
||||
fn indices_per_hash_output(&self) -> u32 {
|
||||
512 / self.n
|
||||
}
|
||||
fn hash_output(&self) -> u8 {
|
||||
(self.indices_per_hash_output() * self.n / 8) as u8
|
||||
}
|
||||
fn collision_bit_length(&self) -> usize {
|
||||
(self.n / (self.k + 1)) as usize
|
||||
}
|
||||
fn collision_byte_length(&self) -> usize {
|
||||
(self.collision_bit_length() + 7) / 8
|
||||
}
|
||||
fn hash_length(&self) -> usize {
|
||||
((self.k as usize) + 1) * self.collision_byte_length()
|
||||
}
|
||||
}
|
||||
|
||||
impl Node {
|
||||
fn new(p: &Params, state: &Blake2b, i: u32) -> Self {
|
||||
let hash = generate_hash(state, i / p.indices_per_hash_output());
|
||||
let start = ((i % p.indices_per_hash_output()) * p.n / 8) as usize;
|
||||
let end = start + (p.n as usize) / 8;
|
||||
Node {
|
||||
hash: expand_array(&hash.as_bytes()[start..end], p.collision_bit_length(), 0),
|
||||
indices: vec![i],
|
||||
}
|
||||
}
|
||||
|
||||
fn from_children(a: Node, b: Node, trim: usize) -> Self {
|
||||
let hash: Vec<_> = a
|
||||
.hash
|
||||
.iter()
|
||||
.zip(b.hash.iter())
|
||||
.skip(trim)
|
||||
.map(|(a, b)| a ^ b)
|
||||
.collect();
|
||||
let indices = if a.indices_before(&b) {
|
||||
let mut indices = a.indices;
|
||||
indices.extend(b.indices.iter());
|
||||
indices
|
||||
} else {
|
||||
let mut indices = b.indices;
|
||||
indices.extend(a.indices.iter());
|
||||
indices
|
||||
};
|
||||
Node {
|
||||
hash: hash,
|
||||
indices: indices,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_children_ref(a: &Node, b: &Node, trim: usize) -> Self {
|
||||
let hash: Vec<_> = a
|
||||
.hash
|
||||
.iter()
|
||||
.zip(b.hash.iter())
|
||||
.skip(trim)
|
||||
.map(|(a, b)| a ^ b)
|
||||
.collect();
|
||||
let mut indices = Vec::with_capacity(a.indices.len() + b.indices.len());
|
||||
if a.indices_before(b) {
|
||||
indices.extend(a.indices.iter());
|
||||
indices.extend(b.indices.iter());
|
||||
} else {
|
||||
indices.extend(b.indices.iter());
|
||||
indices.extend(a.indices.iter());
|
||||
}
|
||||
Node {
|
||||
hash: hash,
|
||||
indices: indices,
|
||||
}
|
||||
}
|
||||
|
||||
fn indices_before(&self, other: &Node) -> bool {
|
||||
// Indices are serialized in big-endian so that integer
|
||||
// comparison is equivalent to array comparison
|
||||
self.indices[0] < other.indices[0]
|
||||
}
|
||||
|
||||
fn is_zero(&self, len: usize) -> bool {
|
||||
self.hash.iter().take(len).all(|v| *v == 0)
|
||||
}
|
||||
}
|
||||
|
||||
fn initialise_state(n: u32, k: u32, digest_len: u8) -> Blake2b {
|
||||
let mut personalization: Vec<u8> = Vec::from("ZcashPoW");
|
||||
personalization.write_u32::<LittleEndian>(n).unwrap();
|
||||
personalization.write_u32::<LittleEndian>(k).unwrap();
|
||||
|
||||
Blake2b::with_params(digest_len as usize, &[], &[], &personalization)
|
||||
}
|
||||
|
||||
fn generate_hash(base_state: &Blake2b, i: u32) -> Blake2bResult {
|
||||
let mut lei = [0u8; 4];
|
||||
(&mut lei[..]).write_u32::<LittleEndian>(i).unwrap();
|
||||
|
||||
let mut state = base_state.clone();
|
||||
state.update(&lei);
|
||||
state.finalize()
|
||||
}
|
||||
|
||||
fn expand_array(vin: &[u8], bit_len: usize, byte_pad: usize) -> Vec<u8> {
|
||||
assert!(bit_len >= 8);
|
||||
assert!(8 * size_of::<u32>() >= 7 + bit_len);
|
||||
|
||||
let out_width = (bit_len + 7) / 8 + byte_pad;
|
||||
let out_len = 8 * out_width * vin.len() / bit_len;
|
||||
|
||||
// Shortcut for parameters where expansion is a no-op
|
||||
if out_len == vin.len() {
|
||||
return vin.to_vec();
|
||||
}
|
||||
|
||||
let mut vout: Vec<u8> = vec![0; out_len];
|
||||
let bit_len_mask: u32 = (1 << bit_len) - 1;
|
||||
|
||||
// The acc_bits least-significant bits of acc_value represent a bit sequence
|
||||
// in big-endian order.
|
||||
let mut acc_bits = 0;
|
||||
let mut acc_value: u32 = 0;
|
||||
|
||||
let mut j = 0;
|
||||
for b in vin {
|
||||
acc_value = (acc_value << 8) | *b as u32;
|
||||
acc_bits += 8;
|
||||
|
||||
// When we have bit_len or more bits in the accumulator, write the next
|
||||
// output element.
|
||||
if acc_bits >= bit_len {
|
||||
acc_bits -= bit_len;
|
||||
for x in byte_pad..out_width {
|
||||
vout[j + x] = ((
|
||||
// Big-endian
|
||||
acc_value >> (acc_bits + (8 * (out_width - x - 1)))
|
||||
) & (
|
||||
// Apply bit_len_mask across byte boundaries
|
||||
(bit_len_mask >> (8 * (out_width - x - 1))) & 0xFF
|
||||
)) as u8;
|
||||
}
|
||||
j += out_width;
|
||||
}
|
||||
}
|
||||
|
||||
vout
|
||||
}
|
||||
|
||||
fn indices_from_minimal(minimal: &[u8], c_bit_len: usize) -> Vec<u32> {
|
||||
assert!(((c_bit_len + 1) + 7) / 8 <= size_of::<u32>());
|
||||
let len_indices = 8 * size_of::<u32>() * minimal.len() / (c_bit_len + 1);
|
||||
let byte_pad = size_of::<u32>() - ((c_bit_len + 1) + 7) / 8;
|
||||
|
||||
let mut csr = Cursor::new(expand_array(minimal, c_bit_len + 1, byte_pad));
|
||||
let mut ret = Vec::with_capacity(len_indices);
|
||||
|
||||
// Big-endian so that lexicographic array comparison is equivalent to integer
|
||||
// comparison
|
||||
while let Ok(i) = csr.read_u32::<BigEndian>() {
|
||||
ret.push(i);
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
fn has_collision(a: &Node, b: &Node, len: usize) -> bool {
|
||||
a.hash
|
||||
.iter()
|
||||
.zip(b.hash.iter())
|
||||
.take(len)
|
||||
.all(|(a, b)| a == b)
|
||||
}
|
||||
|
||||
fn distinct_indices(a: &Node, b: &Node) -> bool {
|
||||
for i in &(a.indices) {
|
||||
for j in &(b.indices) {
|
||||
if i == j {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn validate_subtrees(p: &Params, a: &Node, b: &Node) -> bool {
|
||||
if !has_collision(a, b, p.collision_byte_length()) {
|
||||
// error!("Invalid solution: invalid collision length between StepRows");
|
||||
false
|
||||
} else if b.indices_before(a) {
|
||||
// error!("Invalid solution: Index tree incorrectly ordered");
|
||||
false
|
||||
} else if !distinct_indices(a, b) {
|
||||
// error!("Invalid solution: duplicate indices");
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_valid_solution_iterative(
|
||||
n: u32,
|
||||
k: u32,
|
||||
input: &[u8],
|
||||
nonce: &[u8],
|
||||
indices: &[u32],
|
||||
) -> bool {
|
||||
let p = Params { n: n, k: k };
|
||||
|
||||
let mut state = initialise_state(p.n, p.k, p.hash_output());
|
||||
state.update(input);
|
||||
state.update(nonce);
|
||||
|
||||
let mut rows = Vec::new();
|
||||
for i in indices {
|
||||
rows.push(Node::new(&p, &state, *i));
|
||||
}
|
||||
|
||||
let mut hash_len = p.hash_length();
|
||||
while rows.len() > 1 {
|
||||
let mut cur_rows = Vec::new();
|
||||
for pair in rows.chunks(2) {
|
||||
let a = &pair[0];
|
||||
let b = &pair[1];
|
||||
if !validate_subtrees(&p, a, b) {
|
||||
return false;
|
||||
}
|
||||
cur_rows.push(Node::from_children_ref(a, b, p.collision_byte_length()));
|
||||
}
|
||||
rows = cur_rows;
|
||||
hash_len -= p.collision_byte_length();
|
||||
}
|
||||
|
||||
assert!(rows.len() == 1);
|
||||
return rows[0].is_zero(hash_len);
|
||||
}
|
||||
|
||||
fn tree_validator(p: &Params, state: &Blake2b, indices: &[u32]) -> Option<Node> {
|
||||
if indices.len() > 1 {
|
||||
let end = indices.len();
|
||||
let mid = end / 2;
|
||||
match tree_validator(p, state, &indices[0..mid]) {
|
||||
Some(a) => match tree_validator(p, state, &indices[mid..end]) {
|
||||
Some(b) => {
|
||||
if validate_subtrees(p, &a, &b) {
|
||||
Some(Node::from_children(a, b, p.collision_byte_length()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
},
|
||||
None => None,
|
||||
}
|
||||
} else {
|
||||
Some(Node::new(&p, &state, indices[0]))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_valid_solution_recursive(
|
||||
n: u32,
|
||||
k: u32,
|
||||
input: &[u8],
|
||||
nonce: &[u8],
|
||||
indices: &[u32],
|
||||
) -> bool {
|
||||
let p = Params { n: n, k: k };
|
||||
|
||||
let mut state = initialise_state(p.n, p.k, p.hash_output());
|
||||
state.update(input);
|
||||
state.update(nonce);
|
||||
|
||||
match tree_validator(&p, &state, indices) {
|
||||
Some(root) => {
|
||||
// Hashes were trimmed, so only need to check remaining length
|
||||
root.is_zero(p.collision_byte_length())
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_valid_solution(n: u32, k: u32, input: &[u8], nonce: &[u8], soln: &[u8]) -> bool {
|
||||
let p = Params { n: n, k: k };
|
||||
let indices = indices_from_minimal(soln, p.collision_bit_length());
|
||||
|
||||
// Recursive validation is faster
|
||||
is_valid_solution_recursive(n, k, input, nonce, &indices)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::is_valid_solution_iterative;
|
||||
use super::is_valid_solution_recursive;
|
||||
|
||||
fn is_valid_solution(n: u32, k: u32, input: &[u8], nonce: &[u8], indices: &[u32]) -> bool {
|
||||
let a = is_valid_solution_iterative(n, k, input, nonce, indices);
|
||||
let b = is_valid_solution_recursive(n, k, input, nonce, indices);
|
||||
assert!(a == b);
|
||||
a
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn equihash_test_cases() {
|
||||
let input = b"block header";
|
||||
let mut nonce = [0 as u8; 32];
|
||||
let mut indices = vec![
|
||||
976, 126621, 100174, 123328, 38477, 105390, 38834, 90500, 6411, 116489, 51107, 129167,
|
||||
25557, 92292, 38525, 56514, 1110, 98024, 15426, 74455, 3185, 84007, 24328, 36473,
|
||||
17427, 129451, 27556, 119967, 31704, 62448, 110460, 117894,
|
||||
];
|
||||
assert!(is_valid_solution(96, 5, input, &nonce, &indices));
|
||||
|
||||
indices = vec![
|
||||
1008, 18280, 34711, 57439, 3903, 104059, 81195, 95931, 58336, 118687, 67931, 123026,
|
||||
64235, 95595, 84355, 122946, 8131, 88988, 45130, 58986, 59899, 78278, 94769, 118158,
|
||||
25569, 106598, 44224, 96285, 54009, 67246, 85039, 127667,
|
||||
];
|
||||
assert!(is_valid_solution(96, 5, input, &nonce, &indices));
|
||||
|
||||
indices = vec![
|
||||
4313, 223176, 448870, 1692641, 214911, 551567, 1696002, 1768726, 500589, 938660,
|
||||
724628, 1319625, 632093, 1474613, 665376, 1222606, 244013, 528281, 1741992, 1779660,
|
||||
313314, 996273, 435612, 1270863, 337273, 1385279, 1031587, 1147423, 349396, 734528,
|
||||
902268, 1678799, 10902, 1231236, 1454381, 1873452, 120530, 2034017, 948243, 1160178,
|
||||
198008, 1704079, 1087419, 1734550, 457535, 698704, 649903, 1029510, 75564, 1860165,
|
||||
1057819, 1609847, 449808, 527480, 1106201, 1252890, 207200, 390061, 1557573, 1711408,
|
||||
396772, 1026145, 652307, 1712346, 10680, 1027631, 232412, 974380, 457702, 1827006,
|
||||
1316524, 1400456, 91745, 2032682, 192412, 710106, 556298, 1963798, 1329079, 1504143,
|
||||
102455, 974420, 639216, 1647860, 223846, 529637, 425255, 680712, 154734, 541808,
|
||||
443572, 798134, 322981, 1728849, 1306504, 1696726, 57884, 913814, 607595, 1882692,
|
||||
236616, 1439683, 420968, 943170, 1014827, 1446980, 1468636, 1559477, 1203395, 1760681,
|
||||
1439278, 1628494, 195166, 198686, 349906, 1208465, 917335, 1361918, 937682, 1885495,
|
||||
494922, 1745948, 1320024, 1826734, 847745, 894084, 1484918, 1523367, 7981, 1450024,
|
||||
861459, 1250305, 226676, 329669, 339783, 1935047, 369590, 1564617, 939034, 1908111,
|
||||
1147449, 1315880, 1276715, 1428599, 168956, 1442649, 766023, 1171907, 273361, 1902110,
|
||||
1169410, 1786006, 413021, 1465354, 707998, 1134076, 977854, 1604295, 1369720, 1486036,
|
||||
330340, 1587177, 502224, 1313997, 400402, 1667228, 889478, 946451, 470672, 2019542,
|
||||
1023489, 2067426, 658974, 876859, 794443, 1667524, 440815, 1099076, 897391, 1214133,
|
||||
953386, 1932936, 1100512, 1362504, 874364, 975669, 1277680, 1412800, 1227580, 1857265,
|
||||
1312477, 1514298, 12478, 219890, 534265, 1351062, 65060, 651682, 627900, 1331192,
|
||||
123915, 865936, 1218072, 1732445, 429968, 1097946, 947293, 1323447, 157573, 1212459,
|
||||
923792, 1943189, 488881, 1697044, 915443, 2095861, 333566, 732311, 336101, 1600549,
|
||||
575434, 1978648, 1071114, 1473446, 50017, 54713, 367891, 2055483, 561571, 1714951,
|
||||
715652, 1347279, 584549, 1642138, 1002587, 1125289, 1364767, 1382627, 1387373, 2054399,
|
||||
97237, 1677265, 707752, 1265819, 121088, 1810711, 1755448, 1858538, 444653, 1130822,
|
||||
514258, 1669752, 578843, 729315, 1164894, 1691366, 15609, 1917824, 173620, 587765,
|
||||
122779, 2024998, 804857, 1619761, 110829, 1514369, 410197, 493788, 637666, 1765683,
|
||||
782619, 1186388, 494761, 1536166, 1582152, 1868968, 825150, 1709404, 1273757, 1657222,
|
||||
817285, 1955796, 1014018, 1961262, 873632, 1689675, 985486, 1008905, 130394, 897076,
|
||||
419669, 535509, 980696, 1557389, 1244581, 1738170, 197814, 1879515, 297204, 1165124,
|
||||
883018, 1677146, 1545438, 2017790, 345577, 1821269, 761785, 1014134, 746829, 751041,
|
||||
930466, 1627114, 507500, 588000, 1216514, 1501422, 991142, 1378804, 1797181, 1976685,
|
||||
60742, 780804, 383613, 645316, 770302, 952908, 1105447, 1878268, 504292, 1961414,
|
||||
693833, 1198221, 906863, 1733938, 1315563, 2049718, 230826, 2064804, 1224594, 1434135,
|
||||
897097, 1961763, 993758, 1733428, 306643, 1402222, 532661, 627295, 453009, 973231,
|
||||
1746809, 1857154, 263652, 1683026, 1082106, 1840879, 768542, 1056514, 888164, 1529401,
|
||||
327387, 1708909, 961310, 1453127, 375204, 878797, 1311831, 1969930, 451358, 1229838,
|
||||
583937, 1537472, 467427, 1305086, 812115, 1065593, 532687, 1656280, 954202, 1318066,
|
||||
1164182, 1963300, 1232462, 1722064, 17572, 923473, 1715089, 2079204, 761569, 1557392,
|
||||
1133336, 1183431, 175157, 1560762, 418801, 927810, 734183, 825783, 1844176, 1951050,
|
||||
317246, 336419, 711727, 1630506, 634967, 1595955, 683333, 1461390, 458765, 1834140,
|
||||
1114189, 1761250, 459168, 1897513, 1403594, 1478683, 29456, 1420249, 877950, 1371156,
|
||||
767300, 1848863, 1607180, 1819984, 96859, 1601334, 171532, 2068307, 980009, 2083421,
|
||||
1329455, 2030243, 69434, 1965626, 804515, 1339113, 396271, 1252075, 619032, 2080090,
|
||||
84140, 658024, 507836, 772757, 154310, 1580686, 706815, 1024831, 66704, 614858, 256342,
|
||||
957013, 1488503, 1615769, 1515550, 1888497, 245610, 1333432, 302279, 776959, 263110,
|
||||
1523487, 623933, 2013452, 68977, 122033, 680726, 1849411, 426308, 1292824, 460128,
|
||||
1613657, 234271, 971899, 1320730, 1559313, 1312540, 1837403, 1690310, 2040071, 149918,
|
||||
380012, 785058, 1675320, 267071, 1095925, 1149690, 1318422, 361557, 1376579, 1587551,
|
||||
1715060, 1224593, 1581980, 1354420, 1850496, 151947, 748306, 1987121, 2070676, 273794,
|
||||
981619, 683206, 1485056, 766481, 2047708, 930443, 2040726, 1136227, 1945705, 1722044,
|
||||
1971986,
|
||||
];
|
||||
assert!(!is_valid_solution(96, 5, input, &nonce, &indices));
|
||||
assert!(is_valid_solution(200, 9, input, &nonce, &indices));
|
||||
|
||||
nonce[0] = 1;
|
||||
assert!(!is_valid_solution(96, 5, input, &nonce, &indices));
|
||||
assert!(!is_valid_solution(200, 9, input, &nonce, &indices));
|
||||
|
||||
indices = vec![
|
||||
1911, 96020, 94086, 96830, 7895, 51522, 56142, 62444, 15441, 100732, 48983, 64776,
|
||||
27781, 85932, 101138, 114362, 4497, 14199, 36249, 41817, 23995, 93888, 35798, 96337,
|
||||
5530, 82377, 66438, 85247, 39332, 78978, 83015, 123505,
|
||||
];
|
||||
assert!(is_valid_solution(96, 5, input, &nonce, &indices));
|
||||
|
||||
indices = vec![
|
||||
1505, 1380774, 200806, 1787044, 101056, 1697952, 281464, 374899, 263712, 1532496,
|
||||
264180, 637056, 734225, 1882676, 1112004, 2093109, 193394, 1459136, 525171, 657480,
|
||||
214528, 1221365, 574444, 594726, 501919, 1309358, 1740268, 1989610, 654491, 1068055,
|
||||
919416, 1993208, 17599, 1858176, 1315176, 1901532, 108258, 109600, 1117445, 1936058,
|
||||
70247, 1036984, 628234, 1800109, 149791, 365740, 345683, 563554, 21678, 822781,
|
||||
1423722, 1644228, 792912, 1409641, 805060, 2041985, 453824, 1003179, 934427, 1068834,
|
||||
629003, 1456111, 670049, 1558594, 19016, 1343657, 1698188, 1865216, 45723, 1820952,
|
||||
1160970, 1585983, 422549, 1973097, 1296271, 2006382, 650084, 809838, 871727, 1080419,
|
||||
28500, 1471829, 384406, 619459, 212041, 1466258, 481435, 866461, 145340, 1403843,
|
||||
1339592, 1405761, 163425, 1073771, 285027, 1488210, 167744, 1182267, 1354059, 2089602,
|
||||
921700, 2059931, 1704721, 1853088, 585171, 739246, 747551, 1520527, 590255, 1175747,
|
||||
705292, 998433, 522014, 1931179, 1629531, 1692879, 588830, 1799457, 963672, 1664237,
|
||||
775408, 1926741, 907030, 1466738, 784179, 1972599, 1494787, 1598114, 1736, 1039487,
|
||||
88704, 1302687, 579526, 1476728, 1677992, 1854526, 432470, 2062305, 1471132, 1747579,
|
||||
1521894, 1917599, 1590975, 1936227, 151871, 1999775, 224664, 461809, 704084, 1306665,
|
||||
1316156, 1529628, 876811, 2086004, 1986383, 2012147, 1039505, 1637502, 1432721,
|
||||
1565477, 110385, 342650, 659137, 1285167, 367416, 2007586, 445677, 2084877, 285692,
|
||||
1144365, 988840, 1990372, 748425, 1617758, 1267712, 1510433, 152291, 1256291, 1722179,
|
||||
1995439, 864844, 1623380, 1071853, 1731862, 699978, 1407662, 1048047, 1849702, 962900,
|
||||
1083340, 1378752, 1534902, 11843, 115329, 454796, 548919, 148184, 1686936, 862432,
|
||||
873854, 60753, 999864, 385959, 1528101, 534420, 678401, 590419, 1962518, 54984,
|
||||
1141820, 243305, 1349970, 599681, 1817233, 1632537, 1698724, 580004, 673073, 1403350,
|
||||
2026104, 758881, 970056, 1717966, 2062827, 19624, 148580, 609748, 1588928, 456321,
|
||||
834920, 700532, 1682606, 20012, 441139, 1591072, 1923394, 194034, 1741063, 1156906,
|
||||
1983067, 20703, 1939972, 604581, 963600, 128170, 731716, 606773, 1626824, 139460,
|
||||
1386775, 521911, 2043473, 392180, 449532, 895678, 1453340, 7085, 598416, 1514260,
|
||||
2061068, 279532, 678363, 943255, 1405306, 119114, 2075865, 592839, 1972064, 254647,
|
||||
2078288, 946282, 1567138, 120422, 767626, 213242, 448366, 438457, 1768467, 853790,
|
||||
1509505, 735780, 1979631, 1461410, 1462050, 739008, 1572606, 920754, 1507358, 12883,
|
||||
1681167, 1308399, 1839490, 85599, 1387522, 703262, 1949514, 18523, 1236125, 669105,
|
||||
1464132, 68670, 2085647, 333393, 1731573, 21714, 637827, 985912, 2091029, 84065,
|
||||
1688993, 1574405, 1899543, 134032, 179206, 671016, 1118310, 288960, 861994, 622074,
|
||||
1738892, 10936, 343910, 598016, 1741971, 586348, 1956071, 851053, 1715626, 531385,
|
||||
1213667, 1093995, 1863757, 630365, 1851894, 1328101, 1770446, 31900, 734027, 1078651,
|
||||
1701535, 123276, 1916343, 581822, 1681706, 573135, 818091, 1454710, 2052521, 1150284,
|
||||
1451159, 1482280, 1811430, 26321, 785837, 877980, 2073103, 107324, 727248, 1785460,
|
||||
1840517, 184560, 185640, 364103, 1878753, 518459, 1984029, 964109, 1884200, 74003,
|
||||
527272, 516232, 711247, 148582, 209254, 634610, 1534140, 376714, 1573267, 421225,
|
||||
1265101, 1078858, 1374310, 1806283, 2091298, 23392, 389637, 413663, 1066737, 226164,
|
||||
762552, 1048220, 1583397, 40092, 277435, 775449, 1533894, 202582, 390703, 346741,
|
||||
1027320, 523034, 809424, 584882, 1296934, 528062, 733331, 1212771, 1958651, 653372,
|
||||
1313962, 1366332, 1784489, 1542466, 1580386, 1628948, 2000957, 57069, 1398636, 1250431,
|
||||
1698486, 57289, 596009, 582428, 966130, 167657, 1025537, 1227498, 1630134, 234060,
|
||||
1285209, 265623, 1165779, 68485, 632055, 96019, 1854676, 98410, 158575, 168035,
|
||||
1296171, 158847, 1243959, 977212, 1113647, 363568, 891940, 954593, 1987111, 90101,
|
||||
133251, 1136222, 1255117, 543075, 732768, 749576, 1174878, 422226, 1854657, 1143029,
|
||||
1457135, 927105, 1137382, 1566306, 1661926, 103057, 425126, 698089, 1774942, 911019,
|
||||
1793511, 1623559, 2002409, 457796, 1196971, 724257, 1811147, 956269, 1165590, 1137531,
|
||||
1381215, 201063, 1938529, 986021, 1297857, 921334, 1259083, 1440074, 1939366, 232907,
|
||||
747213, 1349009, 1945364, 689906, 1116453, 1904207, 1916192, 229793, 1576982, 1420059,
|
||||
1644978, 278248, 2024807, 297914, 419798, 555747, 712605, 1012424, 1428921, 890113,
|
||||
1822645, 1082368, 1392894,
|
||||
];
|
||||
assert!(!is_valid_solution(96, 5, input, &nonce, &indices));
|
||||
assert!(is_valid_solution(200, 9, input, &nonce, &indices));
|
||||
|
||||
let input2 = b"Equihash is an asymmetric PoW based on the Generalised Birthday problem.";
|
||||
indices = vec![
|
||||
2261, 15185, 36112, 104243, 23779, 118390, 118332, 130041, 32642, 69878, 76925, 80080,
|
||||
45858, 116805, 92842, 111026, 15972, 115059, 85191, 90330, 68190, 122819, 81830, 91132,
|
||||
23460, 49807, 52426, 80391, 69567, 114474, 104973, 122568,
|
||||
];
|
||||
assert!(is_valid_solution(96, 5, input2, &nonce, &indices));
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
use blake2_rfc::blake2b::Blake2b;
|
||||
use std::io::{self, Read};
|
||||
|
||||
/// Abstraction over a reader which hashes the data being read.
|
||||
pub struct HashReader<R: Read> {
|
||||
reader: R,
|
||||
hasher: Blake2b,
|
||||
}
|
||||
|
||||
impl<R: Read> HashReader<R> {
|
||||
/// Construct a new `HashReader` given an existing `reader` by value.
|
||||
pub fn new(reader: R) -> Self {
|
||||
HashReader {
|
||||
reader: reader,
|
||||
hasher: Blake2b::new(64),
|
||||
}
|
||||
}
|
||||
|
||||
/// Destroy this reader and return the hash of what was read.
|
||||
pub fn into_hash(self) -> String {
|
||||
let hash = self.hasher.finalize();
|
||||
|
||||
let mut s = String::new();
|
||||
for c in hash.as_bytes().iter() {
|
||||
s += &format!("{:02x}", c);
|
||||
}
|
||||
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read> Read for HashReader<R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let bytes = self.reader.read(buf)?;
|
||||
|
||||
if bytes > 0 {
|
||||
self.hasher.update(&buf[0..bytes]);
|
||||
}
|
||||
|
||||
Ok(bytes)
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,74 +0,0 @@
|
||||
use pairing::bls12_381::Bls12;
|
||||
use pairing::{PrimeField, PrimeFieldRepr};
|
||||
use rand::{OsRng, Rng};
|
||||
use sapling_crypto::jubjub::{edwards, JubjubBls12};
|
||||
use sapling_crypto::primitives::{Diversifier, ViewingKey};
|
||||
|
||||
use {
|
||||
librustzcash_sapling_generate_r, librustzcash_sapling_ka_agree,
|
||||
librustzcash_sapling_ka_derivepublic,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_key_agreement() {
|
||||
let params = JubjubBls12::new();
|
||||
let mut rng = OsRng::new().unwrap();
|
||||
|
||||
// Create random viewing key
|
||||
let vk = ViewingKey::<Bls12> {
|
||||
ak: edwards::Point::rand(&mut rng, ¶ms).mul_by_cofactor(¶ms),
|
||||
nk: edwards::Point::rand(&mut rng, ¶ms).mul_by_cofactor(¶ms),
|
||||
};
|
||||
|
||||
// Create a random address with the viewing key
|
||||
let addr = loop {
|
||||
match vk.into_payment_address(Diversifier(rng.gen()), ¶ms) {
|
||||
Some(a) => break a,
|
||||
None => {}
|
||||
}
|
||||
};
|
||||
|
||||
// Grab ivk from our viewing key in serialized form
|
||||
let ivk = vk.ivk();
|
||||
let mut ivk_serialized = [0u8; 32];
|
||||
ivk.into_repr().write_le(&mut ivk_serialized[..]).unwrap();
|
||||
|
||||
// Create random esk
|
||||
let mut esk = [0u8; 32];
|
||||
librustzcash_sapling_generate_r(&mut esk);
|
||||
|
||||
// The sender will create a shared secret with the recipient
|
||||
// by multiplying the pk_d from their address with the esk
|
||||
// we randomly generated
|
||||
let mut shared_secret_sender = [0u8; 32];
|
||||
|
||||
// Serialize pk_d for the call to librustzcash_sapling_ka_agree
|
||||
let mut addr_pk_d = [0u8; 32];
|
||||
addr.pk_d.write(&mut addr_pk_d[..]).unwrap();
|
||||
|
||||
assert!(librustzcash_sapling_ka_agree(
|
||||
&addr_pk_d,
|
||||
&esk,
|
||||
&mut shared_secret_sender
|
||||
));
|
||||
|
||||
// Create epk for the recipient, placed in the transaction. Computed
|
||||
// using the diversifier and esk.
|
||||
let mut epk = [0u8; 32];
|
||||
assert!(librustzcash_sapling_ka_derivepublic(
|
||||
&addr.diversifier.0,
|
||||
&esk,
|
||||
&mut epk
|
||||
));
|
||||
|
||||
// Create sharedSecret with ephemeral key
|
||||
let mut shared_secret_recipient = [0u8; 32];
|
||||
assert!(librustzcash_sapling_ka_agree(
|
||||
&epk,
|
||||
&ivk_serialized,
|
||||
&mut shared_secret_recipient
|
||||
));
|
||||
|
||||
assert!(!shared_secret_sender.iter().all(|&v| v == 0));
|
||||
assert_eq!(shared_secret_sender, shared_secret_recipient);
|
||||
}
|
@ -1,666 +0,0 @@
|
||||
use pairing::{bls12_381::Bls12, PrimeField, PrimeFieldRepr};
|
||||
use sapling_crypto::{
|
||||
jubjub::{fs::FsRepr, FixedGenerators, JubjubEngine, JubjubParams},
|
||||
primitives::{Diversifier, ProofGenerationKey},
|
||||
};
|
||||
|
||||
use super::JUBJUB;
|
||||
|
||||
use {
|
||||
librustzcash_ask_to_ak, librustzcash_check_diversifier, librustzcash_crh_ivk,
|
||||
librustzcash_ivk_to_pkd, librustzcash_nsk_to_nk,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn key_components() {
|
||||
#![allow(dead_code)]
|
||||
struct TestVector {
|
||||
sk: [u8; 32],
|
||||
ask: [u8; 32],
|
||||
nsk: [u8; 32],
|
||||
ovk: [u8; 32],
|
||||
ak: [u8; 32],
|
||||
nk: [u8; 32],
|
||||
ivk: [u8; 32],
|
||||
default_d: [u8; 11],
|
||||
default_pk_d: [u8; 32],
|
||||
note_v: u64,
|
||||
note_r: [u8; 32],
|
||||
note_cm: [u8; 32],
|
||||
};
|
||||
|
||||
// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_key_components.py
|
||||
let test_vectors = vec![
|
||||
TestVector {
|
||||
sk: [
|
||||
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,
|
||||
],
|
||||
ask: [
|
||||
0x85, 0x48, 0xa1, 0x4a, 0x47, 0x3e, 0xa5, 0x47, 0xaa, 0x23, 0x78, 0x40, 0x20, 0x44,
|
||||
0xf8, 0x18, 0xcf, 0x19, 0x11, 0xcf, 0x5d, 0xd2, 0x05, 0x4f, 0x67, 0x83, 0x45, 0xf0,
|
||||
0x0d, 0x0e, 0x88, 0x06,
|
||||
],
|
||||
nsk: [
|
||||
0x30, 0x11, 0x4e, 0xa0, 0xdd, 0x0b, 0xb6, 0x1c, 0xf0, 0xea, 0xea, 0xb6, 0xec, 0x33,
|
||||
0x31, 0xf5, 0x81, 0xb0, 0x42, 0x5e, 0x27, 0x33, 0x85, 0x01, 0x26, 0x2d, 0x7e, 0xac,
|
||||
0x74, 0x5e, 0x6e, 0x05,
|
||||
],
|
||||
ovk: [
|
||||
0x98, 0xd1, 0x69, 0x13, 0xd9, 0x9b, 0x04, 0x17, 0x7c, 0xab, 0xa4, 0x4f, 0x6e, 0x4d,
|
||||
0x22, 0x4e, 0x03, 0xb5, 0xac, 0x03, 0x1d, 0x7c, 0xe4, 0x5e, 0x86, 0x51, 0x38, 0xe1,
|
||||
0xb9, 0x96, 0xd6, 0x3b,
|
||||
],
|
||||
ak: [
|
||||
0xf3, 0x44, 0xec, 0x38, 0x0f, 0xe1, 0x27, 0x3e, 0x30, 0x98, 0xc2, 0x58, 0x8c, 0x5d,
|
||||
0x3a, 0x79, 0x1f, 0xd7, 0xba, 0x95, 0x80, 0x32, 0x76, 0x07, 0x77, 0xfd, 0x0e, 0xfa,
|
||||
0x8e, 0xf1, 0x16, 0x20,
|
||||
],
|
||||
nk: [
|
||||
0xf7, 0xcf, 0x9e, 0x77, 0xf2, 0xe5, 0x86, 0x83, 0x38, 0x3c, 0x15, 0x19, 0xac, 0x7b,
|
||||
0x06, 0x2d, 0x30, 0x04, 0x0e, 0x27, 0xa7, 0x25, 0xfb, 0x88, 0xfb, 0x19, 0xa9, 0x78,
|
||||
0xbd, 0x3f, 0xd6, 0xba,
|
||||
],
|
||||
ivk: [
|
||||
0xb7, 0x0b, 0x7c, 0xd0, 0xed, 0x03, 0xcb, 0xdf, 0xd7, 0xad, 0xa9, 0x50, 0x2e, 0xe2,
|
||||
0x45, 0xb1, 0x3e, 0x56, 0x9d, 0x54, 0xa5, 0x71, 0x9d, 0x2d, 0xaa, 0x0f, 0x5f, 0x14,
|
||||
0x51, 0x47, 0x92, 0x04,
|
||||
],
|
||||
default_d: [
|
||||
0xf1, 0x9d, 0x9b, 0x79, 0x7e, 0x39, 0xf3, 0x37, 0x44, 0x58, 0x39,
|
||||
],
|
||||
default_pk_d: [
|
||||
0xdb, 0x4c, 0xd2, 0xb0, 0xaa, 0xc4, 0xf7, 0xeb, 0x8c, 0xa1, 0x31, 0xf1, 0x65, 0x67,
|
||||
0xc4, 0x45, 0xa9, 0x55, 0x51, 0x26, 0xd3, 0xc2, 0x9f, 0x14, 0xe3, 0xd7, 0x76, 0xe8,
|
||||
0x41, 0xae, 0x74, 0x15,
|
||||
],
|
||||
note_v: 0,
|
||||
note_r: [
|
||||
0x39, 0x17, 0x6d, 0xac, 0x39, 0xac, 0xe4, 0x98, 0x0e, 0xcc, 0x8d, 0x77, 0x8e, 0x89,
|
||||
0x86, 0x02, 0x55, 0xec, 0x36, 0x15, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
],
|
||||
note_cm: [
|
||||
0xcb, 0x3c, 0xf9, 0x15, 0x32, 0x70, 0xd5, 0x7e, 0xb9, 0x14, 0xc6, 0xc2, 0xbc, 0xc0,
|
||||
0x18, 0x50, 0xc9, 0xfe, 0xd4, 0x4f, 0xce, 0x08, 0x06, 0x27, 0x8f, 0x08, 0x3e, 0xf2,
|
||||
0xdd, 0x07, 0x64, 0x39,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01,
|
||||
],
|
||||
ask: [
|
||||
0xc9, 0x43, 0x56, 0x29, 0xbf, 0x8b, 0xff, 0xe5, 0x5e, 0x73, 0x35, 0xec, 0x07, 0x77,
|
||||
0x18, 0xba, 0x60, 0xba, 0x28, 0xd7, 0xac, 0x37, 0x94, 0xb7, 0x4f, 0x51, 0x2c, 0x31,
|
||||
0xaf, 0x0a, 0x53, 0x04,
|
||||
],
|
||||
nsk: [
|
||||
0x11, 0xac, 0xc2, 0xea, 0xd0, 0x7b, 0x5f, 0x00, 0x8c, 0x1f, 0x0f, 0x09, 0x0c, 0xc8,
|
||||
0xdd, 0xf3, 0x35, 0x23, 0x6f, 0xf4, 0xb2, 0x53, 0xc6, 0x49, 0x56, 0x95, 0xe9, 0xd6,
|
||||
0x39, 0xda, 0xcd, 0x08,
|
||||
],
|
||||
ovk: [
|
||||
0x3b, 0x94, 0x62, 0x10, 0xce, 0x6d, 0x1b, 0x16, 0x92, 0xd7, 0x39, 0x2a, 0xc8, 0x4a,
|
||||
0x8b, 0xc8, 0xf0, 0x3b, 0x72, 0x72, 0x3c, 0x7d, 0x36, 0x72, 0x1b, 0x80, 0x9a, 0x79,
|
||||
0xc9, 0xd6, 0xe4, 0x5b,
|
||||
],
|
||||
ak: [
|
||||
0x82, 0xff, 0x5e, 0xff, 0xc5, 0x27, 0xae, 0x84, 0x02, 0x0b, 0xf2, 0xd3, 0x52, 0x01,
|
||||
0xc1, 0x02, 0x19, 0x13, 0x19, 0x47, 0xff, 0x4b, 0x96, 0xf8, 0x81, 0xa4, 0x5f, 0x2e,
|
||||
0x8a, 0xe3, 0x05, 0x18,
|
||||
],
|
||||
nk: [
|
||||
0xc4, 0x53, 0x4d, 0x84, 0x8b, 0xb9, 0x18, 0xcf, 0x4a, 0x7f, 0x8b, 0x98, 0x74, 0x0a,
|
||||
0xb3, 0xcc, 0xee, 0x58, 0x67, 0x95, 0xff, 0x4d, 0xf6, 0x45, 0x47, 0xa8, 0x88, 0x8a,
|
||||
0x6c, 0x74, 0x15, 0xd2,
|
||||
],
|
||||
ivk: [
|
||||
0xc5, 0x18, 0x38, 0x44, 0x66, 0xb2, 0x69, 0x88, 0xb5, 0x10, 0x90, 0x67, 0x41, 0x8d,
|
||||
0x19, 0x2d, 0x9d, 0x6b, 0xd0, 0xd9, 0x23, 0x22, 0x05, 0xd7, 0x74, 0x18, 0xc2, 0x40,
|
||||
0xfc, 0x68, 0xa4, 0x06,
|
||||
],
|
||||
default_d: [
|
||||
0xae, 0xf1, 0x80, 0xf6, 0xe3, 0x4e, 0x35, 0x4b, 0x88, 0x8f, 0x81,
|
||||
],
|
||||
default_pk_d: [
|
||||
0xa6, 0xb1, 0x3e, 0xa3, 0x36, 0xdd, 0xb7, 0xa6, 0x7b, 0xb0, 0x9a, 0x0e, 0x68, 0xe9,
|
||||
0xd3, 0xcf, 0xb3, 0x92, 0x10, 0x83, 0x1e, 0xa3, 0xa2, 0x96, 0xba, 0x09, 0xa9, 0x22,
|
||||
0x06, 0x0f, 0xd3, 0x8b,
|
||||
],
|
||||
note_v: 12227227834928555328,
|
||||
note_r: [
|
||||
0x47, 0x8b, 0xa0, 0xee, 0x6e, 0x1a, 0x75, 0xb6, 0x00, 0x03, 0x6f, 0x26, 0xf1, 0x8b,
|
||||
0x70, 0x15, 0xab, 0x55, 0x6b, 0xed, 0xdf, 0x8b, 0x96, 0x02, 0x38, 0x86, 0x9f, 0x89,
|
||||
0xdd, 0x80, 0x4e, 0x06,
|
||||
],
|
||||
note_cm: [
|
||||
0xb5, 0x78, 0x93, 0x50, 0x0b, 0xfb, 0x85, 0xdf, 0x2e, 0x8b, 0x01, 0xac, 0x45, 0x2f,
|
||||
0x89, 0xe1, 0x0e, 0x26, 0x6b, 0xcf, 0xa3, 0x1c, 0x31, 0xb2, 0x9a, 0x53, 0xae, 0x72,
|
||||
0xca, 0xd4, 0x69, 0x50,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02,
|
||||
],
|
||||
ask: [
|
||||
0xee, 0x1c, 0x3d, 0x7e, 0xfe, 0x0a, 0x78, 0x06, 0x3d, 0x6a, 0xf3, 0xd9, 0xd8, 0x12,
|
||||
0x12, 0xaf, 0x47, 0xb7, 0xc1, 0xb7, 0x61, 0xf8, 0x5c, 0xcb, 0x06, 0x6f, 0xc1, 0x1a,
|
||||
0x6a, 0x42, 0x17, 0x03,
|
||||
],
|
||||
nsk: [
|
||||
0x1d, 0x3b, 0x71, 0x37, 0x55, 0xd7, 0x48, 0x75, 0xe8, 0xea, 0x38, 0xfd, 0x16, 0x6e,
|
||||
0x76, 0xc6, 0x2a, 0x42, 0x50, 0x21, 0x6e, 0x6b, 0xbf, 0xe4, 0x8a, 0x5e, 0x2e, 0xab,
|
||||
0xad, 0x11, 0x7f, 0x0b,
|
||||
],
|
||||
ovk: [
|
||||
0x8b, 0xf4, 0x39, 0x0e, 0x28, 0xdd, 0xc9, 0x5b, 0x83, 0x02, 0xc3, 0x81, 0xd5, 0x81,
|
||||
0x0b, 0x84, 0xba, 0x8e, 0x60, 0x96, 0xe5, 0xa7, 0x68, 0x22, 0x77, 0x4f, 0xd4, 0x9f,
|
||||
0x49, 0x1e, 0x8f, 0x49,
|
||||
],
|
||||
ak: [
|
||||
0xab, 0x83, 0x57, 0x4e, 0xb5, 0xde, 0x85, 0x9a, 0x0a, 0xb8, 0x62, 0x9d, 0xec, 0x34,
|
||||
0xc7, 0xbe, 0xe8, 0xc3, 0xfc, 0x74, 0xdf, 0xa0, 0xb1, 0x9a, 0x3a, 0x74, 0x68, 0xd1,
|
||||
0x5d, 0xca, 0x64, 0xc6,
|
||||
],
|
||||
nk: [
|
||||
0x95, 0xd5, 0x80, 0x53, 0xe0, 0x59, 0x2e, 0x4a, 0x16, 0x9c, 0xc0, 0xb7, 0x92, 0x8a,
|
||||
0xaa, 0xc3, 0xde, 0x24, 0xef, 0x15, 0x31, 0xaa, 0x9e, 0xb6, 0xf4, 0xab, 0x93, 0x91,
|
||||
0x4d, 0xa8, 0xa0, 0x6e,
|
||||
],
|
||||
ivk: [
|
||||
0x47, 0x1c, 0x24, 0xa3, 0xdc, 0x87, 0x30, 0xe7, 0x50, 0x36, 0xc0, 0xa9, 0x5f, 0x3e,
|
||||
0x2f, 0x7d, 0xd1, 0xbe, 0x6f, 0xb9, 0x3a, 0xd2, 0x95, 0x92, 0x20, 0x3d, 0xef, 0x30,
|
||||
0x41, 0x95, 0x45, 0x05,
|
||||
],
|
||||
default_d: [
|
||||
0x75, 0x99, 0xf0, 0xbf, 0x9b, 0x57, 0xcd, 0x2d, 0xc2, 0x99, 0xb6,
|
||||
],
|
||||
default_pk_d: [
|
||||
0x66, 0x14, 0x17, 0x39, 0x51, 0x4b, 0x28, 0xf0, 0x5d, 0xef, 0x8a, 0x18, 0xee, 0xee,
|
||||
0x5e, 0xed, 0x4d, 0x44, 0xc6, 0x22, 0x5c, 0x3c, 0x65, 0xd8, 0x8d, 0xd9, 0x90, 0x77,
|
||||
0x08, 0x01, 0x2f, 0x5a,
|
||||
],
|
||||
note_v: 6007711596147559040,
|
||||
note_r: [
|
||||
0x14, 0x7c, 0xf2, 0xb5, 0x1b, 0x4c, 0x7c, 0x63, 0xcb, 0x77, 0xb9, 0x9e, 0x8b, 0x78,
|
||||
0x3e, 0x5b, 0x51, 0x11, 0xdb, 0x0a, 0x7c, 0xa0, 0x4d, 0x6c, 0x01, 0x4a, 0x1d, 0x7d,
|
||||
0xa8, 0x3b, 0xae, 0x0a,
|
||||
],
|
||||
note_cm: [
|
||||
0xdb, 0x85, 0xa7, 0x0a, 0x98, 0x43, 0x7f, 0x73, 0x16, 0x7f, 0xc3, 0x32, 0xd5, 0xb7,
|
||||
0xb7, 0x40, 0x82, 0x96, 0x66, 0x17, 0x70, 0xb1, 0x01, 0xb0, 0xaa, 0x87, 0x83, 0x9f,
|
||||
0x4e, 0x55, 0xf1, 0x51,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03,
|
||||
],
|
||||
ask: [
|
||||
0x00, 0xc3, 0xa1, 0xe1, 0xca, 0x8f, 0x4e, 0x04, 0x80, 0xee, 0x1e, 0xe9, 0x0c, 0xa7,
|
||||
0x51, 0x78, 0x79, 0xd3, 0xfc, 0x5c, 0x81, 0x5c, 0x09, 0x03, 0xe5, 0xee, 0xbc, 0x94,
|
||||
0xbb, 0x80, 0x95, 0x03,
|
||||
],
|
||||
nsk: [
|
||||
0xe6, 0x62, 0x85, 0xa5, 0xe9, 0xb6, 0x5e, 0x15, 0x7a, 0xd2, 0xfc, 0xd5, 0x43, 0xda,
|
||||
0xd9, 0x8c, 0x67, 0xa5, 0x8a, 0xbd, 0xf2, 0x87, 0xe0, 0x55, 0x06, 0xbd, 0x1c, 0x2e,
|
||||
0x59, 0xb0, 0x72, 0x0b,
|
||||
],
|
||||
ovk: [
|
||||
0x14, 0x76, 0x78, 0xe0, 0x55, 0x3b, 0x97, 0x82, 0x93, 0x47, 0x64, 0x7c, 0x5b, 0xc7,
|
||||
0xda, 0xb4, 0xcc, 0x22, 0x02, 0xb5, 0x4e, 0xc2, 0x9f, 0xd3, 0x1a, 0x3d, 0xe6, 0xbe,
|
||||
0x08, 0x25, 0xfc, 0x5e,
|
||||
],
|
||||
ak: [
|
||||
0x3c, 0x9c, 0xde, 0x7e, 0x5d, 0x0d, 0x38, 0xa8, 0x61, 0x0f, 0xaa, 0xdb, 0xcf, 0x4c,
|
||||
0x34, 0x3f, 0x5d, 0x3c, 0xfa, 0x31, 0x55, 0xa5, 0xb9, 0x46, 0x61, 0xa6, 0x75, 0x3e,
|
||||
0x96, 0xe8, 0x84, 0xea,
|
||||
],
|
||||
nk: [
|
||||
0xb7, 0x7d, 0x36, 0xf5, 0x08, 0x94, 0x1d, 0xbd, 0x61, 0xcf, 0xd0, 0xf1, 0x59, 0xee,
|
||||
0x05, 0xcf, 0xaa, 0x78, 0xa2, 0x6c, 0x94, 0x92, 0x90, 0x38, 0x06, 0xd8, 0x3b, 0x59,
|
||||
0x8d, 0x3c, 0x1c, 0x2a,
|
||||
],
|
||||
ivk: [
|
||||
0x63, 0x6a, 0xa9, 0x64, 0xbf, 0xc2, 0x3c, 0xe4, 0xb1, 0xfc, 0xf7, 0xdf, 0xc9, 0x91,
|
||||
0x79, 0xdd, 0xc4, 0x06, 0xff, 0x55, 0x40, 0x0c, 0x92, 0x95, 0xac, 0xfc, 0x14, 0xf0,
|
||||
0x31, 0xc7, 0x26, 0x00,
|
||||
],
|
||||
default_d: [
|
||||
0x1b, 0x81, 0x61, 0x4f, 0x1d, 0xad, 0xea, 0x0f, 0x8d, 0x0a, 0x58,
|
||||
],
|
||||
default_pk_d: [
|
||||
0x25, 0xeb, 0x55, 0xfc, 0xcf, 0x76, 0x1f, 0xc6, 0x4e, 0x85, 0xa5, 0x88, 0xef, 0xe6,
|
||||
0xea, 0xd7, 0x83, 0x2f, 0xb1, 0xf0, 0xf7, 0xa8, 0x31, 0x65, 0x89, 0x5b, 0xdf, 0xf9,
|
||||
0x42, 0x92, 0x5f, 0x5c,
|
||||
],
|
||||
note_v: 18234939431076114368,
|
||||
note_r: [
|
||||
0x34, 0xa4, 0xb2, 0xa9, 0x14, 0x4f, 0xf5, 0xea, 0x54, 0xef, 0xee, 0x87, 0xcf, 0x90,
|
||||
0x1b, 0x5b, 0xed, 0x5e, 0x35, 0xd2, 0x1f, 0xbb, 0xd7, 0x88, 0xd5, 0xbd, 0x9d, 0x83,
|
||||
0x3e, 0x11, 0x28, 0x04,
|
||||
],
|
||||
note_cm: [
|
||||
0xe0, 0x8c, 0xe4, 0x82, 0xb3, 0xa8, 0xfb, 0x3b, 0x35, 0xcc, 0xdb, 0xe3, 0x43, 0x37,
|
||||
0xbd, 0x10, 0x5d, 0x88, 0x39, 0x21, 0x2e, 0x0d, 0x16, 0x44, 0xb9, 0xd5, 0x5c, 0xaa,
|
||||
0x60, 0xd1, 0x9b, 0x6c,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04,
|
||||
],
|
||||
ask: [
|
||||
0x82, 0x36, 0xd1, 0x9d, 0x32, 0x05, 0xd8, 0x55, 0x43, 0xa0, 0x68, 0x11, 0x34, 0x3f,
|
||||
0x82, 0x7b, 0x65, 0x63, 0x77, 0x0a, 0x49, 0xaa, 0x4d, 0x0c, 0xa0, 0x08, 0x18, 0x05,
|
||||
0xd4, 0xc8, 0xea, 0x0d,
|
||||
],
|
||||
nsk: [
|
||||
0x7e, 0xc1, 0xef, 0x0b, 0xed, 0x82, 0x71, 0x82, 0x72, 0xf0, 0xf4, 0x4f, 0x01, 0x7c,
|
||||
0x48, 0x41, 0x74, 0x51, 0x3d, 0x66, 0x1d, 0xd1, 0x68, 0xaf, 0x02, 0xd2, 0x09, 0x2a,
|
||||
0x1d, 0x8a, 0x05, 0x07,
|
||||
],
|
||||
ovk: [
|
||||
0x1b, 0x6e, 0x75, 0xec, 0xe3, 0xac, 0xe8, 0xdb, 0xa6, 0xa5, 0x41, 0x0d, 0x9a, 0xd4,
|
||||
0x75, 0x56, 0x68, 0xe4, 0xb3, 0x95, 0x85, 0xd6, 0x35, 0xec, 0x1d, 0xa7, 0xc8, 0xdc,
|
||||
0xfd, 0x5f, 0xc4, 0xed,
|
||||
],
|
||||
ak: [
|
||||
0x55, 0xe8, 0x83, 0x89, 0xbb, 0x7e, 0x41, 0xde, 0x13, 0x0c, 0xfa, 0x51, 0xa8, 0x71,
|
||||
0x5f, 0xde, 0x01, 0xff, 0x9c, 0x68, 0x76, 0x64, 0x7f, 0x01, 0x75, 0xad, 0x34, 0xf0,
|
||||
0x58, 0xdd, 0xe0, 0x1a,
|
||||
],
|
||||
nk: [
|
||||
0x72, 0x5d, 0x4a, 0xd6, 0xa1, 0x50, 0x21, 0xcd, 0x1c, 0x48, 0xc5, 0xee, 0x19, 0xde,
|
||||
0x6c, 0x1e, 0x76, 0x8a, 0x2c, 0xc0, 0xa9, 0xa7, 0x30, 0xa0, 0x1b, 0xb2, 0x1c, 0x95,
|
||||
0xe3, 0xd9, 0xe4, 0x3c,
|
||||
],
|
||||
ivk: [
|
||||
0x67, 0xfa, 0x2b, 0xf7, 0xc6, 0x7d, 0x46, 0x58, 0x24, 0x3c, 0x31, 0x7c, 0x0c, 0xb4,
|
||||
0x1f, 0xd3, 0x20, 0x64, 0xdf, 0xd3, 0x70, 0x9f, 0xe0, 0xdc, 0xb7, 0x24, 0xf1, 0x4b,
|
||||
0xb0, 0x1a, 0x1d, 0x04,
|
||||
],
|
||||
default_d: [
|
||||
0xfc, 0xfb, 0x68, 0xa4, 0x0d, 0x4b, 0xc6, 0xa0, 0x4b, 0x09, 0xc4,
|
||||
],
|
||||
default_pk_d: [
|
||||
0x8b, 0x2a, 0x33, 0x7f, 0x03, 0x62, 0x2c, 0x24, 0xff, 0x38, 0x1d, 0x4c, 0x54, 0x6f,
|
||||
0x69, 0x77, 0xf9, 0x05, 0x22, 0xe9, 0x2f, 0xde, 0x44, 0xc9, 0xd1, 0xbb, 0x09, 0x97,
|
||||
0x14, 0xb9, 0xdb, 0x2b,
|
||||
],
|
||||
note_v: 12015423192295118080,
|
||||
note_r: [
|
||||
0xe5, 0x57, 0x85, 0x13, 0x55, 0x74, 0x7c, 0x09, 0xac, 0x59, 0x01, 0x3c, 0xbd, 0xe8,
|
||||
0x59, 0x80, 0x96, 0x4e, 0xc1, 0x84, 0x4d, 0x9c, 0x69, 0x67, 0xca, 0x0c, 0x02, 0x9c,
|
||||
0x84, 0x57, 0xbb, 0x04,
|
||||
],
|
||||
note_cm: [
|
||||
0xbd, 0xc8, 0x54, 0xbf, 0x3e, 0x7b, 0x00, 0x82, 0x1f, 0x3b, 0x8b, 0x85, 0x23, 0x8c,
|
||||
0xcf, 0x1e, 0x67, 0x15, 0xbf, 0xe7, 0x0b, 0x63, 0x2d, 0x04, 0x4b, 0x26, 0xfb, 0x2b,
|
||||
0xc7, 0x1b, 0x7f, 0x36,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05,
|
||||
],
|
||||
ask: [
|
||||
0xea, 0xe6, 0x88, 0x4d, 0x76, 0x4a, 0x05, 0x40, 0x61, 0xa8, 0xf1, 0xc0, 0x07, 0x6c,
|
||||
0x62, 0x4d, 0xcb, 0x73, 0x87, 0x89, 0xf7, 0xad, 0x1e, 0x74, 0x08, 0xe3, 0x1f, 0x24,
|
||||
0xdf, 0xc8, 0x26, 0x07,
|
||||
],
|
||||
nsk: [
|
||||
0xfb, 0xe6, 0x10, 0xf4, 0x2a, 0x41, 0x74, 0x9f, 0x9b, 0x6e, 0x6e, 0x4a, 0x54, 0xb5,
|
||||
0xa3, 0x2e, 0xbf, 0xe8, 0xf4, 0x38, 0x00, 0x88, 0x1b, 0xa6, 0xcd, 0x13, 0xed, 0x0b,
|
||||
0x05, 0x29, 0x46, 0x01,
|
||||
],
|
||||
ovk: [
|
||||
0xc6, 0xbc, 0x1f, 0x39, 0xf0, 0xd7, 0x86, 0x31, 0x4c, 0xb2, 0x0b, 0xf9, 0xab, 0x22,
|
||||
0x85, 0x40, 0x91, 0x35, 0x55, 0xf9, 0x70, 0x69, 0x6b, 0x6d, 0x7c, 0x77, 0xbb, 0x33,
|
||||
0x23, 0x28, 0x37, 0x2a,
|
||||
],
|
||||
ak: [
|
||||
0xe6, 0x82, 0x76, 0x59, 0x14, 0xe3, 0x86, 0x4c, 0x33, 0x9e, 0x57, 0x82, 0xb8, 0x55,
|
||||
0xc0, 0xfd, 0xf4, 0x0e, 0x0d, 0xfc, 0xed, 0xb9, 0xe7, 0xb4, 0x7b, 0xc9, 0x4b, 0x90,
|
||||
0xb3, 0xa4, 0xc9, 0x88,
|
||||
],
|
||||
nk: [
|
||||
0x82, 0x25, 0x6b, 0x95, 0x62, 0x3c, 0x67, 0x02, 0x4b, 0x44, 0x24, 0xd9, 0x14, 0x00,
|
||||
0xa3, 0x70, 0xe7, 0xac, 0x8e, 0x4d, 0x15, 0x48, 0x2a, 0x37, 0x59, 0xe0, 0x0d, 0x21,
|
||||
0x97, 0x49, 0xda, 0xee,
|
||||
],
|
||||
ivk: [
|
||||
0xea, 0x3f, 0x1d, 0x80, 0xe4, 0x30, 0x7c, 0xa7, 0x3b, 0x9f, 0x37, 0x80, 0x1f, 0x91,
|
||||
0xfb, 0xa8, 0x10, 0xcc, 0x41, 0xd2, 0x79, 0xfc, 0x29, 0xf5, 0x64, 0x23, 0x56, 0x54,
|
||||
0xa2, 0x17, 0x8e, 0x03,
|
||||
],
|
||||
default_d: [
|
||||
0xeb, 0x51, 0x98, 0x82, 0xad, 0x1e, 0x5c, 0xc6, 0x54, 0xcd, 0x59,
|
||||
],
|
||||
default_pk_d: [
|
||||
0x6b, 0x27, 0xda, 0xcc, 0xb5, 0xa8, 0x20, 0x7f, 0x53, 0x2d, 0x10, 0xca, 0x23, 0x8f,
|
||||
0x97, 0x86, 0x64, 0x8a, 0x11, 0xb5, 0x96, 0x6e, 0x51, 0xa2, 0xf7, 0xd8, 0x9e, 0x15,
|
||||
0xd2, 0x9b, 0x8f, 0xdf,
|
||||
],
|
||||
note_v: 5795906953514121792,
|
||||
note_r: [
|
||||
0x68, 0xf0, 0x61, 0x04, 0x60, 0x6b, 0x0c, 0x54, 0x49, 0x84, 0x5f, 0xf4, 0xc6, 0x5f,
|
||||
0x73, 0xe9, 0x0f, 0x45, 0xef, 0x5a, 0x43, 0xc9, 0xd7, 0x4c, 0xb2, 0xc8, 0x5c, 0xf5,
|
||||
0x6c, 0x94, 0xc0, 0x02,
|
||||
],
|
||||
note_cm: [
|
||||
0xe8, 0x26, 0x7d, 0x30, 0xac, 0x11, 0xc1, 0x00, 0xbc, 0x7a, 0x0f, 0xdf, 0x91, 0xf7,
|
||||
0x1d, 0x74, 0xc5, 0xbc, 0xf2, 0xe1, 0xef, 0x95, 0x66, 0x90, 0x44, 0x73, 0x01, 0x69,
|
||||
0xde, 0x1a, 0x5b, 0x4c,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06,
|
||||
],
|
||||
ask: [
|
||||
0xe8, 0xf8, 0x16, 0xb4, 0xbc, 0x08, 0xa7, 0xe5, 0x66, 0x75, 0x0c, 0xc2, 0x8a, 0xfe,
|
||||
0x82, 0xa4, 0xce, 0xa9, 0xc2, 0xbe, 0xf2, 0x44, 0xfa, 0x4b, 0x13, 0xc4, 0x73, 0x9b,
|
||||
0x28, 0x07, 0x4c, 0x0d,
|
||||
],
|
||||
nsk: [
|
||||
0x32, 0x61, 0x5b, 0x13, 0x7f, 0x28, 0x01, 0xed, 0x44, 0x6e, 0x48, 0x78, 0x1a, 0xb0,
|
||||
0x63, 0x45, 0x72, 0xe1, 0x8c, 0xfb, 0x06, 0x93, 0x72, 0x1b, 0x88, 0x03, 0xc0, 0x5b,
|
||||
0x82, 0x27, 0xd1, 0x07,
|
||||
],
|
||||
ovk: [
|
||||
0xf6, 0x2c, 0x05, 0xe8, 0x48, 0xa8, 0x73, 0xef, 0x88, 0x5e, 0x12, 0xb0, 0x8c, 0x5e,
|
||||
0x7c, 0xa2, 0xf3, 0x24, 0x24, 0xba, 0xcc, 0x75, 0x4c, 0xb6, 0x97, 0x50, 0x44, 0x4d,
|
||||
0x35, 0x5f, 0x51, 0x06,
|
||||
],
|
||||
ak: [
|
||||
0xff, 0x27, 0xdb, 0x07, 0x51, 0x94, 0x5d, 0x3e, 0xe4, 0xbe, 0x9c, 0xf1, 0x5c, 0x2e,
|
||||
0xa2, 0x11, 0xb2, 0x4b, 0x16, 0x4d, 0x5f, 0x2d, 0x7d, 0xdf, 0xf5, 0xe4, 0xa0, 0x70,
|
||||
0x8f, 0x10, 0xb9, 0x5e,
|
||||
],
|
||||
nk: [
|
||||
0x94, 0x38, 0x85, 0x95, 0x9d, 0x4e, 0xf8, 0xa9, 0xcf, 0xca, 0x07, 0xc4, 0x57, 0xf0,
|
||||
0x9e, 0xc7, 0x4b, 0x96, 0xf9, 0x93, 0xd8, 0xe0, 0xfa, 0x32, 0xb1, 0x9c, 0x03, 0xe3,
|
||||
0xb0, 0x7a, 0x42, 0x0f,
|
||||
],
|
||||
ivk: [
|
||||
0xb5, 0xc5, 0x89, 0x49, 0x43, 0x95, 0x69, 0x33, 0xc0, 0xe5, 0xc1, 0x2d, 0x31, 0x1f,
|
||||
0xc1, 0x2c, 0xba, 0x58, 0x35, 0x4b, 0x5c, 0x38, 0x9e, 0xdc, 0x03, 0xda, 0x55, 0x08,
|
||||
0x4f, 0x74, 0xc2, 0x05,
|
||||
],
|
||||
default_d: [
|
||||
0xbe, 0xbb, 0x0f, 0xb4, 0x6b, 0x8a, 0xaf, 0xf8, 0x90, 0x40, 0xf6,
|
||||
],
|
||||
default_pk_d: [
|
||||
0xd1, 0x1d, 0xa0, 0x1f, 0x0b, 0x43, 0xbd, 0xd5, 0x28, 0x8d, 0x32, 0x38, 0x5b, 0x87,
|
||||
0x71, 0xd2, 0x23, 0x49, 0x3c, 0x69, 0x80, 0x25, 0x44, 0x04, 0x3f, 0x77, 0xcf, 0x1d,
|
||||
0x71, 0xc1, 0xcb, 0x8c,
|
||||
],
|
||||
note_v: 18023134788442677120,
|
||||
note_r: [
|
||||
0x49, 0xf9, 0x0b, 0x47, 0xfd, 0x52, 0xfe, 0xe7, 0xc1, 0xc8, 0x1f, 0x0d, 0xcb, 0x5b,
|
||||
0x74, 0xc3, 0xfb, 0x9b, 0x3e, 0x03, 0x97, 0x6f, 0x8b, 0x75, 0x24, 0xea, 0xba, 0xd0,
|
||||
0x08, 0x89, 0x21, 0x07,
|
||||
],
|
||||
note_cm: [
|
||||
0x57, 0x2b, 0xa2, 0x05, 0x25, 0xb0, 0xac, 0x4d, 0x6d, 0xc0, 0x1a, 0xc2, 0xea, 0x10,
|
||||
0x90, 0xb6, 0xe0, 0xf2, 0xf4, 0xbf, 0x4e, 0xc4, 0xa0, 0xdb, 0x5b, 0xbc, 0xcb, 0x5b,
|
||||
0x78, 0x3a, 0x1e, 0x55,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07,
|
||||
],
|
||||
ask: [
|
||||
0x74, 0xb4, 0x4a, 0x37, 0xf1, 0x50, 0x23, 0xc0, 0x60, 0x42, 0x7e, 0x1d, 0xae, 0xa3,
|
||||
0xf6, 0x43, 0x12, 0xdd, 0x8f, 0xeb, 0x7b, 0x2c, 0xed, 0xf0, 0xdd, 0x55, 0x44, 0x49,
|
||||
0x3f, 0x87, 0x2c, 0x06,
|
||||
],
|
||||
nsk: [
|
||||
0x07, 0x5c, 0x35, 0xdb, 0x8b, 0x1b, 0x25, 0x75, 0x42, 0x23, 0xec, 0xee, 0x34, 0xab,
|
||||
0x73, 0x0d, 0xdd, 0xd1, 0xf1, 0x4a, 0x6a, 0x54, 0xf4, 0xc6, 0xf4, 0x68, 0x45, 0x3c,
|
||||
0x3c, 0x6e, 0xd6, 0x0b,
|
||||
],
|
||||
ovk: [
|
||||
0xe9, 0xe0, 0xdc, 0x1e, 0xd3, 0x11, 0xda, 0xed, 0x64, 0xbd, 0x74, 0xda, 0x5d, 0x94,
|
||||
0xfe, 0x88, 0xa6, 0xea, 0x41, 0x4b, 0x73, 0x12, 0xde, 0x3d, 0x2a, 0x78, 0xf6, 0x46,
|
||||
0x32, 0xbb, 0xe3, 0x73,
|
||||
],
|
||||
ak: [
|
||||
0x28, 0x3f, 0x9a, 0xaf, 0xa9, 0xbc, 0xb3, 0xe6, 0xce, 0x17, 0xe6, 0x32, 0x12, 0x63,
|
||||
0x4c, 0xb3, 0xee, 0x55, 0x0c, 0x47, 0x6b, 0x67, 0x6b, 0xd3, 0x56, 0xa6, 0xdf, 0x8a,
|
||||
0xdf, 0x51, 0xd2, 0x5e,
|
||||
],
|
||||
nk: [
|
||||
0xdc, 0x4c, 0x67, 0xb1, 0x0d, 0x4b, 0x0a, 0x21, 0x8d, 0xc6, 0xe1, 0x48, 0x70, 0x66,
|
||||
0x74, 0x0a, 0x40, 0x93, 0x17, 0x86, 0x6c, 0x32, 0xe6, 0x64, 0xb5, 0x0e, 0x39, 0x7a,
|
||||
0xa8, 0x03, 0x89, 0xd4,
|
||||
],
|
||||
ivk: [
|
||||
0x87, 0x16, 0xc8, 0x28, 0x80, 0xe1, 0x36, 0x83, 0xe1, 0xbb, 0x05, 0x9d, 0xd0, 0x6c,
|
||||
0x80, 0xc9, 0x01, 0x34, 0xa9, 0x6d, 0x5a, 0xfc, 0xa8, 0xaa, 0xc2, 0xbb, 0xf6, 0x8b,
|
||||
0xb0, 0x5f, 0x84, 0x02,
|
||||
],
|
||||
default_d: [
|
||||
0xad, 0x6e, 0x2e, 0x18, 0x5a, 0x31, 0x00, 0xe3, 0xa6, 0xa8, 0xb3,
|
||||
],
|
||||
default_pk_d: [
|
||||
0x32, 0xcb, 0x28, 0x06, 0xb8, 0x82, 0xf1, 0x36, 0x8b, 0x0d, 0x4a, 0x89, 0x8f, 0x72,
|
||||
0xc4, 0xc8, 0xf7, 0x28, 0x13, 0x2c, 0xc1, 0x24, 0x56, 0x94, 0x6e, 0x7f, 0x4c, 0xb0,
|
||||
0xfb, 0x05, 0x8d, 0xa9,
|
||||
],
|
||||
note_v: 11803618549661680832,
|
||||
note_r: [
|
||||
0x51, 0x65, 0xaf, 0xf2, 0x2d, 0xd4, 0xed, 0x56, 0xb4, 0xd8, 0x1d, 0x1f, 0x17, 0x1c,
|
||||
0xc3, 0xd6, 0x43, 0x2f, 0xed, 0x1b, 0xeb, 0xf2, 0x0a, 0x7b, 0xea, 0xb1, 0x2d, 0xb1,
|
||||
0x42, 0xf9, 0x4a, 0x0c,
|
||||
],
|
||||
note_cm: [
|
||||
0xab, 0x7f, 0xc5, 0x66, 0x87, 0x3c, 0xcd, 0xe6, 0x71, 0xf5, 0x98, 0x27, 0x67, 0x85,
|
||||
0x60, 0xa0, 0x06, 0xf8, 0x2b, 0xb7, 0xad, 0xcd, 0x75, 0x22, 0x3f, 0xa8, 0x59, 0x36,
|
||||
0xf7, 0x8c, 0x2b, 0x23,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08,
|
||||
],
|
||||
ask: [
|
||||
0x03, 0x9d, 0xd9, 0x3d, 0xf3, 0x11, 0xff, 0x8f, 0xba, 0xb3, 0xfe, 0x23, 0x02, 0x19,
|
||||
0xcd, 0x42, 0xac, 0x87, 0x94, 0x84, 0xf3, 0x0b, 0x90, 0x3a, 0x3c, 0x1e, 0x67, 0xcc,
|
||||
0xca, 0x5a, 0x7b, 0x0d,
|
||||
],
|
||||
nsk: [
|
||||
0x04, 0x9f, 0xa1, 0x4f, 0x48, 0x6c, 0x75, 0xb9, 0xfa, 0xd7, 0xe3, 0xb6, 0x73, 0xa4,
|
||||
0x43, 0xdd, 0x07, 0x4e, 0xaa, 0x96, 0xed, 0xcb, 0x2a, 0x53, 0xea, 0xaa, 0xbd, 0xaf,
|
||||
0x70, 0xff, 0xbb, 0x08,
|
||||
],
|
||||
ovk: [
|
||||
0x14, 0x7d, 0xd1, 0x1d, 0x77, 0xeb, 0xa1, 0xb1, 0x63, 0x6f, 0xd6, 0x19, 0x0c, 0x62,
|
||||
0xb9, 0xa5, 0xd0, 0x48, 0x1b, 0xee, 0x7e, 0x91, 0x7f, 0xab, 0x02, 0xe2, 0x18, 0x58,
|
||||
0x06, 0x3a, 0xb5, 0x04,
|
||||
],
|
||||
ak: [
|
||||
0x36, 0x40, 0x48, 0xee, 0xdb, 0xe8, 0xca, 0x20, 0x5e, 0xb7, 0xe7, 0xba, 0x0a, 0x90,
|
||||
0x12, 0x16, 0x6c, 0x7c, 0x7b, 0xd9, 0xeb, 0x22, 0x8e, 0x08, 0x48, 0x14, 0x48, 0xc4,
|
||||
0x88, 0xaa, 0x21, 0xd2,
|
||||
],
|
||||
nk: [
|
||||
0xed, 0x60, 0xaf, 0x1c, 0xe7, 0xdf, 0x38, 0x07, 0x0d, 0x38, 0x51, 0x43, 0x2a, 0x96,
|
||||
0x48, 0x0d, 0xb0, 0xb4, 0x17, 0xc3, 0x68, 0x2a, 0x1d, 0x68, 0xe3, 0xe8, 0x93, 0x34,
|
||||
0x23, 0x5c, 0x0b, 0xdf,
|
||||
],
|
||||
ivk: [
|
||||
0x99, 0xc9, 0xb4, 0xb8, 0x4f, 0x4b, 0x4e, 0x35, 0x0f, 0x78, 0x7d, 0x1c, 0xf7, 0x05,
|
||||
0x1d, 0x50, 0xec, 0xc3, 0x4b, 0x1a, 0x5b, 0x20, 0xd2, 0xd2, 0x13, 0x9b, 0x4a, 0xf1,
|
||||
0xf1, 0x60, 0xe0, 0x01,
|
||||
],
|
||||
default_d: [
|
||||
0x21, 0xc9, 0x0e, 0x1c, 0x65, 0x8b, 0x3e, 0xfe, 0x86, 0xaf, 0x58,
|
||||
],
|
||||
default_pk_d: [
|
||||
0x9e, 0x64, 0x17, 0x4b, 0x4a, 0xb9, 0x81, 0x40, 0x5c, 0x32, 0x3b, 0x5e, 0x12, 0x47,
|
||||
0x59, 0x45, 0xa4, 0x6d, 0x4f, 0xed, 0xf8, 0x06, 0x08, 0x28, 0x04, 0x1c, 0xd2, 0x0e,
|
||||
0x62, 0xfd, 0x2c, 0xef,
|
||||
],
|
||||
note_v: 5584102310880684544,
|
||||
note_r: [
|
||||
0x8c, 0x3e, 0x56, 0x44, 0x9d, 0xc8, 0x63, 0x54, 0xd3, 0x3b, 0x02, 0x5e, 0xf2, 0x79,
|
||||
0x34, 0x60, 0xbc, 0xb1, 0x69, 0xf3, 0x32, 0x4e, 0x4a, 0x6b, 0x64, 0xba, 0xa6, 0x08,
|
||||
0x32, 0x31, 0x57, 0x04,
|
||||
],
|
||||
note_cm: [
|
||||
0x7b, 0x48, 0xa8, 0x37, 0x5d, 0x3e, 0xbd, 0x56, 0xbc, 0x64, 0x9b, 0xb5, 0xb5, 0x24,
|
||||
0x23, 0x36, 0xc2, 0xa0, 0x5a, 0x08, 0x03, 0x23, 0x9b, 0x5b, 0x88, 0xfd, 0x92, 0x07,
|
||||
0x8f, 0xea, 0x4d, 0x04,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
|
||||
0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
|
||||
0x09, 0x09, 0x09, 0x09,
|
||||
],
|
||||
ask: [
|
||||
0xeb, 0xbb, 0x40, 0xa9, 0x80, 0xba, 0x3b, 0x88, 0x60, 0x94, 0x8d, 0x01, 0x1e, 0x1b,
|
||||
0xfb, 0x4a, 0xff, 0xe1, 0x6c, 0x65, 0x2e, 0x90, 0xe9, 0x82, 0x58, 0x30, 0x2f, 0x44,
|
||||
0x64, 0xc9, 0x1e, 0x0c,
|
||||
],
|
||||
nsk: [
|
||||
0x68, 0x43, 0x1b, 0x19, 0x91, 0x04, 0x21, 0x52, 0x00, 0xb9, 0x5e, 0xe5, 0xcb, 0x71,
|
||||
0xbf, 0x8b, 0x88, 0x3a, 0x3e, 0x95, 0xb7, 0x98, 0x9c, 0xad, 0x19, 0x70, 0x63, 0x14,
|
||||
0x1e, 0xbb, 0xfd, 0x00,
|
||||
],
|
||||
ovk: [
|
||||
0x57, 0x34, 0x67, 0xa7, 0xb3, 0x0e, 0xad, 0x6c, 0xcc, 0x50, 0x47, 0x44, 0xca, 0x9e,
|
||||
0x1a, 0x28, 0x1a, 0x0d, 0x1a, 0x08, 0x73, 0x8b, 0x06, 0xa0, 0x68, 0x4f, 0xea, 0xcd,
|
||||
0x1e, 0x9d, 0x12, 0x6d,
|
||||
],
|
||||
ak: [
|
||||
0x71, 0xc3, 0x52, 0x3e, 0xec, 0xa3, 0x53, 0x11, 0xfb, 0xd5, 0xd7, 0xe7, 0xd7, 0x0b,
|
||||
0x70, 0x9d, 0x6c, 0x35, 0xa2, 0x4f, 0x26, 0x2b, 0x34, 0xbf, 0x64, 0x05, 0x9b, 0xf2,
|
||||
0xc0, 0x2e, 0x0b, 0xa8,
|
||||
],
|
||||
nk: [
|
||||
0x62, 0x44, 0x00, 0x10, 0x3b, 0x65, 0x69, 0xb7, 0x35, 0x8f, 0xe8, 0x0f, 0x6f, 0x6c,
|
||||
0xad, 0x43, 0x25, 0xde, 0xfd, 0xa9, 0xd9, 0x49, 0x9c, 0x2b, 0x8f, 0x88, 0x6a, 0x62,
|
||||
0x69, 0xa2, 0xaa, 0x52,
|
||||
],
|
||||
ivk: [
|
||||
0xdb, 0x95, 0xea, 0x8b, 0xd9, 0xf9, 0x3d, 0x41, 0xb5, 0xab, 0x2b, 0xeb, 0xc9, 0x1a,
|
||||
0x38, 0xed, 0xd5, 0x27, 0x08, 0x3e, 0x2a, 0x6e, 0xf9, 0xf3, 0xc2, 0x97, 0x02, 0xd5,
|
||||
0xff, 0x89, 0xed, 0x00,
|
||||
],
|
||||
default_d: [
|
||||
0x23, 0x3c, 0x4a, 0xb8, 0x86, 0xa5, 0x5e, 0x3b, 0xa3, 0x74, 0xc0,
|
||||
],
|
||||
default_pk_d: [
|
||||
0xb6, 0x8e, 0x9e, 0xe0, 0xc0, 0x67, 0x8d, 0x7b, 0x30, 0x36, 0x93, 0x1c, 0x83, 0x1a,
|
||||
0x25, 0x25, 0x5f, 0x7e, 0xe4, 0x87, 0x38, 0x5a, 0x30, 0x31, 0x6e, 0x15, 0xf6, 0x48,
|
||||
0x2b, 0x87, 0x4f, 0xda,
|
||||
],
|
||||
note_v: 17811330145809239872,
|
||||
note_r: [
|
||||
0x6e, 0xbb, 0xed, 0x74, 0x36, 0x19, 0xa2, 0x56, 0xf9, 0xad, 0x2e, 0x85, 0x88, 0x0c,
|
||||
0xfa, 0xa9, 0x09, 0x8a, 0x5f, 0xdb, 0x16, 0x29, 0x99, 0x0d, 0x9a, 0x7d, 0x3b, 0xb9,
|
||||
0x3f, 0xc9, 0x00, 0x03,
|
||||
],
|
||||
note_cm: [
|
||||
0xd3, 0x76, 0xa7, 0xbe, 0xe8, 0xce, 0x67, 0xf4, 0xef, 0xde, 0x56, 0xaa, 0x77, 0xcf,
|
||||
0x64, 0x41, 0x9b, 0x0e, 0x55, 0x0a, 0xbb, 0xcb, 0x8e, 0x2b, 0xcb, 0xda, 0x8b, 0x63,
|
||||
0xe4, 0x1d, 0xeb, 0x37,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
for tv in test_vectors {
|
||||
let mut ask_repr = FsRepr::default();
|
||||
let mut nsk_repr = FsRepr::default();
|
||||
ask_repr.read_le(&tv.ask[..]).unwrap();
|
||||
nsk_repr.read_le(&tv.nsk[..]).unwrap();
|
||||
let nsk = <Bls12 as JubjubEngine>::Fs::from_repr(nsk_repr).unwrap();
|
||||
|
||||
let ak = JUBJUB
|
||||
.generator(FixedGenerators::SpendingKeyGenerator)
|
||||
.mul(ask_repr.clone(), &JUBJUB);
|
||||
{
|
||||
let mut vec = Vec::new();
|
||||
ak.write(&mut vec).unwrap();
|
||||
assert_eq!(&vec, &tv.ak);
|
||||
}
|
||||
{
|
||||
let mut ak = [0u8; 32];
|
||||
librustzcash_ask_to_ak(&tv.ask, &mut ak);
|
||||
assert_eq!(&ak, &tv.ak);
|
||||
}
|
||||
|
||||
let pgk = ProofGenerationKey { ak, nsk };
|
||||
let fvk = pgk.into_viewing_key(&JUBJUB);
|
||||
{
|
||||
let mut vec = Vec::new();
|
||||
fvk.nk.write(&mut vec).unwrap();
|
||||
assert_eq!(&vec, &tv.nk);
|
||||
}
|
||||
{
|
||||
let mut nk = [0u8; 32];
|
||||
librustzcash_nsk_to_nk(&tv.nsk, &mut nk);
|
||||
assert_eq!(&nk, &tv.nk);
|
||||
}
|
||||
|
||||
{
|
||||
let mut vec = Vec::new();
|
||||
fvk.ivk().into_repr().write_le(&mut vec).unwrap();
|
||||
assert_eq!(&vec, &tv.ivk);
|
||||
}
|
||||
{
|
||||
let mut ivk = [0u8; 32];
|
||||
librustzcash_crh_ivk(&tv.ak, &tv.nk, &mut ivk);
|
||||
assert_eq!(&ivk, &tv.ivk);
|
||||
}
|
||||
|
||||
let diversifier = Diversifier(tv.default_d);
|
||||
assert!(librustzcash_check_diversifier(&tv.default_d));
|
||||
|
||||
let addr = fvk.into_payment_address(diversifier, &JUBJUB).unwrap();
|
||||
{
|
||||
let mut vec = Vec::new();
|
||||
addr.pk_d.write(&mut vec).unwrap();
|
||||
assert_eq!(&vec, &tv.default_pk_d);
|
||||
}
|
||||
{
|
||||
let mut default_pk_d = [0u8; 32];
|
||||
librustzcash_ivk_to_pkd(&tv.ivk, &tv.default_d, &mut default_pk_d);
|
||||
assert_eq!(&default_pk_d, &tv.default_pk_d);
|
||||
}
|
||||
|
||||
let mut note_r_repr = FsRepr::default();
|
||||
note_r_repr.read_le(&tv.note_r[..]).unwrap();
|
||||
let note_r = <Bls12 as JubjubEngine>::Fs::from_repr(note_r_repr).unwrap();
|
||||
let note = addr.create_note(tv.note_v, note_r, &JUBJUB).unwrap();
|
||||
{
|
||||
let mut vec = Vec::new();
|
||||
note.cm(&JUBJUB).into_repr().write_le(&mut vec).unwrap();
|
||||
assert_eq!(&vec, &tv.note_cm);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
use sapling_crypto::jubjub::{FixedGenerators, JubjubParams};
|
||||
|
||||
use super::JUBJUB;
|
||||
|
||||
mod key_agreement;
|
||||
mod key_components;
|
||||
mod notes;
|
||||
mod signatures;
|
||||
|
||||
#[test]
|
||||
fn sapling_generators() {
|
||||
struct SaplingGenerators {
|
||||
skb: [u8; 32],
|
||||
pkb: [u8; 32],
|
||||
npb: [u8; 32],
|
||||
wprb: [u8; 32],
|
||||
vcvb: [u8; 32],
|
||||
vcrb: [u8; 32],
|
||||
};
|
||||
|
||||
// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_generators.py
|
||||
let sapling_generators = SaplingGenerators {
|
||||
skb: [
|
||||
0x30, 0xb5, 0xf2, 0xaa, 0xad, 0x32, 0x56, 0x30, 0xbc, 0xdd, 0xdb, 0xce, 0x4d, 0x67,
|
||||
0x65, 0x6d, 0x05, 0xfd, 0x1c, 0xc2, 0xd0, 0x37, 0xbb, 0x53, 0x75, 0xb6, 0xe9, 0x6d,
|
||||
0x9e, 0x01, 0xa1, 0xd7,
|
||||
],
|
||||
pkb: [
|
||||
0xe7, 0xe8, 0x5d, 0xe0, 0xf7, 0xf9, 0x7a, 0x46, 0xd2, 0x49, 0xa1, 0xf5, 0xea, 0x51,
|
||||
0xdf, 0x50, 0xcc, 0x48, 0x49, 0x0f, 0x84, 0x01, 0xc9, 0xde, 0x7a, 0x2a, 0xdf, 0x18,
|
||||
0x07, 0xd1, 0xb6, 0xd4,
|
||||
],
|
||||
npb: [
|
||||
0x65, 0x00, 0x2b, 0xc7, 0x36, 0xfa, 0xf7, 0xa3, 0x42, 0x2e, 0xff, 0xff, 0xe8, 0xb8,
|
||||
0x55, 0xe1, 0x8f, 0xba, 0x96, 0xa0, 0x15, 0x8a, 0x9e, 0xfc, 0xa5, 0x84, 0xbf, 0x40,
|
||||
0x54, 0x9d, 0x36, 0xe1,
|
||||
],
|
||||
wprb: [
|
||||
0xac, 0x77, 0x6c, 0x79, 0x65, 0x63, 0xfc, 0xd4, 0x4c, 0xc4, 0x9c, 0xfa, 0xea, 0x8b,
|
||||
0xb7, 0x96, 0x95, 0x2c, 0x26, 0x6e, 0x47, 0x77, 0x9d, 0x94, 0x57, 0x4c, 0x10, 0xad,
|
||||
0x01, 0x75, 0x4b, 0x11,
|
||||
],
|
||||
vcvb: [
|
||||
0xd7, 0xc8, 0x67, 0x06, 0xf5, 0x81, 0x7a, 0xa7, 0x18, 0xcd, 0x1c, 0xfa, 0xd0, 0x32,
|
||||
0x33, 0xbc, 0xd6, 0x4a, 0x77, 0x89, 0xfd, 0x94, 0x22, 0xd3, 0xb1, 0x7a, 0xf6, 0x82,
|
||||
0x3a, 0x7e, 0x6a, 0xc6,
|
||||
],
|
||||
vcrb: [
|
||||
0x8b, 0x6a, 0x0b, 0x38, 0xb9, 0xfa, 0xae, 0x3c, 0x3b, 0x80, 0x3b, 0x47, 0xb0, 0xf1,
|
||||
0x46, 0xad, 0x50, 0xab, 0x22, 0x1e, 0x6e, 0x2a, 0xfb, 0xe6, 0xdb, 0xde, 0x45, 0xcb,
|
||||
0xa9, 0xd3, 0x81, 0xed,
|
||||
],
|
||||
};
|
||||
|
||||
{
|
||||
let mut vec = Vec::new();
|
||||
let p = JUBJUB.generator(FixedGenerators::SpendingKeyGenerator);
|
||||
p.write(&mut vec).unwrap();
|
||||
assert_eq!(&vec, &sapling_generators.skb);
|
||||
}
|
||||
|
||||
{
|
||||
let mut vec = Vec::new();
|
||||
let p = JUBJUB.generator(FixedGenerators::ProofGenerationKey);
|
||||
p.write(&mut vec).unwrap();
|
||||
assert_eq!(&vec, &sapling_generators.pkb);
|
||||
}
|
||||
|
||||
{
|
||||
let mut vec = Vec::new();
|
||||
let p = JUBJUB.generator(FixedGenerators::NullifierPosition);
|
||||
p.write(&mut vec).unwrap();
|
||||
assert_eq!(&vec, &sapling_generators.npb);
|
||||
}
|
||||
|
||||
{
|
||||
let mut vec = Vec::new();
|
||||
let p = JUBJUB.generator(FixedGenerators::NoteCommitmentRandomness);
|
||||
p.write(&mut vec).unwrap();
|
||||
assert_eq!(&vec, &sapling_generators.wprb);
|
||||
}
|
||||
|
||||
{
|
||||
let mut vec = Vec::new();
|
||||
let p = JUBJUB.generator(FixedGenerators::ValueCommitmentValue);
|
||||
p.write(&mut vec).unwrap();
|
||||
assert_eq!(&vec, &sapling_generators.vcvb);
|
||||
}
|
||||
|
||||
{
|
||||
let mut vec = Vec::new();
|
||||
let p = JUBJUB.generator(FixedGenerators::ValueCommitmentRandomness);
|
||||
p.write(&mut vec).unwrap();
|
||||
assert_eq!(&vec, &sapling_generators.vcrb);
|
||||
}
|
||||
}
|
@ -1,673 +0,0 @@
|
||||
use librustzcash_sapling_compute_cm;
|
||||
use librustzcash_sapling_compute_nf;
|
||||
|
||||
#[test]
|
||||
fn notes() {
|
||||
#![allow(dead_code)]
|
||||
struct TestVector {
|
||||
sk: [u8; 32],
|
||||
ask: [u8; 32],
|
||||
nsk: [u8; 32],
|
||||
ovk: [u8; 32],
|
||||
ak: [u8; 32],
|
||||
nk: [u8; 32],
|
||||
ivk: [u8; 32],
|
||||
default_d: [u8; 11],
|
||||
default_pk_d: [u8; 32],
|
||||
note_v: u64,
|
||||
note_r: [u8; 32],
|
||||
note_cm: [u8; 32],
|
||||
note_pos: u64,
|
||||
note_nf: [u8; 32],
|
||||
};
|
||||
|
||||
// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_key_components.py
|
||||
let test_vectors = vec![
|
||||
TestVector {
|
||||
sk: [
|
||||
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,
|
||||
],
|
||||
ask: [
|
||||
0x85, 0x48, 0xa1, 0x4a, 0x47, 0x3e, 0xa5, 0x47, 0xaa, 0x23, 0x78, 0x40, 0x20, 0x44,
|
||||
0xf8, 0x18, 0xcf, 0x19, 0x11, 0xcf, 0x5d, 0xd2, 0x05, 0x4f, 0x67, 0x83, 0x45, 0xf0,
|
||||
0x0d, 0x0e, 0x88, 0x06,
|
||||
],
|
||||
nsk: [
|
||||
0x30, 0x11, 0x4e, 0xa0, 0xdd, 0x0b, 0xb6, 0x1c, 0xf0, 0xea, 0xea, 0xb6, 0xec, 0x33,
|
||||
0x31, 0xf5, 0x81, 0xb0, 0x42, 0x5e, 0x27, 0x33, 0x85, 0x01, 0x26, 0x2d, 0x7e, 0xac,
|
||||
0x74, 0x5e, 0x6e, 0x05,
|
||||
],
|
||||
ovk: [
|
||||
0x98, 0xd1, 0x69, 0x13, 0xd9, 0x9b, 0x04, 0x17, 0x7c, 0xab, 0xa4, 0x4f, 0x6e, 0x4d,
|
||||
0x22, 0x4e, 0x03, 0xb5, 0xac, 0x03, 0x1d, 0x7c, 0xe4, 0x5e, 0x86, 0x51, 0x38, 0xe1,
|
||||
0xb9, 0x96, 0xd6, 0x3b,
|
||||
],
|
||||
ak: [
|
||||
0xf3, 0x44, 0xec, 0x38, 0x0f, 0xe1, 0x27, 0x3e, 0x30, 0x98, 0xc2, 0x58, 0x8c, 0x5d,
|
||||
0x3a, 0x79, 0x1f, 0xd7, 0xba, 0x95, 0x80, 0x32, 0x76, 0x07, 0x77, 0xfd, 0x0e, 0xfa,
|
||||
0x8e, 0xf1, 0x16, 0x20,
|
||||
],
|
||||
nk: [
|
||||
0xf7, 0xcf, 0x9e, 0x77, 0xf2, 0xe5, 0x86, 0x83, 0x38, 0x3c, 0x15, 0x19, 0xac, 0x7b,
|
||||
0x06, 0x2d, 0x30, 0x04, 0x0e, 0x27, 0xa7, 0x25, 0xfb, 0x88, 0xfb, 0x19, 0xa9, 0x78,
|
||||
0xbd, 0x3f, 0xd6, 0xba,
|
||||
],
|
||||
ivk: [
|
||||
0xb7, 0x0b, 0x7c, 0xd0, 0xed, 0x03, 0xcb, 0xdf, 0xd7, 0xad, 0xa9, 0x50, 0x2e, 0xe2,
|
||||
0x45, 0xb1, 0x3e, 0x56, 0x9d, 0x54, 0xa5, 0x71, 0x9d, 0x2d, 0xaa, 0x0f, 0x5f, 0x14,
|
||||
0x51, 0x47, 0x92, 0x04,
|
||||
],
|
||||
default_d: [
|
||||
0xf1, 0x9d, 0x9b, 0x79, 0x7e, 0x39, 0xf3, 0x37, 0x44, 0x58, 0x39,
|
||||
],
|
||||
default_pk_d: [
|
||||
0xdb, 0x4c, 0xd2, 0xb0, 0xaa, 0xc4, 0xf7, 0xeb, 0x8c, 0xa1, 0x31, 0xf1, 0x65, 0x67,
|
||||
0xc4, 0x45, 0xa9, 0x55, 0x51, 0x26, 0xd3, 0xc2, 0x9f, 0x14, 0xe3, 0xd7, 0x76, 0xe8,
|
||||
0x41, 0xae, 0x74, 0x15,
|
||||
],
|
||||
note_v: 0,
|
||||
note_r: [
|
||||
0x39, 0x17, 0x6d, 0xac, 0x39, 0xac, 0xe4, 0x98, 0x0e, 0xcc, 0x8d, 0x77, 0x8e, 0x89,
|
||||
0x86, 0x02, 0x55, 0xec, 0x36, 0x15, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
],
|
||||
note_cm: [
|
||||
0xcb, 0x3c, 0xf9, 0x15, 0x32, 0x70, 0xd5, 0x7e, 0xb9, 0x14, 0xc6, 0xc2, 0xbc, 0xc0,
|
||||
0x18, 0x50, 0xc9, 0xfe, 0xd4, 0x4f, 0xce, 0x08, 0x06, 0x27, 0x8f, 0x08, 0x3e, 0xf2,
|
||||
0xdd, 0x07, 0x64, 0x39,
|
||||
],
|
||||
note_pos: 0,
|
||||
note_nf: [
|
||||
0x44, 0xfa, 0xd6, 0x56, 0x4f, 0xfd, 0xec, 0x9f, 0xa1, 0x9c, 0x43, 0xa2, 0x8f, 0x86,
|
||||
0x1d, 0x5e, 0xbf, 0x60, 0x23, 0x46, 0x00, 0x7d, 0xe7, 0x62, 0x67, 0xd9, 0x75, 0x27,
|
||||
0x47, 0xab, 0x40, 0x63,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01,
|
||||
],
|
||||
ask: [
|
||||
0xc9, 0x43, 0x56, 0x29, 0xbf, 0x8b, 0xff, 0xe5, 0x5e, 0x73, 0x35, 0xec, 0x07, 0x77,
|
||||
0x18, 0xba, 0x60, 0xba, 0x28, 0xd7, 0xac, 0x37, 0x94, 0xb7, 0x4f, 0x51, 0x2c, 0x31,
|
||||
0xaf, 0x0a, 0x53, 0x04,
|
||||
],
|
||||
nsk: [
|
||||
0x11, 0xac, 0xc2, 0xea, 0xd0, 0x7b, 0x5f, 0x00, 0x8c, 0x1f, 0x0f, 0x09, 0x0c, 0xc8,
|
||||
0xdd, 0xf3, 0x35, 0x23, 0x6f, 0xf4, 0xb2, 0x53, 0xc6, 0x49, 0x56, 0x95, 0xe9, 0xd6,
|
||||
0x39, 0xda, 0xcd, 0x08,
|
||||
],
|
||||
ovk: [
|
||||
0x3b, 0x94, 0x62, 0x10, 0xce, 0x6d, 0x1b, 0x16, 0x92, 0xd7, 0x39, 0x2a, 0xc8, 0x4a,
|
||||
0x8b, 0xc8, 0xf0, 0x3b, 0x72, 0x72, 0x3c, 0x7d, 0x36, 0x72, 0x1b, 0x80, 0x9a, 0x79,
|
||||
0xc9, 0xd6, 0xe4, 0x5b,
|
||||
],
|
||||
ak: [
|
||||
0x82, 0xff, 0x5e, 0xff, 0xc5, 0x27, 0xae, 0x84, 0x02, 0x0b, 0xf2, 0xd3, 0x52, 0x01,
|
||||
0xc1, 0x02, 0x19, 0x13, 0x19, 0x47, 0xff, 0x4b, 0x96, 0xf8, 0x81, 0xa4, 0x5f, 0x2e,
|
||||
0x8a, 0xe3, 0x05, 0x18,
|
||||
],
|
||||
nk: [
|
||||
0xc4, 0x53, 0x4d, 0x84, 0x8b, 0xb9, 0x18, 0xcf, 0x4a, 0x7f, 0x8b, 0x98, 0x74, 0x0a,
|
||||
0xb3, 0xcc, 0xee, 0x58, 0x67, 0x95, 0xff, 0x4d, 0xf6, 0x45, 0x47, 0xa8, 0x88, 0x8a,
|
||||
0x6c, 0x74, 0x15, 0xd2,
|
||||
],
|
||||
ivk: [
|
||||
0xc5, 0x18, 0x38, 0x44, 0x66, 0xb2, 0x69, 0x88, 0xb5, 0x10, 0x90, 0x67, 0x41, 0x8d,
|
||||
0x19, 0x2d, 0x9d, 0x6b, 0xd0, 0xd9, 0x23, 0x22, 0x05, 0xd7, 0x74, 0x18, 0xc2, 0x40,
|
||||
0xfc, 0x68, 0xa4, 0x06,
|
||||
],
|
||||
default_d: [
|
||||
0xae, 0xf1, 0x80, 0xf6, 0xe3, 0x4e, 0x35, 0x4b, 0x88, 0x8f, 0x81,
|
||||
],
|
||||
default_pk_d: [
|
||||
0xa6, 0xb1, 0x3e, 0xa3, 0x36, 0xdd, 0xb7, 0xa6, 0x7b, 0xb0, 0x9a, 0x0e, 0x68, 0xe9,
|
||||
0xd3, 0xcf, 0xb3, 0x92, 0x10, 0x83, 0x1e, 0xa3, 0xa2, 0x96, 0xba, 0x09, 0xa9, 0x22,
|
||||
0x06, 0x0f, 0xd3, 0x8b,
|
||||
],
|
||||
note_v: 12227227834928555328,
|
||||
note_r: [
|
||||
0x47, 0x8b, 0xa0, 0xee, 0x6e, 0x1a, 0x75, 0xb6, 0x00, 0x03, 0x6f, 0x26, 0xf1, 0x8b,
|
||||
0x70, 0x15, 0xab, 0x55, 0x6b, 0xed, 0xdf, 0x8b, 0x96, 0x02, 0x38, 0x86, 0x9f, 0x89,
|
||||
0xdd, 0x80, 0x4e, 0x06,
|
||||
],
|
||||
note_cm: [
|
||||
0xb5, 0x78, 0x93, 0x50, 0x0b, 0xfb, 0x85, 0xdf, 0x2e, 0x8b, 0x01, 0xac, 0x45, 0x2f,
|
||||
0x89, 0xe1, 0x0e, 0x26, 0x6b, 0xcf, 0xa3, 0x1c, 0x31, 0xb2, 0x9a, 0x53, 0xae, 0x72,
|
||||
0xca, 0xd4, 0x69, 0x50,
|
||||
],
|
||||
note_pos: 763714296,
|
||||
note_nf: [
|
||||
0x67, 0x9e, 0xb0, 0xc3, 0xa7, 0x57, 0xe2, 0xae, 0x83, 0xcd, 0xb4, 0x2a, 0x1a, 0xb2,
|
||||
0x59, 0xd7, 0x83, 0x88, 0x31, 0x54, 0x19, 0xad, 0xc7, 0x1d, 0x2e, 0x37, 0x63, 0x17,
|
||||
0x4c, 0x2e, 0x9d, 0x93,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02,
|
||||
],
|
||||
ask: [
|
||||
0xee, 0x1c, 0x3d, 0x7e, 0xfe, 0x0a, 0x78, 0x06, 0x3d, 0x6a, 0xf3, 0xd9, 0xd8, 0x12,
|
||||
0x12, 0xaf, 0x47, 0xb7, 0xc1, 0xb7, 0x61, 0xf8, 0x5c, 0xcb, 0x06, 0x6f, 0xc1, 0x1a,
|
||||
0x6a, 0x42, 0x17, 0x03,
|
||||
],
|
||||
nsk: [
|
||||
0x1d, 0x3b, 0x71, 0x37, 0x55, 0xd7, 0x48, 0x75, 0xe8, 0xea, 0x38, 0xfd, 0x16, 0x6e,
|
||||
0x76, 0xc6, 0x2a, 0x42, 0x50, 0x21, 0x6e, 0x6b, 0xbf, 0xe4, 0x8a, 0x5e, 0x2e, 0xab,
|
||||
0xad, 0x11, 0x7f, 0x0b,
|
||||
],
|
||||
ovk: [
|
||||
0x8b, 0xf4, 0x39, 0x0e, 0x28, 0xdd, 0xc9, 0x5b, 0x83, 0x02, 0xc3, 0x81, 0xd5, 0x81,
|
||||
0x0b, 0x84, 0xba, 0x8e, 0x60, 0x96, 0xe5, 0xa7, 0x68, 0x22, 0x77, 0x4f, 0xd4, 0x9f,
|
||||
0x49, 0x1e, 0x8f, 0x49,
|
||||
],
|
||||
ak: [
|
||||
0xab, 0x83, 0x57, 0x4e, 0xb5, 0xde, 0x85, 0x9a, 0x0a, 0xb8, 0x62, 0x9d, 0xec, 0x34,
|
||||
0xc7, 0xbe, 0xe8, 0xc3, 0xfc, 0x74, 0xdf, 0xa0, 0xb1, 0x9a, 0x3a, 0x74, 0x68, 0xd1,
|
||||
0x5d, 0xca, 0x64, 0xc6,
|
||||
],
|
||||
nk: [
|
||||
0x95, 0xd5, 0x80, 0x53, 0xe0, 0x59, 0x2e, 0x4a, 0x16, 0x9c, 0xc0, 0xb7, 0x92, 0x8a,
|
||||
0xaa, 0xc3, 0xde, 0x24, 0xef, 0x15, 0x31, 0xaa, 0x9e, 0xb6, 0xf4, 0xab, 0x93, 0x91,
|
||||
0x4d, 0xa8, 0xa0, 0x6e,
|
||||
],
|
||||
ivk: [
|
||||
0x47, 0x1c, 0x24, 0xa3, 0xdc, 0x87, 0x30, 0xe7, 0x50, 0x36, 0xc0, 0xa9, 0x5f, 0x3e,
|
||||
0x2f, 0x7d, 0xd1, 0xbe, 0x6f, 0xb9, 0x3a, 0xd2, 0x95, 0x92, 0x20, 0x3d, 0xef, 0x30,
|
||||
0x41, 0x95, 0x45, 0x05,
|
||||
],
|
||||
default_d: [
|
||||
0x75, 0x99, 0xf0, 0xbf, 0x9b, 0x57, 0xcd, 0x2d, 0xc2, 0x99, 0xb6,
|
||||
],
|
||||
default_pk_d: [
|
||||
0x66, 0x14, 0x17, 0x39, 0x51, 0x4b, 0x28, 0xf0, 0x5d, 0xef, 0x8a, 0x18, 0xee, 0xee,
|
||||
0x5e, 0xed, 0x4d, 0x44, 0xc6, 0x22, 0x5c, 0x3c, 0x65, 0xd8, 0x8d, 0xd9, 0x90, 0x77,
|
||||
0x08, 0x01, 0x2f, 0x5a,
|
||||
],
|
||||
note_v: 6007711596147559040,
|
||||
note_r: [
|
||||
0x14, 0x7c, 0xf2, 0xb5, 0x1b, 0x4c, 0x7c, 0x63, 0xcb, 0x77, 0xb9, 0x9e, 0x8b, 0x78,
|
||||
0x3e, 0x5b, 0x51, 0x11, 0xdb, 0x0a, 0x7c, 0xa0, 0x4d, 0x6c, 0x01, 0x4a, 0x1d, 0x7d,
|
||||
0xa8, 0x3b, 0xae, 0x0a,
|
||||
],
|
||||
note_cm: [
|
||||
0xdb, 0x85, 0xa7, 0x0a, 0x98, 0x43, 0x7f, 0x73, 0x16, 0x7f, 0xc3, 0x32, 0xd5, 0xb7,
|
||||
0xb7, 0x40, 0x82, 0x96, 0x66, 0x17, 0x70, 0xb1, 0x01, 0xb0, 0xaa, 0x87, 0x83, 0x9f,
|
||||
0x4e, 0x55, 0xf1, 0x51,
|
||||
],
|
||||
note_pos: 1527428592,
|
||||
note_nf: [
|
||||
0xe9, 0x8f, 0x6a, 0x8f, 0x34, 0xff, 0x49, 0x80, 0x59, 0xb3, 0xc7, 0x31, 0xb9, 0x1f,
|
||||
0x45, 0x11, 0x08, 0xc4, 0x95, 0x4d, 0x91, 0x94, 0x84, 0x36, 0x1c, 0xf9, 0xb4, 0x8f,
|
||||
0x59, 0xae, 0x1d, 0x14,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03,
|
||||
],
|
||||
ask: [
|
||||
0x00, 0xc3, 0xa1, 0xe1, 0xca, 0x8f, 0x4e, 0x04, 0x80, 0xee, 0x1e, 0xe9, 0x0c, 0xa7,
|
||||
0x51, 0x78, 0x79, 0xd3, 0xfc, 0x5c, 0x81, 0x5c, 0x09, 0x03, 0xe5, 0xee, 0xbc, 0x94,
|
||||
0xbb, 0x80, 0x95, 0x03,
|
||||
],
|
||||
nsk: [
|
||||
0xe6, 0x62, 0x85, 0xa5, 0xe9, 0xb6, 0x5e, 0x15, 0x7a, 0xd2, 0xfc, 0xd5, 0x43, 0xda,
|
||||
0xd9, 0x8c, 0x67, 0xa5, 0x8a, 0xbd, 0xf2, 0x87, 0xe0, 0x55, 0x06, 0xbd, 0x1c, 0x2e,
|
||||
0x59, 0xb0, 0x72, 0x0b,
|
||||
],
|
||||
ovk: [
|
||||
0x14, 0x76, 0x78, 0xe0, 0x55, 0x3b, 0x97, 0x82, 0x93, 0x47, 0x64, 0x7c, 0x5b, 0xc7,
|
||||
0xda, 0xb4, 0xcc, 0x22, 0x02, 0xb5, 0x4e, 0xc2, 0x9f, 0xd3, 0x1a, 0x3d, 0xe6, 0xbe,
|
||||
0x08, 0x25, 0xfc, 0x5e,
|
||||
],
|
||||
ak: [
|
||||
0x3c, 0x9c, 0xde, 0x7e, 0x5d, 0x0d, 0x38, 0xa8, 0x61, 0x0f, 0xaa, 0xdb, 0xcf, 0x4c,
|
||||
0x34, 0x3f, 0x5d, 0x3c, 0xfa, 0x31, 0x55, 0xa5, 0xb9, 0x46, 0x61, 0xa6, 0x75, 0x3e,
|
||||
0x96, 0xe8, 0x84, 0xea,
|
||||
],
|
||||
nk: [
|
||||
0xb7, 0x7d, 0x36, 0xf5, 0x08, 0x94, 0x1d, 0xbd, 0x61, 0xcf, 0xd0, 0xf1, 0x59, 0xee,
|
||||
0x05, 0xcf, 0xaa, 0x78, 0xa2, 0x6c, 0x94, 0x92, 0x90, 0x38, 0x06, 0xd8, 0x3b, 0x59,
|
||||
0x8d, 0x3c, 0x1c, 0x2a,
|
||||
],
|
||||
ivk: [
|
||||
0x63, 0x6a, 0xa9, 0x64, 0xbf, 0xc2, 0x3c, 0xe4, 0xb1, 0xfc, 0xf7, 0xdf, 0xc9, 0x91,
|
||||
0x79, 0xdd, 0xc4, 0x06, 0xff, 0x55, 0x40, 0x0c, 0x92, 0x95, 0xac, 0xfc, 0x14, 0xf0,
|
||||
0x31, 0xc7, 0x26, 0x00,
|
||||
],
|
||||
default_d: [
|
||||
0x1b, 0x81, 0x61, 0x4f, 0x1d, 0xad, 0xea, 0x0f, 0x8d, 0x0a, 0x58,
|
||||
],
|
||||
default_pk_d: [
|
||||
0x25, 0xeb, 0x55, 0xfc, 0xcf, 0x76, 0x1f, 0xc6, 0x4e, 0x85, 0xa5, 0x88, 0xef, 0xe6,
|
||||
0xea, 0xd7, 0x83, 0x2f, 0xb1, 0xf0, 0xf7, 0xa8, 0x31, 0x65, 0x89, 0x5b, 0xdf, 0xf9,
|
||||
0x42, 0x92, 0x5f, 0x5c,
|
||||
],
|
||||
note_v: 18234939431076114368,
|
||||
note_r: [
|
||||
0x34, 0xa4, 0xb2, 0xa9, 0x14, 0x4f, 0xf5, 0xea, 0x54, 0xef, 0xee, 0x87, 0xcf, 0x90,
|
||||
0x1b, 0x5b, 0xed, 0x5e, 0x35, 0xd2, 0x1f, 0xbb, 0xd7, 0x88, 0xd5, 0xbd, 0x9d, 0x83,
|
||||
0x3e, 0x11, 0x28, 0x04,
|
||||
],
|
||||
note_cm: [
|
||||
0xe0, 0x8c, 0xe4, 0x82, 0xb3, 0xa8, 0xfb, 0x3b, 0x35, 0xcc, 0xdb, 0xe3, 0x43, 0x37,
|
||||
0xbd, 0x10, 0x5d, 0x88, 0x39, 0x21, 0x2e, 0x0d, 0x16, 0x44, 0xb9, 0xd5, 0x5c, 0xaa,
|
||||
0x60, 0xd1, 0x9b, 0x6c,
|
||||
],
|
||||
note_pos: 2291142888,
|
||||
note_nf: [
|
||||
0x55, 0x47, 0xaa, 0x12, 0xff, 0x80, 0xa6, 0xb3, 0x30, 0x4e, 0x3b, 0x05, 0x86, 0x56,
|
||||
0x47, 0x2a, 0xbd, 0x2c, 0x81, 0x83, 0xb5, 0x9d, 0x07, 0x37, 0xb9, 0x3c, 0xee, 0x75,
|
||||
0x8b, 0xec, 0x47, 0xa1,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04,
|
||||
],
|
||||
ask: [
|
||||
0x82, 0x36, 0xd1, 0x9d, 0x32, 0x05, 0xd8, 0x55, 0x43, 0xa0, 0x68, 0x11, 0x34, 0x3f,
|
||||
0x82, 0x7b, 0x65, 0x63, 0x77, 0x0a, 0x49, 0xaa, 0x4d, 0x0c, 0xa0, 0x08, 0x18, 0x05,
|
||||
0xd4, 0xc8, 0xea, 0x0d,
|
||||
],
|
||||
nsk: [
|
||||
0x7e, 0xc1, 0xef, 0x0b, 0xed, 0x82, 0x71, 0x82, 0x72, 0xf0, 0xf4, 0x4f, 0x01, 0x7c,
|
||||
0x48, 0x41, 0x74, 0x51, 0x3d, 0x66, 0x1d, 0xd1, 0x68, 0xaf, 0x02, 0xd2, 0x09, 0x2a,
|
||||
0x1d, 0x8a, 0x05, 0x07,
|
||||
],
|
||||
ovk: [
|
||||
0x1b, 0x6e, 0x75, 0xec, 0xe3, 0xac, 0xe8, 0xdb, 0xa6, 0xa5, 0x41, 0x0d, 0x9a, 0xd4,
|
||||
0x75, 0x56, 0x68, 0xe4, 0xb3, 0x95, 0x85, 0xd6, 0x35, 0xec, 0x1d, 0xa7, 0xc8, 0xdc,
|
||||
0xfd, 0x5f, 0xc4, 0xed,
|
||||
],
|
||||
ak: [
|
||||
0x55, 0xe8, 0x83, 0x89, 0xbb, 0x7e, 0x41, 0xde, 0x13, 0x0c, 0xfa, 0x51, 0xa8, 0x71,
|
||||
0x5f, 0xde, 0x01, 0xff, 0x9c, 0x68, 0x76, 0x64, 0x7f, 0x01, 0x75, 0xad, 0x34, 0xf0,
|
||||
0x58, 0xdd, 0xe0, 0x1a,
|
||||
],
|
||||
nk: [
|
||||
0x72, 0x5d, 0x4a, 0xd6, 0xa1, 0x50, 0x21, 0xcd, 0x1c, 0x48, 0xc5, 0xee, 0x19, 0xde,
|
||||
0x6c, 0x1e, 0x76, 0x8a, 0x2c, 0xc0, 0xa9, 0xa7, 0x30, 0xa0, 0x1b, 0xb2, 0x1c, 0x95,
|
||||
0xe3, 0xd9, 0xe4, 0x3c,
|
||||
],
|
||||
ivk: [
|
||||
0x67, 0xfa, 0x2b, 0xf7, 0xc6, 0x7d, 0x46, 0x58, 0x24, 0x3c, 0x31, 0x7c, 0x0c, 0xb4,
|
||||
0x1f, 0xd3, 0x20, 0x64, 0xdf, 0xd3, 0x70, 0x9f, 0xe0, 0xdc, 0xb7, 0x24, 0xf1, 0x4b,
|
||||
0xb0, 0x1a, 0x1d, 0x04,
|
||||
],
|
||||
default_d: [
|
||||
0xfc, 0xfb, 0x68, 0xa4, 0x0d, 0x4b, 0xc6, 0xa0, 0x4b, 0x09, 0xc4,
|
||||
],
|
||||
default_pk_d: [
|
||||
0x8b, 0x2a, 0x33, 0x7f, 0x03, 0x62, 0x2c, 0x24, 0xff, 0x38, 0x1d, 0x4c, 0x54, 0x6f,
|
||||
0x69, 0x77, 0xf9, 0x05, 0x22, 0xe9, 0x2f, 0xde, 0x44, 0xc9, 0xd1, 0xbb, 0x09, 0x97,
|
||||
0x14, 0xb9, 0xdb, 0x2b,
|
||||
],
|
||||
note_v: 12015423192295118080,
|
||||
note_r: [
|
||||
0xe5, 0x57, 0x85, 0x13, 0x55, 0x74, 0x7c, 0x09, 0xac, 0x59, 0x01, 0x3c, 0xbd, 0xe8,
|
||||
0x59, 0x80, 0x96, 0x4e, 0xc1, 0x84, 0x4d, 0x9c, 0x69, 0x67, 0xca, 0x0c, 0x02, 0x9c,
|
||||
0x84, 0x57, 0xbb, 0x04,
|
||||
],
|
||||
note_cm: [
|
||||
0xbd, 0xc8, 0x54, 0xbf, 0x3e, 0x7b, 0x00, 0x82, 0x1f, 0x3b, 0x8b, 0x85, 0x23, 0x8c,
|
||||
0xcf, 0x1e, 0x67, 0x15, 0xbf, 0xe7, 0x0b, 0x63, 0x2d, 0x04, 0x4b, 0x26, 0xfb, 0x2b,
|
||||
0xc7, 0x1b, 0x7f, 0x36,
|
||||
],
|
||||
note_pos: 3054857184,
|
||||
note_nf: [
|
||||
0x8a, 0x9a, 0xbd, 0xa3, 0xd4, 0xef, 0x85, 0xca, 0xf2, 0x2b, 0xfa, 0xf2, 0xc4, 0x8f,
|
||||
0x62, 0x38, 0x2a, 0x73, 0xa1, 0x62, 0x4e, 0xb8, 0xeb, 0x2b, 0xd0, 0x0d, 0x27, 0x03,
|
||||
0x01, 0xbf, 0x3d, 0x13,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05,
|
||||
],
|
||||
ask: [
|
||||
0xea, 0xe6, 0x88, 0x4d, 0x76, 0x4a, 0x05, 0x40, 0x61, 0xa8, 0xf1, 0xc0, 0x07, 0x6c,
|
||||
0x62, 0x4d, 0xcb, 0x73, 0x87, 0x89, 0xf7, 0xad, 0x1e, 0x74, 0x08, 0xe3, 0x1f, 0x24,
|
||||
0xdf, 0xc8, 0x26, 0x07,
|
||||
],
|
||||
nsk: [
|
||||
0xfb, 0xe6, 0x10, 0xf4, 0x2a, 0x41, 0x74, 0x9f, 0x9b, 0x6e, 0x6e, 0x4a, 0x54, 0xb5,
|
||||
0xa3, 0x2e, 0xbf, 0xe8, 0xf4, 0x38, 0x00, 0x88, 0x1b, 0xa6, 0xcd, 0x13, 0xed, 0x0b,
|
||||
0x05, 0x29, 0x46, 0x01,
|
||||
],
|
||||
ovk: [
|
||||
0xc6, 0xbc, 0x1f, 0x39, 0xf0, 0xd7, 0x86, 0x31, 0x4c, 0xb2, 0x0b, 0xf9, 0xab, 0x22,
|
||||
0x85, 0x40, 0x91, 0x35, 0x55, 0xf9, 0x70, 0x69, 0x6b, 0x6d, 0x7c, 0x77, 0xbb, 0x33,
|
||||
0x23, 0x28, 0x37, 0x2a,
|
||||
],
|
||||
ak: [
|
||||
0xe6, 0x82, 0x76, 0x59, 0x14, 0xe3, 0x86, 0x4c, 0x33, 0x9e, 0x57, 0x82, 0xb8, 0x55,
|
||||
0xc0, 0xfd, 0xf4, 0x0e, 0x0d, 0xfc, 0xed, 0xb9, 0xe7, 0xb4, 0x7b, 0xc9, 0x4b, 0x90,
|
||||
0xb3, 0xa4, 0xc9, 0x88,
|
||||
],
|
||||
nk: [
|
||||
0x82, 0x25, 0x6b, 0x95, 0x62, 0x3c, 0x67, 0x02, 0x4b, 0x44, 0x24, 0xd9, 0x14, 0x00,
|
||||
0xa3, 0x70, 0xe7, 0xac, 0x8e, 0x4d, 0x15, 0x48, 0x2a, 0x37, 0x59, 0xe0, 0x0d, 0x21,
|
||||
0x97, 0x49, 0xda, 0xee,
|
||||
],
|
||||
ivk: [
|
||||
0xea, 0x3f, 0x1d, 0x80, 0xe4, 0x30, 0x7c, 0xa7, 0x3b, 0x9f, 0x37, 0x80, 0x1f, 0x91,
|
||||
0xfb, 0xa8, 0x10, 0xcc, 0x41, 0xd2, 0x79, 0xfc, 0x29, 0xf5, 0x64, 0x23, 0x56, 0x54,
|
||||
0xa2, 0x17, 0x8e, 0x03,
|
||||
],
|
||||
default_d: [
|
||||
0xeb, 0x51, 0x98, 0x82, 0xad, 0x1e, 0x5c, 0xc6, 0x54, 0xcd, 0x59,
|
||||
],
|
||||
default_pk_d: [
|
||||
0x6b, 0x27, 0xda, 0xcc, 0xb5, 0xa8, 0x20, 0x7f, 0x53, 0x2d, 0x10, 0xca, 0x23, 0x8f,
|
||||
0x97, 0x86, 0x64, 0x8a, 0x11, 0xb5, 0x96, 0x6e, 0x51, 0xa2, 0xf7, 0xd8, 0x9e, 0x15,
|
||||
0xd2, 0x9b, 0x8f, 0xdf,
|
||||
],
|
||||
note_v: 5795906953514121792,
|
||||
note_r: [
|
||||
0x68, 0xf0, 0x61, 0x04, 0x60, 0x6b, 0x0c, 0x54, 0x49, 0x84, 0x5f, 0xf4, 0xc6, 0x5f,
|
||||
0x73, 0xe9, 0x0f, 0x45, 0xef, 0x5a, 0x43, 0xc9, 0xd7, 0x4c, 0xb2, 0xc8, 0x5c, 0xf5,
|
||||
0x6c, 0x94, 0xc0, 0x02,
|
||||
],
|
||||
note_cm: [
|
||||
0xe8, 0x26, 0x7d, 0x30, 0xac, 0x11, 0xc1, 0x00, 0xbc, 0x7a, 0x0f, 0xdf, 0x91, 0xf7,
|
||||
0x1d, 0x74, 0xc5, 0xbc, 0xf2, 0xe1, 0xef, 0x95, 0x66, 0x90, 0x44, 0x73, 0x01, 0x69,
|
||||
0xde, 0x1a, 0x5b, 0x4c,
|
||||
],
|
||||
note_pos: 3818571480,
|
||||
note_nf: [
|
||||
0x33, 0x2a, 0xd9, 0x9e, 0xb9, 0xe9, 0x77, 0xeb, 0x62, 0x7a, 0x12, 0x2d, 0xbf, 0xb2,
|
||||
0xf2, 0x5f, 0xe5, 0x88, 0xe5, 0x97, 0x75, 0x3e, 0xc5, 0x58, 0x0f, 0xf2, 0xbe, 0x20,
|
||||
0xb6, 0xc9, 0xa7, 0xe1,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06,
|
||||
],
|
||||
ask: [
|
||||
0xe8, 0xf8, 0x16, 0xb4, 0xbc, 0x08, 0xa7, 0xe5, 0x66, 0x75, 0x0c, 0xc2, 0x8a, 0xfe,
|
||||
0x82, 0xa4, 0xce, 0xa9, 0xc2, 0xbe, 0xf2, 0x44, 0xfa, 0x4b, 0x13, 0xc4, 0x73, 0x9b,
|
||||
0x28, 0x07, 0x4c, 0x0d,
|
||||
],
|
||||
nsk: [
|
||||
0x32, 0x61, 0x5b, 0x13, 0x7f, 0x28, 0x01, 0xed, 0x44, 0x6e, 0x48, 0x78, 0x1a, 0xb0,
|
||||
0x63, 0x45, 0x72, 0xe1, 0x8c, 0xfb, 0x06, 0x93, 0x72, 0x1b, 0x88, 0x03, 0xc0, 0x5b,
|
||||
0x82, 0x27, 0xd1, 0x07,
|
||||
],
|
||||
ovk: [
|
||||
0xf6, 0x2c, 0x05, 0xe8, 0x48, 0xa8, 0x73, 0xef, 0x88, 0x5e, 0x12, 0xb0, 0x8c, 0x5e,
|
||||
0x7c, 0xa2, 0xf3, 0x24, 0x24, 0xba, 0xcc, 0x75, 0x4c, 0xb6, 0x97, 0x50, 0x44, 0x4d,
|
||||
0x35, 0x5f, 0x51, 0x06,
|
||||
],
|
||||
ak: [
|
||||
0xff, 0x27, 0xdb, 0x07, 0x51, 0x94, 0x5d, 0x3e, 0xe4, 0xbe, 0x9c, 0xf1, 0x5c, 0x2e,
|
||||
0xa2, 0x11, 0xb2, 0x4b, 0x16, 0x4d, 0x5f, 0x2d, 0x7d, 0xdf, 0xf5, 0xe4, 0xa0, 0x70,
|
||||
0x8f, 0x10, 0xb9, 0x5e,
|
||||
],
|
||||
nk: [
|
||||
0x94, 0x38, 0x85, 0x95, 0x9d, 0x4e, 0xf8, 0xa9, 0xcf, 0xca, 0x07, 0xc4, 0x57, 0xf0,
|
||||
0x9e, 0xc7, 0x4b, 0x96, 0xf9, 0x93, 0xd8, 0xe0, 0xfa, 0x32, 0xb1, 0x9c, 0x03, 0xe3,
|
||||
0xb0, 0x7a, 0x42, 0x0f,
|
||||
],
|
||||
ivk: [
|
||||
0xb5, 0xc5, 0x89, 0x49, 0x43, 0x95, 0x69, 0x33, 0xc0, 0xe5, 0xc1, 0x2d, 0x31, 0x1f,
|
||||
0xc1, 0x2c, 0xba, 0x58, 0x35, 0x4b, 0x5c, 0x38, 0x9e, 0xdc, 0x03, 0xda, 0x55, 0x08,
|
||||
0x4f, 0x74, 0xc2, 0x05,
|
||||
],
|
||||
default_d: [
|
||||
0xbe, 0xbb, 0x0f, 0xb4, 0x6b, 0x8a, 0xaf, 0xf8, 0x90, 0x40, 0xf6,
|
||||
],
|
||||
default_pk_d: [
|
||||
0xd1, 0x1d, 0xa0, 0x1f, 0x0b, 0x43, 0xbd, 0xd5, 0x28, 0x8d, 0x32, 0x38, 0x5b, 0x87,
|
||||
0x71, 0xd2, 0x23, 0x49, 0x3c, 0x69, 0x80, 0x25, 0x44, 0x04, 0x3f, 0x77, 0xcf, 0x1d,
|
||||
0x71, 0xc1, 0xcb, 0x8c,
|
||||
],
|
||||
note_v: 18023134788442677120,
|
||||
note_r: [
|
||||
0x49, 0xf9, 0x0b, 0x47, 0xfd, 0x52, 0xfe, 0xe7, 0xc1, 0xc8, 0x1f, 0x0d, 0xcb, 0x5b,
|
||||
0x74, 0xc3, 0xfb, 0x9b, 0x3e, 0x03, 0x97, 0x6f, 0x8b, 0x75, 0x24, 0xea, 0xba, 0xd0,
|
||||
0x08, 0x89, 0x21, 0x07,
|
||||
],
|
||||
note_cm: [
|
||||
0x57, 0x2b, 0xa2, 0x05, 0x25, 0xb0, 0xac, 0x4d, 0x6d, 0xc0, 0x1a, 0xc2, 0xea, 0x10,
|
||||
0x90, 0xb6, 0xe0, 0xf2, 0xf4, 0xbf, 0x4e, 0xc4, 0xa0, 0xdb, 0x5b, 0xbc, 0xcb, 0x5b,
|
||||
0x78, 0x3a, 0x1e, 0x55,
|
||||
],
|
||||
note_pos: 287318480,
|
||||
note_nf: [
|
||||
0xfc, 0x74, 0xcd, 0x0e, 0x4b, 0xe0, 0x49, 0x57, 0xb1, 0x96, 0xcf, 0x87, 0x34, 0xae,
|
||||
0x99, 0x23, 0x96, 0xaf, 0x4c, 0xfa, 0x8f, 0xec, 0xbb, 0x86, 0xf9, 0x61, 0xe6, 0xb4,
|
||||
0x07, 0xd5, 0x1e, 0x11,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07,
|
||||
],
|
||||
ask: [
|
||||
0x74, 0xb4, 0x4a, 0x37, 0xf1, 0x50, 0x23, 0xc0, 0x60, 0x42, 0x7e, 0x1d, 0xae, 0xa3,
|
||||
0xf6, 0x43, 0x12, 0xdd, 0x8f, 0xeb, 0x7b, 0x2c, 0xed, 0xf0, 0xdd, 0x55, 0x44, 0x49,
|
||||
0x3f, 0x87, 0x2c, 0x06,
|
||||
],
|
||||
nsk: [
|
||||
0x07, 0x5c, 0x35, 0xdb, 0x8b, 0x1b, 0x25, 0x75, 0x42, 0x23, 0xec, 0xee, 0x34, 0xab,
|
||||
0x73, 0x0d, 0xdd, 0xd1, 0xf1, 0x4a, 0x6a, 0x54, 0xf4, 0xc6, 0xf4, 0x68, 0x45, 0x3c,
|
||||
0x3c, 0x6e, 0xd6, 0x0b,
|
||||
],
|
||||
ovk: [
|
||||
0xe9, 0xe0, 0xdc, 0x1e, 0xd3, 0x11, 0xda, 0xed, 0x64, 0xbd, 0x74, 0xda, 0x5d, 0x94,
|
||||
0xfe, 0x88, 0xa6, 0xea, 0x41, 0x4b, 0x73, 0x12, 0xde, 0x3d, 0x2a, 0x78, 0xf6, 0x46,
|
||||
0x32, 0xbb, 0xe3, 0x73,
|
||||
],
|
||||
ak: [
|
||||
0x28, 0x3f, 0x9a, 0xaf, 0xa9, 0xbc, 0xb3, 0xe6, 0xce, 0x17, 0xe6, 0x32, 0x12, 0x63,
|
||||
0x4c, 0xb3, 0xee, 0x55, 0x0c, 0x47, 0x6b, 0x67, 0x6b, 0xd3, 0x56, 0xa6, 0xdf, 0x8a,
|
||||
0xdf, 0x51, 0xd2, 0x5e,
|
||||
],
|
||||
nk: [
|
||||
0xdc, 0x4c, 0x67, 0xb1, 0x0d, 0x4b, 0x0a, 0x21, 0x8d, 0xc6, 0xe1, 0x48, 0x70, 0x66,
|
||||
0x74, 0x0a, 0x40, 0x93, 0x17, 0x86, 0x6c, 0x32, 0xe6, 0x64, 0xb5, 0x0e, 0x39, 0x7a,
|
||||
0xa8, 0x03, 0x89, 0xd4,
|
||||
],
|
||||
ivk: [
|
||||
0x87, 0x16, 0xc8, 0x28, 0x80, 0xe1, 0x36, 0x83, 0xe1, 0xbb, 0x05, 0x9d, 0xd0, 0x6c,
|
||||
0x80, 0xc9, 0x01, 0x34, 0xa9, 0x6d, 0x5a, 0xfc, 0xa8, 0xaa, 0xc2, 0xbb, 0xf6, 0x8b,
|
||||
0xb0, 0x5f, 0x84, 0x02,
|
||||
],
|
||||
default_d: [
|
||||
0xad, 0x6e, 0x2e, 0x18, 0x5a, 0x31, 0x00, 0xe3, 0xa6, 0xa8, 0xb3,
|
||||
],
|
||||
default_pk_d: [
|
||||
0x32, 0xcb, 0x28, 0x06, 0xb8, 0x82, 0xf1, 0x36, 0x8b, 0x0d, 0x4a, 0x89, 0x8f, 0x72,
|
||||
0xc4, 0xc8, 0xf7, 0x28, 0x13, 0x2c, 0xc1, 0x24, 0x56, 0x94, 0x6e, 0x7f, 0x4c, 0xb0,
|
||||
0xfb, 0x05, 0x8d, 0xa9,
|
||||
],
|
||||
note_v: 11803618549661680832,
|
||||
note_r: [
|
||||
0x51, 0x65, 0xaf, 0xf2, 0x2d, 0xd4, 0xed, 0x56, 0xb4, 0xd8, 0x1d, 0x1f, 0x17, 0x1c,
|
||||
0xc3, 0xd6, 0x43, 0x2f, 0xed, 0x1b, 0xeb, 0xf2, 0x0a, 0x7b, 0xea, 0xb1, 0x2d, 0xb1,
|
||||
0x42, 0xf9, 0x4a, 0x0c,
|
||||
],
|
||||
note_cm: [
|
||||
0xab, 0x7f, 0xc5, 0x66, 0x87, 0x3c, 0xcd, 0xe6, 0x71, 0xf5, 0x98, 0x27, 0x67, 0x85,
|
||||
0x60, 0xa0, 0x06, 0xf8, 0x2b, 0xb7, 0xad, 0xcd, 0x75, 0x22, 0x3f, 0xa8, 0x59, 0x36,
|
||||
0xf7, 0x8c, 0x2b, 0x23,
|
||||
],
|
||||
note_pos: 1051032776,
|
||||
note_nf: [
|
||||
0xd2, 0xe8, 0x87, 0xbd, 0x85, 0x4a, 0x80, 0x2b, 0xce, 0x85, 0x70, 0x53, 0x02, 0x0f,
|
||||
0x5d, 0x3e, 0x7c, 0x8a, 0xe5, 0x26, 0x7c, 0x5b, 0x65, 0x83, 0xb3, 0xd2, 0x12, 0xcc,
|
||||
0x8b, 0xb6, 0x98, 0x90,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08,
|
||||
],
|
||||
ask: [
|
||||
0x03, 0x9d, 0xd9, 0x3d, 0xf3, 0x11, 0xff, 0x8f, 0xba, 0xb3, 0xfe, 0x23, 0x02, 0x19,
|
||||
0xcd, 0x42, 0xac, 0x87, 0x94, 0x84, 0xf3, 0x0b, 0x90, 0x3a, 0x3c, 0x1e, 0x67, 0xcc,
|
||||
0xca, 0x5a, 0x7b, 0x0d,
|
||||
],
|
||||
nsk: [
|
||||
0x04, 0x9f, 0xa1, 0x4f, 0x48, 0x6c, 0x75, 0xb9, 0xfa, 0xd7, 0xe3, 0xb6, 0x73, 0xa4,
|
||||
0x43, 0xdd, 0x07, 0x4e, 0xaa, 0x96, 0xed, 0xcb, 0x2a, 0x53, 0xea, 0xaa, 0xbd, 0xaf,
|
||||
0x70, 0xff, 0xbb, 0x08,
|
||||
],
|
||||
ovk: [
|
||||
0x14, 0x7d, 0xd1, 0x1d, 0x77, 0xeb, 0xa1, 0xb1, 0x63, 0x6f, 0xd6, 0x19, 0x0c, 0x62,
|
||||
0xb9, 0xa5, 0xd0, 0x48, 0x1b, 0xee, 0x7e, 0x91, 0x7f, 0xab, 0x02, 0xe2, 0x18, 0x58,
|
||||
0x06, 0x3a, 0xb5, 0x04,
|
||||
],
|
||||
ak: [
|
||||
0x36, 0x40, 0x48, 0xee, 0xdb, 0xe8, 0xca, 0x20, 0x5e, 0xb7, 0xe7, 0xba, 0x0a, 0x90,
|
||||
0x12, 0x16, 0x6c, 0x7c, 0x7b, 0xd9, 0xeb, 0x22, 0x8e, 0x08, 0x48, 0x14, 0x48, 0xc4,
|
||||
0x88, 0xaa, 0x21, 0xd2,
|
||||
],
|
||||
nk: [
|
||||
0xed, 0x60, 0xaf, 0x1c, 0xe7, 0xdf, 0x38, 0x07, 0x0d, 0x38, 0x51, 0x43, 0x2a, 0x96,
|
||||
0x48, 0x0d, 0xb0, 0xb4, 0x17, 0xc3, 0x68, 0x2a, 0x1d, 0x68, 0xe3, 0xe8, 0x93, 0x34,
|
||||
0x23, 0x5c, 0x0b, 0xdf,
|
||||
],
|
||||
ivk: [
|
||||
0x99, 0xc9, 0xb4, 0xb8, 0x4f, 0x4b, 0x4e, 0x35, 0x0f, 0x78, 0x7d, 0x1c, 0xf7, 0x05,
|
||||
0x1d, 0x50, 0xec, 0xc3, 0x4b, 0x1a, 0x5b, 0x20, 0xd2, 0xd2, 0x13, 0x9b, 0x4a, 0xf1,
|
||||
0xf1, 0x60, 0xe0, 0x01,
|
||||
],
|
||||
default_d: [
|
||||
0x21, 0xc9, 0x0e, 0x1c, 0x65, 0x8b, 0x3e, 0xfe, 0x86, 0xaf, 0x58,
|
||||
],
|
||||
default_pk_d: [
|
||||
0x9e, 0x64, 0x17, 0x4b, 0x4a, 0xb9, 0x81, 0x40, 0x5c, 0x32, 0x3b, 0x5e, 0x12, 0x47,
|
||||
0x59, 0x45, 0xa4, 0x6d, 0x4f, 0xed, 0xf8, 0x06, 0x08, 0x28, 0x04, 0x1c, 0xd2, 0x0e,
|
||||
0x62, 0xfd, 0x2c, 0xef,
|
||||
],
|
||||
note_v: 5584102310880684544,
|
||||
note_r: [
|
||||
0x8c, 0x3e, 0x56, 0x44, 0x9d, 0xc8, 0x63, 0x54, 0xd3, 0x3b, 0x02, 0x5e, 0xf2, 0x79,
|
||||
0x34, 0x60, 0xbc, 0xb1, 0x69, 0xf3, 0x32, 0x4e, 0x4a, 0x6b, 0x64, 0xba, 0xa6, 0x08,
|
||||
0x32, 0x31, 0x57, 0x04,
|
||||
],
|
||||
note_cm: [
|
||||
0x7b, 0x48, 0xa8, 0x37, 0x5d, 0x3e, 0xbd, 0x56, 0xbc, 0x64, 0x9b, 0xb5, 0xb5, 0x24,
|
||||
0x23, 0x36, 0xc2, 0xa0, 0x5a, 0x08, 0x03, 0x23, 0x9b, 0x5b, 0x88, 0xfd, 0x92, 0x07,
|
||||
0x8f, 0xea, 0x4d, 0x04,
|
||||
],
|
||||
note_pos: 1814747072,
|
||||
note_nf: [
|
||||
0xa8, 0x2f, 0x17, 0x50, 0xcc, 0x5b, 0x2b, 0xee, 0x64, 0x9a, 0x36, 0x5c, 0x04, 0x20,
|
||||
0xed, 0x87, 0x07, 0x5b, 0x88, 0x71, 0xfd, 0xa4, 0xa7, 0xf5, 0x84, 0x0d, 0x6b, 0xbe,
|
||||
0xb1, 0x7c, 0xd6, 0x20,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
|
||||
0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
|
||||
0x09, 0x09, 0x09, 0x09,
|
||||
],
|
||||
ask: [
|
||||
0xeb, 0xbb, 0x40, 0xa9, 0x80, 0xba, 0x3b, 0x88, 0x60, 0x94, 0x8d, 0x01, 0x1e, 0x1b,
|
||||
0xfb, 0x4a, 0xff, 0xe1, 0x6c, 0x65, 0x2e, 0x90, 0xe9, 0x82, 0x58, 0x30, 0x2f, 0x44,
|
||||
0x64, 0xc9, 0x1e, 0x0c,
|
||||
],
|
||||
nsk: [
|
||||
0x68, 0x43, 0x1b, 0x19, 0x91, 0x04, 0x21, 0x52, 0x00, 0xb9, 0x5e, 0xe5, 0xcb, 0x71,
|
||||
0xbf, 0x8b, 0x88, 0x3a, 0x3e, 0x95, 0xb7, 0x98, 0x9c, 0xad, 0x19, 0x70, 0x63, 0x14,
|
||||
0x1e, 0xbb, 0xfd, 0x00,
|
||||
],
|
||||
ovk: [
|
||||
0x57, 0x34, 0x67, 0xa7, 0xb3, 0x0e, 0xad, 0x6c, 0xcc, 0x50, 0x47, 0x44, 0xca, 0x9e,
|
||||
0x1a, 0x28, 0x1a, 0x0d, 0x1a, 0x08, 0x73, 0x8b, 0x06, 0xa0, 0x68, 0x4f, 0xea, 0xcd,
|
||||
0x1e, 0x9d, 0x12, 0x6d,
|
||||
],
|
||||
ak: [
|
||||
0x71, 0xc3, 0x52, 0x3e, 0xec, 0xa3, 0x53, 0x11, 0xfb, 0xd5, 0xd7, 0xe7, 0xd7, 0x0b,
|
||||
0x70, 0x9d, 0x6c, 0x35, 0xa2, 0x4f, 0x26, 0x2b, 0x34, 0xbf, 0x64, 0x05, 0x9b, 0xf2,
|
||||
0xc0, 0x2e, 0x0b, 0xa8,
|
||||
],
|
||||
nk: [
|
||||
0x62, 0x44, 0x00, 0x10, 0x3b, 0x65, 0x69, 0xb7, 0x35, 0x8f, 0xe8, 0x0f, 0x6f, 0x6c,
|
||||
0xad, 0x43, 0x25, 0xde, 0xfd, 0xa9, 0xd9, 0x49, 0x9c, 0x2b, 0x8f, 0x88, 0x6a, 0x62,
|
||||
0x69, 0xa2, 0xaa, 0x52,
|
||||
],
|
||||
ivk: [
|
||||
0xdb, 0x95, 0xea, 0x8b, 0xd9, 0xf9, 0x3d, 0x41, 0xb5, 0xab, 0x2b, 0xeb, 0xc9, 0x1a,
|
||||
0x38, 0xed, 0xd5, 0x27, 0x08, 0x3e, 0x2a, 0x6e, 0xf9, 0xf3, 0xc2, 0x97, 0x02, 0xd5,
|
||||
0xff, 0x89, 0xed, 0x00,
|
||||
],
|
||||
default_d: [
|
||||
0x23, 0x3c, 0x4a, 0xb8, 0x86, 0xa5, 0x5e, 0x3b, 0xa3, 0x74, 0xc0,
|
||||
],
|
||||
default_pk_d: [
|
||||
0xb6, 0x8e, 0x9e, 0xe0, 0xc0, 0x67, 0x8d, 0x7b, 0x30, 0x36, 0x93, 0x1c, 0x83, 0x1a,
|
||||
0x25, 0x25, 0x5f, 0x7e, 0xe4, 0x87, 0x38, 0x5a, 0x30, 0x31, 0x6e, 0x15, 0xf6, 0x48,
|
||||
0x2b, 0x87, 0x4f, 0xda,
|
||||
],
|
||||
note_v: 17811330145809239872,
|
||||
note_r: [
|
||||
0x6e, 0xbb, 0xed, 0x74, 0x36, 0x19, 0xa2, 0x56, 0xf9, 0xad, 0x2e, 0x85, 0x88, 0x0c,
|
||||
0xfa, 0xa9, 0x09, 0x8a, 0x5f, 0xdb, 0x16, 0x29, 0x99, 0x0d, 0x9a, 0x7d, 0x3b, 0xb9,
|
||||
0x3f, 0xc9, 0x00, 0x03,
|
||||
],
|
||||
note_cm: [
|
||||
0xd3, 0x76, 0xa7, 0xbe, 0xe8, 0xce, 0x67, 0xf4, 0xef, 0xde, 0x56, 0xaa, 0x77, 0xcf,
|
||||
0x64, 0x41, 0x9b, 0x0e, 0x55, 0x0a, 0xbb, 0xcb, 0x8e, 0x2b, 0xcb, 0xda, 0x8b, 0x63,
|
||||
0xe4, 0x1d, 0xeb, 0x37,
|
||||
],
|
||||
note_pos: 2578461368,
|
||||
note_nf: [
|
||||
0x65, 0x36, 0x74, 0x87, 0x3b, 0x3c, 0x67, 0x0c, 0x58, 0x85, 0x84, 0x73, 0xe7, 0xfe,
|
||||
0x72, 0x19, 0x72, 0xfb, 0x96, 0xe2, 0x15, 0xb8, 0x73, 0x77, 0xa1, 0x7c, 0xa3, 0x71,
|
||||
0x0d, 0x93, 0xc9, 0xe9,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
for tv in test_vectors {
|
||||
// Compute commitment and compare with test vector
|
||||
let mut result = [0u8; 32];
|
||||
assert!(librustzcash_sapling_compute_cm(
|
||||
&tv.default_d,
|
||||
&tv.default_pk_d,
|
||||
tv.note_v,
|
||||
&tv.note_r,
|
||||
&mut result
|
||||
));
|
||||
assert_eq!(&result, &tv.note_cm);
|
||||
|
||||
// Compute nullifier and compare with test vector
|
||||
assert!(librustzcash_sapling_compute_nf(
|
||||
&tv.default_d,
|
||||
&tv.default_pk_d,
|
||||
tv.note_v,
|
||||
&tv.note_r,
|
||||
&tv.ak,
|
||||
&tv.nk,
|
||||
tv.note_pos,
|
||||
&mut result
|
||||
));
|
||||
assert_eq!(&result, &tv.note_nf);
|
||||
}
|
||||
}
|
@ -1,515 +0,0 @@
|
||||
use pairing::{bls12_381::Bls12, PrimeField, PrimeFieldRepr};
|
||||
use sapling_crypto::{
|
||||
jubjub::{FixedGenerators, JubjubEngine},
|
||||
redjubjub::{PrivateKey, PublicKey, Signature},
|
||||
};
|
||||
|
||||
use super::JUBJUB;
|
||||
|
||||
#[test]
|
||||
fn redjubjub_signatures() {
|
||||
struct TestVector {
|
||||
sk: [u8; 32],
|
||||
vk: [u8; 32],
|
||||
alpha: [u8; 32],
|
||||
rsk: [u8; 32],
|
||||
rvk: [u8; 32],
|
||||
m: [u8; 32],
|
||||
sig: [u8; 64],
|
||||
rsig: [u8; 64],
|
||||
};
|
||||
|
||||
// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_signatures.py
|
||||
let test_vectors = vec![
|
||||
TestVector {
|
||||
sk: [
|
||||
0x18, 0xe2, 0x8d, 0xea, 0x5c, 0x11, 0x81, 0x7a, 0xee, 0xb2, 0x1a, 0x19, 0x98, 0x1d,
|
||||
0x28, 0x36, 0x8e, 0xc4, 0x38, 0xaf, 0xc2, 0x5a, 0x8d, 0xb9, 0x4e, 0xbe, 0x08, 0xd7,
|
||||
0xa0, 0x28, 0x8e, 0x09,
|
||||
],
|
||||
vk: [
|
||||
0x9b, 0x01, 0x53, 0xb0, 0x3d, 0x32, 0x0f, 0xe2, 0x3e, 0x28, 0x34, 0xd5, 0xd6, 0x1d,
|
||||
0xbb, 0x1f, 0x51, 0x9b, 0x3f, 0x41, 0xf8, 0xf9, 0x46, 0x15, 0x2b, 0xf0, 0xc3, 0xf2,
|
||||
0x47, 0xd1, 0x18, 0x07,
|
||||
],
|
||||
alpha: [
|
||||
0xff, 0xd1, 0xa1, 0x27, 0x32, 0x52, 0xb1, 0x87, 0xf4, 0xed, 0x32, 0x6d, 0xfc, 0x98,
|
||||
0x85, 0x3e, 0x29, 0x17, 0xc2, 0xb3, 0x63, 0x79, 0xb1, 0x75, 0xda, 0x63, 0xb9, 0xef,
|
||||
0x6d, 0xda, 0x6c, 0x08,
|
||||
],
|
||||
rsk: [
|
||||
0x60, 0x87, 0x38, 0x3b, 0x30, 0x55, 0x9b, 0x31, 0x60, 0x90, 0x85, 0xb9, 0x00, 0x96,
|
||||
0x45, 0xce, 0xb6, 0xa0, 0xc6, 0x61, 0x25, 0x99, 0xd7, 0x28, 0x80, 0x72, 0x8e, 0x61,
|
||||
0x24, 0x4e, 0x7d, 0x03,
|
||||
],
|
||||
rvk: [
|
||||
0xc1, 0xba, 0xbc, 0xb6, 0xea, 0xe2, 0xb9, 0x94, 0xee, 0x6d, 0x65, 0xc1, 0x0b, 0x9d,
|
||||
0xad, 0x59, 0x40, 0xdc, 0x73, 0x5b, 0x07, 0x50, 0x4d, 0xae, 0xd1, 0xe4, 0x6b, 0x07,
|
||||
0x09, 0xb4, 0x51, 0x36,
|
||||
],
|
||||
m: [
|
||||
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,
|
||||
],
|
||||
sig: [
|
||||
0xea, 0xa0, 0x57, 0x47, 0x6b, 0x4a, 0xb4, 0x82, 0x28, 0x8b, 0x93, 0xdf, 0x8f, 0xe0,
|
||||
0xc5, 0xce, 0x9d, 0x78, 0x83, 0x67, 0xf2, 0xbe, 0x55, 0x1b, 0x7f, 0x7a, 0x82, 0xa6,
|
||||
0xdb, 0x36, 0x04, 0x68, 0xde, 0xb9, 0xa7, 0xb7, 0xaf, 0xaa, 0xdf, 0xec, 0xa6, 0xf4,
|
||||
0x81, 0x19, 0x3d, 0xc6, 0x57, 0x57, 0x47, 0xf6, 0x0a, 0x1a, 0x8a, 0x48, 0xff, 0x0a,
|
||||
0xd7, 0x0c, 0xf8, 0xcb, 0x8d, 0x52, 0x8e, 0x08,
|
||||
],
|
||||
rsig: [
|
||||
0xd5, 0x6f, 0x0d, 0x91, 0xaf, 0x42, 0x4e, 0x1f, 0x1c, 0x7f, 0xb8, 0x6b, 0xa4, 0xee,
|
||||
0xd1, 0x43, 0xcc, 0x16, 0x66, 0x0c, 0x5f, 0xe8, 0xd7, 0xdc, 0x0d, 0x28, 0x4b, 0xcf,
|
||||
0x65, 0xa0, 0x89, 0xe9, 0x8b, 0x56, 0x1f, 0x9f, 0x20, 0x1a, 0x63, 0x3d, 0x70, 0x0c,
|
||||
0xd3, 0x98, 0x1e, 0x8c, 0xac, 0x07, 0xb5, 0xa8, 0x7e, 0xfa, 0x61, 0x86, 0x06, 0x2d,
|
||||
0xd8, 0xe5, 0xd6, 0x32, 0x5e, 0x7b, 0x82, 0x02,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x05, 0x96, 0x54, 0xf9, 0x61, 0x27, 0x3d, 0xaf, 0xda, 0x3b, 0x26, 0x77, 0xb3, 0x5c,
|
||||
0x18, 0xaf, 0x6b, 0x11, 0xad, 0xfb, 0x9e, 0xe9, 0x0b, 0x48, 0x93, 0x5e, 0x55, 0x7c,
|
||||
0x8d, 0x5d, 0x9c, 0x04,
|
||||
],
|
||||
vk: [
|
||||
0xfa, 0xf6, 0xc3, 0xb7, 0x37, 0xe8, 0xe6, 0x11, 0xaa, 0xfe, 0xa5, 0x2f, 0x03, 0xbb,
|
||||
0x27, 0x86, 0xe1, 0x83, 0x53, 0xeb, 0xe0, 0xd3, 0x13, 0x9e, 0x3c, 0x54, 0x49, 0x87,
|
||||
0x80, 0xc8, 0xc1, 0x99,
|
||||
],
|
||||
alpha: [
|
||||
0xc3, 0x0b, 0x96, 0x20, 0x8d, 0xa8, 0x00, 0xe1, 0x0a, 0xf0, 0x25, 0x42, 0xce, 0x69,
|
||||
0x4b, 0x7e, 0xd7, 0x6a, 0x28, 0x29, 0x9f, 0x85, 0x99, 0x8e, 0x5d, 0x61, 0x08, 0x12,
|
||||
0x68, 0x1b, 0xf0, 0x03,
|
||||
],
|
||||
rsk: [
|
||||
0xc8, 0xa1, 0xea, 0x19, 0xef, 0xcf, 0x3d, 0x90, 0xe5, 0x2b, 0x4c, 0xb9, 0x81, 0xc6,
|
||||
0x63, 0x2d, 0x43, 0x7c, 0xd5, 0x24, 0x3e, 0x6f, 0xa5, 0xd6, 0xf0, 0xbf, 0x5d, 0x8e,
|
||||
0xf5, 0x78, 0x8c, 0x08,
|
||||
],
|
||||
rvk: [
|
||||
0xd5, 0x24, 0xdc, 0xe7, 0x73, 0x40, 0x69, 0x75, 0x8a, 0x91, 0xf0, 0x07, 0xa8, 0x69,
|
||||
0x50, 0x5d, 0xfc, 0x4a, 0xba, 0x17, 0x20, 0x59, 0x4d, 0x4d, 0x74, 0xf0, 0x07, 0x70,
|
||||
0x0e, 0x62, 0xee, 0x00,
|
||||
],
|
||||
m: [
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01,
|
||||
],
|
||||
sig: [
|
||||
0x22, 0x35, 0x54, 0x94, 0xa8, 0x31, 0x6a, 0xb1, 0x34, 0x73, 0xf5, 0x5e, 0x62, 0x66,
|
||||
0xb2, 0xfb, 0x41, 0x97, 0x31, 0x5e, 0xac, 0x62, 0xf8, 0x2c, 0xc7, 0x3d, 0xca, 0xca,
|
||||
0x19, 0x90, 0x90, 0xf1, 0x5b, 0xe1, 0x98, 0xce, 0x7d, 0x3f, 0x9f, 0xc8, 0xff, 0xf5,
|
||||
0x50, 0xe1, 0x08, 0x81, 0xec, 0x49, 0xff, 0x27, 0x36, 0x9e, 0x7d, 0x4f, 0xd9, 0x64,
|
||||
0x01, 0x53, 0x49, 0x2a, 0x0a, 0x06, 0x25, 0x08,
|
||||
],
|
||||
rsig: [
|
||||
0xf4, 0xb8, 0x94, 0xba, 0x84, 0xce, 0x1e, 0xc3, 0x8a, 0x63, 0x15, 0x2f, 0xc4, 0x09,
|
||||
0xf9, 0x47, 0xd6, 0x1a, 0xbb, 0x1f, 0x48, 0x91, 0x63, 0x6b, 0xc3, 0xee, 0x19, 0xef,
|
||||
0x6d, 0x4b, 0x30, 0xc0, 0xfd, 0x22, 0x86, 0x6b, 0x84, 0xff, 0xbc, 0x7e, 0x2a, 0x78,
|
||||
0xc4, 0x3f, 0x57, 0x83, 0xd2, 0xd2, 0xea, 0xd0, 0x78, 0x59, 0x55, 0x03, 0x74, 0x43,
|
||||
0xc2, 0xf4, 0xd5, 0x2f, 0x78, 0x5e, 0xee, 0x07,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0xad, 0xe7, 0xab, 0xb5, 0x51, 0xc7, 0x9d, 0x0f, 0x0e, 0x42, 0xef, 0x7f, 0x12, 0x06,
|
||||
0xb8, 0x77, 0x12, 0xa8, 0x4a, 0x61, 0xde, 0xa3, 0xf3, 0x7b, 0x42, 0x49, 0x6d, 0x7e,
|
||||
0xfd, 0x12, 0x52, 0x0c,
|
||||
],
|
||||
vk: [
|
||||
0x36, 0x9e, 0xa7, 0x51, 0x76, 0x2f, 0x83, 0x9d, 0x25, 0x70, 0x1a, 0x5e, 0xeb, 0x55,
|
||||
0x1e, 0xc4, 0xf0, 0x6c, 0x12, 0x90, 0xb3, 0xb9, 0xc3, 0xa7, 0x24, 0x40, 0x2d, 0xec,
|
||||
0x02, 0x73, 0x92, 0x21,
|
||||
],
|
||||
alpha: [
|
||||
0x81, 0x92, 0x25, 0x29, 0xa6, 0x3e, 0xe7, 0x43, 0xfc, 0x4f, 0xbb, 0xac, 0x45, 0xc4,
|
||||
0x98, 0x83, 0x16, 0xbc, 0x9b, 0x6e, 0x42, 0x8b, 0x01, 0xa8, 0xd3, 0x1f, 0xc1, 0xc2,
|
||||
0xa6, 0xca, 0x62, 0x05,
|
||||
],
|
||||
rsk: [
|
||||
0x77, 0x4d, 0xda, 0x07, 0x99, 0xf7, 0xed, 0x82, 0x87, 0x81, 0xe2, 0x5f, 0xc4, 0xa9,
|
||||
0xe8, 0x54, 0x28, 0x29, 0xb2, 0xce, 0x1f, 0xf4, 0x8d, 0x1d, 0x6d, 0xb9, 0xfa, 0xdb,
|
||||
0xb9, 0x28, 0x37, 0x03,
|
||||
],
|
||||
rvk: [
|
||||
0x0d, 0x92, 0xad, 0x6d, 0x46, 0xed, 0xac, 0xd0, 0x23, 0xd4, 0xd2, 0xef, 0x70, 0x3a,
|
||||
0x6c, 0xa0, 0xa7, 0x92, 0xcf, 0xc4, 0xb7, 0xda, 0x11, 0xc2, 0x35, 0x3b, 0xc8, 0x45,
|
||||
0xa2, 0x7a, 0x97, 0x4d,
|
||||
],
|
||||
m: [
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02,
|
||||
],
|
||||
sig: [
|
||||
0xdd, 0x65, 0x21, 0x01, 0x4d, 0xff, 0x70, 0x6e, 0x3a, 0x38, 0x52, 0x7a, 0x86, 0xb6,
|
||||
0xc1, 0x6e, 0x94, 0x14, 0x80, 0xe7, 0x33, 0xef, 0xf7, 0x9e, 0xbe, 0x0c, 0x43, 0x03,
|
||||
0x79, 0xd7, 0x57, 0x04, 0x9d, 0xb7, 0x90, 0xcd, 0x5e, 0x14, 0x44, 0x7c, 0x38, 0x6f,
|
||||
0x5f, 0xcb, 0x41, 0x9f, 0x27, 0xc4, 0x41, 0x3f, 0x35, 0x88, 0xfa, 0x21, 0x42, 0xd2,
|
||||
0xcf, 0xba, 0xed, 0x08, 0x2c, 0xc6, 0xdb, 0x07,
|
||||
],
|
||||
rsig: [
|
||||
0xd8, 0x94, 0x45, 0xcb, 0x9b, 0xd1, 0x03, 0x35, 0x69, 0x23, 0x1d, 0xd6, 0x28, 0xaa,
|
||||
0x62, 0x81, 0x09, 0xfe, 0x93, 0x50, 0x2b, 0xf2, 0x2f, 0x9a, 0x5f, 0x37, 0xb1, 0x4e,
|
||||
0x51, 0x7f, 0x9a, 0x20, 0x54, 0xae, 0xe3, 0xc8, 0x1b, 0x60, 0xb3, 0xf0, 0x55, 0x1e,
|
||||
0x32, 0xf7, 0x93, 0x5a, 0xbc, 0x2f, 0x37, 0xb9, 0x9a, 0xb3, 0xec, 0x99, 0x68, 0x02,
|
||||
0xef, 0xd6, 0x50, 0x69, 0xe1, 0x28, 0x12, 0x08,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0xc9, 0xd2, 0xae, 0x1f, 0x6d, 0x32, 0xa6, 0x75, 0xd0, 0x9e, 0xb0, 0x82, 0x3f, 0x46,
|
||||
0x7f, 0xa9, 0x21, 0xb3, 0x28, 0x4a, 0xcb, 0x35, 0xfa, 0xbd, 0xfc, 0x99, 0x4d, 0xe5,
|
||||
0x49, 0xb8, 0x59, 0x0d,
|
||||
],
|
||||
vk: [
|
||||
0x2d, 0x2f, 0x31, 0x6e, 0x5c, 0x36, 0x9a, 0xe4, 0xdd, 0x2c, 0x82, 0x5f, 0x3d, 0x86,
|
||||
0x46, 0x00, 0x58, 0x40, 0x71, 0x84, 0x60, 0x3b, 0x21, 0x2c, 0xf3, 0x45, 0x9f, 0x36,
|
||||
0xc8, 0x69, 0x7f, 0xd8,
|
||||
],
|
||||
alpha: [
|
||||
0xeb, 0xbc, 0x89, 0x03, 0x11, 0x07, 0xc4, 0x4f, 0x47, 0x88, 0x9e, 0xd4, 0xd4, 0x37,
|
||||
0x5a, 0x41, 0x14, 0xcf, 0x8a, 0x75, 0xdd, 0x33, 0xb9, 0x62, 0xf2, 0xd7, 0x59, 0xd3,
|
||||
0xf4, 0xc6, 0xdf, 0x06,
|
||||
],
|
||||
rsk: [
|
||||
0xfd, 0x62, 0x41, 0x4c, 0x1f, 0x2b, 0xd3, 0xf4, 0x94, 0x16, 0x87, 0x8a, 0x80, 0x5d,
|
||||
0x71, 0x44, 0x35, 0x47, 0x7f, 0xbe, 0xa7, 0x2e, 0x4c, 0x1a, 0x46, 0xc2, 0x73, 0x53,
|
||||
0x54, 0xca, 0xbb, 0x05,
|
||||
],
|
||||
rvk: [
|
||||
0xf0, 0x43, 0x0e, 0x95, 0x3b, 0xe6, 0x0b, 0xf4, 0x38, 0xdb, 0xdc, 0xc2, 0x30, 0x3f,
|
||||
0x0e, 0x32, 0xa6, 0xf7, 0xce, 0x2f, 0xbe, 0xdf, 0xb1, 0x3a, 0xc5, 0x18, 0xf7, 0x5a,
|
||||
0x3f, 0xd1, 0x0e, 0xb5,
|
||||
],
|
||||
m: [
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03,
|
||||
],
|
||||
sig: [
|
||||
0x72, 0x79, 0xa7, 0x5c, 0x01, 0x36, 0x75, 0xb3, 0x29, 0x84, 0xe5, 0xc7, 0x3a, 0x98,
|
||||
0x91, 0xeb, 0xf0, 0xb2, 0x29, 0xb1, 0x6e, 0x62, 0x35, 0xba, 0x36, 0xdf, 0xa1, 0xb5,
|
||||
0xa1, 0x0c, 0x5e, 0x44, 0x57, 0x81, 0x91, 0x89, 0x7c, 0x06, 0xb8, 0x52, 0x4a, 0x26,
|
||||
0x74, 0xaa, 0x7a, 0x0c, 0x8c, 0x23, 0x5f, 0x52, 0xd3, 0x3a, 0xc9, 0x2c, 0x70, 0x56,
|
||||
0xb2, 0xbe, 0x95, 0x3c, 0x3f, 0xaa, 0x3d, 0x07,
|
||||
],
|
||||
rsig: [
|
||||
0xaa, 0xd4, 0x82, 0x8c, 0xb3, 0x42, 0xcf, 0x09, 0xb0, 0x0e, 0x30, 0x2c, 0xbb, 0xe7,
|
||||
0xcc, 0x3e, 0x95, 0xfe, 0x1f, 0xf8, 0x28, 0x74, 0x8e, 0x5f, 0x5b, 0xc6, 0x9c, 0xbf,
|
||||
0xde, 0x6e, 0x27, 0x22, 0xd7, 0x64, 0x35, 0x68, 0x7e, 0x85, 0x0c, 0xd3, 0x07, 0xa9,
|
||||
0xc1, 0x82, 0xec, 0x10, 0xe6, 0x88, 0x1d, 0xd6, 0x5e, 0xed, 0xc1, 0x1f, 0xa7, 0xb4,
|
||||
0x6d, 0xe3, 0xa7, 0x19, 0x59, 0xce, 0xc0, 0x02,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x33, 0xbc, 0xd2, 0x86, 0x45, 0x41, 0xb8, 0xbb, 0x7f, 0xdc, 0x77, 0xa1, 0x9d, 0x97,
|
||||
0x0f, 0x92, 0x4e, 0xae, 0xec, 0xf4, 0x10, 0x3c, 0x38, 0xc8, 0xd2, 0xb0, 0x66, 0x81,
|
||||
0x42, 0xf2, 0x7d, 0x09,
|
||||
],
|
||||
vk: [
|
||||
0x74, 0x17, 0x94, 0xe6, 0x2c, 0xf9, 0x32, 0x0c, 0x58, 0xba, 0xc5, 0x94, 0xa2, 0xb9,
|
||||
0x0e, 0x34, 0x0a, 0x6d, 0x8a, 0x68, 0x05, 0x6f, 0x6e, 0xd5, 0xc7, 0x86, 0x8c, 0x5f,
|
||||
0xf3, 0xe4, 0xd6, 0x16,
|
||||
],
|
||||
alpha: [
|
||||
0x7c, 0xe7, 0x25, 0xa5, 0xfe, 0xf6, 0x1b, 0xd4, 0xa1, 0xe9, 0xc7, 0x73, 0x28, 0xe8,
|
||||
0x21, 0x0e, 0xb7, 0x29, 0x2d, 0x95, 0x4c, 0x64, 0xe9, 0x9e, 0x8b, 0xed, 0xd0, 0x7a,
|
||||
0xb3, 0xab, 0x0e, 0x0d,
|
||||
],
|
||||
rsk: [
|
||||
0xf8, 0x76, 0x01, 0x55, 0xe5, 0x29, 0x3d, 0xbf, 0x9e, 0xb5, 0x77, 0x48, 0x32, 0x5f,
|
||||
0xc9, 0xf9, 0x04, 0x9d, 0xe5, 0x88, 0x5c, 0x65, 0xba, 0x60, 0xb5, 0xee, 0x03, 0x97,
|
||||
0x0b, 0xe9, 0x0e, 0x08,
|
||||
],
|
||||
rvk: [
|
||||
0x66, 0x62, 0xba, 0x09, 0x95, 0x0a, 0xcc, 0xd2, 0xce, 0xa3, 0xc7, 0xa8, 0x12, 0x90,
|
||||
0xcd, 0x59, 0x78, 0xa6, 0x2b, 0x5a, 0xc5, 0xbb, 0xc4, 0x8d, 0x9f, 0x58, 0x19, 0xcd,
|
||||
0xc9, 0x64, 0x6f, 0x0a,
|
||||
],
|
||||
m: [
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04,
|
||||
],
|
||||
sig: [
|
||||
0x51, 0x23, 0xb3, 0x1f, 0x84, 0xaf, 0x0c, 0x35, 0x5e, 0x13, 0xe7, 0x8a, 0x64, 0xd7,
|
||||
0xa3, 0xcd, 0xfd, 0x6b, 0xdf, 0xfd, 0xc7, 0x33, 0x38, 0xd9, 0x31, 0x7f, 0x73, 0x43,
|
||||
0x91, 0xa5, 0x5a, 0xe6, 0x25, 0x8f, 0x69, 0x80, 0xb9, 0xc7, 0xd1, 0x90, 0xcf, 0xa3,
|
||||
0x65, 0x81, 0xa9, 0xa4, 0x7a, 0x86, 0x3f, 0xd3, 0xbf, 0x76, 0x59, 0x42, 0x22, 0x95,
|
||||
0xb7, 0x5f, 0xd1, 0x22, 0xc3, 0xdd, 0x8a, 0x05,
|
||||
],
|
||||
rsig: [
|
||||
0x5b, 0xae, 0x25, 0x4f, 0xbd, 0xed, 0x60, 0x7a, 0x5c, 0x48, 0xb5, 0x30, 0x29, 0xf5,
|
||||
0x9b, 0xa7, 0x06, 0x32, 0x48, 0x79, 0xaa, 0x18, 0xd9, 0xc4, 0x73, 0x19, 0x00, 0x4b,
|
||||
0xe0, 0x2c, 0xec, 0xe0, 0xb8, 0xbb, 0x02, 0x4a, 0x7a, 0xab, 0xaa, 0x0a, 0x64, 0x0f,
|
||||
0x3a, 0x54, 0xdc, 0xda, 0xf2, 0x11, 0x31, 0x46, 0x9a, 0x50, 0x06, 0xbe, 0x27, 0x81,
|
||||
0xa5, 0x67, 0xff, 0xa6, 0x50, 0x3a, 0x35, 0x03,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0xca, 0x35, 0x06, 0xd6, 0xaf, 0x77, 0x67, 0xb5, 0x79, 0x0e, 0xf0, 0xc5, 0x19, 0x0f,
|
||||
0xb3, 0xf3, 0x87, 0x7c, 0x4a, 0xab, 0x40, 0xe0, 0xdd, 0x65, 0x1a, 0xbb, 0xda, 0xcb,
|
||||
0x54, 0x4e, 0xd0, 0x05,
|
||||
],
|
||||
vk: [
|
||||
0xba, 0xb6, 0xcf, 0xb5, 0xc8, 0xea, 0x34, 0x91, 0x25, 0x1b, 0x46, 0xd5, 0x2a, 0xca,
|
||||
0x25, 0xd9, 0xe9, 0xaf, 0x69, 0xfa, 0xa9, 0xb4, 0xe4, 0x0b, 0x03, 0xad, 0x00, 0x86,
|
||||
0xde, 0x59, 0xb5, 0x1f,
|
||||
],
|
||||
alpha: [
|
||||
0xbe, 0xa3, 0x87, 0x20, 0x3f, 0x43, 0x76, 0x0a, 0xd3, 0x7d, 0x61, 0xde, 0x0e, 0xb5,
|
||||
0x9f, 0xca, 0x6c, 0xab, 0x75, 0x60, 0xdf, 0x64, 0xfa, 0xbb, 0x95, 0x11, 0x57, 0x9f,
|
||||
0x6f, 0x68, 0x26, 0x06,
|
||||
],
|
||||
rsk: [
|
||||
0x88, 0xd9, 0x8d, 0xf6, 0xee, 0xba, 0xdd, 0xbf, 0x4c, 0x8c, 0x51, 0xa4, 0x28, 0xc4,
|
||||
0x52, 0xbe, 0xf4, 0x27, 0xc0, 0x0b, 0x20, 0x45, 0xd8, 0x21, 0xb0, 0xcc, 0x31, 0x6b,
|
||||
0xc4, 0xb6, 0xf6, 0x0b,
|
||||
],
|
||||
rvk: [
|
||||
0x11, 0x26, 0x7d, 0x14, 0xd5, 0xe0, 0xb2, 0xbb, 0x3c, 0xe0, 0x99, 0xe8, 0xef, 0x84,
|
||||
0x49, 0x47, 0x1c, 0xbc, 0xfc, 0x69, 0x39, 0xa4, 0xb3, 0x48, 0xde, 0xa2, 0xc1, 0x73,
|
||||
0x56, 0xa1, 0xe8, 0xdd,
|
||||
],
|
||||
m: [
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05,
|
||||
],
|
||||
sig: [
|
||||
0xdc, 0x18, 0xc8, 0x8d, 0x96, 0x44, 0x42, 0x40, 0x6d, 0x65, 0x0a, 0xa2, 0xff, 0xbd,
|
||||
0x83, 0xd1, 0x13, 0xbf, 0x6a, 0x19, 0xda, 0x78, 0xf2, 0x66, 0x5b, 0x29, 0x4f, 0xa5,
|
||||
0xfa, 0x45, 0x0b, 0x92, 0x81, 0xa0, 0x7e, 0x32, 0x0c, 0x1a, 0xa3, 0x1d, 0x32, 0x44,
|
||||
0x9e, 0x00, 0xc5, 0xc3, 0x2d, 0xb2, 0xf4, 0x13, 0xdf, 0x0b, 0x63, 0xd0, 0x72, 0x8f,
|
||||
0xa4, 0x09, 0x41, 0xa8, 0xda, 0x02, 0x4f, 0x01,
|
||||
],
|
||||
rsig: [
|
||||
0x59, 0xe2, 0xe8, 0x18, 0x76, 0x6c, 0x50, 0xfc, 0x8f, 0x38, 0x40, 0xb2, 0x72, 0xaf,
|
||||
0x9a, 0xd9, 0x47, 0x56, 0xc8, 0x41, 0x32, 0x95, 0xfc, 0x79, 0x5f, 0xaf, 0xbc, 0xc0,
|
||||
0x71, 0x8e, 0x6c, 0x08, 0x16, 0x9a, 0x00, 0xd5, 0x83, 0x02, 0x77, 0x2a, 0x28, 0x28,
|
||||
0x43, 0xe8, 0x88, 0xd9, 0x81, 0xfa, 0x04, 0x79, 0x5d, 0x01, 0x4c, 0xf9, 0xc8, 0xcd,
|
||||
0xb9, 0x07, 0xff, 0x1b, 0x43, 0x0d, 0x92, 0x00,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0xbc, 0x27, 0x83, 0x8d, 0xe2, 0xa6, 0x14, 0xcf, 0xba, 0x6c, 0x3e, 0x92, 0x2a, 0x8f,
|
||||
0x84, 0x24, 0xd9, 0x85, 0x6f, 0x68, 0x16, 0xf3, 0xbc, 0x61, 0x02, 0x31, 0x3b, 0x7f,
|
||||
0xaf, 0x5c, 0x3a, 0x0c,
|
||||
],
|
||||
vk: [
|
||||
0xd7, 0x9b, 0xe9, 0xff, 0x22, 0x9a, 0x2e, 0x35, 0xf5, 0xbc, 0xa4, 0x48, 0xe5, 0xeb,
|
||||
0x4a, 0x8a, 0xa9, 0x7f, 0xb4, 0x18, 0x02, 0x91, 0x25, 0xcf, 0xba, 0xa7, 0x8a, 0x91,
|
||||
0xa3, 0x82, 0xb0, 0x94,
|
||||
],
|
||||
alpha: [
|
||||
0x21, 0xa7, 0x15, 0x0e, 0x19, 0x4f, 0xed, 0xfe, 0xf9, 0x0c, 0x5d, 0x10, 0xe4, 0x20,
|
||||
0x85, 0x8b, 0xca, 0x40, 0x04, 0x04, 0x0e, 0xb6, 0x81, 0xd1, 0x4e, 0x75, 0xc4, 0x47,
|
||||
0x13, 0x51, 0xcb, 0x02,
|
||||
],
|
||||
rsk: [
|
||||
0x26, 0xa2, 0xa1, 0xc4, 0x9c, 0xe7, 0x6a, 0xfd, 0x31, 0x69, 0xd3, 0xd5, 0x7a, 0x8f,
|
||||
0xa1, 0x09, 0xa3, 0x8b, 0x3f, 0x6b, 0x23, 0x6e, 0xd7, 0x2c, 0xa8, 0xf6, 0xcb, 0x61,
|
||||
0xd8, 0xf8, 0x87, 0x00,
|
||||
],
|
||||
rvk: [
|
||||
0x54, 0xbf, 0x1b, 0xe7, 0x2e, 0x6d, 0x41, 0x20, 0x8b, 0x8a, 0xec, 0x11, 0x61, 0xd3,
|
||||
0xba, 0x59, 0x51, 0x9f, 0xb9, 0x3d, 0xa0, 0x1a, 0x55, 0xe6, 0x78, 0xe2, 0x75, 0x20,
|
||||
0x06, 0x60, 0x36, 0xc9,
|
||||
],
|
||||
m: [
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06,
|
||||
],
|
||||
sig: [
|
||||
0x9a, 0xf6, 0xf2, 0x80, 0x0f, 0x4b, 0x80, 0xf7, 0x93, 0xbe, 0x64, 0x8a, 0x43, 0x9f,
|
||||
0x86, 0xe5, 0x7d, 0xa1, 0xb9, 0x19, 0x99, 0x9e, 0x41, 0x91, 0x09, 0x99, 0xd4, 0x2e,
|
||||
0xd0, 0xf3, 0x89, 0x6d, 0xb7, 0x6e, 0x06, 0x38, 0x8b, 0x27, 0x2c, 0x99, 0x85, 0x8b,
|
||||
0x55, 0x04, 0xd0, 0x2e, 0xc6, 0xb4, 0xd5, 0x25, 0xb8, 0x71, 0x38, 0x10, 0x50, 0x5f,
|
||||
0x4f, 0xc0, 0x31, 0x08, 0x3a, 0x14, 0xbf, 0x09,
|
||||
],
|
||||
rsig: [
|
||||
0x3f, 0x7d, 0x50, 0x71, 0xb8, 0x76, 0x17, 0x49, 0x05, 0x71, 0xa8, 0xbe, 0x91, 0x74,
|
||||
0x9e, 0x69, 0xf6, 0xbc, 0xba, 0x5a, 0xb6, 0x26, 0xe4, 0x2f, 0xf9, 0x2d, 0x0d, 0x7d,
|
||||
0xab, 0x73, 0xf3, 0x03, 0x61, 0xe5, 0xa2, 0x24, 0x99, 0x8e, 0x1f, 0x5e, 0xa1, 0xe5,
|
||||
0xf8, 0x68, 0x9a, 0x06, 0xa2, 0x77, 0x48, 0xbf, 0x74, 0x19, 0x63, 0xef, 0x51, 0x33,
|
||||
0x22, 0xf4, 0xa1, 0xba, 0x99, 0xaa, 0x36, 0x03,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0xb2, 0x08, 0x59, 0xb8, 0x8e, 0xe3, 0x33, 0x8a, 0x64, 0x95, 0x4f, 0x8a, 0x9e, 0x8e,
|
||||
0x9b, 0xf3, 0xe7, 0x11, 0x5a, 0xcf, 0x7c, 0x6e, 0x7f, 0x01, 0x43, 0x2c, 0x5f, 0x76,
|
||||
0x96, 0xd2, 0xd0, 0x05,
|
||||
],
|
||||
vk: [
|
||||
0xa8, 0x1f, 0xe6, 0x84, 0x6d, 0xbe, 0x0a, 0x75, 0xc0, 0xf4, 0x9b, 0x21, 0x32, 0x32,
|
||||
0xbe, 0xad, 0xd1, 0xf9, 0xa5, 0x64, 0x67, 0x3d, 0x25, 0xb9, 0x1e, 0xe0, 0xf1, 0x7c,
|
||||
0xe9, 0xca, 0xa3, 0x63,
|
||||
],
|
||||
alpha: [
|
||||
0x44, 0xd9, 0x08, 0xe1, 0xc1, 0x5e, 0x6b, 0xd9, 0x38, 0x0a, 0x8b, 0x23, 0x5a, 0xce,
|
||||
0x02, 0xfa, 0xc1, 0xc0, 0x87, 0x94, 0x45, 0x4b, 0xcd, 0xb4, 0xa6, 0xf4, 0x8c, 0xea,
|
||||
0x78, 0xa7, 0x4a, 0x04,
|
||||
],
|
||||
rsk: [
|
||||
0xf6, 0xe1, 0x61, 0x99, 0x50, 0x42, 0x9f, 0x63, 0x9d, 0x9f, 0xda, 0xad, 0xf8, 0x5c,
|
||||
0x9e, 0xed, 0xa9, 0xd2, 0xe1, 0x63, 0xc2, 0xb9, 0x4c, 0xb6, 0xe9, 0x20, 0xec, 0x60,
|
||||
0x0f, 0x7a, 0x1b, 0x0a,
|
||||
],
|
||||
rvk: [
|
||||
0x0b, 0x68, 0xd5, 0x0f, 0x91, 0x3c, 0xd1, 0xb7, 0x8b, 0x59, 0x92, 0x1e, 0x16, 0x56,
|
||||
0xd5, 0x76, 0xb0, 0xeb, 0x17, 0x1e, 0xd3, 0x87, 0x0d, 0x39, 0xfe, 0xc6, 0x94, 0x41,
|
||||
0xb3, 0x4b, 0x25, 0x38,
|
||||
],
|
||||
m: [
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07,
|
||||
],
|
||||
sig: [
|
||||
0x64, 0x59, 0x67, 0x6a, 0x94, 0x16, 0x34, 0xec, 0xb6, 0x1e, 0x59, 0xb7, 0x9a, 0x98,
|
||||
0xab, 0xe5, 0x87, 0x6f, 0x35, 0x6f, 0x72, 0x8a, 0xa0, 0x9e, 0x0c, 0xca, 0x9e, 0xfe,
|
||||
0x05, 0x76, 0x1a, 0x33, 0x09, 0xaa, 0x88, 0xb2, 0xfa, 0x0e, 0xe2, 0xd0, 0x4c, 0x1c,
|
||||
0x46, 0xe9, 0xf2, 0xa0, 0x48, 0xd5, 0x9d, 0x55, 0x65, 0xaf, 0xa6, 0xc3, 0xf1, 0x5b,
|
||||
0xce, 0x70, 0x8d, 0xaa, 0xab, 0x7b, 0x34, 0x0e,
|
||||
],
|
||||
rsig: [
|
||||
0xc9, 0x66, 0x84, 0xec, 0x7e, 0xa6, 0x0b, 0xde, 0x87, 0x88, 0x22, 0xdd, 0xca, 0xf6,
|
||||
0xb8, 0xb0, 0xbd, 0x31, 0x98, 0x51, 0x54, 0xdf, 0x9a, 0xd4, 0xf6, 0x90, 0x7d, 0xf8,
|
||||
0xfe, 0xd9, 0x5c, 0x1d, 0x84, 0xfe, 0x67, 0xe6, 0x78, 0x75, 0xa5, 0x39, 0x55, 0x0e,
|
||||
0xb2, 0x51, 0x4f, 0x19, 0x3b, 0x8e, 0xd4, 0x57, 0x25, 0x6c, 0x8d, 0x30, 0x28, 0x1d,
|
||||
0x6f, 0x8b, 0xb9, 0x54, 0x49, 0x24, 0xca, 0x0c,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x32, 0x16, 0xae, 0x47, 0xe9, 0xf5, 0x3e, 0x8a, 0x52, 0x79, 0x6f, 0x24, 0xb6, 0x24,
|
||||
0x60, 0x77, 0x6b, 0xd5, 0xf2, 0x05, 0xa7, 0x8e, 0x15, 0x95, 0xbc, 0x8e, 0xfe, 0xdc,
|
||||
0x51, 0x9d, 0x36, 0x0b,
|
||||
],
|
||||
vk: [
|
||||
0xdf, 0x74, 0xbf, 0x04, 0x79, 0x61, 0xcc, 0x5c, 0xda, 0xc8, 0x28, 0x90, 0xc7, 0x6e,
|
||||
0xc6, 0x75, 0xbd, 0x4e, 0x89, 0xea, 0xd2, 0x80, 0xc9, 0x52, 0xd7, 0xc3, 0x3e, 0xea,
|
||||
0xf2, 0xb5, 0xa6, 0x6b,
|
||||
],
|
||||
alpha: [
|
||||
0xc9, 0x61, 0xf2, 0xdd, 0x93, 0x68, 0x2a, 0xdb, 0x93, 0xf5, 0xc0, 0x5a, 0x73, 0xfd,
|
||||
0xbc, 0x6d, 0x43, 0xc7, 0x0e, 0x1b, 0x15, 0xe8, 0xd5, 0x3e, 0x3f, 0x17, 0xa8, 0x24,
|
||||
0x94, 0xe3, 0xf2, 0x09,
|
||||
],
|
||||
rsk: [
|
||||
0x44, 0x4b, 0xa9, 0x4e, 0x1e, 0x50, 0xd2, 0x94, 0x63, 0x5e, 0x68, 0xb2, 0x95, 0x01,
|
||||
0xb5, 0x3e, 0xae, 0x61, 0xcd, 0x1f, 0xbb, 0x3b, 0x84, 0xcd, 0x52, 0xf6, 0x72, 0x9c,
|
||||
0xfb, 0xcb, 0xab, 0x06,
|
||||
],
|
||||
rvk: [
|
||||
0x0a, 0xfb, 0xe4, 0x06, 0xa8, 0x91, 0xc3, 0xb8, 0xc3, 0x10, 0xc2, 0x15, 0xbc, 0x68,
|
||||
0xa9, 0x13, 0xde, 0x7c, 0xda, 0x06, 0xaf, 0x29, 0x42, 0x00, 0x56, 0x46, 0x8d, 0x0c,
|
||||
0x08, 0x85, 0x5b, 0x28,
|
||||
],
|
||||
m: [
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08,
|
||||
],
|
||||
sig: [
|
||||
0x24, 0x93, 0x2c, 0x1f, 0xaa, 0x01, 0x63, 0xca, 0x9a, 0x7f, 0xcd, 0xe4, 0x76, 0x11,
|
||||
0x29, 0xd2, 0xe5, 0xe9, 0x9c, 0xf5, 0xef, 0xa2, 0x5d, 0x27, 0x04, 0x58, 0x8e, 0x1c,
|
||||
0x75, 0x67, 0x7b, 0x5e, 0xeb, 0xe4, 0x55, 0x04, 0x8d, 0x7c, 0xe1, 0xb0, 0xd2, 0x01,
|
||||
0x27, 0x53, 0xf7, 0x1b, 0x27, 0x25, 0x01, 0x2e, 0xe1, 0x85, 0x49, 0x28, 0x73, 0x18,
|
||||
0xf9, 0xcd, 0x73, 0xf0, 0x7f, 0x0f, 0xb5, 0x02,
|
||||
],
|
||||
rsig: [
|
||||
0xf7, 0xfa, 0x26, 0xca, 0x22, 0xf3, 0x86, 0xc4, 0x3c, 0x19, 0x1a, 0x0b, 0x3e, 0xa6,
|
||||
0x57, 0x7e, 0x8e, 0xea, 0xa3, 0xf3, 0x6b, 0x9b, 0xd1, 0xa3, 0xac, 0x3d, 0xf6, 0xf8,
|
||||
0x83, 0xa3, 0xff, 0xdb, 0x31, 0x32, 0x0b, 0xde, 0x62, 0x7f, 0xf4, 0x6f, 0xc2, 0x26,
|
||||
0x4a, 0x32, 0x63, 0xb9, 0xab, 0x67, 0x12, 0x3b, 0xa5, 0xe1, 0x08, 0x43, 0x20, 0xd9,
|
||||
0x10, 0xb3, 0x94, 0xef, 0x8c, 0x65, 0xba, 0x09,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
sk: [
|
||||
0x85, 0x83, 0x6f, 0x98, 0x32, 0xb2, 0x8d, 0xe7, 0xc6, 0x36, 0x13, 0xe2, 0xa6, 0xed,
|
||||
0x36, 0xfb, 0x1a, 0xb4, 0x4f, 0xb0, 0xc1, 0x3f, 0xa8, 0x79, 0x8c, 0xd9, 0xcd, 0x30,
|
||||
0x30, 0xd4, 0x55, 0x03,
|
||||
],
|
||||
vk: [
|
||||
0xbf, 0xd5, 0xbc, 0x00, 0xc7, 0xc0, 0x22, 0xaa, 0x89, 0x01, 0xae, 0x08, 0x3c, 0x12,
|
||||
0xd5, 0x4b, 0x82, 0xf0, 0xdd, 0xff, 0x8e, 0xd6, 0xdb, 0x9a, 0x12, 0xd5, 0x9a, 0x5e,
|
||||
0xf6, 0xa5, 0xa2, 0xe0,
|
||||
],
|
||||
alpha: [
|
||||
0xa2, 0xe8, 0xb9, 0xe1, 0x6d, 0x6f, 0xf3, 0xca, 0x6c, 0x53, 0xd4, 0xe8, 0x8a, 0xbb,
|
||||
0xb9, 0x9b, 0xe7, 0xaf, 0x7e, 0x36, 0x59, 0x63, 0x1f, 0x1e, 0xae, 0x1e, 0xff, 0x23,
|
||||
0x87, 0x4d, 0x8e, 0x0c,
|
||||
],
|
||||
rsk: [
|
||||
0x70, 0x3f, 0x32, 0xa3, 0x41, 0x13, 0xea, 0xe1, 0xb0, 0x79, 0x1f, 0xfe, 0x9d, 0x88,
|
||||
0x88, 0xf0, 0x01, 0x29, 0x9a, 0xe5, 0x19, 0x68, 0x60, 0x91, 0x91, 0x48, 0x99, 0xef,
|
||||
0xcc, 0x6c, 0x66, 0x01,
|
||||
],
|
||||
rvk: [
|
||||
0xeb, 0x92, 0x97, 0x03, 0x6c, 0xf5, 0x17, 0xe1, 0x5e, 0x9e, 0xfe, 0x39, 0x75, 0x32,
|
||||
0x8d, 0xb4, 0x8e, 0xe7, 0xc2, 0x69, 0x4e, 0x94, 0x6d, 0xb2, 0x5f, 0x52, 0x87, 0x88,
|
||||
0xf6, 0xa1, 0xdb, 0x14,
|
||||
],
|
||||
m: [
|
||||
0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
|
||||
0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
|
||||
0x09, 0x09, 0x09, 0x09,
|
||||
],
|
||||
sig: [
|
||||
0x64, 0xab, 0xd1, 0x25, 0xbf, 0xc4, 0xc6, 0x54, 0xfa, 0xf2, 0xb6, 0xdd, 0x75, 0x3e,
|
||||
0xc6, 0x90, 0x22, 0x4d, 0xbc, 0xab, 0x8c, 0xd6, 0x32, 0xdd, 0x59, 0x3c, 0x91, 0xce,
|
||||
0x3a, 0xb0, 0xbc, 0xad, 0xca, 0x92, 0x76, 0x34, 0x02, 0x1c, 0x31, 0x47, 0x6c, 0x78,
|
||||
0xc5, 0xac, 0x7c, 0xcc, 0xab, 0xbd, 0x6f, 0x92, 0x7d, 0xf2, 0x05, 0xea, 0xa7, 0x07,
|
||||
0xcc, 0x00, 0xd4, 0x7d, 0x39, 0xf3, 0xe4, 0x0c,
|
||||
],
|
||||
rsig: [
|
||||
0xeb, 0x7a, 0x06, 0x5d, 0x75, 0xf8, 0x45, 0xdc, 0x09, 0x41, 0xb7, 0x09, 0xc0, 0xb1,
|
||||
0x49, 0xea, 0xfd, 0x80, 0x5e, 0xa5, 0x8f, 0x38, 0x0b, 0x92, 0xb9, 0xd3, 0x10, 0x8a,
|
||||
0x56, 0x1b, 0xda, 0x17, 0x85, 0xdf, 0x8f, 0x10, 0x1e, 0x0e, 0x14, 0x0f, 0xca, 0xee,
|
||||
0x99, 0xb7, 0xdb, 0xb7, 0xdf, 0xbf, 0x7e, 0x61, 0xf3, 0xa1, 0x2f, 0x46, 0x09, 0x50,
|
||||
0x69, 0xe0, 0x6e, 0x88, 0x96, 0xa9, 0xe4, 0x04,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
for tv in test_vectors {
|
||||
let sk = PrivateKey::<Bls12>::read(&tv.sk[..]).unwrap();
|
||||
let vk = PublicKey::<Bls12>::read(&tv.vk[..], &JUBJUB).unwrap();
|
||||
let rvk = PublicKey::<Bls12>::read(&tv.rvk[..], &JUBJUB).unwrap();
|
||||
let sig = Signature::read(&tv.sig[..]).unwrap();
|
||||
let rsig = Signature::read(&tv.rsig[..]).unwrap();
|
||||
|
||||
let mut alpha_repr = <<Bls12 as JubjubEngine>::Fs as PrimeField>::Repr::default();
|
||||
alpha_repr.read_le(&tv.alpha[..]).unwrap();
|
||||
let alpha = <Bls12 as JubjubEngine>::Fs::from_repr(alpha_repr).unwrap();
|
||||
|
||||
{
|
||||
let mut vec = Vec::new();
|
||||
sk.randomize(alpha.clone()).write(&mut vec).unwrap();
|
||||
assert_eq!(&vec, &tv.rsk);
|
||||
}
|
||||
{
|
||||
let mut vec = Vec::new();
|
||||
vk.randomize(alpha, FixedGenerators::SpendingKeyGenerator, &JUBJUB)
|
||||
.write(&mut vec)
|
||||
.unwrap();
|
||||
assert_eq!(&vec, &tv.rvk);
|
||||
}
|
||||
|
||||
assert!(vk.verify(&tv.m, &sig, FixedGenerators::SpendingKeyGenerator, &JUBJUB));
|
||||
assert!(rvk.verify(&tv.m, &rsig, FixedGenerators::SpendingKeyGenerator, &JUBJUB));
|
||||
assert!(!vk.verify(&tv.m, &rsig, FixedGenerators::SpendingKeyGenerator, &JUBJUB));
|
||||
assert!(!rvk.verify(&tv.m, &sig, FixedGenerators::SpendingKeyGenerator, &JUBJUB));
|
||||
}
|
||||
}
|
3
pairing/.gitignore
vendored
3
pairing/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
target/
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
@ -1,14 +0,0 @@
|
||||
Copyrights in the "pairing" library are retained by their contributors. No
|
||||
copyright assignment is required to contribute to the "pairing" library.
|
||||
|
||||
The "pairing" 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.
|
@ -1,26 +0,0 @@
|
||||
[package]
|
||||
name = "pairing"
|
||||
|
||||
# Remember to change version string in README.md.
|
||||
version = "0.14.2"
|
||||
authors = [
|
||||
"Sean Bowe <ewillbefull@gmail.com>",
|
||||
"Jack Grigg <jack@z.cash>",
|
||||
]
|
||||
license = "MIT/Apache-2.0"
|
||||
|
||||
description = "Pairing-friendly elliptic curve library"
|
||||
documentation = "https://docs.rs/pairing/"
|
||||
homepage = "https://github.com/ebfull/pairing"
|
||||
repository = "https://github.com/ebfull/pairing"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.4"
|
||||
byteorder = "1"
|
||||
ff = { version = "0.4", features = ["derive"] }
|
||||
group = "0.1"
|
||||
|
||||
[features]
|
||||
unstable-features = ["expose-arith"]
|
||||
expose-arith = []
|
||||
default = []
|
@ -1,201 +0,0 @@
|
||||
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.
|
@ -1,23 +0,0 @@
|
||||
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.
|
@ -1,27 +0,0 @@
|
||||
# pairing [![Crates.io](https://img.shields.io/crates/v/pairing.svg)](https://crates.io/crates/pairing) #
|
||||
|
||||
This is a Rust crate for using pairing-friendly elliptic curves. Currently, only the [BLS12-381](https://z.cash/blog/new-snark-curve.html) construction is implemented.
|
||||
|
||||
## [Documentation](https://docs.rs/pairing/)
|
||||
|
||||
Bring the `pairing` crate into your project just as you normally would.
|
||||
|
||||
## Security Warnings
|
||||
|
||||
This library does not make any guarantees about constant-time operations, memory access patterns, or resistance to side-channel attacks.
|
||||
|
||||
## 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.
|
@ -1,127 +0,0 @@
|
||||
mod g1 {
|
||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||
|
||||
use group::CurveProjective;
|
||||
use pairing::bls12_381::*;
|
||||
|
||||
#[bench]
|
||||
fn bench_g1_mul_assign(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(G1, Fr)> = (0..SAMPLES)
|
||||
.map(|_| (G1::rand(&mut rng), Fr::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.mul_assign(v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_g1_add_assign(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(G1, G1)> = (0..SAMPLES)
|
||||
.map(|_| (G1::rand(&mut rng), G1::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.add_assign(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_g1_add_assign_mixed(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(G1, G1Affine)> = (0..SAMPLES)
|
||||
.map(|_| (G1::rand(&mut rng), G1::rand(&mut rng).into()))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.add_assign_mixed(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
mod g2 {
|
||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||
|
||||
use group::CurveProjective;
|
||||
use pairing::bls12_381::*;
|
||||
|
||||
#[bench]
|
||||
fn bench_g2_mul_assign(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(G2, Fr)> = (0..SAMPLES)
|
||||
.map(|_| (G2::rand(&mut rng), Fr::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.mul_assign(v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_g2_add_assign(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(G2, G2)> = (0..SAMPLES)
|
||||
.map(|_| (G2::rand(&mut rng), G2::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.add_assign(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_g2_add_assign_mixed(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(G2, G2Affine)> = (0..SAMPLES)
|
||||
.map(|_| (G2::rand(&mut rng), G2::rand(&mut rng).into()))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.add_assign_mixed(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
}
|
@ -1,268 +0,0 @@
|
||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||
|
||||
use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField};
|
||||
use pairing::bls12_381::*;
|
||||
|
||||
#[bench]
|
||||
fn bench_fq_repr_add_nocarry(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES)
|
||||
.map(|_| {
|
||||
let mut tmp1 = FqRepr::rand(&mut rng);
|
||||
let mut tmp2 = FqRepr::rand(&mut rng);
|
||||
// Shave a few bits off to avoid overflow.
|
||||
for _ in 0..3 {
|
||||
tmp1.div2();
|
||||
tmp2.div2();
|
||||
}
|
||||
(tmp1, tmp2)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.add_nocarry(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq_repr_sub_noborrow(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES)
|
||||
.map(|_| {
|
||||
let tmp1 = FqRepr::rand(&mut rng);
|
||||
let mut tmp2 = tmp1;
|
||||
// Ensure tmp2 is smaller than tmp1.
|
||||
for _ in 0..10 {
|
||||
tmp2.div2();
|
||||
}
|
||||
(tmp1, tmp2)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.sub_noborrow(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq_repr_num_bits(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<FqRepr> = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let tmp = v[count].num_bits();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq_repr_mul2(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<FqRepr> = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count];
|
||||
tmp.mul2();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq_repr_div2(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<FqRepr> = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count];
|
||||
tmp.div2();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq_add_assign(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(Fq, Fq)> = (0..SAMPLES)
|
||||
.map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.add_assign(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq_sub_assign(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(Fq, Fq)> = (0..SAMPLES)
|
||||
.map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.sub_assign(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq_mul_assign(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(Fq, Fq)> = (0..SAMPLES)
|
||||
.map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.mul_assign(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq_square(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<Fq> = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count];
|
||||
tmp.square();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq_inverse(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<Fq> = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
count = (count + 1) % SAMPLES;
|
||||
v[count].inverse()
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq_negate(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<Fq> = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count];
|
||||
tmp.negate();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq_sqrt(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<Fq> = (0..SAMPLES)
|
||||
.map(|_| {
|
||||
let mut tmp = Fq::rand(&mut rng);
|
||||
tmp.square();
|
||||
tmp
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
count = (count + 1) % SAMPLES;
|
||||
v[count].sqrt()
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq_into_repr(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<Fq> = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
count = (count + 1) % SAMPLES;
|
||||
v[count].into_repr()
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq_from_repr(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<FqRepr> = (0..SAMPLES)
|
||||
.map(|_| Fq::rand(&mut rng).into_repr())
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
count = (count + 1) % SAMPLES;
|
||||
Fq::from_repr(v[count])
|
||||
});
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||
|
||||
use ff::Field;
|
||||
use pairing::bls12_381::*;
|
||||
|
||||
#[bench]
|
||||
fn bench_fq12_add_assign(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(Fq12, Fq12)> = (0..SAMPLES)
|
||||
.map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.add_assign(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq12_sub_assign(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(Fq12, Fq12)> = (0..SAMPLES)
|
||||
.map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.sub_assign(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq12_mul_assign(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(Fq12, Fq12)> = (0..SAMPLES)
|
||||
.map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.mul_assign(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq12_squaring(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<Fq12> = (0..SAMPLES).map(|_| Fq12::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count];
|
||||
tmp.square();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq12_inverse(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<Fq12> = (0..SAMPLES).map(|_| Fq12::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let tmp = v[count].inverse();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||
|
||||
use ff::{Field, SqrtField};
|
||||
use pairing::bls12_381::*;
|
||||
|
||||
#[bench]
|
||||
fn bench_fq2_add_assign(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(Fq2, Fq2)> = (0..SAMPLES)
|
||||
.map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.add_assign(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq2_sub_assign(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(Fq2, Fq2)> = (0..SAMPLES)
|
||||
.map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.sub_assign(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq2_mul_assign(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(Fq2, Fq2)> = (0..SAMPLES)
|
||||
.map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.mul_assign(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq2_squaring(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<Fq2> = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count];
|
||||
tmp.square();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq2_inverse(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<Fq2> = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let tmp = v[count].inverse();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fq2_sqrt(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<Fq2> = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let tmp = v[count].sqrt();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
@ -1,268 +0,0 @@
|
||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||
|
||||
use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField};
|
||||
use pairing::bls12_381::*;
|
||||
|
||||
#[bench]
|
||||
fn bench_fr_repr_add_nocarry(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES)
|
||||
.map(|_| {
|
||||
let mut tmp1 = FrRepr::rand(&mut rng);
|
||||
let mut tmp2 = FrRepr::rand(&mut rng);
|
||||
// Shave a few bits off to avoid overflow.
|
||||
for _ in 0..3 {
|
||||
tmp1.div2();
|
||||
tmp2.div2();
|
||||
}
|
||||
(tmp1, tmp2)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.add_nocarry(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fr_repr_sub_noborrow(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES)
|
||||
.map(|_| {
|
||||
let tmp1 = FrRepr::rand(&mut rng);
|
||||
let mut tmp2 = tmp1;
|
||||
// Ensure tmp2 is smaller than tmp1.
|
||||
for _ in 0..10 {
|
||||
tmp2.div2();
|
||||
}
|
||||
(tmp1, tmp2)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.sub_noborrow(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fr_repr_num_bits(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<FrRepr> = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let tmp = v[count].num_bits();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fr_repr_mul2(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<FrRepr> = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count];
|
||||
tmp.mul2();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fr_repr_div2(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<FrRepr> = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count];
|
||||
tmp.div2();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fr_add_assign(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(Fr, Fr)> = (0..SAMPLES)
|
||||
.map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.add_assign(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fr_sub_assign(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(Fr, Fr)> = (0..SAMPLES)
|
||||
.map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.sub_assign(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fr_mul_assign(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(Fr, Fr)> = (0..SAMPLES)
|
||||
.map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count].0;
|
||||
tmp.mul_assign(&v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fr_square(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<Fr> = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count];
|
||||
tmp.square();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fr_inverse(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<Fr> = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
count = (count + 1) % SAMPLES;
|
||||
v[count].inverse()
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fr_negate(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<Fr> = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let mut tmp = v[count];
|
||||
tmp.negate();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fr_sqrt(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<Fr> = (0..SAMPLES)
|
||||
.map(|_| {
|
||||
let mut tmp = Fr::rand(&mut rng);
|
||||
tmp.square();
|
||||
tmp
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
count = (count + 1) % SAMPLES;
|
||||
v[count].sqrt()
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fr_into_repr(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<Fr> = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
count = (count + 1) % SAMPLES;
|
||||
v[count].into_repr()
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fr_from_repr(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<FrRepr> = (0..SAMPLES)
|
||||
.map(|_| Fr::rand(&mut rng).into_repr())
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
count = (count + 1) % SAMPLES;
|
||||
Fr::from_repr(v[count])
|
||||
});
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
mod ec;
|
||||
mod fq;
|
||||
mod fq12;
|
||||
mod fq2;
|
||||
mod fr;
|
||||
|
||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||
|
||||
use pairing::bls12_381::*;
|
||||
use pairing::{Engine, PairingCurveAffine};
|
||||
|
||||
#[bench]
|
||||
fn bench_pairing_g1_preparation(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<G1> = (0..SAMPLES).map(|_| G1::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let tmp = G1Affine::from(v[count]).prepare();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_pairing_g2_preparation(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<G2> = (0..SAMPLES).map(|_| G2::rand(&mut rng)).collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let tmp = G2Affine::from(v[count]).prepare();
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_pairing_miller_loop(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(G1Prepared, G2Prepared)> = (0..SAMPLES)
|
||||
.map(|_| {
|
||||
(
|
||||
G1Affine::from(G1::rand(&mut rng)).prepare(),
|
||||
G2Affine::from(G2::rand(&mut rng)).prepare(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let tmp = Bls12::miller_loop(&[(&v[count].0, &v[count].1)]);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_pairing_final_exponentiation(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<Fq12> = (0..SAMPLES)
|
||||
.map(|_| {
|
||||
(
|
||||
G1Affine::from(G1::rand(&mut rng)).prepare(),
|
||||
G2Affine::from(G2::rand(&mut rng)).prepare(),
|
||||
)
|
||||
})
|
||||
.map(|(ref p, ref q)| Bls12::miller_loop(&[(p, q)]))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let tmp = Bls12::final_exponentiation(&v[count]);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_pairing_full(b: &mut ::test::Bencher) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let v: Vec<(G1, G2)> = (0..SAMPLES)
|
||||
.map(|_| (G1::rand(&mut rng), G2::rand(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
b.iter(|| {
|
||||
let tmp = Bls12::pairing(v[count].0, v[count].1);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
});
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
#![feature(test)]
|
||||
|
||||
extern crate ff;
|
||||
extern crate group;
|
||||
extern crate pairing;
|
||||
extern crate rand;
|
||||
extern crate test;
|
||||
|
||||
mod bls12_381;
|
@ -1,71 +0,0 @@
|
||||
# BLS12-381
|
||||
|
||||
This is an implementation of the BLS12-381 pairing-friendly elliptic curve construction.
|
||||
|
||||
## BLS12 Parameterization
|
||||
|
||||
BLS12 curves are parameterized by a value *x* such that the base field modulus *q* and subgroup *r* can be computed by:
|
||||
|
||||
* q = (x - 1)<sup>2</sup> ((x<sup>4</sup> - x<sup>2</sup> + 1) / 3) + x
|
||||
* r = (x<sup>4</sup> - x<sup>2</sup> + 1)
|
||||
|
||||
Given primes *q* and *r* parameterized as above, we can easily construct an elliptic curve over the prime field F<sub>*q*</sub> which contains a subgroup of order *r* such that *r* | (*q*<sup>12</sup> - 1), giving it an embedding degree of 12. Instantiating its sextic twist over an extension field F<sub>q<sup>2</sup></sub> gives rise to an efficient bilinear pairing function between elements of the order *r* subgroups of either curves, into an order *r* multiplicative subgroup of F<sub>q<sup>12</sup></sub>.
|
||||
|
||||
In zk-SNARK schemes, we require F<sub>r</sub> with large 2<sup>n</sup> roots of unity for performing efficient fast-fourier transforms. As such, guaranteeing that large 2<sup>n</sup> | (r - 1), or equivalently that *x* has a large 2<sup>n</sup> factor, gives rise to BLS12 curves suitable for zk-SNARKs.
|
||||
|
||||
Due to recent research, it is estimated by many that *q* should be approximately 384 bits to target 128-bit security. Conveniently, *r* is approximately 256 bits when *q* is approximately 384 bits, making BLS12 curves ideal for 128-bit security. It also makes them ideal for many zk-SNARK applications, as the scalar field can be used for keying material such as embedded curve constructions.
|
||||
|
||||
Many curves match our descriptions, but we require some extra properties for efficiency purposes:
|
||||
|
||||
* *q* should be smaller than 2<sup>383</sup>, and *r* should be smaller than 2<sup>255</sup>, so that the most significant bit is unset when using 64-bit or 32-bit limbs. This allows for cheap reductions.
|
||||
* F<sub>q<sup>12</sup></sub> is typically constructed using towers of extension fields. As a byproduct of [research](https://eprint.iacr.org/2011/465.pdf) for BLS curves of embedding degree 24, we can identify subfamilies of BLS12 curves (for our purposes, where x mod 72 = {16, 64}) that produce efficient extension field towers and twisting isomorphisms.
|
||||
* We desire *x* of small Hamming weight, to increase the performance of the pairing function.
|
||||
|
||||
## BLS12-381 Instantiation
|
||||
|
||||
The BLS12-381 construction is instantiated by `x = -0xd201000000010000`, which produces the largest `q` and smallest Hamming weight of `x` that meets the above requirements. This produces:
|
||||
|
||||
* q = `0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab` (381 bits)
|
||||
* r = `0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001` (255 bits)
|
||||
|
||||
Our extension field tower is constructed as follows:
|
||||
|
||||
1. F<sub>q<sup>2</sup></sub> is constructed as F<sub>q</sub>(u) / (u<sup>2</sup> - β) where β = -1.
|
||||
2. F<sub>q<sup>6</sup></sub> is constructed as F<sub>q<sup>2</sup></sub>(v) / (v<sup>3</sup> - ξ) where ξ = u + 1
|
||||
3. F<sub>q<sup>12</sup></sub> is constructed as F<sub>q<sup>6</sup></sub>(w) / (w<sup>2</sup> - γ) where γ = v
|
||||
|
||||
Now, we instantiate the elliptic curve E(F<sub>q</sub>) : y<sup>2</sup> = x<sup>3</sup> + 4, and the elliptic curve E'(F<sub>q<sup>2</sup></sub>) : y<sup>2</sup> = x<sup>3</sup> + 4(u + 1).
|
||||
|
||||
The group G<sub>1</sub> is the *r* order subgroup of E, which has cofactor (x - 1)<sup>2</sup> / 3. The group G<sub>2</sub> is the *r* order subgroup of E', which has cofactor (x<sup>8</sup> - 4x<sup>7</sup> + 5x<sup>6</sup> - 4x<sup>4</sup> + 6x<sup>3</sup> - 4x<sup>2</sup> - 4x + 13) / 9.
|
||||
|
||||
### Generators
|
||||
|
||||
The generators of G<sub>1</sub> and G<sub>2</sub> are computed by finding the lexicographically smallest valid `x`-coordinate, and its lexicographically smallest `y`-coordinate and scaling it by the cofactor such that the result is not the point at infinity.
|
||||
|
||||
#### G1
|
||||
|
||||
```
|
||||
x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507
|
||||
y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569
|
||||
```
|
||||
|
||||
#### G2
|
||||
|
||||
```
|
||||
x = 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758*u + 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160
|
||||
y = 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582*u + 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905
|
||||
```
|
||||
|
||||
### Serialization
|
||||
|
||||
* Fq elements are encoded in big-endian form. They occupy 48 bytes in this form.
|
||||
* Fq2 elements are encoded in big-endian form, meaning that the Fq element c0 + c1 * u is represented by the Fq element c1 followed by the Fq element c0. This means Fq2 elements occupy 96 bytes in this form.
|
||||
* The group G1 uses Fq elements for coordinates. The group G2 uses Fq2 elements for coordinates.
|
||||
* G1 and G2 elements can be encoded in uncompressed form (the x-coordinate followed by the y-coordinate) or in compressed form (just the x-coordinate). G1 elements occupy 96 bytes in uncompressed form, and 48 bytes in compressed form. G2 elements occupy 192 bytes in uncompressed form, and 96 bytes in compressed form.
|
||||
|
||||
The most-significant three bits of a G1 or G2 encoding should be masked away before the coordinate(s) are interpreted. These bits are used to unambiguously represent the underlying element:
|
||||
|
||||
* The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form.
|
||||
* The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero.
|
||||
* The third-most significant bit is set if (and only if) this point is in compressed form _and_ it is not the point at infinity _and_ its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate.
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,189 +0,0 @@
|
||||
use super::fq::FROBENIUS_COEFF_FQ12_C1;
|
||||
use super::fq2::Fq2;
|
||||
use super::fq6::Fq6;
|
||||
use ff::Field;
|
||||
use rand::{Rand, Rng};
|
||||
|
||||
/// An element of Fq12, represented by c0 + c1 * w.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Fq12 {
|
||||
pub c0: Fq6,
|
||||
pub c1: Fq6,
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for Fq12 {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
write!(f, "Fq12({} + {} * w)", self.c0, self.c1)
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for Fq12 {
|
||||
fn rand<R: Rng>(rng: &mut R) -> Self {
|
||||
Fq12 {
|
||||
c0: rng.gen(),
|
||||
c1: rng.gen(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Fq12 {
|
||||
pub fn conjugate(&mut self) {
|
||||
self.c1.negate();
|
||||
}
|
||||
|
||||
pub fn mul_by_014(&mut self, c0: &Fq2, c1: &Fq2, c4: &Fq2) {
|
||||
let mut aa = self.c0;
|
||||
aa.mul_by_01(c0, c1);
|
||||
let mut bb = self.c1;
|
||||
bb.mul_by_1(c4);
|
||||
let mut o = *c1;
|
||||
o.add_assign(c4);
|
||||
self.c1.add_assign(&self.c0);
|
||||
self.c1.mul_by_01(c0, &o);
|
||||
self.c1.sub_assign(&aa);
|
||||
self.c1.sub_assign(&bb);
|
||||
self.c0 = bb;
|
||||
self.c0.mul_by_nonresidue();
|
||||
self.c0.add_assign(&aa);
|
||||
}
|
||||
}
|
||||
|
||||
impl Field for Fq12 {
|
||||
fn zero() -> Self {
|
||||
Fq12 {
|
||||
c0: Fq6::zero(),
|
||||
c1: Fq6::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
fn one() -> Self {
|
||||
Fq12 {
|
||||
c0: Fq6::one(),
|
||||
c1: Fq6::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.c0.is_zero() && self.c1.is_zero()
|
||||
}
|
||||
|
||||
fn double(&mut self) {
|
||||
self.c0.double();
|
||||
self.c1.double();
|
||||
}
|
||||
|
||||
fn negate(&mut self) {
|
||||
self.c0.negate();
|
||||
self.c1.negate();
|
||||
}
|
||||
|
||||
fn add_assign(&mut self, other: &Self) {
|
||||
self.c0.add_assign(&other.c0);
|
||||
self.c1.add_assign(&other.c1);
|
||||
}
|
||||
|
||||
fn sub_assign(&mut self, other: &Self) {
|
||||
self.c0.sub_assign(&other.c0);
|
||||
self.c1.sub_assign(&other.c1);
|
||||
}
|
||||
|
||||
fn frobenius_map(&mut self, power: usize) {
|
||||
self.c0.frobenius_map(power);
|
||||
self.c1.frobenius_map(power);
|
||||
|
||||
self.c1.c0.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]);
|
||||
self.c1.c1.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]);
|
||||
self.c1.c2.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]);
|
||||
}
|
||||
|
||||
fn square(&mut self) {
|
||||
let mut ab = self.c0;
|
||||
ab.mul_assign(&self.c1);
|
||||
let mut c0c1 = self.c0;
|
||||
c0c1.add_assign(&self.c1);
|
||||
let mut c0 = self.c1;
|
||||
c0.mul_by_nonresidue();
|
||||
c0.add_assign(&self.c0);
|
||||
c0.mul_assign(&c0c1);
|
||||
c0.sub_assign(&ab);
|
||||
self.c1 = ab;
|
||||
self.c1.add_assign(&ab);
|
||||
ab.mul_by_nonresidue();
|
||||
c0.sub_assign(&ab);
|
||||
self.c0 = c0;
|
||||
}
|
||||
|
||||
fn mul_assign(&mut self, other: &Self) {
|
||||
let mut aa = self.c0;
|
||||
aa.mul_assign(&other.c0);
|
||||
let mut bb = self.c1;
|
||||
bb.mul_assign(&other.c1);
|
||||
let mut o = other.c0;
|
||||
o.add_assign(&other.c1);
|
||||
self.c1.add_assign(&self.c0);
|
||||
self.c1.mul_assign(&o);
|
||||
self.c1.sub_assign(&aa);
|
||||
self.c1.sub_assign(&bb);
|
||||
self.c0 = bb;
|
||||
self.c0.mul_by_nonresidue();
|
||||
self.c0.add_assign(&aa);
|
||||
}
|
||||
|
||||
fn inverse(&self) -> Option<Self> {
|
||||
let mut c0s = self.c0;
|
||||
c0s.square();
|
||||
let mut c1s = self.c1;
|
||||
c1s.square();
|
||||
c1s.mul_by_nonresidue();
|
||||
c0s.sub_assign(&c1s);
|
||||
|
||||
c0s.inverse().map(|t| {
|
||||
let mut tmp = Fq12 { c0: t, c1: t };
|
||||
tmp.c0.mul_assign(&self.c0);
|
||||
tmp.c1.mul_assign(&self.c1);
|
||||
tmp.c1.negate();
|
||||
|
||||
tmp
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use rand::{SeedableRng, XorShiftRng};
|
||||
|
||||
#[test]
|
||||
fn test_fq12_mul_by_014() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let c0 = Fq2::rand(&mut rng);
|
||||
let c1 = Fq2::rand(&mut rng);
|
||||
let c5 = Fq2::rand(&mut rng);
|
||||
let mut a = Fq12::rand(&mut rng);
|
||||
let mut b = a;
|
||||
|
||||
a.mul_by_014(&c0, &c1, &c5);
|
||||
b.mul_assign(&Fq12 {
|
||||
c0: Fq6 {
|
||||
c0: c0,
|
||||
c1: c1,
|
||||
c2: Fq2::zero(),
|
||||
},
|
||||
c1: Fq6 {
|
||||
c0: Fq2::zero(),
|
||||
c1: c5,
|
||||
c2: Fq2::zero(),
|
||||
},
|
||||
});
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fq12_field_tests() {
|
||||
use ff::PrimeField;
|
||||
|
||||
::tests::field::random_field_tests::<Fq12>();
|
||||
::tests::field::random_frobenius_tests::<Fq12, _>(super::fq::Fq::char(), 13);
|
||||
}
|
@ -1,910 +0,0 @@
|
||||
use super::fq::{FROBENIUS_COEFF_FQ2_C1, Fq, NEGATIVE_ONE};
|
||||
use ff::{Field, SqrtField};
|
||||
use rand::{Rand, Rng};
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
/// An element of Fq2, represented by c0 + c1 * u.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Fq2 {
|
||||
pub c0: Fq,
|
||||
pub c1: Fq,
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for Fq2 {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
write!(f, "Fq2({} + {} * u)", self.c0, self.c1)
|
||||
}
|
||||
}
|
||||
|
||||
/// `Fq2` elements are ordered lexicographically.
|
||||
impl Ord for Fq2 {
|
||||
#[inline(always)]
|
||||
fn cmp(&self, other: &Fq2) -> Ordering {
|
||||
match self.c1.cmp(&other.c1) {
|
||||
Ordering::Greater => Ordering::Greater,
|
||||
Ordering::Less => Ordering::Less,
|
||||
Ordering::Equal => self.c0.cmp(&other.c0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Fq2 {
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, other: &Fq2) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Fq2 {
|
||||
/// Multiply this element by the cubic and quadratic nonresidue 1 + u.
|
||||
pub fn mul_by_nonresidue(&mut self) {
|
||||
let t0 = self.c0;
|
||||
self.c0.sub_assign(&self.c1);
|
||||
self.c1.add_assign(&t0);
|
||||
}
|
||||
|
||||
/// Norm of Fq2 as extension field in i over Fq
|
||||
pub fn norm(&self) -> Fq {
|
||||
let mut t0 = self.c0;
|
||||
let mut t1 = self.c1;
|
||||
t0.square();
|
||||
t1.square();
|
||||
t1.add_assign(&t0);
|
||||
|
||||
t1
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for Fq2 {
|
||||
fn rand<R: Rng>(rng: &mut R) -> Self {
|
||||
Fq2 {
|
||||
c0: rng.gen(),
|
||||
c1: rng.gen(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Field for Fq2 {
|
||||
fn zero() -> Self {
|
||||
Fq2 {
|
||||
c0: Fq::zero(),
|
||||
c1: Fq::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
fn one() -> Self {
|
||||
Fq2 {
|
||||
c0: Fq::one(),
|
||||
c1: Fq::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.c0.is_zero() && self.c1.is_zero()
|
||||
}
|
||||
|
||||
fn square(&mut self) {
|
||||
let mut ab = self.c0;
|
||||
ab.mul_assign(&self.c1);
|
||||
let mut c0c1 = self.c0;
|
||||
c0c1.add_assign(&self.c1);
|
||||
let mut c0 = self.c1;
|
||||
c0.negate();
|
||||
c0.add_assign(&self.c0);
|
||||
c0.mul_assign(&c0c1);
|
||||
c0.sub_assign(&ab);
|
||||
self.c1 = ab;
|
||||
self.c1.add_assign(&ab);
|
||||
c0.add_assign(&ab);
|
||||
self.c0 = c0;
|
||||
}
|
||||
|
||||
fn double(&mut self) {
|
||||
self.c0.double();
|
||||
self.c1.double();
|
||||
}
|
||||
|
||||
fn negate(&mut self) {
|
||||
self.c0.negate();
|
||||
self.c1.negate();
|
||||
}
|
||||
|
||||
fn add_assign(&mut self, other: &Self) {
|
||||
self.c0.add_assign(&other.c0);
|
||||
self.c1.add_assign(&other.c1);
|
||||
}
|
||||
|
||||
fn sub_assign(&mut self, other: &Self) {
|
||||
self.c0.sub_assign(&other.c0);
|
||||
self.c1.sub_assign(&other.c1);
|
||||
}
|
||||
|
||||
fn mul_assign(&mut self, other: &Self) {
|
||||
let mut aa = self.c0;
|
||||
aa.mul_assign(&other.c0);
|
||||
let mut bb = self.c1;
|
||||
bb.mul_assign(&other.c1);
|
||||
let mut o = other.c0;
|
||||
o.add_assign(&other.c1);
|
||||
self.c1.add_assign(&self.c0);
|
||||
self.c1.mul_assign(&o);
|
||||
self.c1.sub_assign(&aa);
|
||||
self.c1.sub_assign(&bb);
|
||||
self.c0 = aa;
|
||||
self.c0.sub_assign(&bb);
|
||||
}
|
||||
|
||||
fn inverse(&self) -> Option<Self> {
|
||||
let mut t1 = self.c1;
|
||||
t1.square();
|
||||
let mut t0 = self.c0;
|
||||
t0.square();
|
||||
t0.add_assign(&t1);
|
||||
t0.inverse().map(|t| {
|
||||
let mut tmp = Fq2 {
|
||||
c0: self.c0,
|
||||
c1: self.c1,
|
||||
};
|
||||
tmp.c0.mul_assign(&t);
|
||||
tmp.c1.mul_assign(&t);
|
||||
tmp.c1.negate();
|
||||
|
||||
tmp
|
||||
})
|
||||
}
|
||||
|
||||
fn frobenius_map(&mut self, power: usize) {
|
||||
self.c1.mul_assign(&FROBENIUS_COEFF_FQ2_C1[power % 2]);
|
||||
}
|
||||
}
|
||||
|
||||
impl SqrtField for Fq2 {
|
||||
fn legendre(&self) -> ::ff::LegendreSymbol {
|
||||
self.norm().legendre()
|
||||
}
|
||||
|
||||
fn sqrt(&self) -> Option<Self> {
|
||||
// Algorithm 9, https://eprint.iacr.org/2012/685.pdf
|
||||
|
||||
if self.is_zero() {
|
||||
Some(Self::zero())
|
||||
} else {
|
||||
// a1 = self^((q - 3) / 4)
|
||||
let mut a1 = self.pow([
|
||||
0xee7fbfffffffeaaa,
|
||||
0x7aaffffac54ffff,
|
||||
0xd9cc34a83dac3d89,
|
||||
0xd91dd2e13ce144af,
|
||||
0x92c6e9ed90d2eb35,
|
||||
0x680447a8e5ff9a6,
|
||||
]);
|
||||
let mut alpha = a1;
|
||||
alpha.square();
|
||||
alpha.mul_assign(self);
|
||||
let mut a0 = alpha;
|
||||
a0.frobenius_map(1);
|
||||
a0.mul_assign(&alpha);
|
||||
|
||||
let neg1 = Fq2 {
|
||||
c0: NEGATIVE_ONE,
|
||||
c1: Fq::zero(),
|
||||
};
|
||||
|
||||
if a0 == neg1 {
|
||||
None
|
||||
} else {
|
||||
a1.mul_assign(self);
|
||||
|
||||
if alpha == neg1 {
|
||||
a1.mul_assign(&Fq2 {
|
||||
c0: Fq::zero(),
|
||||
c1: Fq::one(),
|
||||
});
|
||||
} else {
|
||||
alpha.add_assign(&Fq2::one());
|
||||
// alpha = alpha^((q - 1) / 2)
|
||||
alpha = alpha.pow([
|
||||
0xdcff7fffffffd555,
|
||||
0xf55ffff58a9ffff,
|
||||
0xb39869507b587b12,
|
||||
0xb23ba5c279c2895f,
|
||||
0x258dd3db21a5d66b,
|
||||
0xd0088f51cbff34d,
|
||||
]);
|
||||
a1.mul_assign(&alpha);
|
||||
}
|
||||
|
||||
Some(a1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2_ordering() {
|
||||
let mut a = Fq2 {
|
||||
c0: Fq::zero(),
|
||||
c1: Fq::zero(),
|
||||
};
|
||||
|
||||
let mut b = a.clone();
|
||||
|
||||
assert!(a.cmp(&b) == Ordering::Equal);
|
||||
b.c0.add_assign(&Fq::one());
|
||||
assert!(a.cmp(&b) == Ordering::Less);
|
||||
a.c0.add_assign(&Fq::one());
|
||||
assert!(a.cmp(&b) == Ordering::Equal);
|
||||
b.c1.add_assign(&Fq::one());
|
||||
assert!(a.cmp(&b) == Ordering::Less);
|
||||
a.c0.add_assign(&Fq::one());
|
||||
assert!(a.cmp(&b) == Ordering::Less);
|
||||
a.c1.add_assign(&Fq::one());
|
||||
assert!(a.cmp(&b) == Ordering::Greater);
|
||||
b.c0.add_assign(&Fq::one());
|
||||
assert!(a.cmp(&b) == Ordering::Equal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2_basics() {
|
||||
assert_eq!(
|
||||
Fq2 {
|
||||
c0: Fq::zero(),
|
||||
c1: Fq::zero(),
|
||||
},
|
||||
Fq2::zero()
|
||||
);
|
||||
assert_eq!(
|
||||
Fq2 {
|
||||
c0: Fq::one(),
|
||||
c1: Fq::zero(),
|
||||
},
|
||||
Fq2::one()
|
||||
);
|
||||
assert!(Fq2::zero().is_zero());
|
||||
assert!(!Fq2::one().is_zero());
|
||||
assert!(
|
||||
!Fq2 {
|
||||
c0: Fq::zero(),
|
||||
c1: Fq::one(),
|
||||
}.is_zero()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2_squaring() {
|
||||
use super::fq::FqRepr;
|
||||
use ff::PrimeField;
|
||||
|
||||
let mut a = Fq2 {
|
||||
c0: Fq::one(),
|
||||
c1: Fq::one(),
|
||||
}; // u + 1
|
||||
a.square();
|
||||
assert_eq!(
|
||||
a,
|
||||
Fq2 {
|
||||
c0: Fq::zero(),
|
||||
c1: Fq::from_repr(FqRepr::from(2)).unwrap(),
|
||||
}
|
||||
); // 2u
|
||||
|
||||
let mut a = Fq2 {
|
||||
c0: Fq::zero(),
|
||||
c1: Fq::one(),
|
||||
}; // u
|
||||
a.square();
|
||||
assert_eq!(a, {
|
||||
let mut neg1 = Fq::one();
|
||||
neg1.negate();
|
||||
Fq2 {
|
||||
c0: neg1,
|
||||
c1: Fq::zero(),
|
||||
}
|
||||
}); // -1
|
||||
|
||||
let mut a = Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x9c2c6309bbf8b598,
|
||||
0x4eef5c946536f602,
|
||||
0x90e34aab6fb6a6bd,
|
||||
0xf7f295a94e58ae7c,
|
||||
0x41b76dcc1c3fbe5e,
|
||||
0x7080c5fa1d8e042,
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x38f473b3c870a4ab,
|
||||
0x6ad3291177c8c7e5,
|
||||
0xdac5a4c911a4353e,
|
||||
0xbfb99020604137a0,
|
||||
0xfc58a7b7be815407,
|
||||
0x10d1615e75250a21,
|
||||
])).unwrap(),
|
||||
};
|
||||
a.square();
|
||||
assert_eq!(
|
||||
a,
|
||||
Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0xf262c28c538bcf68,
|
||||
0xb9f2a66eae1073ba,
|
||||
0xdc46ab8fad67ae0,
|
||||
0xcb674157618da176,
|
||||
0x4cf17b5893c3d327,
|
||||
0x7eac81369c43361
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0xc1579cf58e980cf8,
|
||||
0xa23eb7e12dd54d98,
|
||||
0xe75138bce4cec7aa,
|
||||
0x38d0d7275a9689e1,
|
||||
0x739c983042779a65,
|
||||
0x1542a61c8a8db994
|
||||
])).unwrap(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2_mul() {
|
||||
use super::fq::FqRepr;
|
||||
use ff::PrimeField;
|
||||
|
||||
let mut a = Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x85c9f989e1461f03,
|
||||
0xa2e33c333449a1d6,
|
||||
0x41e461154a7354a3,
|
||||
0x9ee53e7e84d7532e,
|
||||
0x1c202d8ed97afb45,
|
||||
0x51d3f9253e2516f,
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0xa7348a8b511aedcf,
|
||||
0x143c215d8176b319,
|
||||
0x4cc48081c09b8903,
|
||||
0x9533e4a9a5158be,
|
||||
0x7a5e1ecb676d65f9,
|
||||
0x180c3ee46656b008,
|
||||
])).unwrap(),
|
||||
};
|
||||
a.mul_assign(&Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0xe21f9169805f537e,
|
||||
0xfc87e62e179c285d,
|
||||
0x27ece175be07a531,
|
||||
0xcd460f9f0c23e430,
|
||||
0x6c9110292bfa409,
|
||||
0x2c93a72eb8af83e,
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x4b1c3f936d8992d4,
|
||||
0x1d2a72916dba4c8a,
|
||||
0x8871c508658d1e5f,
|
||||
0x57a06d3135a752ae,
|
||||
0x634cd3c6c565096d,
|
||||
0x19e17334d4e93558,
|
||||
])).unwrap(),
|
||||
});
|
||||
assert_eq!(
|
||||
a,
|
||||
Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x95b5127e6360c7e4,
|
||||
0xde29c31a19a6937e,
|
||||
0xf61a96dacf5a39bc,
|
||||
0x5511fe4d84ee5f78,
|
||||
0x5310a202d92f9963,
|
||||
0x1751afbe166e5399
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x84af0e1bd630117a,
|
||||
0x6c63cd4da2c2aa7,
|
||||
0x5ba6e5430e883d40,
|
||||
0xc975106579c275ee,
|
||||
0x33a9ac82ce4c5083,
|
||||
0x1ef1a36c201589d
|
||||
])).unwrap(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2_inverse() {
|
||||
use super::fq::FqRepr;
|
||||
use ff::PrimeField;
|
||||
|
||||
assert!(Fq2::zero().inverse().is_none());
|
||||
|
||||
let a = Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x85c9f989e1461f03,
|
||||
0xa2e33c333449a1d6,
|
||||
0x41e461154a7354a3,
|
||||
0x9ee53e7e84d7532e,
|
||||
0x1c202d8ed97afb45,
|
||||
0x51d3f9253e2516f,
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0xa7348a8b511aedcf,
|
||||
0x143c215d8176b319,
|
||||
0x4cc48081c09b8903,
|
||||
0x9533e4a9a5158be,
|
||||
0x7a5e1ecb676d65f9,
|
||||
0x180c3ee46656b008,
|
||||
])).unwrap(),
|
||||
};
|
||||
let a = a.inverse().unwrap();
|
||||
assert_eq!(
|
||||
a,
|
||||
Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x70300f9bcb9e594,
|
||||
0xe5ecda5fdafddbb2,
|
||||
0x64bef617d2915a8f,
|
||||
0xdfba703293941c30,
|
||||
0xa6c3d8f9586f2636,
|
||||
0x1351ef01941b70c4
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x8c39fd76a8312cb4,
|
||||
0x15d7b6b95defbff0,
|
||||
0x947143f89faedee9,
|
||||
0xcbf651a0f367afb2,
|
||||
0xdf4e54f0d3ef15a6,
|
||||
0x103bdf241afb0019
|
||||
])).unwrap(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2_addition() {
|
||||
use super::fq::FqRepr;
|
||||
use ff::PrimeField;
|
||||
|
||||
let mut a = Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x2d0078036923ffc7,
|
||||
0x11e59ea221a3b6d2,
|
||||
0x8b1a52e0a90f59ed,
|
||||
0xb966ce3bc2108b13,
|
||||
0xccc649c4b9532bf3,
|
||||
0xf8d295b2ded9dc,
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x977df6efcdaee0db,
|
||||
0x946ae52d684fa7ed,
|
||||
0xbe203411c66fb3a5,
|
||||
0xb3f8afc0ee248cad,
|
||||
0x4e464dea5bcfd41e,
|
||||
0x12d1137b8a6a837,
|
||||
])).unwrap(),
|
||||
};
|
||||
a.add_assign(&Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x619a02d78dc70ef2,
|
||||
0xb93adfc9119e33e8,
|
||||
0x4bf0b99a9f0dca12,
|
||||
0x3b88899a42a6318f,
|
||||
0x986a4a62fa82a49d,
|
||||
0x13ce433fa26027f5,
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x66323bf80b58b9b9,
|
||||
0xa1379b6facf6e596,
|
||||
0x402aef1fb797e32f,
|
||||
0x2236f55246d0d44d,
|
||||
0x4c8c1800eb104566,
|
||||
0x11d6e20e986c2085,
|
||||
])).unwrap(),
|
||||
});
|
||||
assert_eq!(
|
||||
a,
|
||||
Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x8e9a7adaf6eb0eb9,
|
||||
0xcb207e6b3341eaba,
|
||||
0xd70b0c7b481d23ff,
|
||||
0xf4ef57d604b6bca2,
|
||||
0x65309427b3d5d090,
|
||||
0x14c715d5553f01d2
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0xfdb032e7d9079a94,
|
||||
0x35a2809d15468d83,
|
||||
0xfe4b23317e0796d5,
|
||||
0xd62fa51334f560fa,
|
||||
0x9ad265eb46e01984,
|
||||
0x1303f3465112c8bc
|
||||
])).unwrap(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2_subtraction() {
|
||||
use super::fq::FqRepr;
|
||||
use ff::PrimeField;
|
||||
|
||||
let mut a = Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x2d0078036923ffc7,
|
||||
0x11e59ea221a3b6d2,
|
||||
0x8b1a52e0a90f59ed,
|
||||
0xb966ce3bc2108b13,
|
||||
0xccc649c4b9532bf3,
|
||||
0xf8d295b2ded9dc,
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x977df6efcdaee0db,
|
||||
0x946ae52d684fa7ed,
|
||||
0xbe203411c66fb3a5,
|
||||
0xb3f8afc0ee248cad,
|
||||
0x4e464dea5bcfd41e,
|
||||
0x12d1137b8a6a837,
|
||||
])).unwrap(),
|
||||
};
|
||||
a.sub_assign(&Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x619a02d78dc70ef2,
|
||||
0xb93adfc9119e33e8,
|
||||
0x4bf0b99a9f0dca12,
|
||||
0x3b88899a42a6318f,
|
||||
0x986a4a62fa82a49d,
|
||||
0x13ce433fa26027f5,
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x66323bf80b58b9b9,
|
||||
0xa1379b6facf6e596,
|
||||
0x402aef1fb797e32f,
|
||||
0x2236f55246d0d44d,
|
||||
0x4c8c1800eb104566,
|
||||
0x11d6e20e986c2085,
|
||||
])).unwrap(),
|
||||
});
|
||||
assert_eq!(
|
||||
a,
|
||||
Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x8565752bdb5c9b80,
|
||||
0x7756bed7c15982e9,
|
||||
0xa65a6be700b285fe,
|
||||
0xe255902672ef6c43,
|
||||
0x7f77a718021c342d,
|
||||
0x72ba14049fe9881
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0xeb4abaf7c255d1cd,
|
||||
0x11df49bc6cacc256,
|
||||
0xe52617930588c69a,
|
||||
0xf63905f39ad8cb1f,
|
||||
0x4cd5dd9fb40b3b8f,
|
||||
0x957411359ba6e4c
|
||||
])).unwrap(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2_negation() {
|
||||
use super::fq::FqRepr;
|
||||
use ff::PrimeField;
|
||||
|
||||
let mut a = Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x2d0078036923ffc7,
|
||||
0x11e59ea221a3b6d2,
|
||||
0x8b1a52e0a90f59ed,
|
||||
0xb966ce3bc2108b13,
|
||||
0xccc649c4b9532bf3,
|
||||
0xf8d295b2ded9dc,
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x977df6efcdaee0db,
|
||||
0x946ae52d684fa7ed,
|
||||
0xbe203411c66fb3a5,
|
||||
0xb3f8afc0ee248cad,
|
||||
0x4e464dea5bcfd41e,
|
||||
0x12d1137b8a6a837,
|
||||
])).unwrap(),
|
||||
};
|
||||
a.negate();
|
||||
assert_eq!(
|
||||
a,
|
||||
Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x8cfe87fc96dbaae4,
|
||||
0xcc6615c8fb0492d,
|
||||
0xdc167fc04da19c37,
|
||||
0xab107d49317487ab,
|
||||
0x7e555df189f880e3,
|
||||
0x19083f5486a10cbd
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x228109103250c9d0,
|
||||
0x8a411ad149045812,
|
||||
0xa9109e8f3041427e,
|
||||
0xb07e9bc405608611,
|
||||
0xfcd559cbe77bd8b8,
|
||||
0x18d400b280d93e62
|
||||
])).unwrap(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2_doubling() {
|
||||
use super::fq::FqRepr;
|
||||
use ff::PrimeField;
|
||||
|
||||
let mut a = Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x2d0078036923ffc7,
|
||||
0x11e59ea221a3b6d2,
|
||||
0x8b1a52e0a90f59ed,
|
||||
0xb966ce3bc2108b13,
|
||||
0xccc649c4b9532bf3,
|
||||
0xf8d295b2ded9dc,
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x977df6efcdaee0db,
|
||||
0x946ae52d684fa7ed,
|
||||
0xbe203411c66fb3a5,
|
||||
0xb3f8afc0ee248cad,
|
||||
0x4e464dea5bcfd41e,
|
||||
0x12d1137b8a6a837,
|
||||
])).unwrap(),
|
||||
};
|
||||
a.double();
|
||||
assert_eq!(
|
||||
a,
|
||||
Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x5a00f006d247ff8e,
|
||||
0x23cb3d4443476da4,
|
||||
0x1634a5c1521eb3da,
|
||||
0x72cd9c7784211627,
|
||||
0x998c938972a657e7,
|
||||
0x1f1a52b65bdb3b9
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x2efbeddf9b5dc1b6,
|
||||
0x28d5ca5ad09f4fdb,
|
||||
0x7c4068238cdf674b,
|
||||
0x67f15f81dc49195b,
|
||||
0x9c8c9bd4b79fa83d,
|
||||
0x25a226f714d506e
|
||||
])).unwrap(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2_frobenius_map() {
|
||||
use super::fq::FqRepr;
|
||||
use ff::PrimeField;
|
||||
|
||||
let mut a = Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x2d0078036923ffc7,
|
||||
0x11e59ea221a3b6d2,
|
||||
0x8b1a52e0a90f59ed,
|
||||
0xb966ce3bc2108b13,
|
||||
0xccc649c4b9532bf3,
|
||||
0xf8d295b2ded9dc,
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x977df6efcdaee0db,
|
||||
0x946ae52d684fa7ed,
|
||||
0xbe203411c66fb3a5,
|
||||
0xb3f8afc0ee248cad,
|
||||
0x4e464dea5bcfd41e,
|
||||
0x12d1137b8a6a837,
|
||||
])).unwrap(),
|
||||
};
|
||||
a.frobenius_map(0);
|
||||
assert_eq!(
|
||||
a,
|
||||
Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x2d0078036923ffc7,
|
||||
0x11e59ea221a3b6d2,
|
||||
0x8b1a52e0a90f59ed,
|
||||
0xb966ce3bc2108b13,
|
||||
0xccc649c4b9532bf3,
|
||||
0xf8d295b2ded9dc
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x977df6efcdaee0db,
|
||||
0x946ae52d684fa7ed,
|
||||
0xbe203411c66fb3a5,
|
||||
0xb3f8afc0ee248cad,
|
||||
0x4e464dea5bcfd41e,
|
||||
0x12d1137b8a6a837
|
||||
])).unwrap(),
|
||||
}
|
||||
);
|
||||
a.frobenius_map(1);
|
||||
assert_eq!(
|
||||
a,
|
||||
Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x2d0078036923ffc7,
|
||||
0x11e59ea221a3b6d2,
|
||||
0x8b1a52e0a90f59ed,
|
||||
0xb966ce3bc2108b13,
|
||||
0xccc649c4b9532bf3,
|
||||
0xf8d295b2ded9dc
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x228109103250c9d0,
|
||||
0x8a411ad149045812,
|
||||
0xa9109e8f3041427e,
|
||||
0xb07e9bc405608611,
|
||||
0xfcd559cbe77bd8b8,
|
||||
0x18d400b280d93e62
|
||||
])).unwrap(),
|
||||
}
|
||||
);
|
||||
a.frobenius_map(1);
|
||||
assert_eq!(
|
||||
a,
|
||||
Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x2d0078036923ffc7,
|
||||
0x11e59ea221a3b6d2,
|
||||
0x8b1a52e0a90f59ed,
|
||||
0xb966ce3bc2108b13,
|
||||
0xccc649c4b9532bf3,
|
||||
0xf8d295b2ded9dc
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x977df6efcdaee0db,
|
||||
0x946ae52d684fa7ed,
|
||||
0xbe203411c66fb3a5,
|
||||
0xb3f8afc0ee248cad,
|
||||
0x4e464dea5bcfd41e,
|
||||
0x12d1137b8a6a837
|
||||
])).unwrap(),
|
||||
}
|
||||
);
|
||||
a.frobenius_map(2);
|
||||
assert_eq!(
|
||||
a,
|
||||
Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x2d0078036923ffc7,
|
||||
0x11e59ea221a3b6d2,
|
||||
0x8b1a52e0a90f59ed,
|
||||
0xb966ce3bc2108b13,
|
||||
0xccc649c4b9532bf3,
|
||||
0xf8d295b2ded9dc
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0x977df6efcdaee0db,
|
||||
0x946ae52d684fa7ed,
|
||||
0xbe203411c66fb3a5,
|
||||
0xb3f8afc0ee248cad,
|
||||
0x4e464dea5bcfd41e,
|
||||
0x12d1137b8a6a837
|
||||
])).unwrap(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2_sqrt() {
|
||||
use super::fq::FqRepr;
|
||||
use ff::PrimeField;
|
||||
|
||||
assert_eq!(
|
||||
Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x476b4c309720e227,
|
||||
0x34c2d04faffdab6,
|
||||
0xa57e6fc1bab51fd9,
|
||||
0xdb4a116b5bf74aa1,
|
||||
0x1e58b2159dfe10e2,
|
||||
0x7ca7da1f13606ac
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0xfa8de88b7516d2c3,
|
||||
0x371a75ed14f41629,
|
||||
0x4cec2dca577a3eb6,
|
||||
0x212611bca4e99121,
|
||||
0x8ee5394d77afb3d,
|
||||
0xec92336650e49d5
|
||||
])).unwrap(),
|
||||
}.sqrt()
|
||||
.unwrap(),
|
||||
Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0x40b299b2704258c5,
|
||||
0x6ef7de92e8c68b63,
|
||||
0x6d2ddbe552203e82,
|
||||
0x8d7f1f723d02c1d3,
|
||||
0x881b3e01b611c070,
|
||||
0x10f6963bbad2ebc5
|
||||
])).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0xc099534fc209e752,
|
||||
0x7670594665676447,
|
||||
0x28a20faed211efe7,
|
||||
0x6b852aeaf2afcb1b,
|
||||
0xa4c93b08105d71a9,
|
||||
0x8d7cfff94216330
|
||||
])).unwrap(),
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Fq2 {
|
||||
c0: Fq::from_repr(FqRepr([
|
||||
0xb9f78429d1517a6b,
|
||||
0x1eabfffeb153ffff,
|
||||
0x6730d2a0f6b0f624,
|
||||
0x64774b84f38512bf,
|
||||
0x4b1ba7b6434bacd7,
|
||||
0x1a0111ea397fe69a
|
||||
])).unwrap(),
|
||||
c1: Fq::zero(),
|
||||
}.sqrt()
|
||||
.unwrap(),
|
||||
Fq2 {
|
||||
c0: Fq::zero(),
|
||||
c1: Fq::from_repr(FqRepr([
|
||||
0xb9fefffffd4357a3,
|
||||
0x1eabfffeb153ffff,
|
||||
0x6730d2a0f6b0f624,
|
||||
0x64774b84f38512bf,
|
||||
0x4b1ba7b6434bacd7,
|
||||
0x1a0111ea397fe69a
|
||||
])).unwrap(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2_legendre() {
|
||||
use ff::LegendreSymbol::*;
|
||||
|
||||
assert_eq!(Zero, Fq2::zero().legendre());
|
||||
// i^2 = -1
|
||||
let mut m1 = Fq2::one();
|
||||
m1.negate();
|
||||
assert_eq!(QuadraticResidue, m1.legendre());
|
||||
m1.mul_by_nonresidue();
|
||||
assert_eq!(QuadraticNonResidue, m1.legendre());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use rand::{SeedableRng, XorShiftRng};
|
||||
|
||||
#[test]
|
||||
fn test_fq2_mul_nonresidue() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let nqr = Fq2 {
|
||||
c0: Fq::one(),
|
||||
c1: Fq::one(),
|
||||
};
|
||||
|
||||
for _ in 0..1000 {
|
||||
let mut a = Fq2::rand(&mut rng);
|
||||
let mut b = a;
|
||||
a.mul_by_nonresidue();
|
||||
b.mul_assign(&nqr);
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fq2_field_tests() {
|
||||
use ff::PrimeField;
|
||||
|
||||
::tests::field::random_field_tests::<Fq2>();
|
||||
::tests::field::random_sqrt_tests::<Fq2>();
|
||||
::tests::field::random_frobenius_tests::<Fq2, _>(super::fq::Fq::char(), 13);
|
||||
}
|
@ -1,374 +0,0 @@
|
||||
use super::fq::{FROBENIUS_COEFF_FQ6_C1, FROBENIUS_COEFF_FQ6_C2};
|
||||
use super::fq2::Fq2;
|
||||
use ff::Field;
|
||||
use rand::{Rand, Rng};
|
||||
|
||||
/// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2).
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Fq6 {
|
||||
pub c0: Fq2,
|
||||
pub c1: Fq2,
|
||||
pub c2: Fq2,
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for Fq6 {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
write!(f, "Fq6({} + {} * v, {} * v^2)", self.c0, self.c1, self.c2)
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for Fq6 {
|
||||
fn rand<R: Rng>(rng: &mut R) -> Self {
|
||||
Fq6 {
|
||||
c0: rng.gen(),
|
||||
c1: rng.gen(),
|
||||
c2: rng.gen(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Fq6 {
|
||||
/// Multiply by quadratic nonresidue v.
|
||||
pub fn mul_by_nonresidue(&mut self) {
|
||||
use std::mem::swap;
|
||||
swap(&mut self.c0, &mut self.c1);
|
||||
swap(&mut self.c0, &mut self.c2);
|
||||
|
||||
self.c0.mul_by_nonresidue();
|
||||
}
|
||||
|
||||
pub fn mul_by_1(&mut self, c1: &Fq2) {
|
||||
let mut b_b = self.c1;
|
||||
b_b.mul_assign(c1);
|
||||
|
||||
let mut t1 = *c1;
|
||||
{
|
||||
let mut tmp = self.c1;
|
||||
tmp.add_assign(&self.c2);
|
||||
|
||||
t1.mul_assign(&tmp);
|
||||
t1.sub_assign(&b_b);
|
||||
t1.mul_by_nonresidue();
|
||||
}
|
||||
|
||||
let mut t2 = *c1;
|
||||
{
|
||||
let mut tmp = self.c0;
|
||||
tmp.add_assign(&self.c1);
|
||||
|
||||
t2.mul_assign(&tmp);
|
||||
t2.sub_assign(&b_b);
|
||||
}
|
||||
|
||||
self.c0 = t1;
|
||||
self.c1 = t2;
|
||||
self.c2 = b_b;
|
||||
}
|
||||
|
||||
pub fn mul_by_01(&mut self, c0: &Fq2, c1: &Fq2) {
|
||||
let mut a_a = self.c0;
|
||||
let mut b_b = self.c1;
|
||||
a_a.mul_assign(c0);
|
||||
b_b.mul_assign(c1);
|
||||
|
||||
let mut t1 = *c1;
|
||||
{
|
||||
let mut tmp = self.c1;
|
||||
tmp.add_assign(&self.c2);
|
||||
|
||||
t1.mul_assign(&tmp);
|
||||
t1.sub_assign(&b_b);
|
||||
t1.mul_by_nonresidue();
|
||||
t1.add_assign(&a_a);
|
||||
}
|
||||
|
||||
let mut t3 = *c0;
|
||||
{
|
||||
let mut tmp = self.c0;
|
||||
tmp.add_assign(&self.c2);
|
||||
|
||||
t3.mul_assign(&tmp);
|
||||
t3.sub_assign(&a_a);
|
||||
t3.add_assign(&b_b);
|
||||
}
|
||||
|
||||
let mut t2 = *c0;
|
||||
t2.add_assign(c1);
|
||||
{
|
||||
let mut tmp = self.c0;
|
||||
tmp.add_assign(&self.c1);
|
||||
|
||||
t2.mul_assign(&tmp);
|
||||
t2.sub_assign(&a_a);
|
||||
t2.sub_assign(&b_b);
|
||||
}
|
||||
|
||||
self.c0 = t1;
|
||||
self.c1 = t2;
|
||||
self.c2 = t3;
|
||||
}
|
||||
}
|
||||
|
||||
impl Field for Fq6 {
|
||||
fn zero() -> Self {
|
||||
Fq6 {
|
||||
c0: Fq2::zero(),
|
||||
c1: Fq2::zero(),
|
||||
c2: Fq2::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
fn one() -> Self {
|
||||
Fq6 {
|
||||
c0: Fq2::one(),
|
||||
c1: Fq2::zero(),
|
||||
c2: Fq2::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.c0.is_zero() && self.c1.is_zero() && self.c2.is_zero()
|
||||
}
|
||||
|
||||
fn double(&mut self) {
|
||||
self.c0.double();
|
||||
self.c1.double();
|
||||
self.c2.double();
|
||||
}
|
||||
|
||||
fn negate(&mut self) {
|
||||
self.c0.negate();
|
||||
self.c1.negate();
|
||||
self.c2.negate();
|
||||
}
|
||||
|
||||
fn add_assign(&mut self, other: &Self) {
|
||||
self.c0.add_assign(&other.c0);
|
||||
self.c1.add_assign(&other.c1);
|
||||
self.c2.add_assign(&other.c2);
|
||||
}
|
||||
|
||||
fn sub_assign(&mut self, other: &Self) {
|
||||
self.c0.sub_assign(&other.c0);
|
||||
self.c1.sub_assign(&other.c1);
|
||||
self.c2.sub_assign(&other.c2);
|
||||
}
|
||||
|
||||
fn frobenius_map(&mut self, power: usize) {
|
||||
self.c0.frobenius_map(power);
|
||||
self.c1.frobenius_map(power);
|
||||
self.c2.frobenius_map(power);
|
||||
|
||||
self.c1.mul_assign(&FROBENIUS_COEFF_FQ6_C1[power % 6]);
|
||||
self.c2.mul_assign(&FROBENIUS_COEFF_FQ6_C2[power % 6]);
|
||||
}
|
||||
|
||||
fn square(&mut self) {
|
||||
let mut s0 = self.c0;
|
||||
s0.square();
|
||||
let mut ab = self.c0;
|
||||
ab.mul_assign(&self.c1);
|
||||
let mut s1 = ab;
|
||||
s1.double();
|
||||
let mut s2 = self.c0;
|
||||
s2.sub_assign(&self.c1);
|
||||
s2.add_assign(&self.c2);
|
||||
s2.square();
|
||||
let mut bc = self.c1;
|
||||
bc.mul_assign(&self.c2);
|
||||
let mut s3 = bc;
|
||||
s3.double();
|
||||
let mut s4 = self.c2;
|
||||
s4.square();
|
||||
|
||||
self.c0 = s3;
|
||||
self.c0.mul_by_nonresidue();
|
||||
self.c0.add_assign(&s0);
|
||||
|
||||
self.c1 = s4;
|
||||
self.c1.mul_by_nonresidue();
|
||||
self.c1.add_assign(&s1);
|
||||
|
||||
self.c2 = s1;
|
||||
self.c2.add_assign(&s2);
|
||||
self.c2.add_assign(&s3);
|
||||
self.c2.sub_assign(&s0);
|
||||
self.c2.sub_assign(&s4);
|
||||
}
|
||||
|
||||
fn mul_assign(&mut self, other: &Self) {
|
||||
let mut a_a = self.c0;
|
||||
let mut b_b = self.c1;
|
||||
let mut c_c = self.c2;
|
||||
a_a.mul_assign(&other.c0);
|
||||
b_b.mul_assign(&other.c1);
|
||||
c_c.mul_assign(&other.c2);
|
||||
|
||||
let mut t1 = other.c1;
|
||||
t1.add_assign(&other.c2);
|
||||
{
|
||||
let mut tmp = self.c1;
|
||||
tmp.add_assign(&self.c2);
|
||||
|
||||
t1.mul_assign(&tmp);
|
||||
t1.sub_assign(&b_b);
|
||||
t1.sub_assign(&c_c);
|
||||
t1.mul_by_nonresidue();
|
||||
t1.add_assign(&a_a);
|
||||
}
|
||||
|
||||
let mut t3 = other.c0;
|
||||
t3.add_assign(&other.c2);
|
||||
{
|
||||
let mut tmp = self.c0;
|
||||
tmp.add_assign(&self.c2);
|
||||
|
||||
t3.mul_assign(&tmp);
|
||||
t3.sub_assign(&a_a);
|
||||
t3.add_assign(&b_b);
|
||||
t3.sub_assign(&c_c);
|
||||
}
|
||||
|
||||
let mut t2 = other.c0;
|
||||
t2.add_assign(&other.c1);
|
||||
{
|
||||
let mut tmp = self.c0;
|
||||
tmp.add_assign(&self.c1);
|
||||
|
||||
t2.mul_assign(&tmp);
|
||||
t2.sub_assign(&a_a);
|
||||
t2.sub_assign(&b_b);
|
||||
c_c.mul_by_nonresidue();
|
||||
t2.add_assign(&c_c);
|
||||
}
|
||||
|
||||
self.c0 = t1;
|
||||
self.c1 = t2;
|
||||
self.c2 = t3;
|
||||
}
|
||||
|
||||
fn inverse(&self) -> Option<Self> {
|
||||
let mut c0 = self.c2;
|
||||
c0.mul_by_nonresidue();
|
||||
c0.mul_assign(&self.c1);
|
||||
c0.negate();
|
||||
{
|
||||
let mut c0s = self.c0;
|
||||
c0s.square();
|
||||
c0.add_assign(&c0s);
|
||||
}
|
||||
let mut c1 = self.c2;
|
||||
c1.square();
|
||||
c1.mul_by_nonresidue();
|
||||
{
|
||||
let mut c01 = self.c0;
|
||||
c01.mul_assign(&self.c1);
|
||||
c1.sub_assign(&c01);
|
||||
}
|
||||
let mut c2 = self.c1;
|
||||
c2.square();
|
||||
{
|
||||
let mut c02 = self.c0;
|
||||
c02.mul_assign(&self.c2);
|
||||
c2.sub_assign(&c02);
|
||||
}
|
||||
|
||||
let mut tmp1 = self.c2;
|
||||
tmp1.mul_assign(&c1);
|
||||
let mut tmp2 = self.c1;
|
||||
tmp2.mul_assign(&c2);
|
||||
tmp1.add_assign(&tmp2);
|
||||
tmp1.mul_by_nonresidue();
|
||||
tmp2 = self.c0;
|
||||
tmp2.mul_assign(&c0);
|
||||
tmp1.add_assign(&tmp2);
|
||||
|
||||
match tmp1.inverse() {
|
||||
Some(t) => {
|
||||
let mut tmp = Fq6 {
|
||||
c0: t,
|
||||
c1: t,
|
||||
c2: t,
|
||||
};
|
||||
tmp.c0.mul_assign(&c0);
|
||||
tmp.c1.mul_assign(&c1);
|
||||
tmp.c2.mul_assign(&c2);
|
||||
|
||||
Some(tmp)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use rand::{SeedableRng, XorShiftRng};
|
||||
|
||||
#[test]
|
||||
fn test_fq6_mul_nonresidue() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let nqr = Fq6 {
|
||||
c0: Fq2::zero(),
|
||||
c1: Fq2::one(),
|
||||
c2: Fq2::zero(),
|
||||
};
|
||||
|
||||
for _ in 0..1000 {
|
||||
let mut a = Fq6::rand(&mut rng);
|
||||
let mut b = a;
|
||||
a.mul_by_nonresidue();
|
||||
b.mul_assign(&nqr);
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq6_mul_by_1() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let c1 = Fq2::rand(&mut rng);
|
||||
let mut a = Fq6::rand(&mut rng);
|
||||
let mut b = a;
|
||||
|
||||
a.mul_by_1(&c1);
|
||||
b.mul_assign(&Fq6 {
|
||||
c0: Fq2::zero(),
|
||||
c1: c1,
|
||||
c2: Fq2::zero(),
|
||||
});
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq6_mul_by_01() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let c0 = Fq2::rand(&mut rng);
|
||||
let c1 = Fq2::rand(&mut rng);
|
||||
let mut a = Fq6::rand(&mut rng);
|
||||
let mut b = a;
|
||||
|
||||
a.mul_by_01(&c0, &c1);
|
||||
b.mul_assign(&Fq6 {
|
||||
c0: c0,
|
||||
c1: c1,
|
||||
c2: Fq2::zero(),
|
||||
});
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fq6_field_tests() {
|
||||
use ff::PrimeField;
|
||||
|
||||
::tests::field::random_field_tests::<Fq6>();
|
||||
::tests::field::random_frobenius_tests::<Fq6, _>(super::fq::Fq::char(), 13);
|
||||
}
|
@ -1,986 +0,0 @@
|
||||
use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr};
|
||||
|
||||
#[derive(PrimeField)]
|
||||
#[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"]
|
||||
#[PrimeFieldGenerator = "7"]
|
||||
pub struct Fr(FrRepr);
|
||||
|
||||
#[cfg(test)]
|
||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||
|
||||
#[test]
|
||||
fn test_fr_repr_ordering() {
|
||||
fn assert_equality(a: FrRepr, b: FrRepr) {
|
||||
assert_eq!(a, b);
|
||||
assert!(a.cmp(&b) == ::std::cmp::Ordering::Equal);
|
||||
}
|
||||
|
||||
fn assert_lt(a: FrRepr, b: FrRepr) {
|
||||
assert!(a < b);
|
||||
assert!(b > a);
|
||||
}
|
||||
|
||||
assert_equality(
|
||||
FrRepr([9999, 9999, 9999, 9999]),
|
||||
FrRepr([9999, 9999, 9999, 9999]),
|
||||
);
|
||||
assert_equality(
|
||||
FrRepr([9999, 9998, 9999, 9999]),
|
||||
FrRepr([9999, 9998, 9999, 9999]),
|
||||
);
|
||||
assert_equality(
|
||||
FrRepr([9999, 9999, 9999, 9997]),
|
||||
FrRepr([9999, 9999, 9999, 9997]),
|
||||
);
|
||||
assert_lt(
|
||||
FrRepr([9999, 9997, 9999, 9998]),
|
||||
FrRepr([9999, 9997, 9999, 9999]),
|
||||
);
|
||||
assert_lt(
|
||||
FrRepr([9999, 9997, 9998, 9999]),
|
||||
FrRepr([9999, 9997, 9999, 9999]),
|
||||
);
|
||||
assert_lt(
|
||||
FrRepr([9, 9999, 9999, 9997]),
|
||||
FrRepr([9999, 9999, 9999, 9997]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_repr_from() {
|
||||
assert_eq!(FrRepr::from(100), FrRepr([100, 0, 0, 0]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_repr_is_odd() {
|
||||
assert!(!FrRepr::from(0).is_odd());
|
||||
assert!(FrRepr::from(0).is_even());
|
||||
assert!(FrRepr::from(1).is_odd());
|
||||
assert!(!FrRepr::from(1).is_even());
|
||||
assert!(!FrRepr::from(324834872).is_odd());
|
||||
assert!(FrRepr::from(324834872).is_even());
|
||||
assert!(FrRepr::from(324834873).is_odd());
|
||||
assert!(!FrRepr::from(324834873).is_even());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_repr_is_zero() {
|
||||
assert!(FrRepr::from(0).is_zero());
|
||||
assert!(!FrRepr::from(1).is_zero());
|
||||
assert!(!FrRepr([0, 0, 1, 0]).is_zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_repr_div2() {
|
||||
let mut a = FrRepr([
|
||||
0xbd2920b19c972321,
|
||||
0x174ed0466a3be37e,
|
||||
0xd468d5e3b551f0b5,
|
||||
0xcb67c072733beefc,
|
||||
]);
|
||||
a.div2();
|
||||
assert_eq!(
|
||||
a,
|
||||
FrRepr([
|
||||
0x5e949058ce4b9190,
|
||||
0x8ba76823351df1bf,
|
||||
0x6a346af1daa8f85a,
|
||||
0x65b3e039399df77e
|
||||
])
|
||||
);
|
||||
for _ in 0..10 {
|
||||
a.div2();
|
||||
}
|
||||
assert_eq!(
|
||||
a,
|
||||
FrRepr([
|
||||
0x6fd7a524163392e4,
|
||||
0x16a2e9da08cd477c,
|
||||
0xdf9a8d1abc76aa3e,
|
||||
0x196cf80e4e677d
|
||||
])
|
||||
);
|
||||
for _ in 0..200 {
|
||||
a.div2();
|
||||
}
|
||||
assert_eq!(a, FrRepr([0x196cf80e4e67, 0x0, 0x0, 0x0]));
|
||||
for _ in 0..40 {
|
||||
a.div2();
|
||||
}
|
||||
assert_eq!(a, FrRepr([0x19, 0x0, 0x0, 0x0]));
|
||||
for _ in 0..4 {
|
||||
a.div2();
|
||||
}
|
||||
assert_eq!(a, FrRepr([0x1, 0x0, 0x0, 0x0]));
|
||||
a.div2();
|
||||
assert!(a.is_zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_repr_shr() {
|
||||
let mut a = FrRepr([
|
||||
0xb33fbaec482a283f,
|
||||
0x997de0d3a88cb3df,
|
||||
0x9af62d2a9a0e5525,
|
||||
0x36003ab08de70da1,
|
||||
]);
|
||||
a.shr(0);
|
||||
assert_eq!(
|
||||
a,
|
||||
FrRepr([
|
||||
0xb33fbaec482a283f,
|
||||
0x997de0d3a88cb3df,
|
||||
0x9af62d2a9a0e5525,
|
||||
0x36003ab08de70da1
|
||||
])
|
||||
);
|
||||
a.shr(1);
|
||||
assert_eq!(
|
||||
a,
|
||||
FrRepr([
|
||||
0xd99fdd762415141f,
|
||||
0xccbef069d44659ef,
|
||||
0xcd7b16954d072a92,
|
||||
0x1b001d5846f386d0
|
||||
])
|
||||
);
|
||||
a.shr(50);
|
||||
assert_eq!(
|
||||
a,
|
||||
FrRepr([
|
||||
0xbc1a7511967bf667,
|
||||
0xc5a55341caa4b32f,
|
||||
0x75611bce1b4335e,
|
||||
0x6c0
|
||||
])
|
||||
);
|
||||
a.shr(130);
|
||||
assert_eq!(a, FrRepr([0x1d5846f386d0cd7, 0x1b0, 0x0, 0x0]));
|
||||
a.shr(64);
|
||||
assert_eq!(a, FrRepr([0x1b0, 0x0, 0x0, 0x0]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_repr_mul2() {
|
||||
let mut a = FrRepr::from(23712937547);
|
||||
a.mul2();
|
||||
assert_eq!(a, FrRepr([0xb0acd6c96, 0x0, 0x0, 0x0]));
|
||||
for _ in 0..60 {
|
||||
a.mul2();
|
||||
}
|
||||
assert_eq!(a, FrRepr([0x6000000000000000, 0xb0acd6c9, 0x0, 0x0]));
|
||||
for _ in 0..128 {
|
||||
a.mul2();
|
||||
}
|
||||
assert_eq!(a, FrRepr([0x0, 0x0, 0x6000000000000000, 0xb0acd6c9]));
|
||||
for _ in 0..60 {
|
||||
a.mul2();
|
||||
}
|
||||
assert_eq!(a, FrRepr([0x0, 0x0, 0x0, 0x9600000000000000]));
|
||||
for _ in 0..7 {
|
||||
a.mul2();
|
||||
}
|
||||
assert!(a.is_zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_repr_num_bits() {
|
||||
let mut a = FrRepr::from(0);
|
||||
assert_eq!(0, a.num_bits());
|
||||
a = FrRepr::from(1);
|
||||
for i in 1..257 {
|
||||
assert_eq!(i, a.num_bits());
|
||||
a.mul2();
|
||||
}
|
||||
assert_eq!(0, a.num_bits());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_repr_sub_noborrow() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let mut t = FrRepr([
|
||||
0x8e62a7e85264e2c3,
|
||||
0xb23d34c1941d3ca,
|
||||
0x5976930b7502dd15,
|
||||
0x600f3fb517bf5495,
|
||||
]);
|
||||
t.sub_noborrow(&FrRepr([
|
||||
0xd64f669809cbc6a4,
|
||||
0xfa76cb9d90cf7637,
|
||||
0xfefb0df9038d43b3,
|
||||
0x298a30c744b31acf,
|
||||
]));
|
||||
assert!(
|
||||
t == FrRepr([
|
||||
0xb813415048991c1f,
|
||||
0x10ad07ae88725d92,
|
||||
0x5a7b851271759961,
|
||||
0x36850eedd30c39c5
|
||||
])
|
||||
);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let mut a = FrRepr::rand(&mut rng);
|
||||
a.0[3] >>= 30;
|
||||
let mut b = a;
|
||||
for _ in 0..10 {
|
||||
b.mul2();
|
||||
}
|
||||
let mut c = b;
|
||||
for _ in 0..10 {
|
||||
c.mul2();
|
||||
}
|
||||
|
||||
assert!(a < b);
|
||||
assert!(b < c);
|
||||
|
||||
let mut csub_ba = c;
|
||||
csub_ba.sub_noborrow(&b);
|
||||
csub_ba.sub_noborrow(&a);
|
||||
|
||||
let mut csub_ab = c;
|
||||
csub_ab.sub_noborrow(&a);
|
||||
csub_ab.sub_noborrow(&b);
|
||||
|
||||
assert_eq!(csub_ab, csub_ba);
|
||||
}
|
||||
|
||||
// Subtracting r+1 from r should produce -1 (mod 2**256)
|
||||
let mut qplusone = FrRepr([
|
||||
0xffffffff00000001,
|
||||
0x53bda402fffe5bfe,
|
||||
0x3339d80809a1d805,
|
||||
0x73eda753299d7d48,
|
||||
]);
|
||||
qplusone.sub_noborrow(&FrRepr([
|
||||
0xffffffff00000002,
|
||||
0x53bda402fffe5bfe,
|
||||
0x3339d80809a1d805,
|
||||
0x73eda753299d7d48,
|
||||
]));
|
||||
assert_eq!(
|
||||
qplusone,
|
||||
FrRepr([
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_legendre() {
|
||||
use ff::LegendreSymbol::*;
|
||||
use ff::SqrtField;
|
||||
|
||||
assert_eq!(QuadraticResidue, Fr::one().legendre());
|
||||
assert_eq!(Zero, Fr::zero().legendre());
|
||||
|
||||
let e = FrRepr([
|
||||
0x0dbc5349cd5664da,
|
||||
0x8ac5b6296e3ae29d,
|
||||
0x127cb819feceaa3b,
|
||||
0x3a6b21fb03867191,
|
||||
]);
|
||||
assert_eq!(QuadraticResidue, Fr::from_repr(e).unwrap().legendre());
|
||||
let e = FrRepr([
|
||||
0x96341aefd047c045,
|
||||
0x9b5f4254500a4d65,
|
||||
0x1ee08223b68ac240,
|
||||
0x31d9cd545c0ec7c6,
|
||||
]);
|
||||
assert_eq!(QuadraticNonResidue, Fr::from_repr(e).unwrap().legendre());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_repr_add_nocarry() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let mut t = FrRepr([
|
||||
0xd64f669809cbc6a4,
|
||||
0xfa76cb9d90cf7637,
|
||||
0xfefb0df9038d43b3,
|
||||
0x298a30c744b31acf,
|
||||
]);
|
||||
t.add_nocarry(&FrRepr([
|
||||
0x8e62a7e85264e2c3,
|
||||
0xb23d34c1941d3ca,
|
||||
0x5976930b7502dd15,
|
||||
0x600f3fb517bf5495,
|
||||
]));
|
||||
assert_eq!(
|
||||
t,
|
||||
FrRepr([
|
||||
0x64b20e805c30a967,
|
||||
0x59a9ee9aa114a02,
|
||||
0x5871a104789020c9,
|
||||
0x8999707c5c726f65
|
||||
])
|
||||
);
|
||||
|
||||
// Test for the associativity of addition.
|
||||
for _ in 0..1000 {
|
||||
let mut a = FrRepr::rand(&mut rng);
|
||||
let mut b = FrRepr::rand(&mut rng);
|
||||
let mut c = FrRepr::rand(&mut rng);
|
||||
|
||||
// Unset the first few bits, so that overflow won't occur.
|
||||
a.0[3] >>= 3;
|
||||
b.0[3] >>= 3;
|
||||
c.0[3] >>= 3;
|
||||
|
||||
let mut abc = a;
|
||||
abc.add_nocarry(&b);
|
||||
abc.add_nocarry(&c);
|
||||
|
||||
let mut acb = a;
|
||||
acb.add_nocarry(&c);
|
||||
acb.add_nocarry(&b);
|
||||
|
||||
let mut bac = b;
|
||||
bac.add_nocarry(&a);
|
||||
bac.add_nocarry(&c);
|
||||
|
||||
let mut bca = b;
|
||||
bca.add_nocarry(&c);
|
||||
bca.add_nocarry(&a);
|
||||
|
||||
let mut cab = c;
|
||||
cab.add_nocarry(&a);
|
||||
cab.add_nocarry(&b);
|
||||
|
||||
let mut cba = c;
|
||||
cba.add_nocarry(&b);
|
||||
cba.add_nocarry(&a);
|
||||
|
||||
assert_eq!(abc, acb);
|
||||
assert_eq!(abc, bac);
|
||||
assert_eq!(abc, bca);
|
||||
assert_eq!(abc, cab);
|
||||
assert_eq!(abc, cba);
|
||||
}
|
||||
|
||||
// Adding 1 to (2^256 - 1) should produce zero
|
||||
let mut x = FrRepr([
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
]);
|
||||
x.add_nocarry(&FrRepr::from(1));
|
||||
assert!(x.is_zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_is_valid() {
|
||||
let mut a = Fr(MODULUS);
|
||||
assert!(!a.is_valid());
|
||||
a.0.sub_noborrow(&FrRepr::from(1));
|
||||
assert!(a.is_valid());
|
||||
assert!(Fr(FrRepr::from(0)).is_valid());
|
||||
assert!(
|
||||
Fr(FrRepr([
|
||||
0xffffffff00000000,
|
||||
0x53bda402fffe5bfe,
|
||||
0x3339d80809a1d805,
|
||||
0x73eda753299d7d48
|
||||
])).is_valid()
|
||||
);
|
||||
assert!(
|
||||
!Fr(FrRepr([
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff
|
||||
])).is_valid()
|
||||
);
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let a = Fr::rand(&mut rng);
|
||||
assert!(a.is_valid());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_add_assign() {
|
||||
{
|
||||
// Random number
|
||||
let mut tmp = Fr(FrRepr([
|
||||
0x437ce7616d580765,
|
||||
0xd42d1ccb29d1235b,
|
||||
0xed8f753821bd1423,
|
||||
0x4eede1c9c89528ca,
|
||||
]));
|
||||
assert!(tmp.is_valid());
|
||||
// Test that adding zero has no effect.
|
||||
tmp.add_assign(&Fr(FrRepr::from(0)));
|
||||
assert_eq!(
|
||||
tmp,
|
||||
Fr(FrRepr([
|
||||
0x437ce7616d580765,
|
||||
0xd42d1ccb29d1235b,
|
||||
0xed8f753821bd1423,
|
||||
0x4eede1c9c89528ca
|
||||
]))
|
||||
);
|
||||
// Add one and test for the result.
|
||||
tmp.add_assign(&Fr(FrRepr::from(1)));
|
||||
assert_eq!(
|
||||
tmp,
|
||||
Fr(FrRepr([
|
||||
0x437ce7616d580766,
|
||||
0xd42d1ccb29d1235b,
|
||||
0xed8f753821bd1423,
|
||||
0x4eede1c9c89528ca
|
||||
]))
|
||||
);
|
||||
// Add another random number that exercises the reduction.
|
||||
tmp.add_assign(&Fr(FrRepr([
|
||||
0x946f435944f7dc79,
|
||||
0xb55e7ee6533a9b9b,
|
||||
0x1e43b84c2f6194ca,
|
||||
0x58717ab525463496,
|
||||
])));
|
||||
assert_eq!(
|
||||
tmp,
|
||||
Fr(FrRepr([
|
||||
0xd7ec2abbb24fe3de,
|
||||
0x35cdf7ae7d0d62f7,
|
||||
0xd899557c477cd0e9,
|
||||
0x3371b52bc43de018
|
||||
]))
|
||||
);
|
||||
// Add one to (r - 1) and test for the result.
|
||||
tmp = Fr(FrRepr([
|
||||
0xffffffff00000000,
|
||||
0x53bda402fffe5bfe,
|
||||
0x3339d80809a1d805,
|
||||
0x73eda753299d7d48,
|
||||
]));
|
||||
tmp.add_assign(&Fr(FrRepr::from(1)));
|
||||
assert!(tmp.0.is_zero());
|
||||
// Add a random number to another one such that the result is r - 1
|
||||
tmp = Fr(FrRepr([
|
||||
0xade5adacdccb6190,
|
||||
0xaa21ee0f27db3ccd,
|
||||
0x2550f4704ae39086,
|
||||
0x591d1902e7c5ba27,
|
||||
]));
|
||||
tmp.add_assign(&Fr(FrRepr([
|
||||
0x521a525223349e70,
|
||||
0xa99bb5f3d8231f31,
|
||||
0xde8e397bebe477e,
|
||||
0x1ad08e5041d7c321,
|
||||
])));
|
||||
assert_eq!(
|
||||
tmp,
|
||||
Fr(FrRepr([
|
||||
0xffffffff00000000,
|
||||
0x53bda402fffe5bfe,
|
||||
0x3339d80809a1d805,
|
||||
0x73eda753299d7d48
|
||||
]))
|
||||
);
|
||||
// Add one to the result and test for it.
|
||||
tmp.add_assign(&Fr(FrRepr::from(1)));
|
||||
assert!(tmp.0.is_zero());
|
||||
}
|
||||
|
||||
// Test associativity
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Generate a, b, c and ensure (a + b) + c == a + (b + c).
|
||||
let a = Fr::rand(&mut rng);
|
||||
let b = Fr::rand(&mut rng);
|
||||
let c = Fr::rand(&mut rng);
|
||||
|
||||
let mut tmp1 = a;
|
||||
tmp1.add_assign(&b);
|
||||
tmp1.add_assign(&c);
|
||||
|
||||
let mut tmp2 = b;
|
||||
tmp2.add_assign(&c);
|
||||
tmp2.add_assign(&a);
|
||||
|
||||
assert!(tmp1.is_valid());
|
||||
assert!(tmp2.is_valid());
|
||||
assert_eq!(tmp1, tmp2);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_sub_assign() {
|
||||
{
|
||||
// Test arbitrary subtraction that tests reduction.
|
||||
let mut tmp = Fr(FrRepr([
|
||||
0x6a68c64b6f735a2b,
|
||||
0xd5f4d143fe0a1972,
|
||||
0x37c17f3829267c62,
|
||||
0xa2f37391f30915c,
|
||||
]));
|
||||
tmp.sub_assign(&Fr(FrRepr([
|
||||
0xade5adacdccb6190,
|
||||
0xaa21ee0f27db3ccd,
|
||||
0x2550f4704ae39086,
|
||||
0x591d1902e7c5ba27,
|
||||
])));
|
||||
assert_eq!(
|
||||
tmp,
|
||||
Fr(FrRepr([
|
||||
0xbc83189d92a7f89c,
|
||||
0x7f908737d62d38a3,
|
||||
0x45aa62cfe7e4c3e1,
|
||||
0x24ffc5896108547d
|
||||
]))
|
||||
);
|
||||
|
||||
// Test the opposite subtraction which doesn't test reduction.
|
||||
tmp = Fr(FrRepr([
|
||||
0xade5adacdccb6190,
|
||||
0xaa21ee0f27db3ccd,
|
||||
0x2550f4704ae39086,
|
||||
0x591d1902e7c5ba27,
|
||||
]));
|
||||
tmp.sub_assign(&Fr(FrRepr([
|
||||
0x6a68c64b6f735a2b,
|
||||
0xd5f4d143fe0a1972,
|
||||
0x37c17f3829267c62,
|
||||
0xa2f37391f30915c,
|
||||
])));
|
||||
assert_eq!(
|
||||
tmp,
|
||||
Fr(FrRepr([
|
||||
0x437ce7616d580765,
|
||||
0xd42d1ccb29d1235b,
|
||||
0xed8f753821bd1423,
|
||||
0x4eede1c9c89528ca
|
||||
]))
|
||||
);
|
||||
|
||||
// Test for sensible results with zero
|
||||
tmp = Fr(FrRepr::from(0));
|
||||
tmp.sub_assign(&Fr(FrRepr::from(0)));
|
||||
assert!(tmp.is_zero());
|
||||
|
||||
tmp = Fr(FrRepr([
|
||||
0x437ce7616d580765,
|
||||
0xd42d1ccb29d1235b,
|
||||
0xed8f753821bd1423,
|
||||
0x4eede1c9c89528ca,
|
||||
]));
|
||||
tmp.sub_assign(&Fr(FrRepr::from(0)));
|
||||
assert_eq!(
|
||||
tmp,
|
||||
Fr(FrRepr([
|
||||
0x437ce7616d580765,
|
||||
0xd42d1ccb29d1235b,
|
||||
0xed8f753821bd1423,
|
||||
0x4eede1c9c89528ca
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Ensure that (a - b) + (b - a) = 0.
|
||||
let a = Fr::rand(&mut rng);
|
||||
let b = Fr::rand(&mut rng);
|
||||
|
||||
let mut tmp1 = a;
|
||||
tmp1.sub_assign(&b);
|
||||
|
||||
let mut tmp2 = b;
|
||||
tmp2.sub_assign(&a);
|
||||
|
||||
tmp1.add_assign(&tmp2);
|
||||
assert!(tmp1.is_zero());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_mul_assign() {
|
||||
let mut tmp = Fr(FrRepr([
|
||||
0x6b7e9b8faeefc81a,
|
||||
0xe30a8463f348ba42,
|
||||
0xeff3cb67a8279c9c,
|
||||
0x3d303651bd7c774d,
|
||||
]));
|
||||
tmp.mul_assign(&Fr(FrRepr([
|
||||
0x13ae28e3bc35ebeb,
|
||||
0xa10f4488075cae2c,
|
||||
0x8160e95a853c3b5d,
|
||||
0x5ae3f03b561a841d,
|
||||
])));
|
||||
assert!(
|
||||
tmp == Fr(FrRepr([
|
||||
0x23717213ce710f71,
|
||||
0xdbee1fe53a16e1af,
|
||||
0xf565d3e1c2a48000,
|
||||
0x4426507ee75df9d7
|
||||
]))
|
||||
);
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000000 {
|
||||
// Ensure that (a * b) * c = a * (b * c)
|
||||
let a = Fr::rand(&mut rng);
|
||||
let b = Fr::rand(&mut rng);
|
||||
let c = Fr::rand(&mut rng);
|
||||
|
||||
let mut tmp1 = a;
|
||||
tmp1.mul_assign(&b);
|
||||
tmp1.mul_assign(&c);
|
||||
|
||||
let mut tmp2 = b;
|
||||
tmp2.mul_assign(&c);
|
||||
tmp2.mul_assign(&a);
|
||||
|
||||
assert_eq!(tmp1, tmp2);
|
||||
}
|
||||
|
||||
for _ in 0..1000000 {
|
||||
// Ensure that r * (a + b + c) = r*a + r*b + r*c
|
||||
|
||||
let r = Fr::rand(&mut rng);
|
||||
let mut a = Fr::rand(&mut rng);
|
||||
let mut b = Fr::rand(&mut rng);
|
||||
let mut c = Fr::rand(&mut rng);
|
||||
|
||||
let mut tmp1 = a;
|
||||
tmp1.add_assign(&b);
|
||||
tmp1.add_assign(&c);
|
||||
tmp1.mul_assign(&r);
|
||||
|
||||
a.mul_assign(&r);
|
||||
b.mul_assign(&r);
|
||||
c.mul_assign(&r);
|
||||
|
||||
a.add_assign(&b);
|
||||
a.add_assign(&c);
|
||||
|
||||
assert_eq!(tmp1, a);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_squaring() {
|
||||
let mut a = Fr(FrRepr([
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0x73eda753299d7d47,
|
||||
]));
|
||||
assert!(a.is_valid());
|
||||
a.square();
|
||||
assert_eq!(
|
||||
a,
|
||||
Fr::from_repr(FrRepr([
|
||||
0xc0d698e7bde077b8,
|
||||
0xb79a310579e76ec2,
|
||||
0xac1da8d0a9af4e5f,
|
||||
0x13f629c49bf23e97
|
||||
])).unwrap()
|
||||
);
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000000 {
|
||||
// Ensure that (a * a) = a^2
|
||||
let a = Fr::rand(&mut rng);
|
||||
|
||||
let mut tmp = a;
|
||||
tmp.square();
|
||||
|
||||
let mut tmp2 = a;
|
||||
tmp2.mul_assign(&a);
|
||||
|
||||
assert_eq!(tmp, tmp2);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_inverse() {
|
||||
assert!(Fr::zero().inverse().is_none());
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let one = Fr::one();
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Ensure that a * a^-1 = 1
|
||||
let mut a = Fr::rand(&mut rng);
|
||||
let ainv = a.inverse().unwrap();
|
||||
a.mul_assign(&ainv);
|
||||
assert_eq!(a, one);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_double() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Ensure doubling a is equivalent to adding a to itself.
|
||||
let mut a = Fr::rand(&mut rng);
|
||||
let mut b = a;
|
||||
b.add_assign(&a);
|
||||
a.double();
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_negate() {
|
||||
{
|
||||
let mut a = Fr::zero();
|
||||
a.negate();
|
||||
|
||||
assert!(a.is_zero());
|
||||
}
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Ensure (a - (-a)) = 0.
|
||||
let mut a = Fr::rand(&mut rng);
|
||||
let mut b = a;
|
||||
b.negate();
|
||||
a.add_assign(&b);
|
||||
|
||||
assert!(a.is_zero());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_pow() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for i in 0..1000 {
|
||||
// Exponentiate by various small numbers and ensure it consists with repeated
|
||||
// multiplication.
|
||||
let a = Fr::rand(&mut rng);
|
||||
let target = a.pow(&[i]);
|
||||
let mut c = Fr::one();
|
||||
for _ in 0..i {
|
||||
c.mul_assign(&a);
|
||||
}
|
||||
assert_eq!(c, target);
|
||||
}
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Exponentiating by the modulus should have no effect in a prime field.
|
||||
let a = Fr::rand(&mut rng);
|
||||
|
||||
assert_eq!(a, a.pow(Fr::char()));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_sqrt() {
|
||||
use ff::SqrtField;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
assert_eq!(Fr::zero().sqrt().unwrap(), Fr::zero());
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Ensure sqrt(a^2) = a or -a
|
||||
let a = Fr::rand(&mut rng);
|
||||
let mut nega = a;
|
||||
nega.negate();
|
||||
let mut b = a;
|
||||
b.square();
|
||||
|
||||
let b = b.sqrt().unwrap();
|
||||
|
||||
assert!(a == b || nega == b);
|
||||
}
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Ensure sqrt(a)^2 = a for random a
|
||||
let a = Fr::rand(&mut rng);
|
||||
|
||||
if let Some(mut tmp) = a.sqrt() {
|
||||
tmp.square();
|
||||
|
||||
assert_eq!(a, tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_from_into_repr() {
|
||||
// r + 1 should not be in the field
|
||||
assert!(
|
||||
Fr::from_repr(FrRepr([
|
||||
0xffffffff00000002,
|
||||
0x53bda402fffe5bfe,
|
||||
0x3339d80809a1d805,
|
||||
0x73eda753299d7d48
|
||||
])).is_err()
|
||||
);
|
||||
|
||||
// r should not be in the field
|
||||
assert!(Fr::from_repr(Fr::char()).is_err());
|
||||
|
||||
// Multiply some arbitrary representations to see if the result is as expected.
|
||||
let a = FrRepr([
|
||||
0x25ebe3a3ad3c0c6a,
|
||||
0x6990e39d092e817c,
|
||||
0x941f900d42f5658e,
|
||||
0x44f8a103b38a71e0,
|
||||
]);
|
||||
let mut a_fr = Fr::from_repr(a).unwrap();
|
||||
let b = FrRepr([
|
||||
0x264e9454885e2475,
|
||||
0x46f7746bb0308370,
|
||||
0x4683ef5347411f9,
|
||||
0x58838d7f208d4492,
|
||||
]);
|
||||
let b_fr = Fr::from_repr(b).unwrap();
|
||||
let c = FrRepr([
|
||||
0x48a09ab93cfc740d,
|
||||
0x3a6600fbfc7a671,
|
||||
0x838567017501d767,
|
||||
0x7161d6da77745512,
|
||||
]);
|
||||
a_fr.mul_assign(&b_fr);
|
||||
assert_eq!(a_fr.into_repr(), c);
|
||||
|
||||
// Zero should be in the field.
|
||||
assert!(Fr::from_repr(FrRepr::from(0)).unwrap().is_zero());
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Try to turn Fr elements into representations and back again, and compare.
|
||||
let a = Fr::rand(&mut rng);
|
||||
let a_repr = a.into_repr();
|
||||
let b_repr = FrRepr::from(a);
|
||||
assert_eq!(a_repr, b_repr);
|
||||
let a_again = Fr::from_repr(a_repr).unwrap();
|
||||
|
||||
assert_eq!(a, a_again);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_repr_display() {
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
FrRepr([
|
||||
0x2829c242fa826143,
|
||||
0x1f32cf4dd4330917,
|
||||
0x932e4e479d168cd9,
|
||||
0x513c77587f563f64
|
||||
])
|
||||
),
|
||||
"0x513c77587f563f64932e4e479d168cd91f32cf4dd43309172829c242fa826143".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
FrRepr([
|
||||
0x25ebe3a3ad3c0c6a,
|
||||
0x6990e39d092e817c,
|
||||
0x941f900d42f5658e,
|
||||
0x44f8a103b38a71e0
|
||||
])
|
||||
),
|
||||
"0x44f8a103b38a71e0941f900d42f5658e6990e39d092e817c25ebe3a3ad3c0c6a".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
FrRepr([
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff,
|
||||
0xffffffffffffffff
|
||||
])
|
||||
),
|
||||
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
format!("{}", FrRepr([0, 0, 0, 0])),
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000".to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_display() {
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
Fr::from_repr(FrRepr([
|
||||
0xc3cae746a3b5ecc7,
|
||||
0x185ec8eb3f5b5aee,
|
||||
0x684499ffe4b9dd99,
|
||||
0x7c9bba7afb68faa
|
||||
])).unwrap()
|
||||
),
|
||||
"Fr(0x07c9bba7afb68faa684499ffe4b9dd99185ec8eb3f5b5aeec3cae746a3b5ecc7)".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
Fr::from_repr(FrRepr([
|
||||
0x44c71298ff198106,
|
||||
0xb0ad10817df79b6a,
|
||||
0xd034a80a2b74132b,
|
||||
0x41cf9a1336f50719
|
||||
])).unwrap()
|
||||
),
|
||||
"Fr(0x41cf9a1336f50719d034a80a2b74132bb0ad10817df79b6a44c71298ff198106)".to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_num_bits() {
|
||||
assert_eq!(Fr::NUM_BITS, 255);
|
||||
assert_eq!(Fr::CAPACITY, 254);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_root_of_unity() {
|
||||
use ff::SqrtField;
|
||||
|
||||
assert_eq!(Fr::S, 32);
|
||||
assert_eq!(
|
||||
Fr::multiplicative_generator(),
|
||||
Fr::from_repr(FrRepr::from(7)).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
Fr::multiplicative_generator().pow([
|
||||
0xfffe5bfeffffffff,
|
||||
0x9a1d80553bda402,
|
||||
0x299d7d483339d808,
|
||||
0x73eda753
|
||||
]),
|
||||
Fr::root_of_unity()
|
||||
);
|
||||
assert_eq!(Fr::root_of_unity().pow([1 << Fr::S]), Fr::one());
|
||||
assert!(Fr::multiplicative_generator().sqrt().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fr_field_tests() {
|
||||
::tests::field::random_field_tests::<Fr>();
|
||||
::tests::field::random_sqrt_tests::<Fr>();
|
||||
::tests::field::random_frobenius_tests::<Fr, _>(Fr::char(), 13);
|
||||
::tests::field::from_str_tests::<Fr>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fr_repr_tests() {
|
||||
::tests::repr::random_repr_tests::<FrRepr>();
|
||||
}
|
@ -1,370 +0,0 @@
|
||||
mod ec;
|
||||
mod fq;
|
||||
mod fq12;
|
||||
mod fq2;
|
||||
mod fq6;
|
||||
mod fr;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use self::ec::{
|
||||
G1, G1Affine, G1Compressed, G1Prepared, G1Uncompressed, G2, G2Affine, G2Compressed, G2Prepared,
|
||||
G2Uncompressed,
|
||||
};
|
||||
pub use self::fq::{Fq, FqRepr};
|
||||
pub use self::fq12::Fq12;
|
||||
pub use self::fq2::Fq2;
|
||||
pub use self::fq6::Fq6;
|
||||
pub use self::fr::{Fr, FrRepr};
|
||||
|
||||
use super::{Engine, PairingCurveAffine};
|
||||
|
||||
use ff::{BitIterator, Field, ScalarEngine};
|
||||
use group::CurveAffine;
|
||||
|
||||
// The BLS parameter x for BLS12-381 is -0xd201000000010000
|
||||
const BLS_X: u64 = 0xd201000000010000;
|
||||
const BLS_X_IS_NEGATIVE: bool = true;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Bls12;
|
||||
|
||||
impl ScalarEngine for Bls12 {
|
||||
type Fr = Fr;
|
||||
}
|
||||
|
||||
impl Engine for Bls12 {
|
||||
type G1 = G1;
|
||||
type G1Affine = G1Affine;
|
||||
type G2 = G2;
|
||||
type G2Affine = G2Affine;
|
||||
type Fq = Fq;
|
||||
type Fqe = Fq2;
|
||||
type Fqk = Fq12;
|
||||
|
||||
fn miller_loop<'a, I>(i: I) -> Self::Fqk
|
||||
where
|
||||
I: IntoIterator<
|
||||
Item = &'a (
|
||||
&'a <Self::G1Affine as PairingCurveAffine>::Prepared,
|
||||
&'a <Self::G2Affine as PairingCurveAffine>::Prepared,
|
||||
),
|
||||
>,
|
||||
{
|
||||
let mut pairs = vec![];
|
||||
for &(p, q) in i {
|
||||
if !p.is_zero() && !q.is_zero() {
|
||||
pairs.push((p, q.coeffs.iter()));
|
||||
}
|
||||
}
|
||||
|
||||
// Twisting isomorphism from E to E'
|
||||
fn ell(f: &mut Fq12, coeffs: &(Fq2, Fq2, Fq2), p: &G1Affine) {
|
||||
let mut c0 = coeffs.0;
|
||||
let mut c1 = coeffs.1;
|
||||
|
||||
c0.c0.mul_assign(&p.y);
|
||||
c0.c1.mul_assign(&p.y);
|
||||
|
||||
c1.c0.mul_assign(&p.x);
|
||||
c1.c1.mul_assign(&p.x);
|
||||
|
||||
// Sparse multiplication in Fq12
|
||||
f.mul_by_014(&coeffs.2, &c1, &c0);
|
||||
}
|
||||
|
||||
let mut f = Fq12::one();
|
||||
|
||||
let mut found_one = false;
|
||||
for i in BitIterator::new(&[BLS_X >> 1]) {
|
||||
if !found_one {
|
||||
found_one = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
for &mut (p, ref mut coeffs) in &mut pairs {
|
||||
ell(&mut f, coeffs.next().unwrap(), &p.0);
|
||||
}
|
||||
|
||||
if i {
|
||||
for &mut (p, ref mut coeffs) in &mut pairs {
|
||||
ell(&mut f, coeffs.next().unwrap(), &p.0);
|
||||
}
|
||||
}
|
||||
|
||||
f.square();
|
||||
}
|
||||
|
||||
for &mut (p, ref mut coeffs) in &mut pairs {
|
||||
ell(&mut f, coeffs.next().unwrap(), &p.0);
|
||||
}
|
||||
|
||||
if BLS_X_IS_NEGATIVE {
|
||||
f.conjugate();
|
||||
}
|
||||
|
||||
f
|
||||
}
|
||||
|
||||
fn final_exponentiation(r: &Fq12) -> Option<Fq12> {
|
||||
let mut f1 = *r;
|
||||
f1.conjugate();
|
||||
|
||||
match r.inverse() {
|
||||
Some(mut f2) => {
|
||||
let mut r = f1;
|
||||
r.mul_assign(&f2);
|
||||
f2 = r;
|
||||
r.frobenius_map(2);
|
||||
r.mul_assign(&f2);
|
||||
|
||||
fn exp_by_x(f: &mut Fq12, x: u64) {
|
||||
*f = f.pow(&[x]);
|
||||
if BLS_X_IS_NEGATIVE {
|
||||
f.conjugate();
|
||||
}
|
||||
}
|
||||
|
||||
let mut x = BLS_X;
|
||||
let mut y0 = r;
|
||||
y0.square();
|
||||
let mut y1 = y0;
|
||||
exp_by_x(&mut y1, x);
|
||||
x >>= 1;
|
||||
let mut y2 = y1;
|
||||
exp_by_x(&mut y2, x);
|
||||
x <<= 1;
|
||||
let mut y3 = r;
|
||||
y3.conjugate();
|
||||
y1.mul_assign(&y3);
|
||||
y1.conjugate();
|
||||
y1.mul_assign(&y2);
|
||||
y2 = y1;
|
||||
exp_by_x(&mut y2, x);
|
||||
y3 = y2;
|
||||
exp_by_x(&mut y3, x);
|
||||
y1.conjugate();
|
||||
y3.mul_assign(&y1);
|
||||
y1.conjugate();
|
||||
y1.frobenius_map(3);
|
||||
y2.frobenius_map(2);
|
||||
y1.mul_assign(&y2);
|
||||
y2 = y3;
|
||||
exp_by_x(&mut y2, x);
|
||||
y2.mul_assign(&y0);
|
||||
y2.mul_assign(&r);
|
||||
y1.mul_assign(&y2);
|
||||
y2 = y3;
|
||||
y2.frobenius_map(1);
|
||||
y1.mul_assign(&y2);
|
||||
|
||||
Some(y1)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl G2Prepared {
|
||||
pub fn is_zero(&self) -> bool {
|
||||
self.infinity
|
||||
}
|
||||
|
||||
pub fn from_affine(q: G2Affine) -> Self {
|
||||
if q.is_zero() {
|
||||
return G2Prepared {
|
||||
coeffs: vec![],
|
||||
infinity: true,
|
||||
};
|
||||
}
|
||||
|
||||
fn doubling_step(r: &mut G2) -> (Fq2, Fq2, Fq2) {
|
||||
// Adaptation of Algorithm 26, https://eprint.iacr.org/2010/354.pdf
|
||||
let mut tmp0 = r.x;
|
||||
tmp0.square();
|
||||
|
||||
let mut tmp1 = r.y;
|
||||
tmp1.square();
|
||||
|
||||
let mut tmp2 = tmp1;
|
||||
tmp2.square();
|
||||
|
||||
let mut tmp3 = tmp1;
|
||||
tmp3.add_assign(&r.x);
|
||||
tmp3.square();
|
||||
tmp3.sub_assign(&tmp0);
|
||||
tmp3.sub_assign(&tmp2);
|
||||
tmp3.double();
|
||||
|
||||
let mut tmp4 = tmp0;
|
||||
tmp4.double();
|
||||
tmp4.add_assign(&tmp0);
|
||||
|
||||
let mut tmp6 = r.x;
|
||||
tmp6.add_assign(&tmp4);
|
||||
|
||||
let mut tmp5 = tmp4;
|
||||
tmp5.square();
|
||||
|
||||
let mut zsquared = r.z;
|
||||
zsquared.square();
|
||||
|
||||
r.x = tmp5;
|
||||
r.x.sub_assign(&tmp3);
|
||||
r.x.sub_assign(&tmp3);
|
||||
|
||||
r.z.add_assign(&r.y);
|
||||
r.z.square();
|
||||
r.z.sub_assign(&tmp1);
|
||||
r.z.sub_assign(&zsquared);
|
||||
|
||||
r.y = tmp3;
|
||||
r.y.sub_assign(&r.x);
|
||||
r.y.mul_assign(&tmp4);
|
||||
|
||||
tmp2.double();
|
||||
tmp2.double();
|
||||
tmp2.double();
|
||||
|
||||
r.y.sub_assign(&tmp2);
|
||||
|
||||
tmp3 = tmp4;
|
||||
tmp3.mul_assign(&zsquared);
|
||||
tmp3.double();
|
||||
tmp3.negate();
|
||||
|
||||
tmp6.square();
|
||||
tmp6.sub_assign(&tmp0);
|
||||
tmp6.sub_assign(&tmp5);
|
||||
|
||||
tmp1.double();
|
||||
tmp1.double();
|
||||
|
||||
tmp6.sub_assign(&tmp1);
|
||||
|
||||
tmp0 = r.z;
|
||||
tmp0.mul_assign(&zsquared);
|
||||
tmp0.double();
|
||||
|
||||
(tmp0, tmp3, tmp6)
|
||||
}
|
||||
|
||||
fn addition_step(r: &mut G2, q: &G2Affine) -> (Fq2, Fq2, Fq2) {
|
||||
// Adaptation of Algorithm 27, https://eprint.iacr.org/2010/354.pdf
|
||||
let mut zsquared = r.z;
|
||||
zsquared.square();
|
||||
|
||||
let mut ysquared = q.y;
|
||||
ysquared.square();
|
||||
|
||||
let mut t0 = zsquared;
|
||||
t0.mul_assign(&q.x);
|
||||
|
||||
let mut t1 = q.y;
|
||||
t1.add_assign(&r.z);
|
||||
t1.square();
|
||||
t1.sub_assign(&ysquared);
|
||||
t1.sub_assign(&zsquared);
|
||||
t1.mul_assign(&zsquared);
|
||||
|
||||
let mut t2 = t0;
|
||||
t2.sub_assign(&r.x);
|
||||
|
||||
let mut t3 = t2;
|
||||
t3.square();
|
||||
|
||||
let mut t4 = t3;
|
||||
t4.double();
|
||||
t4.double();
|
||||
|
||||
let mut t5 = t4;
|
||||
t5.mul_assign(&t2);
|
||||
|
||||
let mut t6 = t1;
|
||||
t6.sub_assign(&r.y);
|
||||
t6.sub_assign(&r.y);
|
||||
|
||||
let mut t9 = t6;
|
||||
t9.mul_assign(&q.x);
|
||||
|
||||
let mut t7 = t4;
|
||||
t7.mul_assign(&r.x);
|
||||
|
||||
r.x = t6;
|
||||
r.x.square();
|
||||
r.x.sub_assign(&t5);
|
||||
r.x.sub_assign(&t7);
|
||||
r.x.sub_assign(&t7);
|
||||
|
||||
r.z.add_assign(&t2);
|
||||
r.z.square();
|
||||
r.z.sub_assign(&zsquared);
|
||||
r.z.sub_assign(&t3);
|
||||
|
||||
let mut t10 = q.y;
|
||||
t10.add_assign(&r.z);
|
||||
|
||||
let mut t8 = t7;
|
||||
t8.sub_assign(&r.x);
|
||||
t8.mul_assign(&t6);
|
||||
|
||||
t0 = r.y;
|
||||
t0.mul_assign(&t5);
|
||||
t0.double();
|
||||
|
||||
r.y = t8;
|
||||
r.y.sub_assign(&t0);
|
||||
|
||||
t10.square();
|
||||
t10.sub_assign(&ysquared);
|
||||
|
||||
let mut ztsquared = r.z;
|
||||
ztsquared.square();
|
||||
|
||||
t10.sub_assign(&ztsquared);
|
||||
|
||||
t9.double();
|
||||
t9.sub_assign(&t10);
|
||||
|
||||
t10 = r.z;
|
||||
t10.double();
|
||||
|
||||
t6.negate();
|
||||
|
||||
t1 = t6;
|
||||
t1.double();
|
||||
|
||||
(t10, t1, t9)
|
||||
}
|
||||
|
||||
let mut coeffs = vec![];
|
||||
let mut r: G2 = q.into();
|
||||
|
||||
let mut found_one = false;
|
||||
for i in BitIterator::new([BLS_X >> 1]) {
|
||||
if !found_one {
|
||||
found_one = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
coeffs.push(doubling_step(&mut r));
|
||||
|
||||
if i {
|
||||
coeffs.push(addition_step(&mut r, &q));
|
||||
}
|
||||
}
|
||||
|
||||
coeffs.push(doubling_step(&mut r));
|
||||
|
||||
G2Prepared {
|
||||
coeffs,
|
||||
infinity: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bls12_engine_tests() {
|
||||
::tests::engine::engine_tests::<Bls12>();
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,614 +0,0 @@
|
||||
use ff::PrimeFieldRepr;
|
||||
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
|
||||
|
||||
use super::*;
|
||||
use *;
|
||||
|
||||
#[test]
|
||||
fn test_pairing_result_against_relic() {
|
||||
/*
|
||||
Sent to me from Diego Aranha (author of RELIC library):
|
||||
|
||||
1250EBD871FC0A92 A7B2D83168D0D727 272D441BEFA15C50 3DD8E90CE98DB3E7 B6D194F60839C508 A84305AACA1789B6
|
||||
089A1C5B46E5110B 86750EC6A5323488 68A84045483C92B7 AF5AF689452EAFAB F1A8943E50439F1D 59882A98EAA0170F
|
||||
1368BB445C7C2D20 9703F239689CE34C 0378A68E72A6B3B2 16DA0E22A5031B54 DDFF57309396B38C 881C4C849EC23E87
|
||||
193502B86EDB8857 C273FA075A505129 37E0794E1E65A761 7C90D8BD66065B1F FFE51D7A579973B1 315021EC3C19934F
|
||||
01B2F522473D1713 91125BA84DC4007C FBF2F8DA752F7C74 185203FCCA589AC7 19C34DFFBBAAD843 1DAD1C1FB597AAA5
|
||||
018107154F25A764 BD3C79937A45B845 46DA634B8F6BE14A 8061E55CCEBA478B 23F7DACAA35C8CA7 8BEAE9624045B4B6
|
||||
19F26337D205FB46 9CD6BD15C3D5A04D C88784FBB3D0B2DB DEA54D43B2B73F2C BB12D58386A8703E 0F948226E47EE89D
|
||||
06FBA23EB7C5AF0D 9F80940CA771B6FF D5857BAAF222EB95 A7D2809D61BFE02E 1BFD1B68FF02F0B8 102AE1C2D5D5AB1A
|
||||
11B8B424CD48BF38 FCEF68083B0B0EC5 C81A93B330EE1A67 7D0D15FF7B984E89 78EF48881E32FAC9 1B93B47333E2BA57
|
||||
03350F55A7AEFCD3 C31B4FCB6CE5771C C6A0E9786AB59733 20C806AD36082910 7BA810C5A09FFDD9 BE2291A0C25A99A2
|
||||
04C581234D086A99 02249B64728FFD21 A189E87935A95405 1C7CDBA7B3872629 A4FAFC05066245CB 9108F0242D0FE3EF
|
||||
0F41E58663BF08CF 068672CBD01A7EC7 3BACA4D72CA93544 DEFF686BFD6DF543 D48EAA24AFE47E1E FDE449383B676631
|
||||
*/
|
||||
|
||||
assert_eq!(Bls12::pairing(G1::one(), G2::one()), Fq12 {
|
||||
c0: Fq6 {
|
||||
c0: Fq2 {
|
||||
c0: Fq::from_str("2819105605953691245277803056322684086884703000473961065716485506033588504203831029066448642358042597501014294104502").unwrap(),
|
||||
c1: Fq::from_str("1323968232986996742571315206151405965104242542339680722164220900812303524334628370163366153839984196298685227734799").unwrap()
|
||||
},
|
||||
c1: Fq2 {
|
||||
c0: Fq::from_str("2987335049721312504428602988447616328830341722376962214011674875969052835043875658579425548512925634040144704192135").unwrap(),
|
||||
c1: Fq::from_str("3879723582452552452538684314479081967502111497413076598816163759028842927668327542875108457755966417881797966271311").unwrap()
|
||||
},
|
||||
c2: Fq2 {
|
||||
c0: Fq::from_str("261508182517997003171385743374653339186059518494239543139839025878870012614975302676296704930880982238308326681253").unwrap(),
|
||||
c1: Fq::from_str("231488992246460459663813598342448669854473942105054381511346786719005883340876032043606739070883099647773793170614").unwrap()
|
||||
}
|
||||
},
|
||||
c1: Fq6 {
|
||||
c0: Fq2 {
|
||||
c0: Fq::from_str("3993582095516422658773669068931361134188738159766715576187490305611759126554796569868053818105850661142222948198557").unwrap(),
|
||||
c1: Fq::from_str("1074773511698422344502264006159859710502164045911412750831641680783012525555872467108249271286757399121183508900634").unwrap()
|
||||
},
|
||||
c1: Fq2 {
|
||||
c0: Fq::from_str("2727588299083545686739024317998512740561167011046940249988557419323068809019137624943703910267790601287073339193943").unwrap(),
|
||||
c1: Fq::from_str("493643299814437640914745677854369670041080344349607504656543355799077485536288866009245028091988146107059514546594").unwrap()
|
||||
},
|
||||
c2: Fq2 {
|
||||
c0: Fq::from_str("734401332196641441839439105942623141234148957972407782257355060229193854324927417865401895596108124443575283868655").unwrap(),
|
||||
c1: Fq::from_str("2348330098288556420918672502923664952620152483128593484301759394583320358354186482723629999370241674973832318248497").unwrap()
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn test_vectors<G: CurveProjective, E: EncodedPoint<Affine = G::Affine>>(expected: &[u8]) {
|
||||
let mut e = G::zero();
|
||||
|
||||
let mut v = vec![];
|
||||
{
|
||||
let mut expected = expected;
|
||||
for _ in 0..1000 {
|
||||
let e_affine = e.into_affine();
|
||||
let encoded = E::from_affine(e_affine);
|
||||
v.extend_from_slice(encoded.as_ref());
|
||||
|
||||
let mut decoded = E::empty();
|
||||
decoded.as_mut().copy_from_slice(&expected[0..E::size()]);
|
||||
expected = &expected[E::size()..];
|
||||
let decoded = decoded.into_affine().unwrap();
|
||||
assert_eq!(e_affine, decoded);
|
||||
|
||||
e.add_assign(&G::one());
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(&v[..], expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_g1_uncompressed_valid_vectors() {
|
||||
test_vectors::<G1, G1Uncompressed>(include_bytes!("g1_uncompressed_valid_test_vectors.dat"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_g1_compressed_valid_vectors() {
|
||||
test_vectors::<G1, G1Compressed>(include_bytes!("g1_compressed_valid_test_vectors.dat"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_g2_uncompressed_valid_vectors() {
|
||||
test_vectors::<G2, G2Uncompressed>(include_bytes!("g2_uncompressed_valid_test_vectors.dat"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_g2_compressed_valid_vectors() {
|
||||
test_vectors::<G2, G2Compressed>(include_bytes!("g2_compressed_valid_test_vectors.dat"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_g1_uncompressed_invalid_vectors() {
|
||||
{
|
||||
let z = G1Affine::zero().into_uncompressed();
|
||||
|
||||
{
|
||||
let mut z = z;
|
||||
z.as_mut()[0] |= 0b1000_0000;
|
||||
if let Err(GroupDecodingError::UnexpectedCompressionMode) = z.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because we expected an uncompressed point");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut z = z;
|
||||
z.as_mut()[0] |= 0b0010_0000;
|
||||
if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because the parity bit should not be set if the point is at infinity");
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0..G1Uncompressed::size() {
|
||||
let mut z = z;
|
||||
z.as_mut()[i] |= 0b0000_0001;
|
||||
if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let o = G1Affine::one().into_uncompressed();
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
o.as_mut()[0] |= 0b1000_0000;
|
||||
if let Err(GroupDecodingError::UnexpectedCompressionMode) = o.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because we expected an uncompressed point");
|
||||
}
|
||||
}
|
||||
|
||||
let m = Fq::char();
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
m.write_be(&mut o.as_mut()[0..]).unwrap();
|
||||
|
||||
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
|
||||
assert_eq!(coordinate, "x coordinate");
|
||||
} else {
|
||||
panic!("should have rejected the point")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
m.write_be(&mut o.as_mut()[48..]).unwrap();
|
||||
|
||||
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
|
||||
assert_eq!(coordinate, "y coordinate");
|
||||
} else {
|
||||
panic!("should have rejected the point")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let m = Fq::zero().into_repr();
|
||||
|
||||
let mut o = o;
|
||||
m.write_be(&mut o.as_mut()[0..]).unwrap();
|
||||
|
||||
if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because it isn't on the curve")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
let mut x = Fq::one();
|
||||
|
||||
loop {
|
||||
let mut x3b = x;
|
||||
x3b.square();
|
||||
x3b.mul_assign(&x);
|
||||
x3b.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); // TODO: perhaps expose coeff_b through API?
|
||||
|
||||
if let Some(y) = x3b.sqrt() {
|
||||
// We know this is on the curve, but it's likely not going to be in the correct subgroup.
|
||||
x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
|
||||
y.into_repr().write_be(&mut o.as_mut()[48..]).unwrap();
|
||||
|
||||
if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() {
|
||||
break;
|
||||
} else {
|
||||
panic!(
|
||||
"should have rejected the point because it isn't in the correct subgroup"
|
||||
)
|
||||
}
|
||||
} else {
|
||||
x.add_assign(&Fq::one());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_g2_uncompressed_invalid_vectors() {
|
||||
{
|
||||
let z = G2Affine::zero().into_uncompressed();
|
||||
|
||||
{
|
||||
let mut z = z;
|
||||
z.as_mut()[0] |= 0b1000_0000;
|
||||
if let Err(GroupDecodingError::UnexpectedCompressionMode) = z.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because we expected an uncompressed point");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut z = z;
|
||||
z.as_mut()[0] |= 0b0010_0000;
|
||||
if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because the parity bit should not be set if the point is at infinity");
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0..G2Uncompressed::size() {
|
||||
let mut z = z;
|
||||
z.as_mut()[i] |= 0b0000_0001;
|
||||
if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let o = G2Affine::one().into_uncompressed();
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
o.as_mut()[0] |= 0b1000_0000;
|
||||
if let Err(GroupDecodingError::UnexpectedCompressionMode) = o.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because we expected an uncompressed point");
|
||||
}
|
||||
}
|
||||
|
||||
let m = Fq::char();
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
m.write_be(&mut o.as_mut()[0..]).unwrap();
|
||||
|
||||
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
|
||||
assert_eq!(coordinate, "x coordinate (c1)");
|
||||
} else {
|
||||
panic!("should have rejected the point")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
m.write_be(&mut o.as_mut()[48..]).unwrap();
|
||||
|
||||
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
|
||||
assert_eq!(coordinate, "x coordinate (c0)");
|
||||
} else {
|
||||
panic!("should have rejected the point")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
m.write_be(&mut o.as_mut()[96..]).unwrap();
|
||||
|
||||
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
|
||||
assert_eq!(coordinate, "y coordinate (c1)");
|
||||
} else {
|
||||
panic!("should have rejected the point")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
m.write_be(&mut o.as_mut()[144..]).unwrap();
|
||||
|
||||
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
|
||||
assert_eq!(coordinate, "y coordinate (c0)");
|
||||
} else {
|
||||
panic!("should have rejected the point")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let m = Fq::zero().into_repr();
|
||||
|
||||
let mut o = o;
|
||||
m.write_be(&mut o.as_mut()[0..]).unwrap();
|
||||
m.write_be(&mut o.as_mut()[48..]).unwrap();
|
||||
|
||||
if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because it isn't on the curve")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
let mut x = Fq2::one();
|
||||
|
||||
loop {
|
||||
let mut x3b = x;
|
||||
x3b.square();
|
||||
x3b.mul_assign(&x);
|
||||
x3b.add_assign(&Fq2 {
|
||||
c0: Fq::from_repr(FqRepr::from(4)).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr::from(4)).unwrap(),
|
||||
}); // TODO: perhaps expose coeff_b through API?
|
||||
|
||||
if let Some(y) = x3b.sqrt() {
|
||||
// We know this is on the curve, but it's likely not going to be in the correct subgroup.
|
||||
x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
|
||||
x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap();
|
||||
y.c1.into_repr().write_be(&mut o.as_mut()[96..]).unwrap();
|
||||
y.c0.into_repr().write_be(&mut o.as_mut()[144..]).unwrap();
|
||||
|
||||
if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() {
|
||||
break;
|
||||
} else {
|
||||
panic!(
|
||||
"should have rejected the point because it isn't in the correct subgroup"
|
||||
)
|
||||
}
|
||||
} else {
|
||||
x.add_assign(&Fq2::one());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_g1_compressed_invalid_vectors() {
|
||||
{
|
||||
let z = G1Affine::zero().into_compressed();
|
||||
|
||||
{
|
||||
let mut z = z;
|
||||
z.as_mut()[0] &= 0b0111_1111;
|
||||
if let Err(GroupDecodingError::UnexpectedCompressionMode) = z.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because we expected a compressed point");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut z = z;
|
||||
z.as_mut()[0] |= 0b0010_0000;
|
||||
if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because the parity bit should not be set if the point is at infinity");
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0..G1Compressed::size() {
|
||||
let mut z = z;
|
||||
z.as_mut()[i] |= 0b0000_0001;
|
||||
if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let o = G1Affine::one().into_compressed();
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
o.as_mut()[0] &= 0b0111_1111;
|
||||
if let Err(GroupDecodingError::UnexpectedCompressionMode) = o.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because we expected a compressed point");
|
||||
}
|
||||
}
|
||||
|
||||
let m = Fq::char();
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
m.write_be(&mut o.as_mut()[0..]).unwrap();
|
||||
o.as_mut()[0] |= 0b1000_0000;
|
||||
|
||||
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
|
||||
assert_eq!(coordinate, "x coordinate");
|
||||
} else {
|
||||
panic!("should have rejected the point")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
let mut x = Fq::one();
|
||||
|
||||
loop {
|
||||
let mut x3b = x;
|
||||
x3b.square();
|
||||
x3b.mul_assign(&x);
|
||||
x3b.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); // TODO: perhaps expose coeff_b through API?
|
||||
|
||||
if let Some(_) = x3b.sqrt() {
|
||||
x.add_assign(&Fq::one());
|
||||
} else {
|
||||
x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
|
||||
o.as_mut()[0] |= 0b1000_0000;
|
||||
|
||||
if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() {
|
||||
break;
|
||||
} else {
|
||||
panic!("should have rejected the point because it isn't on the curve")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
let mut x = Fq::one();
|
||||
|
||||
loop {
|
||||
let mut x3b = x;
|
||||
x3b.square();
|
||||
x3b.mul_assign(&x);
|
||||
x3b.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); // TODO: perhaps expose coeff_b through API?
|
||||
|
||||
if let Some(_) = x3b.sqrt() {
|
||||
// We know this is on the curve, but it's likely not going to be in the correct subgroup.
|
||||
x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
|
||||
o.as_mut()[0] |= 0b1000_0000;
|
||||
|
||||
if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() {
|
||||
break;
|
||||
} else {
|
||||
panic!(
|
||||
"should have rejected the point because it isn't in the correct subgroup"
|
||||
)
|
||||
}
|
||||
} else {
|
||||
x.add_assign(&Fq::one());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_g2_compressed_invalid_vectors() {
|
||||
{
|
||||
let z = G2Affine::zero().into_compressed();
|
||||
|
||||
{
|
||||
let mut z = z;
|
||||
z.as_mut()[0] &= 0b0111_1111;
|
||||
if let Err(GroupDecodingError::UnexpectedCompressionMode) = z.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because we expected a compressed point");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut z = z;
|
||||
z.as_mut()[0] |= 0b0010_0000;
|
||||
if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because the parity bit should not be set if the point is at infinity");
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0..G2Compressed::size() {
|
||||
let mut z = z;
|
||||
z.as_mut()[i] |= 0b0000_0001;
|
||||
if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let o = G2Affine::one().into_compressed();
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
o.as_mut()[0] &= 0b0111_1111;
|
||||
if let Err(GroupDecodingError::UnexpectedCompressionMode) = o.into_affine() {
|
||||
// :)
|
||||
} else {
|
||||
panic!("should have rejected the point because we expected a compressed point");
|
||||
}
|
||||
}
|
||||
|
||||
let m = Fq::char();
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
m.write_be(&mut o.as_mut()[0..]).unwrap();
|
||||
o.as_mut()[0] |= 0b1000_0000;
|
||||
|
||||
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
|
||||
assert_eq!(coordinate, "x coordinate (c1)");
|
||||
} else {
|
||||
panic!("should have rejected the point")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
m.write_be(&mut o.as_mut()[48..]).unwrap();
|
||||
o.as_mut()[0] |= 0b1000_0000;
|
||||
|
||||
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
|
||||
assert_eq!(coordinate, "x coordinate (c0)");
|
||||
} else {
|
||||
panic!("should have rejected the point")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
let mut x = Fq2 {
|
||||
c0: Fq::one(),
|
||||
c1: Fq::one(),
|
||||
};
|
||||
|
||||
loop {
|
||||
let mut x3b = x;
|
||||
x3b.square();
|
||||
x3b.mul_assign(&x);
|
||||
x3b.add_assign(&Fq2 {
|
||||
c0: Fq::from_repr(FqRepr::from(4)).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr::from(4)).unwrap(),
|
||||
}); // TODO: perhaps expose coeff_b through API?
|
||||
|
||||
if let Some(_) = x3b.sqrt() {
|
||||
x.add_assign(&Fq2::one());
|
||||
} else {
|
||||
x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
|
||||
x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap();
|
||||
o.as_mut()[0] |= 0b1000_0000;
|
||||
|
||||
if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() {
|
||||
break;
|
||||
} else {
|
||||
panic!("should have rejected the point because it isn't on the curve")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut o = o;
|
||||
let mut x = Fq2 {
|
||||
c0: Fq::one(),
|
||||
c1: Fq::one(),
|
||||
};
|
||||
|
||||
loop {
|
||||
let mut x3b = x;
|
||||
x3b.square();
|
||||
x3b.mul_assign(&x);
|
||||
x3b.add_assign(&Fq2 {
|
||||
c0: Fq::from_repr(FqRepr::from(4)).unwrap(),
|
||||
c1: Fq::from_repr(FqRepr::from(4)).unwrap(),
|
||||
}); // TODO: perhaps expose coeff_b through API?
|
||||
|
||||
if let Some(_) = x3b.sqrt() {
|
||||
// We know this is on the curve, but it's likely not going to be in the correct subgroup.
|
||||
x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
|
||||
x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap();
|
||||
o.as_mut()[0] |= 0b1000_0000;
|
||||
|
||||
if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() {
|
||||
break;
|
||||
} else {
|
||||
panic!(
|
||||
"should have rejected the point because it isn't in the correct subgroup"
|
||||
)
|
||||
}
|
||||
} else {
|
||||
x.add_assign(&Fq2::one());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
// `clippy` is a code linting tool for improving code quality by catching
|
||||
// common mistakes or strange code patterns. If the `cargo-clippy` feature
|
||||
// is provided, all compiler warnings are prohibited.
|
||||
#![cfg_attr(feature = "cargo-clippy", deny(warnings))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(inline_always))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(many_single_char_names))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(new_without_default_derive))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(write_literal))]
|
||||
// Force public structures to implement Debug
|
||||
#![deny(missing_debug_implementations)]
|
||||
|
||||
extern crate byteorder;
|
||||
#[macro_use]
|
||||
extern crate ff;
|
||||
extern crate group;
|
||||
extern crate rand;
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests;
|
||||
|
||||
pub mod bls12_381;
|
||||
|
||||
use ff::{Field, PrimeField, ScalarEngine, SqrtField};
|
||||
use group::{CurveAffine, CurveProjective};
|
||||
|
||||
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
|
||||
/// with well-defined relationships. In particular, the G1/G2 curve groups are
|
||||
/// of prime order `r`, and are equipped with a bilinear pairing function.
|
||||
pub trait Engine: ScalarEngine {
|
||||
/// The projective representation of an element in G1.
|
||||
type G1: CurveProjective<
|
||||
Engine = Self,
|
||||
Base = Self::Fq,
|
||||
Scalar = Self::Fr,
|
||||
Affine = Self::G1Affine,
|
||||
>
|
||||
+ From<Self::G1Affine>;
|
||||
|
||||
/// The affine representation of an element in G1.
|
||||
type G1Affine: PairingCurveAffine<
|
||||
Engine = Self,
|
||||
Base = Self::Fq,
|
||||
Scalar = Self::Fr,
|
||||
Projective = Self::G1,
|
||||
Pair = Self::G2Affine,
|
||||
PairingResult = Self::Fqk,
|
||||
>
|
||||
+ From<Self::G1>;
|
||||
|
||||
/// The projective representation of an element in G2.
|
||||
type G2: CurveProjective<
|
||||
Engine = Self,
|
||||
Base = Self::Fqe,
|
||||
Scalar = Self::Fr,
|
||||
Affine = Self::G2Affine,
|
||||
>
|
||||
+ From<Self::G2Affine>;
|
||||
|
||||
/// The affine representation of an element in G2.
|
||||
type G2Affine: PairingCurveAffine<
|
||||
Engine = Self,
|
||||
Base = Self::Fqe,
|
||||
Scalar = Self::Fr,
|
||||
Projective = Self::G2,
|
||||
Pair = Self::G1Affine,
|
||||
PairingResult = Self::Fqk,
|
||||
>
|
||||
+ From<Self::G2>;
|
||||
|
||||
/// The base field that hosts G1.
|
||||
type Fq: PrimeField + SqrtField;
|
||||
|
||||
/// The extension field that hosts G2.
|
||||
type Fqe: SqrtField;
|
||||
|
||||
/// The extension field that hosts the target group of the pairing.
|
||||
type Fqk: Field;
|
||||
|
||||
/// Perform a miller loop with some number of (G1, G2) pairs.
|
||||
fn miller_loop<'a, I>(i: I) -> Self::Fqk
|
||||
where
|
||||
I: IntoIterator<
|
||||
Item = &'a (
|
||||
&'a <Self::G1Affine as PairingCurveAffine>::Prepared,
|
||||
&'a <Self::G2Affine as PairingCurveAffine>::Prepared,
|
||||
),
|
||||
>;
|
||||
|
||||
/// Perform final exponentiation of the result of a miller loop.
|
||||
fn final_exponentiation(&Self::Fqk) -> Option<Self::Fqk>;
|
||||
|
||||
/// Performs a complete pairing operation `(p, q)`.
|
||||
fn pairing<G1, G2>(p: G1, q: G2) -> Self::Fqk
|
||||
where
|
||||
G1: Into<Self::G1Affine>,
|
||||
G2: Into<Self::G2Affine>,
|
||||
{
|
||||
Self::final_exponentiation(&Self::miller_loop(
|
||||
[(&(p.into().prepare()), &(q.into().prepare()))].into_iter(),
|
||||
)).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Affine representation of an elliptic curve point that can be used
|
||||
/// to perform pairings.
|
||||
pub trait PairingCurveAffine: CurveAffine {
|
||||
type Prepared: Clone + Send + Sync + 'static;
|
||||
type Pair: PairingCurveAffine<Pair = Self>;
|
||||
type PairingResult: Field;
|
||||
|
||||
/// Prepares this element for pairing purposes.
|
||||
fn prepare(&self) -> Self::Prepared;
|
||||
|
||||
/// Perform a pairing
|
||||
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult;
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
use group::{CurveAffine, CurveProjective};
|
||||
use rand::{Rand, SeedableRng, XorShiftRng};
|
||||
|
||||
use {Engine, Field, PairingCurveAffine, PrimeField};
|
||||
|
||||
pub fn engine_tests<E: Engine>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..10 {
|
||||
let a = E::G1::rand(&mut rng).into_affine();
|
||||
let b = E::G2::rand(&mut rng).into_affine();
|
||||
|
||||
assert!(a.pairing_with(&b) == b.pairing_with(&a));
|
||||
assert!(a.pairing_with(&b) == E::pairing(a, b));
|
||||
}
|
||||
|
||||
for _ in 0..1000 {
|
||||
let z1 = E::G1Affine::zero().prepare();
|
||||
let z2 = E::G2Affine::zero().prepare();
|
||||
|
||||
let a = E::G1::rand(&mut rng).into_affine().prepare();
|
||||
let b = E::G2::rand(&mut rng).into_affine().prepare();
|
||||
let c = E::G1::rand(&mut rng).into_affine().prepare();
|
||||
let d = E::G2::rand(&mut rng).into_affine().prepare();
|
||||
|
||||
assert_eq!(
|
||||
E::Fqk::one(),
|
||||
E::final_exponentiation(&E::miller_loop(&[(&z1, &b)])).unwrap()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
E::Fqk::one(),
|
||||
E::final_exponentiation(&E::miller_loop(&[(&a, &z2)])).unwrap()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
E::final_exponentiation(&E::miller_loop(&[(&z1, &b), (&c, &d)])).unwrap(),
|
||||
E::final_exponentiation(&E::miller_loop(&[(&a, &z2), (&c, &d)])).unwrap()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
E::final_exponentiation(&E::miller_loop(&[(&a, &b), (&z1, &d)])).unwrap(),
|
||||
E::final_exponentiation(&E::miller_loop(&[(&a, &b), (&c, &z2)])).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
random_bilinearity_tests::<E>();
|
||||
random_miller_loop_tests::<E>();
|
||||
}
|
||||
|
||||
fn random_miller_loop_tests<E: Engine>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
// Exercise the miller loop for a reduced pairing
|
||||
for _ in 0..1000 {
|
||||
let a = E::G1::rand(&mut rng);
|
||||
let b = E::G2::rand(&mut rng);
|
||||
|
||||
let p2 = E::pairing(a, b);
|
||||
|
||||
let a = a.into_affine().prepare();
|
||||
let b = b.into_affine().prepare();
|
||||
|
||||
let p1 = E::final_exponentiation(&E::miller_loop(&[(&a, &b)])).unwrap();
|
||||
|
||||
assert_eq!(p1, p2);
|
||||
}
|
||||
|
||||
// Exercise a double miller loop
|
||||
for _ in 0..1000 {
|
||||
let a = E::G1::rand(&mut rng);
|
||||
let b = E::G2::rand(&mut rng);
|
||||
let c = E::G1::rand(&mut rng);
|
||||
let d = E::G2::rand(&mut rng);
|
||||
|
||||
let ab = E::pairing(a, b);
|
||||
let cd = E::pairing(c, d);
|
||||
|
||||
let mut abcd = ab;
|
||||
abcd.mul_assign(&cd);
|
||||
|
||||
let a = a.into_affine().prepare();
|
||||
let b = b.into_affine().prepare();
|
||||
let c = c.into_affine().prepare();
|
||||
let d = d.into_affine().prepare();
|
||||
|
||||
let abcd_with_double_loop =
|
||||
E::final_exponentiation(&E::miller_loop(&[(&a, &b), (&c, &d)])).unwrap();
|
||||
|
||||
assert_eq!(abcd, abcd_with_double_loop);
|
||||
}
|
||||
}
|
||||
|
||||
fn random_bilinearity_tests<E: Engine>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let a = E::G1::rand(&mut rng);
|
||||
let b = E::G2::rand(&mut rng);
|
||||
|
||||
let c = E::Fr::rand(&mut rng);
|
||||
let d = E::Fr::rand(&mut rng);
|
||||
|
||||
let mut ac = a;
|
||||
ac.mul_assign(c);
|
||||
|
||||
let mut ad = a;
|
||||
ad.mul_assign(d);
|
||||
|
||||
let mut bc = b;
|
||||
bc.mul_assign(c);
|
||||
|
||||
let mut bd = b;
|
||||
bd.mul_assign(d);
|
||||
|
||||
let acbd = E::pairing(ac, bd);
|
||||
let adbc = E::pairing(ad, bc);
|
||||
|
||||
let mut cd = c;
|
||||
cd.mul_assign(&d);
|
||||
|
||||
let abcd = E::pairing(a, b).pow(cd.into_repr());
|
||||
|
||||
assert_eq!(acbd, adbc);
|
||||
assert_eq!(acbd, abcd);
|
||||
}
|
||||
}
|
@ -1,266 +0,0 @@
|
||||
use ff::{Field, LegendreSymbol, PrimeField, SqrtField};
|
||||
use rand::{Rng, SeedableRng, XorShiftRng};
|
||||
|
||||
pub fn random_frobenius_tests<F: Field, C: AsRef<[u64]>>(characteristic: C, maxpower: usize) {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..100 {
|
||||
for i in 0..(maxpower + 1) {
|
||||
let mut a = F::rand(&mut rng);
|
||||
let mut b = a;
|
||||
|
||||
for _ in 0..i {
|
||||
a = a.pow(&characteristic);
|
||||
}
|
||||
b.frobenius_map(i);
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn random_sqrt_tests<F: SqrtField>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..10000 {
|
||||
let a = F::rand(&mut rng);
|
||||
let mut b = a;
|
||||
b.square();
|
||||
assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue);
|
||||
|
||||
let b = b.sqrt().unwrap();
|
||||
let mut negb = b;
|
||||
negb.negate();
|
||||
|
||||
assert!(a == b || a == negb);
|
||||
}
|
||||
|
||||
let mut c = F::one();
|
||||
for _ in 0..10000 {
|
||||
let mut b = c;
|
||||
b.square();
|
||||
assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue);
|
||||
|
||||
b = b.sqrt().unwrap();
|
||||
|
||||
if b != c {
|
||||
b.negate();
|
||||
}
|
||||
|
||||
assert_eq!(b, c);
|
||||
|
||||
c.add_assign(&F::one());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn random_field_tests<F: Field>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
random_multiplication_tests::<F, _>(&mut rng);
|
||||
random_addition_tests::<F, _>(&mut rng);
|
||||
random_subtraction_tests::<F, _>(&mut rng);
|
||||
random_negation_tests::<F, _>(&mut rng);
|
||||
random_doubling_tests::<F, _>(&mut rng);
|
||||
random_squaring_tests::<F, _>(&mut rng);
|
||||
random_inversion_tests::<F, _>(&mut rng);
|
||||
random_expansion_tests::<F, _>(&mut rng);
|
||||
|
||||
assert!(F::zero().is_zero());
|
||||
{
|
||||
let mut z = F::zero();
|
||||
z.negate();
|
||||
assert!(z.is_zero());
|
||||
}
|
||||
|
||||
assert!(F::zero().inverse().is_none());
|
||||
|
||||
// Multiplication by zero
|
||||
{
|
||||
let mut a = F::rand(&mut rng);
|
||||
a.mul_assign(&F::zero());
|
||||
assert!(a.is_zero());
|
||||
}
|
||||
|
||||
// Addition by zero
|
||||
{
|
||||
let mut a = F::rand(&mut rng);
|
||||
let copy = a;
|
||||
a.add_assign(&F::zero());
|
||||
assert_eq!(a, copy);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str_tests<F: PrimeField>() {
|
||||
{
|
||||
let a = "84395729384759238745923745892374598234705297301958723458712394587103249587213984572934750213947582345792304758273458972349582734958273495872304598234";
|
||||
let b = "38495729084572938457298347502349857029384609283450692834058293405982304598230458230495820394850293845098234059823049582309485203948502938452093482039";
|
||||
let c = "3248875134290623212325429203829831876024364170316860259933542844758450336418538569901990710701240661702808867062612075657861768196242274635305077449545396068598317421057721935408562373834079015873933065667961469731886739181625866970316226171512545167081793907058686908697431878454091011239990119126";
|
||||
|
||||
let mut a = F::from_str(a).unwrap();
|
||||
let b = F::from_str(b).unwrap();
|
||||
let c = F::from_str(c).unwrap();
|
||||
|
||||
a.mul_assign(&b);
|
||||
|
||||
assert_eq!(a, c);
|
||||
}
|
||||
|
||||
{
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let n: u64 = rng.gen();
|
||||
|
||||
let a = F::from_str(&format!("{}", n)).unwrap();
|
||||
let b = F::from_repr(n.into()).unwrap();
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
assert!(F::from_str("").is_none());
|
||||
assert!(F::from_str("0").unwrap().is_zero());
|
||||
assert!(F::from_str("00").is_none());
|
||||
assert!(F::from_str("00000000000").is_none());
|
||||
}
|
||||
|
||||
fn random_multiplication_tests<F: Field, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..10000 {
|
||||
let a = F::rand(rng);
|
||||
let b = F::rand(rng);
|
||||
let c = F::rand(rng);
|
||||
|
||||
let mut t0 = a; // (a * b) * c
|
||||
t0.mul_assign(&b);
|
||||
t0.mul_assign(&c);
|
||||
|
||||
let mut t1 = a; // (a * c) * b
|
||||
t1.mul_assign(&c);
|
||||
t1.mul_assign(&b);
|
||||
|
||||
let mut t2 = b; // (b * c) * a
|
||||
t2.mul_assign(&c);
|
||||
t2.mul_assign(&a);
|
||||
|
||||
assert_eq!(t0, t1);
|
||||
assert_eq!(t1, t2);
|
||||
}
|
||||
}
|
||||
|
||||
fn random_addition_tests<F: Field, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..10000 {
|
||||
let a = F::rand(rng);
|
||||
let b = F::rand(rng);
|
||||
let c = F::rand(rng);
|
||||
|
||||
let mut t0 = a; // (a + b) + c
|
||||
t0.add_assign(&b);
|
||||
t0.add_assign(&c);
|
||||
|
||||
let mut t1 = a; // (a + c) + b
|
||||
t1.add_assign(&c);
|
||||
t1.add_assign(&b);
|
||||
|
||||
let mut t2 = b; // (b + c) + a
|
||||
t2.add_assign(&c);
|
||||
t2.add_assign(&a);
|
||||
|
||||
assert_eq!(t0, t1);
|
||||
assert_eq!(t1, t2);
|
||||
}
|
||||
}
|
||||
|
||||
fn random_subtraction_tests<F: Field, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..10000 {
|
||||
let a = F::rand(rng);
|
||||
let b = F::rand(rng);
|
||||
|
||||
let mut t0 = a; // (a - b)
|
||||
t0.sub_assign(&b);
|
||||
|
||||
let mut t1 = b; // (b - a)
|
||||
t1.sub_assign(&a);
|
||||
|
||||
let mut t2 = t0; // (a - b) + (b - a) = 0
|
||||
t2.add_assign(&t1);
|
||||
|
||||
assert!(t2.is_zero());
|
||||
}
|
||||
}
|
||||
|
||||
fn random_negation_tests<F: Field, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..10000 {
|
||||
let a = F::rand(rng);
|
||||
let mut b = a;
|
||||
b.negate();
|
||||
b.add_assign(&a);
|
||||
|
||||
assert!(b.is_zero());
|
||||
}
|
||||
}
|
||||
|
||||
fn random_doubling_tests<F: Field, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..10000 {
|
||||
let mut a = F::rand(rng);
|
||||
let mut b = a;
|
||||
a.add_assign(&b);
|
||||
b.double();
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
fn random_squaring_tests<F: Field, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..10000 {
|
||||
let mut a = F::rand(rng);
|
||||
let mut b = a;
|
||||
a.mul_assign(&b);
|
||||
b.square();
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
fn random_inversion_tests<F: Field, R: Rng>(rng: &mut R) {
|
||||
assert!(F::zero().inverse().is_none());
|
||||
|
||||
for _ in 0..10000 {
|
||||
let mut a = F::rand(rng);
|
||||
let b = a.inverse().unwrap(); // probablistically nonzero
|
||||
a.mul_assign(&b);
|
||||
|
||||
assert_eq!(a, F::one());
|
||||
}
|
||||
}
|
||||
|
||||
fn random_expansion_tests<F: Field, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..10000 {
|
||||
// Compare (a + b)(c + d) and (a*c + b*c + a*d + b*d)
|
||||
|
||||
let a = F::rand(rng);
|
||||
let b = F::rand(rng);
|
||||
let c = F::rand(rng);
|
||||
let d = F::rand(rng);
|
||||
|
||||
let mut t0 = a;
|
||||
t0.add_assign(&b);
|
||||
let mut t1 = c;
|
||||
t1.add_assign(&d);
|
||||
t0.mul_assign(&t1);
|
||||
|
||||
let mut t2 = a;
|
||||
t2.mul_assign(&c);
|
||||
let mut t3 = b;
|
||||
t3.mul_assign(&c);
|
||||
let mut t4 = a;
|
||||
t4.mul_assign(&d);
|
||||
let mut t5 = b;
|
||||
t5.mul_assign(&d);
|
||||
|
||||
t2.add_assign(&t3);
|
||||
t2.add_assign(&t4);
|
||||
t2.add_assign(&t5);
|
||||
|
||||
assert_eq!(t0, t2);
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
pub mod engine;
|
||||
pub mod field;
|
||||
pub mod repr;
|
@ -1,98 +0,0 @@
|
||||
use ff::PrimeFieldRepr;
|
||||
use rand::{SeedableRng, XorShiftRng};
|
||||
|
||||
pub fn random_repr_tests<R: PrimeFieldRepr>() {
|
||||
random_encoding_tests::<R>();
|
||||
random_shl_tests::<R>();
|
||||
random_shr_tests::<R>();
|
||||
}
|
||||
|
||||
fn random_encoding_tests<R: PrimeFieldRepr>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let r = R::rand(&mut rng);
|
||||
|
||||
// Big endian
|
||||
{
|
||||
let mut rdecoded = R::default();
|
||||
|
||||
let mut v: Vec<u8> = vec![];
|
||||
r.write_be(&mut v).unwrap();
|
||||
rdecoded.read_be(&v[0..]).unwrap();
|
||||
|
||||
assert_eq!(r, rdecoded);
|
||||
}
|
||||
|
||||
// Little endian
|
||||
{
|
||||
let mut rdecoded = R::default();
|
||||
|
||||
let mut v: Vec<u8> = vec![];
|
||||
r.write_le(&mut v).unwrap();
|
||||
rdecoded.read_le(&v[0..]).unwrap();
|
||||
|
||||
assert_eq!(r, rdecoded);
|
||||
}
|
||||
|
||||
{
|
||||
let mut rdecoded_le = R::default();
|
||||
let mut rdecoded_be_flip = R::default();
|
||||
|
||||
let mut v: Vec<u8> = vec![];
|
||||
r.write_le(&mut v).unwrap();
|
||||
|
||||
// This reads in little-endian, so we are done.
|
||||
rdecoded_le.read_le(&v[..]).unwrap();
|
||||
|
||||
// This reads in big-endian, so we perform a swap of the
|
||||
// bytes beforehand.
|
||||
let v: Vec<u8> = v.into_iter().rev().collect();
|
||||
rdecoded_be_flip.read_be(&v[..]).unwrap();
|
||||
|
||||
assert_eq!(rdecoded_le, rdecoded_be_flip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn random_shl_tests<R: PrimeFieldRepr>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..100 {
|
||||
let r = R::rand(&mut rng);
|
||||
|
||||
for shift in 0..(r.num_bits() + 1) {
|
||||
let mut r1 = r;
|
||||
let mut r2 = r;
|
||||
|
||||
for _ in 0..shift {
|
||||
r1.mul2();
|
||||
}
|
||||
|
||||
r2.shl(shift);
|
||||
|
||||
assert_eq!(r1, r2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn random_shr_tests<R: PrimeFieldRepr>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..100 {
|
||||
let r = R::rand(&mut rng);
|
||||
|
||||
for shift in 0..(r.num_bits() + 1) {
|
||||
let mut r1 = r;
|
||||
let mut r2 = r;
|
||||
|
||||
for _ in 0..shift {
|
||||
r1.div2();
|
||||
}
|
||||
|
||||
r2.shr(shift);
|
||||
|
||||
assert_eq!(r1, r2);
|
||||
}
|
||||
}
|
||||
}
|
3
sapling-crypto/.gitignore
vendored
3
sapling-crypto/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
/target/
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
@ -1,14 +0,0 @@
|
||||
Copyrights in the "sapling-crypto" library are retained by their contributors. No
|
||||
copyright assignment is required to contribute to the "sapling-crypto" library.
|
||||
|
||||
The "sapling-crypto" 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.
|
@ -1,27 +0,0 @@
|
||||
[package]
|
||||
authors = ["Sean Bowe <sean@z.cash>"]
|
||||
description = "Cryptographic library for Zcash Sapling"
|
||||
documentation = "https://github.com/zcash-hackworks/sapling"
|
||||
homepage = "https://github.com/zcash-hackworks/sapling"
|
||||
license = "MIT/Apache-2.0"
|
||||
name = "sapling-crypto"
|
||||
repository = "https://github.com/zcash-hackworks/sapling"
|
||||
version = "0.0.1"
|
||||
|
||||
[dependencies.pairing]
|
||||
path = "../pairing"
|
||||
features = ["expose-arith"]
|
||||
|
||||
[dependencies]
|
||||
bellman = { path = "../bellman" }
|
||||
rand = "0.4"
|
||||
digest = "0.7"
|
||||
byteorder = "1"
|
||||
|
||||
[dependencies.blake2-rfc]
|
||||
git = "https://github.com/gtank/blake2-rfc"
|
||||
rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
|
||||
|
||||
[dev-dependencies]
|
||||
hex-literal = "0.1"
|
||||
rust-crypto = "0.2"
|
@ -1,201 +0,0 @@
|
||||
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.
|
@ -1,23 +0,0 @@
|
||||
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.
|
@ -1,23 +0,0 @@
|
||||
# sapling-crypto
|
||||
|
||||
This repository contains a (work-in-progress) implementation of Zcash's "Sapling" cryptography.
|
||||
|
||||
## Security Warnings
|
||||
|
||||
This library is currently under development and has not been reviewed.
|
||||
|
||||
## 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.
|
@ -1,23 +0,0 @@
|
||||
#![feature(test)]
|
||||
|
||||
extern crate rand;
|
||||
extern crate test;
|
||||
extern crate pairing;
|
||||
extern crate sapling_crypto;
|
||||
|
||||
use rand::{Rand, thread_rng};
|
||||
use pairing::bls12_381::Bls12;
|
||||
use sapling_crypto::jubjub::JubjubBls12;
|
||||
use sapling_crypto::pedersen_hash::{pedersen_hash, Personalization};
|
||||
|
||||
#[bench]
|
||||
fn bench_pedersen_hash(b: &mut test::Bencher) {
|
||||
let params = JubjubBls12::new();
|
||||
let rng = &mut thread_rng();
|
||||
let bits = (0..510).map(|_| bool::rand(rng)).collect::<Vec<_>>();
|
||||
let personalization = Personalization::MerkleTree(31);
|
||||
|
||||
b.iter(|| {
|
||||
pedersen_hash::<Bls12, _>(personalization, bits.clone(), ¶ms)
|
||||
});
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
extern crate sapling_crypto;
|
||||
extern crate bellman;
|
||||
extern crate rand;
|
||||
extern crate pairing;
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
use sapling_crypto::jubjub::{
|
||||
JubjubBls12,
|
||||
edwards,
|
||||
fs,
|
||||
};
|
||||
use sapling_crypto::circuit::sapling::{
|
||||
Spend
|
||||
};
|
||||
use sapling_crypto::primitives::{
|
||||
Diversifier,
|
||||
ProofGenerationKey,
|
||||
ValueCommitment
|
||||
};
|
||||
use bellman::groth16::*;
|
||||
use rand::{XorShiftRng, SeedableRng, Rng};
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
|
||||
const TREE_DEPTH: usize = 32;
|
||||
|
||||
fn main() {
|
||||
let jubjub_params = &JubjubBls12::new();
|
||||
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
println!("Creating sample parameters...");
|
||||
let groth_params = generate_random_parameters::<Bls12, _, _>(
|
||||
Spend {
|
||||
params: jubjub_params,
|
||||
value_commitment: None,
|
||||
proof_generation_key: None,
|
||||
payment_address: None,
|
||||
commitment_randomness: None,
|
||||
ar: None,
|
||||
auth_path: vec![None; TREE_DEPTH],
|
||||
anchor: None
|
||||
},
|
||||
rng
|
||||
).unwrap();
|
||||
|
||||
const SAMPLES: u32 = 50;
|
||||
|
||||
let mut total_time = Duration::new(0, 0);
|
||||
for _ in 0..SAMPLES {
|
||||
let value_commitment = ValueCommitment {
|
||||
value: 1,
|
||||
randomness: rng.gen()
|
||||
};
|
||||
|
||||
let nsk: fs::Fs = rng.gen();
|
||||
let ak = edwards::Point::rand(rng, jubjub_params).mul_by_cofactor(jubjub_params);
|
||||
|
||||
let proof_generation_key = ProofGenerationKey {
|
||||
ak: ak.clone(),
|
||||
nsk: nsk.clone()
|
||||
};
|
||||
|
||||
let viewing_key = proof_generation_key.into_viewing_key(jubjub_params);
|
||||
|
||||
let payment_address;
|
||||
|
||||
loop {
|
||||
let diversifier = Diversifier(rng.gen());
|
||||
|
||||
if let Some(p) = viewing_key.into_payment_address(
|
||||
diversifier,
|
||||
jubjub_params
|
||||
)
|
||||
{
|
||||
payment_address = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let commitment_randomness: fs::Fs = rng.gen();
|
||||
let auth_path = vec![Some((rng.gen(), rng.gen())); TREE_DEPTH];
|
||||
let ar: fs::Fs = rng.gen();
|
||||
let anchor: Fr = rng.gen();
|
||||
|
||||
let start = Instant::now();
|
||||
let _ = create_random_proof(Spend {
|
||||
params: jubjub_params,
|
||||
value_commitment: Some(value_commitment),
|
||||
proof_generation_key: Some(proof_generation_key),
|
||||
payment_address: Some(payment_address),
|
||||
commitment_randomness: Some(commitment_randomness),
|
||||
ar: Some(ar),
|
||||
auth_path: auth_path,
|
||||
anchor: Some(anchor)
|
||||
}, &groth_params, rng).unwrap();
|
||||
total_time += start.elapsed();
|
||||
}
|
||||
let avg = total_time / SAMPLES;
|
||||
let avg = avg.subsec_nanos() as f64 / 1_000_000_000f64
|
||||
+ (avg.as_secs() as f64);
|
||||
|
||||
println!("Average proving time (in seconds): {}", avg);
|
||||
}
|
@ -1,438 +0,0 @@
|
||||
use pairing::{
|
||||
Engine,
|
||||
};
|
||||
|
||||
use bellman::{
|
||||
SynthesisError,
|
||||
ConstraintSystem
|
||||
};
|
||||
|
||||
use super::boolean::{
|
||||
Boolean
|
||||
};
|
||||
|
||||
use super::uint32::{
|
||||
UInt32
|
||||
};
|
||||
|
||||
use super::multieq::MultiEq;
|
||||
|
||||
/*
|
||||
2.1. Parameters
|
||||
The following table summarizes various parameters and their ranges:
|
||||
| BLAKE2b | BLAKE2s |
|
||||
--------------+------------------+------------------+
|
||||
Bits in word | w = 64 | w = 32 |
|
||||
Rounds in F | r = 12 | r = 10 |
|
||||
Block bytes | bb = 128 | bb = 64 |
|
||||
Hash bytes | 1 <= nn <= 64 | 1 <= nn <= 32 |
|
||||
Key bytes | 0 <= kk <= 64 | 0 <= kk <= 32 |
|
||||
Input bytes | 0 <= ll < 2**128 | 0 <= ll < 2**64 |
|
||||
--------------+------------------+------------------+
|
||||
G Rotation | (R1, R2, R3, R4) | (R1, R2, R3, R4) |
|
||||
constants = | (32, 24, 16, 63) | (16, 12, 8, 7) |
|
||||
--------------+------------------+------------------+
|
||||
*/
|
||||
|
||||
const R1: usize = 16;
|
||||
const R2: usize = 12;
|
||||
const R3: usize = 8;
|
||||
const R4: usize = 7;
|
||||
|
||||
/*
|
||||
Round | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
||||
----------+-------------------------------------------------+
|
||||
SIGMA[0] | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
||||
SIGMA[1] | 14 10 4 8 9 15 13 6 1 12 0 2 11 7 5 3 |
|
||||
SIGMA[2] | 11 8 12 0 5 2 15 13 10 14 3 6 7 1 9 4 |
|
||||
SIGMA[3] | 7 9 3 1 13 12 11 14 2 6 5 10 4 0 15 8 |
|
||||
SIGMA[4] | 9 0 5 7 2 4 10 15 14 1 11 12 6 8 3 13 |
|
||||
SIGMA[5] | 2 12 6 10 0 11 8 3 4 13 7 5 15 14 1 9 |
|
||||
SIGMA[6] | 12 5 1 15 14 13 4 10 0 7 6 3 9 2 8 11 |
|
||||
SIGMA[7] | 13 11 7 14 12 1 3 9 5 0 15 4 8 6 2 10 |
|
||||
SIGMA[8] | 6 15 14 9 11 3 0 8 12 2 13 7 1 4 10 5 |
|
||||
SIGMA[9] | 10 2 8 4 7 6 1 5 15 11 9 14 3 12 13 0 |
|
||||
----------+-------------------------------------------------+
|
||||
*/
|
||||
|
||||
const SIGMA: [[usize; 16]; 10] = [
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
||||
[14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
|
||||
[11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
|
||||
[7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
|
||||
[9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
|
||||
[2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
|
||||
[12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
|
||||
[13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
|
||||
[6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
|
||||
[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0]
|
||||
];
|
||||
|
||||
/*
|
||||
3.1. Mixing Function G
|
||||
The G primitive function mixes two input words, "x" and "y", into
|
||||
four words indexed by "a", "b", "c", and "d" in the working vector
|
||||
v[0..15]. The full modified vector is returned. The rotation
|
||||
constants (R1, R2, R3, R4) are given in Section 2.1.
|
||||
FUNCTION G( v[0..15], a, b, c, d, x, y )
|
||||
|
|
||||
| v[a] := (v[a] + v[b] + x) mod 2**w
|
||||
| v[d] := (v[d] ^ v[a]) >>> R1
|
||||
| v[c] := (v[c] + v[d]) mod 2**w
|
||||
| v[b] := (v[b] ^ v[c]) >>> R2
|
||||
| v[a] := (v[a] + v[b] + y) mod 2**w
|
||||
| v[d] := (v[d] ^ v[a]) >>> R3
|
||||
| v[c] := (v[c] + v[d]) mod 2**w
|
||||
| v[b] := (v[b] ^ v[c]) >>> R4
|
||||
|
|
||||
| RETURN v[0..15]
|
||||
|
|
||||
END FUNCTION.
|
||||
*/
|
||||
|
||||
fn mixing_g<E: Engine, CS: ConstraintSystem<E>, M>(
|
||||
mut cs: M,
|
||||
v: &mut [UInt32],
|
||||
a: usize,
|
||||
b: usize,
|
||||
c: usize,
|
||||
d: usize,
|
||||
x: &UInt32,
|
||||
y: &UInt32
|
||||
) -> Result<(), SynthesisError>
|
||||
where M: ConstraintSystem<E, Root=MultiEq<E, CS>>
|
||||
{
|
||||
v[a] = UInt32::addmany(cs.namespace(|| "mixing step 1"), &[v[a].clone(), v[b].clone(), x.clone()])?;
|
||||
v[d] = v[d].xor(cs.namespace(|| "mixing step 2"), &v[a])?.rotr(R1);
|
||||
v[c] = UInt32::addmany(cs.namespace(|| "mixing step 3"), &[v[c].clone(), v[d].clone()])?;
|
||||
v[b] = v[b].xor(cs.namespace(|| "mixing step 4"), &v[c])?.rotr(R2);
|
||||
v[a] = UInt32::addmany(cs.namespace(|| "mixing step 5"), &[v[a].clone(), v[b].clone(), y.clone()])?;
|
||||
v[d] = v[d].xor(cs.namespace(|| "mixing step 6"), &v[a])?.rotr(R3);
|
||||
v[c] = UInt32::addmany(cs.namespace(|| "mixing step 7"), &[v[c].clone(), v[d].clone()])?;
|
||||
v[b] = v[b].xor(cs.namespace(|| "mixing step 8"), &v[c])?.rotr(R4);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/*
|
||||
3.2. Compression Function F
|
||||
Compression function F takes as an argument the state vector "h",
|
||||
message block vector "m" (last block is padded with zeros to full
|
||||
block size, if required), 2w-bit offset counter "t", and final block
|
||||
indicator flag "f". Local vector v[0..15] is used in processing. F
|
||||
returns a new state vector. The number of rounds, "r", is 12 for
|
||||
BLAKE2b and 10 for BLAKE2s. Rounds are numbered from 0 to r - 1.
|
||||
FUNCTION F( h[0..7], m[0..15], t, f )
|
||||
|
|
||||
| // Initialize local work vector v[0..15]
|
||||
| v[0..7] := h[0..7] // First half from state.
|
||||
| v[8..15] := IV[0..7] // Second half from IV.
|
||||
|
|
||||
| v[12] := v[12] ^ (t mod 2**w) // Low word of the offset.
|
||||
| v[13] := v[13] ^ (t >> w) // High word.
|
||||
|
|
||||
| IF f = TRUE THEN // last block flag?
|
||||
| | v[14] := v[14] ^ 0xFF..FF // Invert all bits.
|
||||
| END IF.
|
||||
|
|
||||
| // Cryptographic mixing
|
||||
| FOR i = 0 TO r - 1 DO // Ten or twelve rounds.
|
||||
| |
|
||||
| | // Message word selection permutation for this round.
|
||||
| | s[0..15] := SIGMA[i mod 10][0..15]
|
||||
| |
|
||||
| | v := G( v, 0, 4, 8, 12, m[s[ 0]], m[s[ 1]] )
|
||||
| | v := G( v, 1, 5, 9, 13, m[s[ 2]], m[s[ 3]] )
|
||||
| | v := G( v, 2, 6, 10, 14, m[s[ 4]], m[s[ 5]] )
|
||||
| | v := G( v, 3, 7, 11, 15, m[s[ 6]], m[s[ 7]] )
|
||||
| |
|
||||
| | v := G( v, 0, 5, 10, 15, m[s[ 8]], m[s[ 9]] )
|
||||
| | v := G( v, 1, 6, 11, 12, m[s[10]], m[s[11]] )
|
||||
| | v := G( v, 2, 7, 8, 13, m[s[12]], m[s[13]] )
|
||||
| | v := G( v, 3, 4, 9, 14, m[s[14]], m[s[15]] )
|
||||
| |
|
||||
| END FOR
|
||||
|
|
||||
| FOR i = 0 TO 7 DO // XOR the two halves.
|
||||
| | h[i] := h[i] ^ v[i] ^ v[i + 8]
|
||||
| END FOR.
|
||||
|
|
||||
| RETURN h[0..7] // New state.
|
||||
|
|
||||
END FUNCTION.
|
||||
*/
|
||||
|
||||
|
||||
fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>(
|
||||
mut cs: CS,
|
||||
h: &mut [UInt32],
|
||||
m: &[UInt32],
|
||||
t: u64,
|
||||
f: bool
|
||||
) -> Result<(), SynthesisError>
|
||||
{
|
||||
assert_eq!(h.len(), 8);
|
||||
assert_eq!(m.len(), 16);
|
||||
|
||||
/*
|
||||
static const uint32_t blake2s_iv[8] =
|
||||
{
|
||||
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
|
||||
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
|
||||
};
|
||||
*/
|
||||
|
||||
let mut v = Vec::with_capacity(16);
|
||||
v.extend_from_slice(h);
|
||||
v.push(UInt32::constant(0x6A09E667));
|
||||
v.push(UInt32::constant(0xBB67AE85));
|
||||
v.push(UInt32::constant(0x3C6EF372));
|
||||
v.push(UInt32::constant(0xA54FF53A));
|
||||
v.push(UInt32::constant(0x510E527F));
|
||||
v.push(UInt32::constant(0x9B05688C));
|
||||
v.push(UInt32::constant(0x1F83D9AB));
|
||||
v.push(UInt32::constant(0x5BE0CD19));
|
||||
|
||||
assert_eq!(v.len(), 16);
|
||||
|
||||
v[12] = v[12].xor(cs.namespace(|| "first xor"), &UInt32::constant(t as u32))?;
|
||||
v[13] = v[13].xor(cs.namespace(|| "second xor"), &UInt32::constant((t >> 32) as u32))?;
|
||||
|
||||
if f {
|
||||
v[14] = v[14].xor(cs.namespace(|| "third xor"), &UInt32::constant(u32::max_value()))?;
|
||||
}
|
||||
|
||||
{
|
||||
let mut cs = MultiEq::new(&mut cs);
|
||||
|
||||
for i in 0..10 {
|
||||
let mut cs = cs.namespace(|| format!("round {}", i));
|
||||
|
||||
let s = SIGMA[i % 10];
|
||||
|
||||
mixing_g(cs.namespace(|| "mixing invocation 1"), &mut v, 0, 4, 8, 12, &m[s[ 0]], &m[s[ 1]])?;
|
||||
mixing_g(cs.namespace(|| "mixing invocation 2"), &mut v, 1, 5, 9, 13, &m[s[ 2]], &m[s[ 3]])?;
|
||||
mixing_g(cs.namespace(|| "mixing invocation 3"), &mut v, 2, 6, 10, 14, &m[s[ 4]], &m[s[ 5]])?;
|
||||
mixing_g(cs.namespace(|| "mixing invocation 4"), &mut v, 3, 7, 11, 15, &m[s[ 6]], &m[s[ 7]])?;
|
||||
|
||||
mixing_g(cs.namespace(|| "mixing invocation 5"), &mut v, 0, 5, 10, 15, &m[s[ 8]], &m[s[ 9]])?;
|
||||
mixing_g(cs.namespace(|| "mixing invocation 6"), &mut v, 1, 6, 11, 12, &m[s[10]], &m[s[11]])?;
|
||||
mixing_g(cs.namespace(|| "mixing invocation 7"), &mut v, 2, 7, 8, 13, &m[s[12]], &m[s[13]])?;
|
||||
mixing_g(cs.namespace(|| "mixing invocation 8"), &mut v, 3, 4, 9, 14, &m[s[14]], &m[s[15]])?;
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0..8 {
|
||||
let mut cs = cs.namespace(|| format!("h[{i}] ^ v[{i}] ^ v[{i} + 8]", i=i));
|
||||
|
||||
h[i] = h[i].xor(cs.namespace(|| "first xor"), &v[i])?;
|
||||
h[i] = h[i].xor(cs.namespace(|| "second xor"), &v[i + 8])?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION BLAKE2( d[0..dd-1], ll, kk, nn )
|
||||
|
|
||||
| h[0..7] := IV[0..7] // Initialization Vector.
|
||||
|
|
||||
| // Parameter block p[0]
|
||||
| h[0] := h[0] ^ 0x01010000 ^ (kk << 8) ^ nn
|
||||
|
|
||||
| // Process padded key and data blocks
|
||||
| IF dd > 1 THEN
|
||||
| | FOR i = 0 TO dd - 2 DO
|
||||
| | | h := F( h, d[i], (i + 1) * bb, FALSE )
|
||||
| | END FOR.
|
||||
| END IF.
|
||||
|
|
||||
| // Final block.
|
||||
| IF kk = 0 THEN
|
||||
| | h := F( h, d[dd - 1], ll, TRUE )
|
||||
| ELSE
|
||||
| | h := F( h, d[dd - 1], ll + bb, TRUE )
|
||||
| END IF.
|
||||
|
|
||||
| RETURN first "nn" bytes from little-endian word array h[].
|
||||
|
|
||||
END FUNCTION.
|
||||
*/
|
||||
|
||||
pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
|
||||
mut cs: CS,
|
||||
input: &[Boolean],
|
||||
personalization: &[u8]
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
{
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
assert_eq!(personalization.len(), 8);
|
||||
assert!(input.len() % 8 == 0);
|
||||
|
||||
let mut h = Vec::with_capacity(8);
|
||||
h.push(UInt32::constant(0x6A09E667 ^ 0x01010000 ^ 32));
|
||||
h.push(UInt32::constant(0xBB67AE85));
|
||||
h.push(UInt32::constant(0x3C6EF372));
|
||||
h.push(UInt32::constant(0xA54FF53A));
|
||||
h.push(UInt32::constant(0x510E527F));
|
||||
h.push(UInt32::constant(0x9B05688C));
|
||||
|
||||
// Personalization is stored here
|
||||
h.push(UInt32::constant(0x1F83D9AB ^ LittleEndian::read_u32(&personalization[0..4])));
|
||||
h.push(UInt32::constant(0x5BE0CD19 ^ LittleEndian::read_u32(&personalization[4..8])));
|
||||
|
||||
let mut blocks: Vec<Vec<UInt32>> = vec![];
|
||||
|
||||
for block in input.chunks(512) {
|
||||
let mut this_block = Vec::with_capacity(16);
|
||||
for word in block.chunks(32) {
|
||||
let mut tmp = word.to_vec();
|
||||
while tmp.len() < 32 {
|
||||
tmp.push(Boolean::constant(false));
|
||||
}
|
||||
this_block.push(UInt32::from_bits(&tmp));
|
||||
}
|
||||
while this_block.len() < 16 {
|
||||
this_block.push(UInt32::constant(0));
|
||||
}
|
||||
blocks.push(this_block);
|
||||
}
|
||||
|
||||
if blocks.len() == 0 {
|
||||
blocks.push((0..16).map(|_| UInt32::constant(0)).collect());
|
||||
}
|
||||
|
||||
for (i, block) in blocks[0..blocks.len() - 1].iter().enumerate() {
|
||||
let cs = cs.namespace(|| format!("block {}", i));
|
||||
|
||||
blake2s_compression(cs, &mut h, block, ((i as u64) + 1) * 64, false)?;
|
||||
}
|
||||
|
||||
{
|
||||
let cs = cs.namespace(|| "final block");
|
||||
|
||||
blake2s_compression(cs, &mut h, &blocks[blocks.len() - 1], (input.len() / 8) as u64, true)?;
|
||||
}
|
||||
|
||||
Ok(h.iter().flat_map(|b| b.into_bits()).collect())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use rand::{XorShiftRng, SeedableRng, Rng};
|
||||
use pairing::bls12_381::{Bls12};
|
||||
use ::circuit::boolean::{Boolean, AllocatedBit};
|
||||
use ::circuit::test::TestConstraintSystem;
|
||||
use super::blake2s;
|
||||
use bellman::{ConstraintSystem};
|
||||
use blake2_rfc::blake2s::Blake2s;
|
||||
|
||||
#[test]
|
||||
fn test_blank_hash() {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
let input_bits = vec![];
|
||||
let out = blake2s(&mut cs, &input_bits, b"12345678").unwrap();
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 0);
|
||||
|
||||
// >>> import blake2s from hashlib
|
||||
// >>> h = blake2s(digest_size=32, person=b'12345678')
|
||||
// >>> h.hexdigest()
|
||||
let expected = hex!("c59f682376d137f3f255e671e207d1f2374ebe504e9314208a52d9f88d69e8c8");
|
||||
|
||||
let mut out = out.into_iter();
|
||||
for b in expected.into_iter() {
|
||||
for i in 0..8 {
|
||||
let c = out.next().unwrap().get_value().unwrap();
|
||||
|
||||
assert_eq!(c, (b >> i) & 1u8 == 1u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2s_constraints() {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
let input_bits: Vec<_> = (0..512).map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into()).collect();
|
||||
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 21518);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2s_precomp_constraints() {
|
||||
// Test that 512 fixed leading bits (constants)
|
||||
// doesn't result in more constraints.
|
||||
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
let input_bits: Vec<_> = (0..512)
|
||||
.map(|_| Boolean::constant(rng.gen()))
|
||||
.chain((0..512)
|
||||
.map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into()))
|
||||
.collect();
|
||||
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 21518);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2s_constant_constraints() {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
let input_bits: Vec<_> = (0..512).map(|_| Boolean::constant(rng.gen())).collect();
|
||||
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
|
||||
assert_eq!(cs.num_constraints(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2s() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0))
|
||||
{
|
||||
let mut h = Blake2s::with_params(32, &[], &[], b"12345678");
|
||||
|
||||
let data: Vec<u8> = (0..input_len).map(|_| rng.gen()).collect();
|
||||
|
||||
h.update(&data);
|
||||
|
||||
let hash_result = h.finalize();
|
||||
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let mut input_bits = vec![];
|
||||
|
||||
for (byte_i, input_byte) in data.into_iter().enumerate() {
|
||||
for bit_i in 0..8 {
|
||||
let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i));
|
||||
|
||||
input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into());
|
||||
}
|
||||
}
|
||||
|
||||
let r = blake2s(&mut cs, &input_bits, b"12345678").unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
let mut s = hash_result.as_ref().iter()
|
||||
.flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8));
|
||||
|
||||
for b in r {
|
||||
match b {
|
||||
Boolean::Is(b) => {
|
||||
assert!(s.next().unwrap() == b.get_value().unwrap());
|
||||
},
|
||||
Boolean::Not(b) => {
|
||||
assert!(s.next().unwrap() != b.get_value().unwrap());
|
||||
},
|
||||
Boolean::Constant(b) => {
|
||||
assert!(input_len == 0);
|
||||
assert!(s.next().unwrap() == b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,113 +0,0 @@
|
||||
use pairing::{Engine, Field, PrimeField};
|
||||
use bellman::{ConstraintSystem, SynthesisError};
|
||||
use super::boolean::{Boolean};
|
||||
use super::num::Num;
|
||||
use super::Assignment;
|
||||
|
||||
/// Takes a sequence of booleans and exposes them as compact
|
||||
/// public inputs
|
||||
pub fn pack_into_inputs<E, CS>(
|
||||
mut cs: CS,
|
||||
bits: &[Boolean]
|
||||
) -> Result<(), SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>
|
||||
{
|
||||
for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate()
|
||||
{
|
||||
let mut num = Num::<E>::zero();
|
||||
let mut coeff = E::Fr::one();
|
||||
for bit in bits {
|
||||
num = num.add_bool_with_coeff(CS::one(), bit, coeff);
|
||||
|
||||
coeff.double();
|
||||
}
|
||||
|
||||
let input = cs.alloc_input(|| format!("input {}", i), || {
|
||||
Ok(*num.get_value().get()?)
|
||||
})?;
|
||||
|
||||
// num * 1 = input
|
||||
cs.enforce(
|
||||
|| format!("packing constraint {}", i),
|
||||
|_| num.lc(E::Fr::one()),
|
||||
|lc| lc + CS::one(),
|
||||
|lc| lc + input
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn bytes_to_bits(bytes: &[u8]) -> Vec<bool>
|
||||
{
|
||||
bytes.iter()
|
||||
.flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec<bool>
|
||||
{
|
||||
bytes.iter()
|
||||
.flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn compute_multipacking<E: Engine>(
|
||||
bits: &[bool]
|
||||
) -> Vec<E::Fr>
|
||||
{
|
||||
let mut result = vec![];
|
||||
|
||||
for bits in bits.chunks(E::Fr::CAPACITY as usize)
|
||||
{
|
||||
let mut cur = E::Fr::zero();
|
||||
let mut coeff = E::Fr::one();
|
||||
|
||||
for bit in bits {
|
||||
if *bit {
|
||||
cur.add_assign(&coeff);
|
||||
}
|
||||
|
||||
coeff.double();
|
||||
}
|
||||
|
||||
result.push(cur);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multipacking() {
|
||||
use rand::{SeedableRng, Rng, XorShiftRng};
|
||||
use bellman::{ConstraintSystem};
|
||||
use pairing::bls12_381::{Bls12};
|
||||
use ::circuit::test::*;
|
||||
use super::boolean::{AllocatedBit, Boolean};
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for num_bits in 0..1500 {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let bits: Vec<bool> = (0..num_bits).map(|_| rng.gen()).collect();
|
||||
|
||||
let circuit_bits = bits.iter().enumerate()
|
||||
.map(|(i, &b)| {
|
||||
Boolean::from(
|
||||
AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("bit {}", i)),
|
||||
Some(b)
|
||||
).unwrap()
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let expected_inputs = compute_multipacking::<Bls12>(&bits);
|
||||
|
||||
pack_into_inputs(cs.namespace(|| "pack"), &circuit_bits).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
assert!(cs.verify(&expected_inputs));
|
||||
}
|
||||
}
|
@ -1,194 +0,0 @@
|
||||
use super::*;
|
||||
use super::ecc::{
|
||||
MontgomeryPoint,
|
||||
EdwardsPoint
|
||||
};
|
||||
use super::boolean::Boolean;
|
||||
use ::jubjub::*;
|
||||
use bellman::{
|
||||
ConstraintSystem
|
||||
};
|
||||
use super::lookup::*;
|
||||
pub use pedersen_hash::Personalization;
|
||||
|
||||
impl Personalization {
|
||||
fn get_constant_bools(&self) -> Vec<Boolean> {
|
||||
self.get_bits()
|
||||
.into_iter()
|
||||
.map(|e| Boolean::constant(e))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pedersen_hash<E: JubjubEngine, CS>(
|
||||
mut cs: CS,
|
||||
personalization: Personalization,
|
||||
bits: &[Boolean],
|
||||
params: &E::Params
|
||||
) -> Result<EdwardsPoint<E>, SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
{
|
||||
let personalization = personalization.get_constant_bools();
|
||||
assert_eq!(personalization.len(), 6);
|
||||
|
||||
let mut edwards_result = None;
|
||||
let mut bits = personalization.iter().chain(bits.iter());
|
||||
let mut segment_generators = params.pedersen_circuit_generators().iter();
|
||||
let boolean_false = Boolean::constant(false);
|
||||
|
||||
let mut segment_i = 0;
|
||||
loop {
|
||||
let mut segment_result = None;
|
||||
let mut segment_windows = &segment_generators.next()
|
||||
.expect("enough segments")[..];
|
||||
|
||||
let mut window_i = 0;
|
||||
while let Some(a) = bits.next() {
|
||||
let b = bits.next().unwrap_or(&boolean_false);
|
||||
let c = bits.next().unwrap_or(&boolean_false);
|
||||
|
||||
let tmp = lookup3_xy_with_conditional_negation(
|
||||
cs.namespace(|| format!("segment {}, window {}", segment_i, window_i)),
|
||||
&[a.clone(), b.clone(), c.clone()],
|
||||
&segment_windows[0]
|
||||
)?;
|
||||
|
||||
let tmp = MontgomeryPoint::interpret_unchecked(tmp.0, tmp.1);
|
||||
|
||||
match segment_result {
|
||||
None => {
|
||||
segment_result = Some(tmp);
|
||||
},
|
||||
Some(ref mut segment_result) => {
|
||||
*segment_result = tmp.add(
|
||||
cs.namespace(|| format!("addition of segment {}, window {}", segment_i, window_i)),
|
||||
segment_result,
|
||||
params
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
segment_windows = &segment_windows[1..];
|
||||
|
||||
if segment_windows.len() == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
window_i += 1;
|
||||
}
|
||||
|
||||
match segment_result {
|
||||
Some(segment_result) => {
|
||||
// Convert this segment into twisted Edwards form.
|
||||
let segment_result = segment_result.into_edwards(
|
||||
cs.namespace(|| format!("conversion of segment {} into edwards", segment_i)),
|
||||
params
|
||||
)?;
|
||||
|
||||
match edwards_result {
|
||||
Some(ref mut edwards_result) => {
|
||||
*edwards_result = segment_result.add(
|
||||
cs.namespace(|| format!("addition of segment {} to accumulator", segment_i)),
|
||||
edwards_result,
|
||||
params
|
||||
)?;
|
||||
},
|
||||
None => {
|
||||
edwards_result = Some(segment_result);
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {
|
||||
// We didn't process any new bits.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
segment_i += 1;
|
||||
}
|
||||
|
||||
Ok(edwards_result.unwrap())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use rand::{SeedableRng, Rng, XorShiftRng};
|
||||
use super::*;
|
||||
use ::circuit::test::*;
|
||||
use ::circuit::boolean::{Boolean, AllocatedBit};
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
use pairing::PrimeField;
|
||||
|
||||
#[test]
|
||||
fn test_pedersen_hash_constraints() {
|
||||
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
let params = &JubjubBls12::new();
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let input: Vec<bool> = (0..(Fr::NUM_BITS * 2)).map(|_| rng.gen()).collect();
|
||||
|
||||
let input_bools: Vec<Boolean> = input.iter().enumerate().map(|(i, b)| {
|
||||
Boolean::from(
|
||||
AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap()
|
||||
)
|
||||
}).collect();
|
||||
|
||||
pedersen_hash(
|
||||
cs.namespace(|| "pedersen hash"),
|
||||
Personalization::NoteCommitment,
|
||||
&input_bools,
|
||||
params
|
||||
).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 1377);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pedersen_hash() {
|
||||
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
let params = &JubjubBls12::new();
|
||||
|
||||
for length in 0..751 {
|
||||
for _ in 0..5 {
|
||||
let mut input: Vec<bool> = (0..length).map(|_| rng.gen()).collect();
|
||||
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let input_bools: Vec<Boolean> = input.iter().enumerate().map(|(i, b)| {
|
||||
Boolean::from(
|
||||
AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap()
|
||||
)
|
||||
}).collect();
|
||||
|
||||
let res = pedersen_hash(
|
||||
cs.namespace(|| "pedersen hash"),
|
||||
Personalization::MerkleTree(1),
|
||||
&input_bools,
|
||||
params
|
||||
).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
let expected = ::pedersen_hash::pedersen_hash::<Bls12, _>(
|
||||
Personalization::MerkleTree(1),
|
||||
input.clone().into_iter(),
|
||||
params
|
||||
).into_xy();
|
||||
|
||||
assert_eq!(res.get_x().get_value().unwrap(), expected.0);
|
||||
assert_eq!(res.get_y().get_value().unwrap(), expected.1);
|
||||
|
||||
// Test against the output of a different personalization
|
||||
let unexpected = ::pedersen_hash::pedersen_hash::<Bls12, _>(
|
||||
Personalization::MerkleTree(0),
|
||||
input.into_iter(),
|
||||
params
|
||||
).into_xy();
|
||||
|
||||
assert!(res.get_x().get_value().unwrap() != unexpected.0);
|
||||
assert!(res.get_y().get_value().unwrap() != unexpected.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,817 +0,0 @@
|
||||
use pairing::{
|
||||
PrimeField,
|
||||
PrimeFieldRepr,
|
||||
Field,
|
||||
};
|
||||
|
||||
use bellman::{
|
||||
SynthesisError,
|
||||
ConstraintSystem,
|
||||
Circuit
|
||||
};
|
||||
|
||||
use jubjub::{
|
||||
JubjubEngine,
|
||||
FixedGenerators
|
||||
};
|
||||
|
||||
use constants;
|
||||
|
||||
use primitives::{
|
||||
ValueCommitment,
|
||||
ProofGenerationKey,
|
||||
PaymentAddress
|
||||
};
|
||||
|
||||
use super::Assignment;
|
||||
use super::boolean;
|
||||
use super::ecc;
|
||||
use super::pedersen_hash;
|
||||
use super::blake2s;
|
||||
use super::num;
|
||||
use super::multipack;
|
||||
|
||||
pub const TREE_DEPTH: usize = 32;
|
||||
|
||||
/// This is an instance of the `Spend` circuit.
|
||||
pub struct Spend<'a, E: JubjubEngine> {
|
||||
pub params: &'a E::Params,
|
||||
|
||||
/// Pedersen commitment to the value being spent
|
||||
pub value_commitment: Option<ValueCommitment<E>>,
|
||||
|
||||
/// Key required to construct proofs for spending notes
|
||||
/// for a particular spending key
|
||||
pub proof_generation_key: Option<ProofGenerationKey<E>>,
|
||||
|
||||
/// The payment address associated with the note
|
||||
pub payment_address: Option<PaymentAddress<E>>,
|
||||
|
||||
/// The randomness of the note commitment
|
||||
pub commitment_randomness: Option<E::Fs>,
|
||||
|
||||
/// Re-randomization of the public key
|
||||
pub ar: Option<E::Fs>,
|
||||
|
||||
/// The authentication path of the commitment in the tree
|
||||
pub auth_path: Vec<Option<(E::Fr, bool)>>,
|
||||
|
||||
/// The anchor; the root of the tree. If the note being
|
||||
/// spent is zero-value, this can be anything.
|
||||
pub anchor: Option<E::Fr>
|
||||
}
|
||||
|
||||
/// This is an output circuit instance.
|
||||
pub struct Output<'a, E: JubjubEngine> {
|
||||
pub params: &'a E::Params,
|
||||
|
||||
/// Pedersen commitment to the value being spent
|
||||
pub value_commitment: Option<ValueCommitment<E>>,
|
||||
|
||||
/// The payment address of the recipient
|
||||
pub payment_address: Option<PaymentAddress<E>>,
|
||||
|
||||
/// The randomness used to hide the note commitment data
|
||||
pub commitment_randomness: Option<E::Fs>,
|
||||
|
||||
/// The ephemeral secret key for DH with recipient
|
||||
pub esk: Option<E::Fs>
|
||||
}
|
||||
|
||||
/// Exposes a Pedersen commitment to the value as an
|
||||
/// input to the circuit
|
||||
fn expose_value_commitment<E, CS>(
|
||||
mut cs: CS,
|
||||
value_commitment: Option<ValueCommitment<E>>,
|
||||
params: &E::Params
|
||||
) -> Result<Vec<boolean::Boolean>, SynthesisError>
|
||||
where E: JubjubEngine,
|
||||
CS: ConstraintSystem<E>
|
||||
{
|
||||
// Booleanize the value into little-endian bit order
|
||||
let value_bits = boolean::u64_into_boolean_vec_le(
|
||||
cs.namespace(|| "value"),
|
||||
value_commitment.as_ref().map(|c| c.value)
|
||||
)?;
|
||||
|
||||
// Compute the note value in the exponent
|
||||
let value = ecc::fixed_base_multiplication(
|
||||
cs.namespace(|| "compute the value in the exponent"),
|
||||
FixedGenerators::ValueCommitmentValue,
|
||||
&value_bits,
|
||||
params
|
||||
)?;
|
||||
|
||||
// Booleanize the randomness. This does not ensure
|
||||
// the bit representation is "in the field" because
|
||||
// it doesn't matter for security.
|
||||
let rcv = boolean::field_into_boolean_vec_le(
|
||||
cs.namespace(|| "rcv"),
|
||||
value_commitment.as_ref().map(|c| c.randomness)
|
||||
)?;
|
||||
|
||||
// Compute the randomness in the exponent
|
||||
let rcv = ecc::fixed_base_multiplication(
|
||||
cs.namespace(|| "computation of rcv"),
|
||||
FixedGenerators::ValueCommitmentRandomness,
|
||||
&rcv,
|
||||
params
|
||||
)?;
|
||||
|
||||
// Compute the Pedersen commitment to the value
|
||||
let cv = value.add(
|
||||
cs.namespace(|| "computation of cv"),
|
||||
&rcv,
|
||||
params
|
||||
)?;
|
||||
|
||||
// Expose the commitment as an input to the circuit
|
||||
cv.inputize(cs.namespace(|| "commitment point"))?;
|
||||
|
||||
Ok(value_bits)
|
||||
}
|
||||
|
||||
impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
|
||||
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError>
|
||||
{
|
||||
// Prover witnesses ak (ensures that it's on the curve)
|
||||
let ak = ecc::EdwardsPoint::witness(
|
||||
cs.namespace(|| "ak"),
|
||||
self.proof_generation_key.as_ref().map(|k| k.ak.clone()),
|
||||
self.params
|
||||
)?;
|
||||
|
||||
// There are no sensible attacks on small order points
|
||||
// of ak (that we're aware of!) but it's a cheap check,
|
||||
// so we do it.
|
||||
ak.assert_not_small_order(
|
||||
cs.namespace(|| "ak not small order"),
|
||||
self.params
|
||||
)?;
|
||||
|
||||
// Rerandomize ak and expose it as an input to the circuit
|
||||
{
|
||||
let ar = boolean::field_into_boolean_vec_le(
|
||||
cs.namespace(|| "ar"),
|
||||
self.ar
|
||||
)?;
|
||||
|
||||
// Compute the randomness in the exponent
|
||||
let ar = ecc::fixed_base_multiplication(
|
||||
cs.namespace(|| "computation of randomization for the signing key"),
|
||||
FixedGenerators::SpendingKeyGenerator,
|
||||
&ar,
|
||||
self.params
|
||||
)?;
|
||||
|
||||
let rk = ak.add(
|
||||
cs.namespace(|| "computation of rk"),
|
||||
&ar,
|
||||
self.params
|
||||
)?;
|
||||
|
||||
rk.inputize(cs.namespace(|| "rk"))?;
|
||||
}
|
||||
|
||||
// Compute nk = [nsk] ProofGenerationKey
|
||||
let nk;
|
||||
{
|
||||
// Witness nsk as bits
|
||||
let nsk = boolean::field_into_boolean_vec_le(
|
||||
cs.namespace(|| "nsk"),
|
||||
self.proof_generation_key.as_ref().map(|k| k.nsk.clone())
|
||||
)?;
|
||||
|
||||
// NB: We don't ensure that the bit representation of nsk
|
||||
// is "in the field" (Fs) because it's not used except to
|
||||
// demonstrate the prover knows it. If they know a
|
||||
// congruency then that's equivalent.
|
||||
|
||||
// Compute nk = [nsk] ProvingPublicKey
|
||||
nk = ecc::fixed_base_multiplication(
|
||||
cs.namespace(|| "computation of nk"),
|
||||
FixedGenerators::ProofGenerationKey,
|
||||
&nsk,
|
||||
self.params
|
||||
)?;
|
||||
}
|
||||
|
||||
// This is the "viewing key" preimage for CRH^ivk
|
||||
let mut ivk_preimage = vec![];
|
||||
|
||||
// Place ak in the preimage for CRH^ivk
|
||||
ivk_preimage.extend(
|
||||
ak.repr(cs.namespace(|| "representation of ak"))?
|
||||
);
|
||||
|
||||
// This is the nullifier preimage for PRF^nf
|
||||
let mut nf_preimage = vec![];
|
||||
|
||||
// Extend ivk and nf preimages with the representation of
|
||||
// nk.
|
||||
{
|
||||
let repr_nk = nk.repr(
|
||||
cs.namespace(|| "representation of nk")
|
||||
)?;
|
||||
|
||||
ivk_preimage.extend(repr_nk.iter().cloned());
|
||||
nf_preimage.extend(repr_nk);
|
||||
}
|
||||
|
||||
assert_eq!(ivk_preimage.len(), 512);
|
||||
assert_eq!(nf_preimage.len(), 256);
|
||||
|
||||
// Compute the incoming viewing key ivk
|
||||
let mut ivk = blake2s::blake2s(
|
||||
cs.namespace(|| "computation of ivk"),
|
||||
&ivk_preimage,
|
||||
constants::CRH_IVK_PERSONALIZATION
|
||||
)?;
|
||||
|
||||
// drop_5 to ensure it's in the field
|
||||
ivk.truncate(E::Fs::CAPACITY as usize);
|
||||
|
||||
// Witness g_d, checking that it's on the curve.
|
||||
let g_d = {
|
||||
// This binding is to avoid a weird edge case in Rust's
|
||||
// ownership/borrowing rules. self is partially moved
|
||||
// above, but the closure for and_then will have to
|
||||
// move self (or a reference to self) to reference
|
||||
// self.params, so we have to copy self.params here.
|
||||
let params = self.params;
|
||||
|
||||
ecc::EdwardsPoint::witness(
|
||||
cs.namespace(|| "witness g_d"),
|
||||
self.payment_address.as_ref().and_then(|a| a.g_d(params)),
|
||||
self.params
|
||||
)?
|
||||
};
|
||||
|
||||
// Check that g_d is not small order. Technically, this check
|
||||
// is already done in the Output circuit, and this proof ensures
|
||||
// g_d is bound to a product of that check, but for defense in
|
||||
// depth let's check it anyway. It's cheap.
|
||||
g_d.assert_not_small_order(
|
||||
cs.namespace(|| "g_d not small order"),
|
||||
self.params
|
||||
)?;
|
||||
|
||||
// Compute pk_d = g_d^ivk
|
||||
let pk_d = g_d.mul(
|
||||
cs.namespace(|| "compute pk_d"),
|
||||
&ivk,
|
||||
self.params
|
||||
)?;
|
||||
|
||||
// Compute note contents:
|
||||
// value (in big endian) followed by g_d and pk_d
|
||||
let mut note_contents = vec![];
|
||||
|
||||
// Handle the value; we'll need it later for the
|
||||
// dummy input check.
|
||||
let mut value_num = num::Num::zero();
|
||||
{
|
||||
// Get the value in little-endian bit order
|
||||
let value_bits = expose_value_commitment(
|
||||
cs.namespace(|| "value commitment"),
|
||||
self.value_commitment,
|
||||
self.params
|
||||
)?;
|
||||
|
||||
// Compute the note's value as a linear combination
|
||||
// of the bits.
|
||||
let mut coeff = E::Fr::one();
|
||||
for bit in &value_bits {
|
||||
value_num = value_num.add_bool_with_coeff(
|
||||
CS::one(),
|
||||
bit,
|
||||
coeff
|
||||
);
|
||||
coeff.double();
|
||||
}
|
||||
|
||||
// Place the value in the note
|
||||
note_contents.extend(value_bits);
|
||||
}
|
||||
|
||||
// Place g_d in the note
|
||||
note_contents.extend(
|
||||
g_d.repr(cs.namespace(|| "representation of g_d"))?
|
||||
);
|
||||
|
||||
// Place pk_d in the note
|
||||
note_contents.extend(
|
||||
pk_d.repr(cs.namespace(|| "representation of pk_d"))?
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
note_contents.len(),
|
||||
64 + // value
|
||||
256 + // g_d
|
||||
256 // p_d
|
||||
);
|
||||
|
||||
// Compute the hash of the note contents
|
||||
let mut cm = pedersen_hash::pedersen_hash(
|
||||
cs.namespace(|| "note content hash"),
|
||||
pedersen_hash::Personalization::NoteCommitment,
|
||||
¬e_contents,
|
||||
self.params
|
||||
)?;
|
||||
|
||||
{
|
||||
// Booleanize the randomness for the note commitment
|
||||
let rcm = boolean::field_into_boolean_vec_le(
|
||||
cs.namespace(|| "rcm"),
|
||||
self.commitment_randomness
|
||||
)?;
|
||||
|
||||
// Compute the note commitment randomness in the exponent
|
||||
let rcm = ecc::fixed_base_multiplication(
|
||||
cs.namespace(|| "computation of commitment randomness"),
|
||||
FixedGenerators::NoteCommitmentRandomness,
|
||||
&rcm,
|
||||
self.params
|
||||
)?;
|
||||
|
||||
// Randomize the note commitment. Pedersen hashes are not
|
||||
// themselves hiding commitments.
|
||||
cm = cm.add(
|
||||
cs.namespace(|| "randomization of note commitment"),
|
||||
&rcm,
|
||||
self.params
|
||||
)?;
|
||||
}
|
||||
|
||||
// This will store (least significant bit first)
|
||||
// the position of the note in the tree, for use
|
||||
// in nullifier computation.
|
||||
let mut position_bits = vec![];
|
||||
|
||||
// This is an injective encoding, as cur is a
|
||||
// point in the prime order subgroup.
|
||||
let mut cur = cm.get_x().clone();
|
||||
|
||||
// Ascend the merkle tree authentication path
|
||||
for (i, e) in self.auth_path.into_iter().enumerate() {
|
||||
let cs = &mut cs.namespace(|| format!("merkle tree hash {}", i));
|
||||
|
||||
// Determines if the current subtree is the "right" leaf at this
|
||||
// depth of the tree.
|
||||
let cur_is_right = boolean::Boolean::from(boolean::AllocatedBit::alloc(
|
||||
cs.namespace(|| "position bit"),
|
||||
e.map(|e| e.1)
|
||||
)?);
|
||||
|
||||
// Push this boolean for nullifier computation later
|
||||
position_bits.push(cur_is_right.clone());
|
||||
|
||||
// Witness the authentication path element adjacent
|
||||
// at this depth.
|
||||
let path_element = num::AllocatedNum::alloc(
|
||||
cs.namespace(|| "path element"),
|
||||
|| {
|
||||
Ok(e.get()?.0)
|
||||
}
|
||||
)?;
|
||||
|
||||
// Swap the two if the current subtree is on the right
|
||||
let (xl, xr) = num::AllocatedNum::conditionally_reverse(
|
||||
cs.namespace(|| "conditional reversal of preimage"),
|
||||
&cur,
|
||||
&path_element,
|
||||
&cur_is_right
|
||||
)?;
|
||||
|
||||
// We don't need to be strict, because the function is
|
||||
// collision-resistant. If the prover witnesses a congruency,
|
||||
// they will be unable to find an authentication path in the
|
||||
// tree with high probability.
|
||||
let mut preimage = vec![];
|
||||
preimage.extend(xl.into_bits_le(cs.namespace(|| "xl into bits"))?);
|
||||
preimage.extend(xr.into_bits_le(cs.namespace(|| "xr into bits"))?);
|
||||
|
||||
// Compute the new subtree value
|
||||
cur = pedersen_hash::pedersen_hash(
|
||||
cs.namespace(|| "computation of pedersen hash"),
|
||||
pedersen_hash::Personalization::MerkleTree(i),
|
||||
&preimage,
|
||||
self.params
|
||||
)?.get_x().clone(); // Injective encoding
|
||||
}
|
||||
|
||||
{
|
||||
let real_anchor_value = self.anchor;
|
||||
|
||||
// Allocate the "real" anchor that will be exposed.
|
||||
let rt = num::AllocatedNum::alloc(
|
||||
cs.namespace(|| "conditional anchor"),
|
||||
|| {
|
||||
Ok(*real_anchor_value.get()?)
|
||||
}
|
||||
)?;
|
||||
|
||||
// (cur - rt) * value = 0
|
||||
// if value is zero, cur and rt can be different
|
||||
// if value is nonzero, they must be equal
|
||||
cs.enforce(
|
||||
|| "conditionally enforce correct root",
|
||||
|lc| lc + cur.get_variable() - rt.get_variable(),
|
||||
|lc| lc + &value_num.lc(E::Fr::one()),
|
||||
|lc| lc
|
||||
);
|
||||
|
||||
// Expose the anchor
|
||||
rt.inputize(cs.namespace(|| "anchor"))?;
|
||||
}
|
||||
|
||||
// Compute the cm + g^position for preventing
|
||||
// faerie gold attacks
|
||||
let mut rho = cm;
|
||||
{
|
||||
// Compute the position in the exponent
|
||||
let position = ecc::fixed_base_multiplication(
|
||||
cs.namespace(|| "g^position"),
|
||||
FixedGenerators::NullifierPosition,
|
||||
&position_bits,
|
||||
self.params
|
||||
)?;
|
||||
|
||||
// Add the position to the commitment
|
||||
rho = rho.add(
|
||||
cs.namespace(|| "faerie gold prevention"),
|
||||
&position,
|
||||
self.params
|
||||
)?;
|
||||
}
|
||||
|
||||
// Let's compute nf = BLAKE2s(nk || rho)
|
||||
nf_preimage.extend(
|
||||
rho.repr(cs.namespace(|| "representation of rho"))?
|
||||
);
|
||||
|
||||
assert_eq!(nf_preimage.len(), 512);
|
||||
|
||||
// Compute nf
|
||||
let nf = blake2s::blake2s(
|
||||
cs.namespace(|| "nf computation"),
|
||||
&nf_preimage,
|
||||
constants::PRF_NF_PERSONALIZATION
|
||||
)?;
|
||||
|
||||
multipack::pack_into_inputs(cs.namespace(|| "pack nullifier"), &nf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
|
||||
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError>
|
||||
{
|
||||
// Let's start to construct our note, which contains
|
||||
// value (big endian)
|
||||
let mut note_contents = vec![];
|
||||
|
||||
// Expose the value commitment and place the value
|
||||
// in the note.
|
||||
note_contents.extend(expose_value_commitment(
|
||||
cs.namespace(|| "value commitment"),
|
||||
self.value_commitment,
|
||||
self.params
|
||||
)?);
|
||||
|
||||
// Let's deal with g_d
|
||||
{
|
||||
let params = self.params;
|
||||
|
||||
// Prover witnesses g_d, ensuring it's on the
|
||||
// curve.
|
||||
let g_d = ecc::EdwardsPoint::witness(
|
||||
cs.namespace(|| "witness g_d"),
|
||||
self.payment_address.as_ref().and_then(|a| a.g_d(params)),
|
||||
self.params
|
||||
)?;
|
||||
|
||||
// g_d is ensured to be large order. The relationship
|
||||
// between g_d and pk_d ultimately binds ivk to the
|
||||
// note. If this were a small order point, it would
|
||||
// not do this correctly, and the prover could
|
||||
// double-spend by finding random ivk's that satisfy
|
||||
// the relationship.
|
||||
//
|
||||
// Further, if it were small order, epk would be
|
||||
// small order too!
|
||||
g_d.assert_not_small_order(
|
||||
cs.namespace(|| "g_d not small order"),
|
||||
self.params
|
||||
)?;
|
||||
|
||||
// Extend our note contents with the representation of
|
||||
// g_d.
|
||||
note_contents.extend(
|
||||
g_d.repr(cs.namespace(|| "representation of g_d"))?
|
||||
);
|
||||
|
||||
// Booleanize our ephemeral secret key
|
||||
let esk = boolean::field_into_boolean_vec_le(
|
||||
cs.namespace(|| "esk"),
|
||||
self.esk
|
||||
)?;
|
||||
|
||||
// Create the ephemeral public key from g_d.
|
||||
let epk = g_d.mul(
|
||||
cs.namespace(|| "epk computation"),
|
||||
&esk,
|
||||
self.params
|
||||
)?;
|
||||
|
||||
// Expose epk publicly.
|
||||
epk.inputize(cs.namespace(|| "epk"))?;
|
||||
}
|
||||
|
||||
// Now let's deal with pk_d. We don't do any checks and
|
||||
// essentially allow the prover to witness any 256 bits
|
||||
// they would like.
|
||||
{
|
||||
// Just grab pk_d from the witness
|
||||
let pk_d = self.payment_address.as_ref().map(|e| e.pk_d.into_xy());
|
||||
|
||||
// Witness the y-coordinate, encoded as little
|
||||
// endian bits (to match the representation)
|
||||
let y_contents = boolean::field_into_boolean_vec_le(
|
||||
cs.namespace(|| "pk_d bits of y"),
|
||||
pk_d.map(|e| e.1)
|
||||
)?;
|
||||
|
||||
// Witness the sign bit
|
||||
let sign_bit = boolean::Boolean::from(boolean::AllocatedBit::alloc(
|
||||
cs.namespace(|| "pk_d bit of x"),
|
||||
pk_d.map(|e| e.0.into_repr().is_odd())
|
||||
)?);
|
||||
|
||||
// Extend the note with pk_d representation
|
||||
note_contents.extend(y_contents);
|
||||
note_contents.push(sign_bit);
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
note_contents.len(),
|
||||
64 + // value
|
||||
256 + // g_d
|
||||
256 // pk_d
|
||||
);
|
||||
|
||||
// Compute the hash of the note contents
|
||||
let mut cm = pedersen_hash::pedersen_hash(
|
||||
cs.namespace(|| "note content hash"),
|
||||
pedersen_hash::Personalization::NoteCommitment,
|
||||
¬e_contents,
|
||||
self.params
|
||||
)?;
|
||||
|
||||
{
|
||||
// Booleanize the randomness
|
||||
let rcm = boolean::field_into_boolean_vec_le(
|
||||
cs.namespace(|| "rcm"),
|
||||
self.commitment_randomness
|
||||
)?;
|
||||
|
||||
// Compute the note commitment randomness in the exponent
|
||||
let rcm = ecc::fixed_base_multiplication(
|
||||
cs.namespace(|| "computation of commitment randomness"),
|
||||
FixedGenerators::NoteCommitmentRandomness,
|
||||
&rcm,
|
||||
self.params
|
||||
)?;
|
||||
|
||||
// Randomize our note commitment
|
||||
cm = cm.add(
|
||||
cs.namespace(|| "randomization of note commitment"),
|
||||
&rcm,
|
||||
self.params
|
||||
)?;
|
||||
}
|
||||
|
||||
// Only the x-coordinate of the output is revealed,
|
||||
// since we know it is prime order, and we know that
|
||||
// the x-coordinate is an injective encoding for
|
||||
// prime-order elements.
|
||||
cm.get_x().inputize(cs.namespace(|| "commitment"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_input_circuit_with_bls12_381() {
|
||||
use pairing::{Field, BitIterator};
|
||||
use pairing::bls12_381::*;
|
||||
use rand::{SeedableRng, Rng, XorShiftRng};
|
||||
use ::circuit::test::*;
|
||||
use jubjub::{JubjubBls12, fs, edwards};
|
||||
|
||||
let params = &JubjubBls12::new();
|
||||
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let tree_depth = 32;
|
||||
|
||||
for _ in 0..10 {
|
||||
let value_commitment = ValueCommitment {
|
||||
value: rng.gen(),
|
||||
randomness: rng.gen()
|
||||
};
|
||||
|
||||
let nsk: fs::Fs = rng.gen();
|
||||
let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params);
|
||||
|
||||
let proof_generation_key = ::primitives::ProofGenerationKey {
|
||||
ak: ak.clone(),
|
||||
nsk: nsk.clone()
|
||||
};
|
||||
|
||||
let viewing_key = proof_generation_key.into_viewing_key(params);
|
||||
|
||||
let payment_address;
|
||||
|
||||
loop {
|
||||
let diversifier = ::primitives::Diversifier(rng.gen());
|
||||
|
||||
if let Some(p) = viewing_key.into_payment_address(
|
||||
diversifier,
|
||||
params
|
||||
)
|
||||
{
|
||||
payment_address = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let g_d = payment_address.diversifier.g_d(params).unwrap();
|
||||
let commitment_randomness: fs::Fs = rng.gen();
|
||||
let auth_path = vec![Some((rng.gen(), rng.gen())); tree_depth];
|
||||
let ar: fs::Fs = rng.gen();
|
||||
|
||||
{
|
||||
let rk = viewing_key.rk(ar, params).into_xy();
|
||||
let expected_value_cm = value_commitment.cm(params).into_xy();
|
||||
let note = ::primitives::Note {
|
||||
value: value_commitment.value,
|
||||
g_d: g_d.clone(),
|
||||
pk_d: payment_address.pk_d.clone(),
|
||||
r: commitment_randomness.clone()
|
||||
};
|
||||
|
||||
let mut position = 0u64;
|
||||
let cm: Fr = note.cm(params);
|
||||
let mut cur = cm.clone();
|
||||
|
||||
for (i, val) in auth_path.clone().into_iter().enumerate()
|
||||
{
|
||||
let (uncle, b) = val.unwrap();
|
||||
|
||||
let mut lhs = cur;
|
||||
let mut rhs = uncle;
|
||||
|
||||
if b {
|
||||
::std::mem::swap(&mut lhs, &mut rhs);
|
||||
}
|
||||
|
||||
let mut lhs: Vec<bool> = BitIterator::new(lhs.into_repr()).collect();
|
||||
let mut rhs: Vec<bool> = BitIterator::new(rhs.into_repr()).collect();
|
||||
|
||||
lhs.reverse();
|
||||
rhs.reverse();
|
||||
|
||||
cur = ::pedersen_hash::pedersen_hash::<Bls12, _>(
|
||||
::pedersen_hash::Personalization::MerkleTree(i),
|
||||
lhs.into_iter()
|
||||
.take(Fr::NUM_BITS as usize)
|
||||
.chain(rhs.into_iter().take(Fr::NUM_BITS as usize)),
|
||||
params
|
||||
).into_xy().0;
|
||||
|
||||
if b {
|
||||
position |= 1 << i;
|
||||
}
|
||||
}
|
||||
|
||||
let expected_nf = note.nf(&viewing_key, position, params);
|
||||
let expected_nf = multipack::bytes_to_bits_le(&expected_nf);
|
||||
let expected_nf = multipack::compute_multipacking::<Bls12>(&expected_nf);
|
||||
assert_eq!(expected_nf.len(), 2);
|
||||
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let instance = Spend {
|
||||
params: params,
|
||||
value_commitment: Some(value_commitment.clone()),
|
||||
proof_generation_key: Some(proof_generation_key.clone()),
|
||||
payment_address: Some(payment_address.clone()),
|
||||
commitment_randomness: Some(commitment_randomness),
|
||||
ar: Some(ar),
|
||||
auth_path: auth_path.clone(),
|
||||
anchor: Some(cur)
|
||||
};
|
||||
|
||||
instance.synthesize(&mut cs).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 98777);
|
||||
assert_eq!(cs.hash(), "d37c738e83df5d9b0bb6495ac96abf21bcb2697477e2c15c2c7916ff7a3b6a89");
|
||||
|
||||
assert_eq!(cs.get("randomization of note commitment/x3/num"), cm);
|
||||
|
||||
assert_eq!(cs.num_inputs(), 8);
|
||||
assert_eq!(cs.get_input(0, "ONE"), Fr::one());
|
||||
assert_eq!(cs.get_input(1, "rk/x/input variable"), rk.0);
|
||||
assert_eq!(cs.get_input(2, "rk/y/input variable"), rk.1);
|
||||
assert_eq!(cs.get_input(3, "value commitment/commitment point/x/input variable"), expected_value_cm.0);
|
||||
assert_eq!(cs.get_input(4, "value commitment/commitment point/y/input variable"), expected_value_cm.1);
|
||||
assert_eq!(cs.get_input(5, "anchor/input variable"), cur);
|
||||
assert_eq!(cs.get_input(6, "pack nullifier/input 0"), expected_nf[0]);
|
||||
assert_eq!(cs.get_input(7, "pack nullifier/input 1"), expected_nf[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_output_circuit_with_bls12_381() {
|
||||
use pairing::{Field};
|
||||
use pairing::bls12_381::*;
|
||||
use rand::{SeedableRng, Rng, XorShiftRng};
|
||||
use ::circuit::test::*;
|
||||
use jubjub::{JubjubBls12, fs, edwards};
|
||||
|
||||
let params = &JubjubBls12::new();
|
||||
let rng = &mut XorShiftRng::from_seed([0x3dbe6258, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..100 {
|
||||
let value_commitment = ValueCommitment {
|
||||
value: rng.gen(),
|
||||
randomness: rng.gen()
|
||||
};
|
||||
|
||||
let nsk: fs::Fs = rng.gen();
|
||||
let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params);
|
||||
|
||||
let proof_generation_key = ::primitives::ProofGenerationKey {
|
||||
ak: ak.clone(),
|
||||
nsk: nsk.clone()
|
||||
};
|
||||
|
||||
let viewing_key = proof_generation_key.into_viewing_key(params);
|
||||
|
||||
let payment_address;
|
||||
|
||||
loop {
|
||||
let diversifier = ::primitives::Diversifier(rng.gen());
|
||||
|
||||
if let Some(p) = viewing_key.into_payment_address(
|
||||
diversifier,
|
||||
params
|
||||
)
|
||||
{
|
||||
payment_address = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let commitment_randomness: fs::Fs = rng.gen();
|
||||
let esk: fs::Fs = rng.gen();
|
||||
|
||||
{
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let instance = Output {
|
||||
params: params,
|
||||
value_commitment: Some(value_commitment.clone()),
|
||||
payment_address: Some(payment_address.clone()),
|
||||
commitment_randomness: Some(commitment_randomness),
|
||||
esk: Some(esk.clone())
|
||||
};
|
||||
|
||||
instance.synthesize(&mut cs).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 7827);
|
||||
assert_eq!(cs.hash(), "c26d5cdfe6ccd65c03390902c02e11393ea6bb96aae32a7f2ecb12eb9103faee");
|
||||
|
||||
let expected_cm = payment_address.create_note(
|
||||
value_commitment.value,
|
||||
commitment_randomness,
|
||||
params
|
||||
).expect("should be valid").cm(params);
|
||||
|
||||
let expected_value_cm = value_commitment.cm(params).into_xy();
|
||||
|
||||
let expected_epk = payment_address.g_d(params).expect("should be valid").mul(esk, params);
|
||||
let expected_epk_xy = expected_epk.into_xy();
|
||||
|
||||
assert_eq!(cs.num_inputs(), 6);
|
||||
assert_eq!(cs.get_input(0, "ONE"), Fr::one());
|
||||
assert_eq!(cs.get_input(1, "value commitment/commitment point/x/input variable"), expected_value_cm.0);
|
||||
assert_eq!(cs.get_input(2, "value commitment/commitment point/y/input variable"), expected_value_cm.1);
|
||||
assert_eq!(cs.get_input(3, "epk/x/input variable"), expected_epk_xy.0);
|
||||
assert_eq!(cs.get_input(4, "epk/y/input variable"), expected_epk_xy.1);
|
||||
assert_eq!(cs.get_input(5, "commitment/input variable"), expected_cm);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
use pairing::{Engine};
|
||||
use bellman::{ConstraintSystem, SynthesisError};
|
||||
use circuit::sha256::{
|
||||
sha256
|
||||
};
|
||||
use circuit::boolean::{
|
||||
Boolean
|
||||
};
|
||||
|
||||
pub fn note_comm<E, CS>(
|
||||
cs: CS,
|
||||
a_pk: &[Boolean],
|
||||
value: &[Boolean],
|
||||
rho: &[Boolean],
|
||||
r: &[Boolean]
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>
|
||||
{
|
||||
assert_eq!(a_pk.len(), 256);
|
||||
assert_eq!(value.len(), 64);
|
||||
assert_eq!(rho.len(), 256);
|
||||
assert_eq!(r.len(), 256);
|
||||
|
||||
let mut image = vec![];
|
||||
image.push(Boolean::constant(true));
|
||||
image.push(Boolean::constant(false));
|
||||
image.push(Boolean::constant(true));
|
||||
image.push(Boolean::constant(true));
|
||||
image.push(Boolean::constant(false));
|
||||
image.push(Boolean::constant(false));
|
||||
image.push(Boolean::constant(false));
|
||||
image.push(Boolean::constant(false));
|
||||
image.extend(a_pk.iter().cloned());
|
||||
image.extend(value.iter().cloned());
|
||||
image.extend(rho.iter().cloned());
|
||||
image.extend(r.iter().cloned());
|
||||
|
||||
sha256(
|
||||
cs,
|
||||
&image
|
||||
)
|
||||
}
|
@ -1,226 +0,0 @@
|
||||
use pairing::{Engine};
|
||||
use bellman::{ConstraintSystem, SynthesisError};
|
||||
use circuit::sha256::{
|
||||
sha256_block_no_padding
|
||||
};
|
||||
use circuit::boolean::{
|
||||
AllocatedBit,
|
||||
Boolean
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use super::prfs::*;
|
||||
use super::commitment::note_comm;
|
||||
|
||||
pub struct InputNote {
|
||||
pub nf: Vec<Boolean>,
|
||||
pub mac: Vec<Boolean>,
|
||||
}
|
||||
|
||||
impl InputNote {
|
||||
pub fn compute<E, CS>(
|
||||
mut cs: CS,
|
||||
a_sk: Option<SpendingKey>,
|
||||
rho: Option<UniqueRandomness>,
|
||||
r: Option<CommitmentRandomness>,
|
||||
value: &NoteValue,
|
||||
h_sig: &[Boolean],
|
||||
nonce: bool,
|
||||
auth_path: [Option<([u8; 32], bool)>; TREE_DEPTH],
|
||||
rt: &[Boolean]
|
||||
) -> Result<InputNote, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>
|
||||
{
|
||||
let a_sk = witness_u252(
|
||||
cs.namespace(|| "a_sk"),
|
||||
a_sk.as_ref().map(|a_sk| &a_sk.0[..])
|
||||
)?;
|
||||
|
||||
let rho = witness_u256(
|
||||
cs.namespace(|| "rho"),
|
||||
rho.as_ref().map(|rho| &rho.0[..])
|
||||
)?;
|
||||
|
||||
let r = witness_u256(
|
||||
cs.namespace(|| "r"),
|
||||
r.as_ref().map(|r| &r.0[..])
|
||||
)?;
|
||||
|
||||
let a_pk = prf_a_pk(
|
||||
cs.namespace(|| "a_pk computation"),
|
||||
&a_sk
|
||||
)?;
|
||||
|
||||
let nf = prf_nf(
|
||||
cs.namespace(|| "nf computation"),
|
||||
&a_sk,
|
||||
&rho
|
||||
)?;
|
||||
|
||||
let mac = prf_pk(
|
||||
cs.namespace(|| "mac computation"),
|
||||
&a_sk,
|
||||
h_sig,
|
||||
nonce
|
||||
)?;
|
||||
|
||||
let cm = note_comm(
|
||||
cs.namespace(|| "cm computation"),
|
||||
&a_pk,
|
||||
&value.bits_le(),
|
||||
&rho,
|
||||
&r
|
||||
)?;
|
||||
|
||||
// Witness into the merkle tree
|
||||
let mut cur = cm.clone();
|
||||
|
||||
for (i, layer) in auth_path.into_iter().enumerate() {
|
||||
let cs = &mut cs.namespace(|| format!("layer {}", i));
|
||||
|
||||
let cur_is_right = AllocatedBit::alloc(
|
||||
cs.namespace(|| "cur is right"),
|
||||
layer.as_ref().map(|&(_, p)| p)
|
||||
)?;
|
||||
|
||||
let lhs = cur;
|
||||
let rhs = witness_u256(
|
||||
cs.namespace(|| "sibling"),
|
||||
layer.as_ref().map(|&(ref sibling, _)| &sibling[..])
|
||||
)?;
|
||||
|
||||
// Conditionally swap if cur is right
|
||||
let preimage = conditionally_swap_u256(
|
||||
cs.namespace(|| "conditional swap"),
|
||||
&lhs[..],
|
||||
&rhs[..],
|
||||
&cur_is_right
|
||||
)?;
|
||||
|
||||
cur = sha256_block_no_padding(
|
||||
cs.namespace(|| "hash of this layer"),
|
||||
&preimage
|
||||
)?;
|
||||
}
|
||||
|
||||
// enforce must be true if the value is nonzero
|
||||
let enforce = AllocatedBit::alloc(
|
||||
cs.namespace(|| "enforce"),
|
||||
value.get_value().map(|n| n != 0)
|
||||
)?;
|
||||
|
||||
// value * (1 - enforce) = 0
|
||||
// If `value` is zero, `enforce` _can_ be zero.
|
||||
// If `value` is nonzero, `enforce` _must_ be one.
|
||||
cs.enforce(
|
||||
|| "enforce validity",
|
||||
|_| value.lc(),
|
||||
|lc| lc + CS::one() - enforce.get_variable(),
|
||||
|lc| lc
|
||||
);
|
||||
|
||||
assert_eq!(cur.len(), rt.len());
|
||||
|
||||
// Check that the anchor (exposed as a public input)
|
||||
// is equal to the merkle tree root that we calculated
|
||||
// for this note
|
||||
for (i, (cur, rt)) in cur.into_iter().zip(rt.iter()).enumerate() {
|
||||
// (cur - rt) * enforce = 0
|
||||
// if enforce is zero, cur and rt can be different
|
||||
// if enforce is one, they must be equal
|
||||
cs.enforce(
|
||||
|| format!("conditionally enforce correct root for bit {}", i),
|
||||
|_| cur.lc(CS::one(), E::Fr::one()) - &rt.lc(CS::one(), E::Fr::one()),
|
||||
|lc| lc + enforce.get_variable(),
|
||||
|lc| lc
|
||||
);
|
||||
}
|
||||
|
||||
Ok(InputNote {
|
||||
mac: mac,
|
||||
nf: nf
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Swaps two 256-bit blobs conditionally, returning the
|
||||
/// 512-bit concatenation.
|
||||
pub fn conditionally_swap_u256<E, CS>(
|
||||
mut cs: CS,
|
||||
lhs: &[Boolean],
|
||||
rhs: &[Boolean],
|
||||
condition: &AllocatedBit
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>,
|
||||
{
|
||||
assert_eq!(lhs.len(), 256);
|
||||
assert_eq!(rhs.len(), 256);
|
||||
|
||||
let mut new_lhs = vec![];
|
||||
let mut new_rhs = vec![];
|
||||
|
||||
for (i, (lhs, rhs)) in lhs.iter().zip(rhs.iter()).enumerate() {
|
||||
let cs = &mut cs.namespace(|| format!("bit {}", i));
|
||||
|
||||
let x = Boolean::from(AllocatedBit::alloc(
|
||||
cs.namespace(|| "x"),
|
||||
condition.get_value().and_then(|v| {
|
||||
if v {
|
||||
rhs.get_value()
|
||||
} else {
|
||||
lhs.get_value()
|
||||
}
|
||||
})
|
||||
)?);
|
||||
|
||||
// x = (1-condition)lhs + (condition)rhs
|
||||
// x = lhs - lhs(condition) + rhs(condition)
|
||||
// x - lhs = condition (rhs - lhs)
|
||||
// if condition is zero, we don't swap, so
|
||||
// x - lhs = 0
|
||||
// x = lhs
|
||||
// if condition is one, we do swap, so
|
||||
// x - lhs = rhs - lhs
|
||||
// x = rhs
|
||||
cs.enforce(
|
||||
|| "conditional swap for x",
|
||||
|lc| lc + &rhs.lc(CS::one(), E::Fr::one())
|
||||
- &lhs.lc(CS::one(), E::Fr::one()),
|
||||
|lc| lc + condition.get_variable(),
|
||||
|lc| lc + &x.lc(CS::one(), E::Fr::one())
|
||||
- &lhs.lc(CS::one(), E::Fr::one())
|
||||
);
|
||||
|
||||
let y = Boolean::from(AllocatedBit::alloc(
|
||||
cs.namespace(|| "y"),
|
||||
condition.get_value().and_then(|v| {
|
||||
if v {
|
||||
lhs.get_value()
|
||||
} else {
|
||||
rhs.get_value()
|
||||
}
|
||||
})
|
||||
)?);
|
||||
|
||||
// y = (1-condition)rhs + (condition)lhs
|
||||
// y - rhs = condition (lhs - rhs)
|
||||
cs.enforce(
|
||||
|| "conditional swap for y",
|
||||
|lc| lc + &lhs.lc(CS::one(), E::Fr::one())
|
||||
- &rhs.lc(CS::one(), E::Fr::one()),
|
||||
|lc| lc + condition.get_variable(),
|
||||
|lc| lc + &y.lc(CS::one(), E::Fr::one())
|
||||
- &rhs.lc(CS::one(), E::Fr::one())
|
||||
);
|
||||
|
||||
new_lhs.push(x);
|
||||
new_rhs.push(y);
|
||||
}
|
||||
|
||||
let mut f = new_lhs;
|
||||
f.extend(new_rhs);
|
||||
|
||||
assert_eq!(f.len(), 512);
|
||||
|
||||
Ok(f)
|
||||
}
|
@ -1,488 +0,0 @@
|
||||
use pairing::{Engine, Field};
|
||||
use bellman::{ConstraintSystem, SynthesisError, Circuit, LinearCombination};
|
||||
use circuit::boolean::{
|
||||
AllocatedBit,
|
||||
Boolean
|
||||
};
|
||||
use circuit::multipack::pack_into_inputs;
|
||||
|
||||
mod prfs;
|
||||
mod commitment;
|
||||
mod input;
|
||||
mod output;
|
||||
|
||||
use self::input::*;
|
||||
use self::output::*;
|
||||
|
||||
pub const TREE_DEPTH: usize = 29;
|
||||
|
||||
pub struct SpendingKey(pub [u8; 32]);
|
||||
pub struct PayingKey(pub [u8; 32]);
|
||||
pub struct UniqueRandomness(pub [u8; 32]);
|
||||
pub struct CommitmentRandomness(pub [u8; 32]);
|
||||
|
||||
pub struct JoinSplit {
|
||||
pub vpub_old: Option<u64>,
|
||||
pub vpub_new: Option<u64>,
|
||||
pub h_sig: Option<[u8; 32]>,
|
||||
pub phi: Option<[u8; 32]>,
|
||||
pub inputs: Vec<JSInput>,
|
||||
pub outputs: Vec<JSOutput>,
|
||||
pub rt: Option<[u8; 32]>,
|
||||
}
|
||||
|
||||
pub struct JSInput {
|
||||
pub value: Option<u64>,
|
||||
pub a_sk: Option<SpendingKey>,
|
||||
pub rho: Option<UniqueRandomness>,
|
||||
pub r: Option<CommitmentRandomness>,
|
||||
pub auth_path: [Option<([u8; 32], bool)>; TREE_DEPTH]
|
||||
}
|
||||
|
||||
pub struct JSOutput {
|
||||
pub value: Option<u64>,
|
||||
pub a_pk: Option<PayingKey>,
|
||||
pub r: Option<CommitmentRandomness>
|
||||
}
|
||||
|
||||
impl<E: Engine> Circuit<E> for JoinSplit {
|
||||
fn synthesize<CS: ConstraintSystem<E>>(
|
||||
self,
|
||||
cs: &mut CS
|
||||
) -> Result<(), SynthesisError>
|
||||
{
|
||||
assert_eq!(self.inputs.len(), 2);
|
||||
assert_eq!(self.outputs.len(), 2);
|
||||
|
||||
// vpub_old is the value entering the
|
||||
// JoinSplit from the "outside" value
|
||||
// pool
|
||||
let vpub_old = NoteValue::new(
|
||||
cs.namespace(|| "vpub_old"),
|
||||
self.vpub_old
|
||||
)?;
|
||||
|
||||
// vpub_new is the value leaving the
|
||||
// JoinSplit into the "outside" value
|
||||
// pool
|
||||
let vpub_new = NoteValue::new(
|
||||
cs.namespace(|| "vpub_new"),
|
||||
self.vpub_new
|
||||
)?;
|
||||
|
||||
// The left hand side of the balance equation
|
||||
// vpub_old + inputs[0].value + inputs[1].value
|
||||
let mut lhs = vpub_old.lc();
|
||||
|
||||
// The right hand side of the balance equation
|
||||
// vpub_old + inputs[0].value + inputs[1].value
|
||||
let mut rhs = vpub_new.lc();
|
||||
|
||||
// Witness rt (merkle tree root)
|
||||
let rt = witness_u256(
|
||||
cs.namespace(|| "rt"),
|
||||
self.rt.as_ref().map(|v| &v[..])
|
||||
).unwrap();
|
||||
|
||||
// Witness h_sig
|
||||
let h_sig = witness_u256(
|
||||
cs.namespace(|| "h_sig"),
|
||||
self.h_sig.as_ref().map(|v| &v[..])
|
||||
).unwrap();
|
||||
|
||||
// Witness phi
|
||||
let phi = witness_u252(
|
||||
cs.namespace(|| "phi"),
|
||||
self.phi.as_ref().map(|v| &v[..])
|
||||
).unwrap();
|
||||
|
||||
let mut input_notes = vec![];
|
||||
let mut lhs_total = self.vpub_old;
|
||||
|
||||
// Iterate over the JoinSplit inputs
|
||||
for (i, input) in self.inputs.into_iter().enumerate() {
|
||||
let cs = &mut cs.namespace(|| format!("input {}", i));
|
||||
|
||||
// Accumulate the value of the left hand side
|
||||
if let Some(value) = input.value {
|
||||
lhs_total = lhs_total.map(|v| v.wrapping_add(value));
|
||||
}
|
||||
|
||||
// Allocate the value of the note
|
||||
let value = NoteValue::new(
|
||||
cs.namespace(|| "value"),
|
||||
input.value
|
||||
)?;
|
||||
|
||||
// Compute the nonce (for PRF inputs) which is false
|
||||
// for the first input, and true for the second input.
|
||||
let nonce = match i {
|
||||
0 => false,
|
||||
1 => true,
|
||||
_ => unreachable!()
|
||||
};
|
||||
|
||||
// Perform input note computations
|
||||
input_notes.push(InputNote::compute(
|
||||
cs.namespace(|| "note"),
|
||||
input.a_sk,
|
||||
input.rho,
|
||||
input.r,
|
||||
&value,
|
||||
&h_sig,
|
||||
nonce,
|
||||
input.auth_path,
|
||||
&rt
|
||||
)?);
|
||||
|
||||
// Add the note value to the left hand side of
|
||||
// the balance equation
|
||||
lhs = lhs + &value.lc();
|
||||
}
|
||||
|
||||
// Rebind lhs so that it isn't mutable anymore
|
||||
let lhs = lhs;
|
||||
|
||||
// See zcash/zcash/issues/854
|
||||
{
|
||||
// Expected sum of the left hand side of the balance
|
||||
// equation, expressed as a 64-bit unsigned integer
|
||||
let lhs_total = NoteValue::new(
|
||||
cs.namespace(|| "total value of left hand side"),
|
||||
lhs_total
|
||||
)?;
|
||||
|
||||
// Enforce that the left hand side can be expressed as a 64-bit
|
||||
// integer
|
||||
cs.enforce(
|
||||
|| "left hand side can be expressed as a 64-bit unsigned integer",
|
||||
|_| lhs.clone(),
|
||||
|lc| lc + CS::one(),
|
||||
|_| lhs_total.lc()
|
||||
);
|
||||
}
|
||||
|
||||
let mut output_notes = vec![];
|
||||
|
||||
// Iterate over the JoinSplit outputs
|
||||
for (i, output) in self.outputs.into_iter().enumerate() {
|
||||
let cs = &mut cs.namespace(|| format!("output {}", i));
|
||||
|
||||
let value = NoteValue::new(
|
||||
cs.namespace(|| "value"),
|
||||
output.value
|
||||
)?;
|
||||
|
||||
// Compute the nonce (for PRF inputs) which is false
|
||||
// for the first output, and true for the second output.
|
||||
let nonce = match i {
|
||||
0 => false,
|
||||
1 => true,
|
||||
_ => unreachable!()
|
||||
};
|
||||
|
||||
// Perform output note computations
|
||||
output_notes.push(OutputNote::compute(
|
||||
cs.namespace(|| "note"),
|
||||
output.a_pk,
|
||||
&value,
|
||||
output.r,
|
||||
&phi,
|
||||
&h_sig,
|
||||
nonce
|
||||
)?);
|
||||
|
||||
// Add the note value to the right hand side of
|
||||
// the balance equation
|
||||
rhs = rhs + &value.lc();
|
||||
}
|
||||
|
||||
// Enforce that balance is equal
|
||||
cs.enforce(
|
||||
|| "balance equation",
|
||||
|_| lhs.clone(),
|
||||
|lc| lc + CS::one(),
|
||||
|_| rhs
|
||||
);
|
||||
|
||||
let mut public_inputs = vec![];
|
||||
public_inputs.extend(rt);
|
||||
public_inputs.extend(h_sig);
|
||||
|
||||
for note in input_notes {
|
||||
public_inputs.extend(note.nf);
|
||||
public_inputs.extend(note.mac);
|
||||
}
|
||||
|
||||
for note in output_notes {
|
||||
public_inputs.extend(note.cm);
|
||||
}
|
||||
|
||||
public_inputs.extend(vpub_old.bits_le());
|
||||
public_inputs.extend(vpub_new.bits_le());
|
||||
|
||||
pack_into_inputs(cs.namespace(|| "input packing"), &public_inputs)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NoteValue {
|
||||
value: Option<u64>,
|
||||
// Least significant digit first
|
||||
bits: Vec<AllocatedBit>
|
||||
}
|
||||
|
||||
impl NoteValue {
|
||||
fn new<E, CS>(
|
||||
mut cs: CS,
|
||||
value: Option<u64>
|
||||
) -> Result<NoteValue, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>,
|
||||
{
|
||||
let mut values;
|
||||
match value {
|
||||
Some(mut val) => {
|
||||
values = vec![];
|
||||
for _ in 0..64 {
|
||||
values.push(Some(val & 1 == 1));
|
||||
val >>= 1;
|
||||
}
|
||||
},
|
||||
None => {
|
||||
values = vec![None; 64];
|
||||
}
|
||||
}
|
||||
|
||||
let mut bits = vec![];
|
||||
for (i, value) in values.into_iter().enumerate() {
|
||||
bits.push(
|
||||
AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("bit {}", i)),
|
||||
value
|
||||
)?
|
||||
);
|
||||
}
|
||||
|
||||
Ok(NoteValue {
|
||||
value: value,
|
||||
bits: bits
|
||||
})
|
||||
}
|
||||
|
||||
/// Encodes the bits of the value into little-endian
|
||||
/// byte order.
|
||||
fn bits_le(&self) -> Vec<Boolean> {
|
||||
self.bits.chunks(8)
|
||||
.flat_map(|v| v.iter().rev())
|
||||
.cloned()
|
||||
.map(|e| Boolean::from(e))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Computes this value as a linear combination of
|
||||
/// its bits.
|
||||
fn lc<E: Engine>(&self) -> LinearCombination<E> {
|
||||
let mut tmp = LinearCombination::zero();
|
||||
|
||||
let mut coeff = E::Fr::one();
|
||||
for b in &self.bits {
|
||||
tmp = tmp + (coeff, b.get_variable());
|
||||
coeff.double();
|
||||
}
|
||||
|
||||
tmp
|
||||
}
|
||||
|
||||
fn get_value(&self) -> Option<u64> {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
/// Witnesses some bytes in the constraint system,
|
||||
/// skipping the first `skip_bits`.
|
||||
fn witness_bits<E, CS>(
|
||||
mut cs: CS,
|
||||
value: Option<&[u8]>,
|
||||
num_bits: usize,
|
||||
skip_bits: usize
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>,
|
||||
{
|
||||
let bit_values = if let Some(value) = value {
|
||||
let mut tmp = vec![];
|
||||
for b in value.iter()
|
||||
.flat_map(|&m| (0..8).rev().map(move |i| m >> i & 1 == 1))
|
||||
.skip(skip_bits)
|
||||
{
|
||||
tmp.push(Some(b));
|
||||
}
|
||||
tmp
|
||||
} else {
|
||||
vec![None; num_bits]
|
||||
};
|
||||
assert_eq!(bit_values.len(), num_bits);
|
||||
|
||||
let mut bits = vec![];
|
||||
|
||||
for (i, value) in bit_values.into_iter().enumerate() {
|
||||
bits.push(Boolean::from(AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("bit {}", i)),
|
||||
value
|
||||
)?));
|
||||
}
|
||||
|
||||
Ok(bits)
|
||||
}
|
||||
|
||||
fn witness_u256<E, CS>(
|
||||
cs: CS,
|
||||
value: Option<&[u8]>,
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>,
|
||||
{
|
||||
witness_bits(cs, value, 256, 0)
|
||||
}
|
||||
|
||||
fn witness_u252<E, CS>(
|
||||
cs: CS,
|
||||
value: Option<&[u8]>,
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>,
|
||||
{
|
||||
witness_bits(cs, value, 252, 4)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sprout_constraints() {
|
||||
use pairing::bls12_381::{Bls12};
|
||||
use ::circuit::test::*;
|
||||
|
||||
use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian};
|
||||
|
||||
let test_vector = include_bytes!("test_vectors.dat");
|
||||
let mut test_vector = &test_vector[..];
|
||||
|
||||
fn get_u256<R: ReadBytesExt>(mut reader: R) -> [u8; 32] {
|
||||
let mut result = [0u8; 32];
|
||||
|
||||
for i in 0..32 {
|
||||
result[i] = reader.read_u8().unwrap();
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
while test_vector.len() != 0 {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let phi = Some(get_u256(&mut test_vector));
|
||||
let rt = Some(get_u256(&mut test_vector));
|
||||
let h_sig = Some(get_u256(&mut test_vector));
|
||||
|
||||
let mut inputs = vec![];
|
||||
for _ in 0..2 {
|
||||
test_vector.read_u8().unwrap();
|
||||
|
||||
let mut auth_path = [None; TREE_DEPTH];
|
||||
for i in (0..TREE_DEPTH).rev() {
|
||||
test_vector.read_u8().unwrap();
|
||||
|
||||
let sibling = get_u256(&mut test_vector);
|
||||
|
||||
auth_path[i] = Some((sibling, false));
|
||||
}
|
||||
let mut position = test_vector.read_u64::<LittleEndian>().unwrap();
|
||||
for i in 0..TREE_DEPTH {
|
||||
auth_path[i].as_mut().map(|p| {
|
||||
p.1 = (position & 1) == 1
|
||||
});
|
||||
|
||||
position >>= 1;
|
||||
}
|
||||
|
||||
// a_pk
|
||||
let _ = Some(SpendingKey(get_u256(&mut test_vector)));
|
||||
let value = Some(test_vector.read_u64::<LittleEndian>().unwrap());
|
||||
let rho = Some(UniqueRandomness(get_u256(&mut test_vector)));
|
||||
let r = Some(CommitmentRandomness(get_u256(&mut test_vector)));
|
||||
let a_sk = Some(SpendingKey(get_u256(&mut test_vector)));
|
||||
|
||||
inputs.push(
|
||||
JSInput {
|
||||
value: value,
|
||||
a_sk: a_sk,
|
||||
rho: rho,
|
||||
r: r,
|
||||
auth_path: auth_path
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let mut outputs = vec![];
|
||||
|
||||
for _ in 0..2 {
|
||||
let a_pk = Some(PayingKey(get_u256(&mut test_vector)));
|
||||
let value = Some(test_vector.read_u64::<LittleEndian>().unwrap());
|
||||
get_u256(&mut test_vector);
|
||||
let r = Some(CommitmentRandomness(get_u256(&mut test_vector)));
|
||||
|
||||
outputs.push(
|
||||
JSOutput {
|
||||
value: value,
|
||||
a_pk: a_pk,
|
||||
r: r
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let vpub_old = Some(test_vector.read_u64::<LittleEndian>().unwrap());
|
||||
let vpub_new = Some(test_vector.read_u64::<LittleEndian>().unwrap());
|
||||
|
||||
let nf1 = get_u256(&mut test_vector);
|
||||
let nf2 = get_u256(&mut test_vector);
|
||||
|
||||
let cm1 = get_u256(&mut test_vector);
|
||||
let cm2 = get_u256(&mut test_vector);
|
||||
|
||||
let mac1 = get_u256(&mut test_vector);
|
||||
let mac2 = get_u256(&mut test_vector);
|
||||
|
||||
let js = JoinSplit {
|
||||
vpub_old: vpub_old,
|
||||
vpub_new: vpub_new,
|
||||
h_sig: h_sig,
|
||||
phi: phi,
|
||||
inputs: inputs,
|
||||
outputs: outputs,
|
||||
rt: rt
|
||||
};
|
||||
|
||||
js.synthesize(&mut cs).unwrap();
|
||||
|
||||
if let Some(s) = cs.which_is_unsatisfied() {
|
||||
panic!("{:?}", s);
|
||||
}
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 1989085);
|
||||
assert_eq!(cs.num_inputs(), 10);
|
||||
assert_eq!(cs.hash(), "1a228d3c6377130d1778c7885811dc8b8864049cb5af8aff7e6cd46c5bc4b84c");
|
||||
|
||||
let mut expected_inputs = vec![];
|
||||
expected_inputs.extend(rt.unwrap().to_vec());
|
||||
expected_inputs.extend(h_sig.unwrap().to_vec());
|
||||
expected_inputs.extend(nf1.to_vec());
|
||||
expected_inputs.extend(mac1.to_vec());
|
||||
expected_inputs.extend(nf2.to_vec());
|
||||
expected_inputs.extend(mac2.to_vec());
|
||||
expected_inputs.extend(cm1.to_vec());
|
||||
expected_inputs.extend(cm2.to_vec());
|
||||
expected_inputs.write_u64::<LittleEndian>(vpub_old.unwrap()).unwrap();
|
||||
expected_inputs.write_u64::<LittleEndian>(vpub_new.unwrap()).unwrap();
|
||||
|
||||
use circuit::multipack;
|
||||
|
||||
let expected_inputs = multipack::bytes_to_bits(&expected_inputs);
|
||||
let expected_inputs = multipack::compute_multipacking::<Bls12>(&expected_inputs);
|
||||
|
||||
assert!(cs.verify(&expected_inputs));
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
use pairing::{Engine};
|
||||
use bellman::{ConstraintSystem, SynthesisError};
|
||||
use circuit::boolean::{Boolean};
|
||||
|
||||
use super::*;
|
||||
use super::prfs::*;
|
||||
use super::commitment::note_comm;
|
||||
|
||||
pub struct OutputNote {
|
||||
pub cm: Vec<Boolean>
|
||||
}
|
||||
|
||||
impl OutputNote {
|
||||
pub fn compute<'a, E, CS>(
|
||||
mut cs: CS,
|
||||
a_pk: Option<PayingKey>,
|
||||
value: &NoteValue,
|
||||
r: Option<CommitmentRandomness>,
|
||||
phi: &[Boolean],
|
||||
h_sig: &[Boolean],
|
||||
nonce: bool
|
||||
) -> Result<Self, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>,
|
||||
{
|
||||
let rho = prf_rho(
|
||||
cs.namespace(|| "rho"),
|
||||
phi,
|
||||
h_sig,
|
||||
nonce
|
||||
)?;
|
||||
|
||||
let a_pk = witness_u256(
|
||||
cs.namespace(|| "a_pk"),
|
||||
a_pk.as_ref().map(|a_pk| &a_pk.0[..])
|
||||
)?;
|
||||
|
||||
let r = witness_u256(
|
||||
cs.namespace(|| "r"),
|
||||
r.as_ref().map(|r| &r.0[..])
|
||||
)?;
|
||||
|
||||
let cm = note_comm(
|
||||
cs.namespace(|| "cm computation"),
|
||||
&a_pk,
|
||||
&value.bits_le(),
|
||||
&rho,
|
||||
&r
|
||||
)?;
|
||||
|
||||
Ok(OutputNote {
|
||||
cm: cm
|
||||
})
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
use pairing::{Engine};
|
||||
use bellman::{ConstraintSystem, SynthesisError};
|
||||
use circuit::sha256::{
|
||||
sha256_block_no_padding
|
||||
};
|
||||
use circuit::boolean::{
|
||||
Boolean
|
||||
};
|
||||
|
||||
fn prf<E, CS>(
|
||||
cs: CS,
|
||||
a: bool,
|
||||
b: bool,
|
||||
c: bool,
|
||||
d: bool,
|
||||
x: &[Boolean],
|
||||
y: &[Boolean]
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>
|
||||
{
|
||||
assert_eq!(x.len(), 252);
|
||||
assert_eq!(y.len(), 256);
|
||||
|
||||
let mut image = vec![];
|
||||
image.push(Boolean::constant(a));
|
||||
image.push(Boolean::constant(b));
|
||||
image.push(Boolean::constant(c));
|
||||
image.push(Boolean::constant(d));
|
||||
image.extend(x.iter().cloned());
|
||||
image.extend(y.iter().cloned());
|
||||
|
||||
assert_eq!(image.len(), 512);
|
||||
|
||||
sha256_block_no_padding(
|
||||
cs,
|
||||
&image
|
||||
)
|
||||
}
|
||||
|
||||
pub fn prf_a_pk<E, CS>(
|
||||
cs: CS,
|
||||
a_sk: &[Boolean]
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>
|
||||
{
|
||||
prf(cs, true, true, false, false, a_sk, &(0..256).map(|_| Boolean::constant(false)).collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
pub fn prf_nf<E, CS>(
|
||||
cs: CS,
|
||||
a_sk: &[Boolean],
|
||||
rho: &[Boolean]
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>
|
||||
{
|
||||
prf(cs, true, true, true, false, a_sk, rho)
|
||||
}
|
||||
|
||||
pub fn prf_pk<E, CS>(
|
||||
cs: CS,
|
||||
a_sk: &[Boolean],
|
||||
h_sig: &[Boolean],
|
||||
nonce: bool
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>
|
||||
{
|
||||
prf(cs, false, nonce, false, false, a_sk, h_sig)
|
||||
}
|
||||
|
||||
pub fn prf_rho<E, CS>(
|
||||
cs: CS,
|
||||
phi: &[Boolean],
|
||||
h_sig: &[Boolean],
|
||||
nonce: bool
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>
|
||||
{
|
||||
prf(cs, false, nonce, true, false, phi, h_sig)
|
||||
}
|
Binary file not shown.
@ -1,40 +0,0 @@
|
||||
/// First 64 bytes of the BLAKE2s input during group hash.
|
||||
/// This is chosen to be some random string that we couldn't have anticipated when we designed
|
||||
/// the algorithm, for rigidity purposes.
|
||||
/// We deliberately use an ASCII hex string of 32 bytes here.
|
||||
pub const GH_FIRST_BLOCK: &'static [u8; 64]
|
||||
= b"096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0";
|
||||
|
||||
// BLAKE2s invocation personalizations
|
||||
/// BLAKE2s Personalization for CRH^ivk = BLAKE2s(ak | nk)
|
||||
pub const CRH_IVK_PERSONALIZATION: &'static [u8; 8]
|
||||
= b"Zcashivk";
|
||||
|
||||
/// BLAKE2s Personalization for PRF^nf = BLAKE2s(nk | rho)
|
||||
pub const PRF_NF_PERSONALIZATION: &'static [u8; 8]
|
||||
= b"Zcash_nf";
|
||||
|
||||
// Group hash personalizations
|
||||
/// BLAKE2s Personalization for Pedersen hash generators.
|
||||
pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8]
|
||||
= b"Zcash_PH";
|
||||
|
||||
/// BLAKE2s Personalization for the group hash for key diversification
|
||||
pub const KEY_DIVERSIFICATION_PERSONALIZATION: &'static [u8; 8]
|
||||
= b"Zcash_gd";
|
||||
|
||||
/// BLAKE2s Personalization for the spending key base point
|
||||
pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &'static [u8; 8]
|
||||
= b"Zcash_G_";
|
||||
|
||||
/// BLAKE2s Personalization for the proof generation key base point
|
||||
pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8]
|
||||
= b"Zcash_H_";
|
||||
|
||||
/// BLAKE2s Personalization for the value commitment generator for the value
|
||||
pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &'static [u8; 8]
|
||||
= b"Zcash_cv";
|
||||
|
||||
/// BLAKE2s Personalization for the nullifier position generator (for computing rho)
|
||||
pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &'static [u8; 8]
|
||||
= b"Zcash_J_";
|
@ -1,46 +0,0 @@
|
||||
use jubjub::{
|
||||
JubjubEngine,
|
||||
PrimeOrder,
|
||||
edwards
|
||||
};
|
||||
|
||||
use pairing::{
|
||||
PrimeField
|
||||
};
|
||||
|
||||
use blake2_rfc::blake2s::Blake2s;
|
||||
use constants;
|
||||
|
||||
/// Produces a random point in the Jubjub curve.
|
||||
/// The point is guaranteed to be prime order
|
||||
/// and not the identity.
|
||||
pub fn group_hash<E: JubjubEngine>(
|
||||
tag: &[u8],
|
||||
personalization: &[u8],
|
||||
params: &E::Params
|
||||
) -> Option<edwards::Point<E, PrimeOrder>>
|
||||
{
|
||||
assert_eq!(personalization.len(), 8);
|
||||
|
||||
// Check to see that scalar field is 255 bits
|
||||
assert!(E::Fr::NUM_BITS == 255);
|
||||
|
||||
let mut h = Blake2s::with_params(32, &[], &[], personalization);
|
||||
h.update(constants::GH_FIRST_BLOCK);
|
||||
h.update(tag);
|
||||
let h = h.finalize().as_ref().to_vec();
|
||||
assert!(h.len() == 32);
|
||||
|
||||
match edwards::Point::<E, _>::read(&h[..], params) {
|
||||
Ok(p) => {
|
||||
let p = p.mul_by_cofactor(params);
|
||||
|
||||
if p != edwards::Point::zero() {
|
||||
Some(p)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
Err(_) => None
|
||||
}
|
||||
}
|
@ -1,523 +0,0 @@
|
||||
use pairing::{
|
||||
Field,
|
||||
SqrtField,
|
||||
PrimeField,
|
||||
PrimeFieldRepr,
|
||||
BitIterator
|
||||
};
|
||||
|
||||
use super::{
|
||||
JubjubEngine,
|
||||
JubjubParams,
|
||||
Unknown,
|
||||
PrimeOrder,
|
||||
montgomery
|
||||
};
|
||||
|
||||
use rand::{
|
||||
Rng
|
||||
};
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use std::io::{
|
||||
self,
|
||||
Write,
|
||||
Read
|
||||
};
|
||||
|
||||
// Represents the affine point (X/Z, Y/Z) via the extended
|
||||
// twisted Edwards coordinates.
|
||||
//
|
||||
// See "Twisted Edwards Curves Revisited"
|
||||
// Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson
|
||||
pub struct Point<E: JubjubEngine, Subgroup> {
|
||||
x: E::Fr,
|
||||
y: E::Fr,
|
||||
t: E::Fr,
|
||||
z: E::Fr,
|
||||
_marker: PhantomData<Subgroup>
|
||||
}
|
||||
|
||||
fn convert_subgroup<E: JubjubEngine, S1, S2>(from: &Point<E, S1>) -> Point<E, S2>
|
||||
{
|
||||
Point {
|
||||
x: from.x,
|
||||
y: from.y,
|
||||
t: from.t,
|
||||
z: from.z,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
convert_subgroup(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine, Subgroup> PartialEq for Point<E, Subgroup> {
|
||||
fn eq(&self, other: &Point<E, Subgroup>) -> bool {
|
||||
// p1 = (x1/z1, y1/z1)
|
||||
// p2 = (x2/z2, y2/z2)
|
||||
// Deciding that these two points are equal is a matter of
|
||||
// determining that x1/z1 = x2/z2, or equivalently that
|
||||
// x1*z2 = x2*z1, and similarly for y.
|
||||
|
||||
let mut x1 = self.x;
|
||||
x1.mul_assign(&other.z);
|
||||
|
||||
let mut y1 = self.y;
|
||||
y1.mul_assign(&other.z);
|
||||
|
||||
let mut x2 = other.x;
|
||||
x2.mul_assign(&self.z);
|
||||
|
||||
let mut y2 = other.y;
|
||||
y2.mul_assign(&self.z);
|
||||
|
||||
x1 == x2 && y1 == y2
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> Point<E, Unknown> {
|
||||
pub fn read<R: Read>(
|
||||
reader: R,
|
||||
params: &E::Params
|
||||
) -> io::Result<Self>
|
||||
{
|
||||
let mut y_repr = <E::Fr as PrimeField>::Repr::default();
|
||||
y_repr.read_le(reader)?;
|
||||
|
||||
let x_sign = (y_repr.as_ref()[3] >> 63) == 1;
|
||||
y_repr.as_mut()[3] &= 0x7fffffffffffffff;
|
||||
|
||||
match E::Fr::from_repr(y_repr) {
|
||||
Ok(y) => {
|
||||
match Self::get_for_y(y, x_sign, params) {
|
||||
Some(p) => Ok(p),
|
||||
None => {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve"))
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidInput, "y is not in field"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_for_y(y: E::Fr, sign: bool, params: &E::Params) -> Option<Self>
|
||||
{
|
||||
// Given a y on the curve, x^2 = (y^2 - 1) / (dy^2 + 1)
|
||||
// This is defined for all valid y-coordinates,
|
||||
// as dy^2 + 1 = 0 has no solution in Fr.
|
||||
|
||||
// tmp1 = y^2
|
||||
let mut tmp1 = y;
|
||||
tmp1.square();
|
||||
|
||||
// tmp2 = (y^2 * d) + 1
|
||||
let mut tmp2 = tmp1;
|
||||
tmp2.mul_assign(params.edwards_d());
|
||||
tmp2.add_assign(&E::Fr::one());
|
||||
|
||||
// tmp1 = y^2 - 1
|
||||
tmp1.sub_assign(&E::Fr::one());
|
||||
|
||||
match tmp2.inverse() {
|
||||
Some(tmp2) => {
|
||||
// tmp1 = (y^2 - 1) / (dy^2 + 1)
|
||||
tmp1.mul_assign(&tmp2);
|
||||
|
||||
match tmp1.sqrt() {
|
||||
Some(mut x) => {
|
||||
if x.into_repr().is_odd() != sign {
|
||||
x.negate();
|
||||
}
|
||||
|
||||
let mut t = x;
|
||||
t.mul_assign(&y);
|
||||
|
||||
Some(Point {
|
||||
x: x,
|
||||
y: y,
|
||||
t: t,
|
||||
z: E::Fr::one(),
|
||||
_marker: PhantomData
|
||||
})
|
||||
},
|
||||
None => None
|
||||
}
|
||||
},
|
||||
None => None
|
||||
}
|
||||
}
|
||||
|
||||
/// This guarantees the point is in the prime order subgroup
|
||||
#[must_use]
|
||||
pub fn mul_by_cofactor(&self, params: &E::Params) -> Point<E, PrimeOrder>
|
||||
{
|
||||
let tmp = self.double(params)
|
||||
.double(params)
|
||||
.double(params);
|
||||
|
||||
convert_subgroup(&tmp)
|
||||
}
|
||||
|
||||
pub fn rand<R: Rng>(rng: &mut R, params: &E::Params) -> Self
|
||||
{
|
||||
loop {
|
||||
let y: E::Fr = rng.gen();
|
||||
|
||||
if let Some(p) = Self::get_for_y(y, rng.gen(), params) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
pub fn write<W: Write>(
|
||||
&self,
|
||||
writer: W
|
||||
) -> io::Result<()>
|
||||
{
|
||||
let (x, y) = self.into_xy();
|
||||
|
||||
assert_eq!(E::Fr::NUM_BITS, 255);
|
||||
|
||||
let x_repr = x.into_repr();
|
||||
let mut y_repr = y.into_repr();
|
||||
if x_repr.is_odd() {
|
||||
y_repr.as_mut()[3] |= 0x8000000000000000u64;
|
||||
}
|
||||
|
||||
y_repr.write_le(writer)
|
||||
}
|
||||
|
||||
/// Convert from a Montgomery point
|
||||
pub fn from_montgomery(
|
||||
m: &montgomery::Point<E, Subgroup>,
|
||||
params: &E::Params
|
||||
) -> Self
|
||||
{
|
||||
match m.into_xy() {
|
||||
None => {
|
||||
// Map the point at infinity to the neutral element.
|
||||
Point::zero()
|
||||
},
|
||||
Some((x, y)) => {
|
||||
// The map from a Montgomery curve is defined as:
|
||||
// (x, y) -> (u, v) where
|
||||
// u = x / y
|
||||
// v = (x - 1) / (x + 1)
|
||||
//
|
||||
// This map is not defined for y = 0 and x = -1.
|
||||
//
|
||||
// y = 0 is a valid point only for x = 0:
|
||||
// y^2 = x^3 + A.x^2 + x
|
||||
// 0 = x^3 + A.x^2 + x
|
||||
// 0 = x(x^2 + A.x + 1)
|
||||
// We have: x = 0 OR x^2 + A.x + 1 = 0
|
||||
// x^2 + A.x + 1 = 0
|
||||
// (2.x + A)^2 = A^2 - 4 (Complete the square.)
|
||||
// The left hand side is a square, and so if A^2 - 4
|
||||
// is nonsquare, there is no solution. Indeed, A^2 - 4
|
||||
// is nonsquare.
|
||||
//
|
||||
// (0, 0) is a point of order 2, and so we map it to
|
||||
// (0, -1) in the twisted Edwards curve, which is the
|
||||
// only point of order 2 that is not the neutral element.
|
||||
if y.is_zero() {
|
||||
// This must be the point (0, 0) as above.
|
||||
let mut neg1 = E::Fr::one();
|
||||
neg1.negate();
|
||||
|
||||
Point {
|
||||
x: E::Fr::zero(),
|
||||
y: neg1,
|
||||
t: E::Fr::zero(),
|
||||
z: E::Fr::one(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
} else {
|
||||
// Otherwise, as stated above, the mapping is still
|
||||
// not defined at x = -1. However, x = -1 is not
|
||||
// on the curve when A - 2 is nonsquare:
|
||||
// y^2 = x^3 + A.x^2 + x
|
||||
// y^2 = (-1) + A + (-1)
|
||||
// y^2 = A - 2
|
||||
// Indeed, A - 2 is nonsquare.
|
||||
//
|
||||
// We need to map into (projective) extended twisted
|
||||
// Edwards coordinates (X, Y, T, Z) which represents
|
||||
// the point (X/Z, Y/Z) with Z nonzero and T = XY/Z.
|
||||
//
|
||||
// Thus, we compute...
|
||||
//
|
||||
// u = x(x + 1)
|
||||
// v = y(x - 1)
|
||||
// t = x(x - 1)
|
||||
// z = y(x + 1) (Cannot be nonzero, as above.)
|
||||
//
|
||||
// ... which represents the point ( x / y , (x - 1) / (x + 1) )
|
||||
// as required by the mapping and preserves the property of
|
||||
// the auxiliary coordinate t.
|
||||
//
|
||||
// We need to scale the coordinate, so u and t will have
|
||||
// an extra factor s.
|
||||
|
||||
// u = xs
|
||||
let mut u = x;
|
||||
u.mul_assign(params.scale());
|
||||
|
||||
// v = x - 1
|
||||
let mut v = x;
|
||||
v.sub_assign(&E::Fr::one());
|
||||
|
||||
// t = xs(x - 1)
|
||||
let mut t = u;
|
||||
t.mul_assign(&v);
|
||||
|
||||
// z = (x + 1)
|
||||
let mut z = x;
|
||||
z.add_assign(&E::Fr::one());
|
||||
|
||||
// u = xs(x + 1)
|
||||
u.mul_assign(&z);
|
||||
|
||||
// z = y(x + 1)
|
||||
z.mul_assign(&y);
|
||||
|
||||
// v = y(x - 1)
|
||||
v.mul_assign(&y);
|
||||
|
||||
Point {
|
||||
x: u,
|
||||
y: v,
|
||||
t: t,
|
||||
z: z,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to cast this as a prime order element, failing if it's
|
||||
/// not in the prime order subgroup.
|
||||
pub fn as_prime_order(&self, params: &E::Params) -> Option<Point<E, PrimeOrder>> {
|
||||
if self.mul(E::Fs::char(), params) == Point::zero() {
|
||||
Some(convert_subgroup(self))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zero() -> Self {
|
||||
Point {
|
||||
x: E::Fr::zero(),
|
||||
y: E::Fr::one(),
|
||||
t: E::Fr::zero(),
|
||||
z: E::Fr::one(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_xy(&self) -> (E::Fr, E::Fr)
|
||||
{
|
||||
let zinv = self.z.inverse().unwrap();
|
||||
|
||||
let mut x = self.x;
|
||||
x.mul_assign(&zinv);
|
||||
|
||||
let mut y = self.y;
|
||||
y.mul_assign(&zinv);
|
||||
|
||||
(x, y)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn negate(&self) -> Self {
|
||||
let mut p = self.clone();
|
||||
|
||||
p.x.negate();
|
||||
p.t.negate();
|
||||
|
||||
p
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn double(&self, _: &E::Params) -> Self {
|
||||
// See "Twisted Edwards Curves Revisited"
|
||||
// Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson
|
||||
// Section 3.3
|
||||
// http://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd
|
||||
|
||||
// A = X1^2
|
||||
let mut a = self.x;
|
||||
a.square();
|
||||
|
||||
// B = Y1^2
|
||||
let mut b = self.y;
|
||||
b.square();
|
||||
|
||||
// C = 2*Z1^2
|
||||
let mut c = self.z;
|
||||
c.square();
|
||||
c.double();
|
||||
|
||||
// D = a*A
|
||||
// = -A
|
||||
let mut d = a;
|
||||
d.negate();
|
||||
|
||||
// E = (X1+Y1)^2 - A - B
|
||||
let mut e = self.x;
|
||||
e.add_assign(&self.y);
|
||||
e.square();
|
||||
e.add_assign(&d); // -A = D
|
||||
e.sub_assign(&b);
|
||||
|
||||
// G = D+B
|
||||
let mut g = d;
|
||||
g.add_assign(&b);
|
||||
|
||||
// F = G-C
|
||||
let mut f = g;
|
||||
f.sub_assign(&c);
|
||||
|
||||
// H = D-B
|
||||
let mut h = d;
|
||||
h.sub_assign(&b);
|
||||
|
||||
// X3 = E*F
|
||||
let mut x3 = e;
|
||||
x3.mul_assign(&f);
|
||||
|
||||
// Y3 = G*H
|
||||
let mut y3 = g;
|
||||
y3.mul_assign(&h);
|
||||
|
||||
// T3 = E*H
|
||||
let mut t3 = e;
|
||||
t3.mul_assign(&h);
|
||||
|
||||
// Z3 = F*G
|
||||
let mut z3 = f;
|
||||
z3.mul_assign(&g);
|
||||
|
||||
Point {
|
||||
x: x3,
|
||||
y: y3,
|
||||
t: t3,
|
||||
z: z3,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn add(&self, other: &Self, params: &E::Params) -> Self
|
||||
{
|
||||
// See "Twisted Edwards Curves Revisited"
|
||||
// Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson
|
||||
// 3.1 Unified Addition in E^e
|
||||
|
||||
// A = x1 * x2
|
||||
let mut a = self.x;
|
||||
a.mul_assign(&other.x);
|
||||
|
||||
// B = y1 * y2
|
||||
let mut b = self.y;
|
||||
b.mul_assign(&other.y);
|
||||
|
||||
// C = d * t1 * t2
|
||||
let mut c = params.edwards_d().clone();
|
||||
c.mul_assign(&self.t);
|
||||
c.mul_assign(&other.t);
|
||||
|
||||
// D = z1 * z2
|
||||
let mut d = self.z;
|
||||
d.mul_assign(&other.z);
|
||||
|
||||
// H = B - aA
|
||||
// = B + A
|
||||
let mut h = b;
|
||||
h.add_assign(&a);
|
||||
|
||||
// E = (x1 + y1) * (x2 + y2) - A - B
|
||||
// = (x1 + y1) * (x2 + y2) - H
|
||||
let mut e = self.x;
|
||||
e.add_assign(&self.y);
|
||||
{
|
||||
let mut tmp = other.x;
|
||||
tmp.add_assign(&other.y);
|
||||
e.mul_assign(&tmp);
|
||||
}
|
||||
e.sub_assign(&h);
|
||||
|
||||
// F = D - C
|
||||
let mut f = d;
|
||||
f.sub_assign(&c);
|
||||
|
||||
// G = D + C
|
||||
let mut g = d;
|
||||
g.add_assign(&c);
|
||||
|
||||
// x3 = E * F
|
||||
let mut x3 = e;
|
||||
x3.mul_assign(&f);
|
||||
|
||||
// y3 = G * H
|
||||
let mut y3 = g;
|
||||
y3.mul_assign(&h);
|
||||
|
||||
// t3 = E * H
|
||||
let mut t3 = e;
|
||||
t3.mul_assign(&h);
|
||||
|
||||
// z3 = F * G
|
||||
let mut z3 = f;
|
||||
z3.mul_assign(&g);
|
||||
|
||||
Point {
|
||||
x: x3,
|
||||
y: y3,
|
||||
t: t3,
|
||||
z: z3,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn mul<S: Into<<E::Fs as PrimeField>::Repr>>(
|
||||
&self,
|
||||
scalar: S,
|
||||
params: &E::Params
|
||||
) -> Self
|
||||
{
|
||||
// Standard double-and-add scalar multiplication
|
||||
|
||||
let mut res = Self::zero();
|
||||
|
||||
for b in BitIterator::new(scalar.into()) {
|
||||
res = res.double(params);
|
||||
|
||||
if b {
|
||||
res = res.add(self, params);
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,435 +0,0 @@
|
||||
//! Jubjub is a twisted Edwards curve defined over the BLS12-381 scalar
|
||||
//! field, Fr. It takes the form `-x^2 + y^2 = 1 + dx^2y^2` with
|
||||
//! `d = -(10240/10241)`. It is birationally equivalent to a Montgomery
|
||||
//! curve of the form `y^2 = x^3 + Ax^2 + x` with `A = 40962`. This
|
||||
//! value `A` is the smallest integer choice such that:
|
||||
//!
|
||||
//! * `(A - 2) / 4` is a small integer (`10240`).
|
||||
//! * `A^2 - 4` is quadratic nonresidue.
|
||||
//! * The group order of the curve and its quadratic twist has a large
|
||||
//! prime factor.
|
||||
//!
|
||||
//! Jubjub has `s = 0x0e7db4ea6533afa906673b0101343b00a6682093ccc81082d0970e5ed6f72cb7`
|
||||
//! as the prime subgroup order, with cofactor 8. (The twist has
|
||||
//! cofactor 4.)
|
||||
//!
|
||||
//! It is a complete twisted Edwards curve, so the equivalence with
|
||||
//! the Montgomery curve forms a group isomorphism, allowing points
|
||||
//! to be freely converted between the two forms.
|
||||
|
||||
use pairing::{
|
||||
Engine,
|
||||
Field,
|
||||
PrimeField,
|
||||
SqrtField
|
||||
};
|
||||
|
||||
use group_hash::group_hash;
|
||||
|
||||
use constants;
|
||||
|
||||
use pairing::bls12_381::{
|
||||
Bls12,
|
||||
Fr
|
||||
};
|
||||
|
||||
/// This is an implementation of the twisted Edwards Jubjub curve.
|
||||
pub mod edwards;
|
||||
|
||||
/// This is an implementation of the birationally equivalent
|
||||
/// Montgomery curve.
|
||||
pub mod montgomery;
|
||||
|
||||
/// This is an implementation of the scalar field for Jubjub.
|
||||
pub mod fs;
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests;
|
||||
|
||||
/// Point of unknown order.
|
||||
pub enum Unknown { }
|
||||
|
||||
/// Point of prime order.
|
||||
pub enum PrimeOrder { }
|
||||
|
||||
/// Fixed generators of the Jubjub curve of unknown
|
||||
/// exponent.
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum FixedGenerators {
|
||||
/// The prover will demonstrate knowledge of discrete log
|
||||
/// with respect to this base when they are constructing
|
||||
/// a proof, in order to authorize proof construction.
|
||||
ProofGenerationKey = 0,
|
||||
|
||||
/// The note commitment is randomized over this generator.
|
||||
NoteCommitmentRandomness = 1,
|
||||
|
||||
/// The node commitment is randomized again by the position
|
||||
/// in order to supply the nullifier computation with a
|
||||
/// unique input w.r.t. the note being spent, to prevent
|
||||
/// Faerie gold attacks.
|
||||
NullifierPosition = 2,
|
||||
|
||||
/// The value commitment is used to check balance between
|
||||
/// inputs and outputs. The value is placed over this
|
||||
/// generator.
|
||||
ValueCommitmentValue = 3,
|
||||
/// The value commitment is randomized over this generator,
|
||||
/// for privacy.
|
||||
ValueCommitmentRandomness = 4,
|
||||
|
||||
/// The spender proves discrete log with respect to this
|
||||
/// base at spend time.
|
||||
SpendingKeyGenerator = 5,
|
||||
|
||||
Max = 6
|
||||
}
|
||||
|
||||
pub trait ToUniform {
|
||||
fn to_uniform(digest: &[u8]) -> Self;
|
||||
}
|
||||
|
||||
/// This is an extension to the pairing Engine trait which
|
||||
/// offers a scalar field for the embedded curve (Jubjub)
|
||||
/// and some pre-computed parameters.
|
||||
pub trait JubjubEngine: Engine {
|
||||
/// The scalar field of the Jubjub curve
|
||||
type Fs: PrimeField + SqrtField + ToUniform;
|
||||
/// The parameters of Jubjub and the Sapling protocol
|
||||
type Params: JubjubParams<Self>;
|
||||
}
|
||||
|
||||
/// The pre-computed parameters for Jubjub, including curve
|
||||
/// constants and various limits and window tables.
|
||||
pub trait JubjubParams<E: JubjubEngine>: Sized {
|
||||
/// The `d` constant of the twisted Edwards curve.
|
||||
fn edwards_d(&self) -> &E::Fr;
|
||||
/// The `A` constant of the birationally equivalent Montgomery curve.
|
||||
fn montgomery_a(&self) -> &E::Fr;
|
||||
/// The `A` constant, doubled.
|
||||
fn montgomery_2a(&self) -> &E::Fr;
|
||||
/// The scaling factor used for conversion from the Montgomery form.
|
||||
fn scale(&self) -> &E::Fr;
|
||||
/// Returns the generators (for each segment) used in all Pedersen commitments.
|
||||
fn pedersen_hash_generators(&self) -> &[edwards::Point<E, PrimeOrder>];
|
||||
/// Returns the exp table for Pedersen hashes.
|
||||
fn pedersen_hash_exp_table(&self) -> &[Vec<Vec<edwards::Point<E, PrimeOrder>>>];
|
||||
/// Returns the maximum number of chunks per segment of the Pedersen hash.
|
||||
fn pedersen_hash_chunks_per_generator(&self) -> usize;
|
||||
/// Returns the pre-computed window tables [-4, 3, 2, 1, 1, 2, 3, 4] of different
|
||||
/// magnitudes of the Pedersen hash segment generators.
|
||||
fn pedersen_circuit_generators(&self) -> &[Vec<Vec<(E::Fr, E::Fr)>>];
|
||||
|
||||
/// Returns the number of chunks needed to represent a full scalar during fixed-base
|
||||
/// exponentiation.
|
||||
fn fixed_base_chunks_per_generator(&self) -> usize;
|
||||
/// Returns a fixed generator.
|
||||
fn generator(&self, base: FixedGenerators) -> &edwards::Point<E, PrimeOrder>;
|
||||
/// Returns a window table [0, 1, ..., 8] for different magnitudes of some
|
||||
/// fixed generator.
|
||||
fn circuit_generators(&self, FixedGenerators) -> &[Vec<(E::Fr, E::Fr)>];
|
||||
/// Returns the window size for exponentiation of Pedersen hash generators
|
||||
/// outside the circuit
|
||||
fn pedersen_hash_exp_window_size() -> u32;
|
||||
}
|
||||
|
||||
impl JubjubEngine for Bls12 {
|
||||
type Fs = self::fs::Fs;
|
||||
type Params = JubjubBls12;
|
||||
}
|
||||
|
||||
pub struct JubjubBls12 {
|
||||
edwards_d: Fr,
|
||||
montgomery_a: Fr,
|
||||
montgomery_2a: Fr,
|
||||
scale: Fr,
|
||||
|
||||
pedersen_hash_generators: Vec<edwards::Point<Bls12, PrimeOrder>>,
|
||||
pedersen_hash_exp: Vec<Vec<Vec<edwards::Point<Bls12, PrimeOrder>>>>,
|
||||
pedersen_circuit_generators: Vec<Vec<Vec<(Fr, Fr)>>>,
|
||||
|
||||
fixed_base_generators: Vec<edwards::Point<Bls12, PrimeOrder>>,
|
||||
fixed_base_circuit_generators: Vec<Vec<Vec<(Fr, Fr)>>>,
|
||||
}
|
||||
|
||||
impl JubjubParams<Bls12> for JubjubBls12 {
|
||||
fn edwards_d(&self) -> &Fr { &self.edwards_d }
|
||||
fn montgomery_a(&self) -> &Fr { &self.montgomery_a }
|
||||
fn montgomery_2a(&self) -> &Fr { &self.montgomery_2a }
|
||||
fn scale(&self) -> &Fr { &self.scale }
|
||||
fn pedersen_hash_generators(&self) -> &[edwards::Point<Bls12, PrimeOrder>] {
|
||||
&self.pedersen_hash_generators
|
||||
}
|
||||
fn pedersen_hash_exp_table(&self) -> &[Vec<Vec<edwards::Point<Bls12, PrimeOrder>>>] {
|
||||
&self.pedersen_hash_exp
|
||||
}
|
||||
fn pedersen_hash_chunks_per_generator(&self) -> usize {
|
||||
63
|
||||
}
|
||||
fn fixed_base_chunks_per_generator(&self) -> usize {
|
||||
84
|
||||
}
|
||||
fn pedersen_circuit_generators(&self) -> &[Vec<Vec<(Fr, Fr)>>] {
|
||||
&self.pedersen_circuit_generators
|
||||
}
|
||||
fn generator(&self, base: FixedGenerators) -> &edwards::Point<Bls12, PrimeOrder>
|
||||
{
|
||||
&self.fixed_base_generators[base as usize]
|
||||
}
|
||||
fn circuit_generators(&self, base: FixedGenerators) -> &[Vec<(Fr, Fr)>]
|
||||
{
|
||||
&self.fixed_base_circuit_generators[base as usize][..]
|
||||
}
|
||||
fn pedersen_hash_exp_window_size() -> u32 {
|
||||
8
|
||||
}
|
||||
}
|
||||
|
||||
impl JubjubBls12 {
|
||||
pub fn new() -> Self {
|
||||
let montgomery_a = Fr::from_str("40962").unwrap();
|
||||
let mut montgomery_2a = montgomery_a;
|
||||
montgomery_2a.double();
|
||||
|
||||
let mut tmp_params = JubjubBls12 {
|
||||
// d = -(10240/10241)
|
||||
edwards_d: Fr::from_str("19257038036680949359750312669786877991949435402254120286184196891950884077233").unwrap(),
|
||||
// A = 40962
|
||||
montgomery_a: montgomery_a,
|
||||
// 2A = 2.A
|
||||
montgomery_2a: montgomery_2a,
|
||||
// scaling factor = sqrt(4 / (a - d))
|
||||
scale: Fr::from_str("17814886934372412843466061268024708274627479829237077604635722030778476050649").unwrap(),
|
||||
|
||||
// We'll initialize these below
|
||||
pedersen_hash_generators: vec![],
|
||||
pedersen_hash_exp: vec![],
|
||||
pedersen_circuit_generators: vec![],
|
||||
fixed_base_generators: vec![],
|
||||
fixed_base_circuit_generators: vec![],
|
||||
};
|
||||
|
||||
fn find_group_hash<E: JubjubEngine>(
|
||||
m: &[u8],
|
||||
personalization: &[u8; 8],
|
||||
params: &E::Params
|
||||
) -> edwards::Point<E, PrimeOrder>
|
||||
{
|
||||
let mut tag = m.to_vec();
|
||||
let i = tag.len();
|
||||
tag.push(0u8);
|
||||
|
||||
loop {
|
||||
let gh = group_hash(
|
||||
&tag,
|
||||
personalization,
|
||||
params
|
||||
);
|
||||
|
||||
// We don't want to overflow and start reusing generators
|
||||
assert!(tag[i] != u8::max_value());
|
||||
tag[i] += 1;
|
||||
|
||||
if let Some(gh) = gh {
|
||||
break gh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the bases for the Pedersen hashes
|
||||
{
|
||||
let mut pedersen_hash_generators = vec![];
|
||||
|
||||
for m in 0..5 {
|
||||
use byteorder::{WriteBytesExt, LittleEndian};
|
||||
|
||||
let mut segment_number = [0u8; 4];
|
||||
(&mut segment_number[0..4]).write_u32::<LittleEndian>(m).unwrap();
|
||||
|
||||
pedersen_hash_generators.push(
|
||||
find_group_hash(
|
||||
&segment_number,
|
||||
constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION,
|
||||
&tmp_params
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Check for duplicates, far worse than spec inconsistencies!
|
||||
for (i, p1) in pedersen_hash_generators.iter().enumerate() {
|
||||
if p1 == &edwards::Point::zero() {
|
||||
panic!("Neutral element!");
|
||||
}
|
||||
|
||||
for p2 in pedersen_hash_generators.iter().skip(i+1) {
|
||||
if p1 == p2 {
|
||||
panic!("Duplicate generator!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tmp_params.pedersen_hash_generators = pedersen_hash_generators;
|
||||
}
|
||||
|
||||
// Create the exp table for the Pedersen hash generators
|
||||
{
|
||||
let mut pedersen_hash_exp = vec![];
|
||||
|
||||
for g in &tmp_params.pedersen_hash_generators {
|
||||
let mut g = g.clone();
|
||||
|
||||
let window = JubjubBls12::pedersen_hash_exp_window_size();
|
||||
|
||||
let mut tables = vec![];
|
||||
|
||||
let mut num_bits = 0;
|
||||
while num_bits <= fs::Fs::NUM_BITS {
|
||||
let mut table = Vec::with_capacity(1 << window);
|
||||
|
||||
let mut base = edwards::Point::zero();
|
||||
|
||||
for _ in 0..(1 << window) {
|
||||
table.push(base.clone());
|
||||
base = base.add(&g, &tmp_params);
|
||||
}
|
||||
|
||||
tables.push(table);
|
||||
num_bits += window;
|
||||
|
||||
for _ in 0..window {
|
||||
g = g.double(&tmp_params);
|
||||
}
|
||||
}
|
||||
|
||||
pedersen_hash_exp.push(tables);
|
||||
}
|
||||
|
||||
tmp_params.pedersen_hash_exp = pedersen_hash_exp;
|
||||
}
|
||||
|
||||
// Create the bases for other parts of the protocol
|
||||
{
|
||||
let mut fixed_base_generators = vec![edwards::Point::zero(); FixedGenerators::Max as usize];
|
||||
|
||||
fixed_base_generators[FixedGenerators::ProofGenerationKey as usize] =
|
||||
find_group_hash(&[], constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION, &tmp_params);
|
||||
|
||||
fixed_base_generators[FixedGenerators::NoteCommitmentRandomness as usize] =
|
||||
find_group_hash(b"r", constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, &tmp_params);
|
||||
|
||||
fixed_base_generators[FixedGenerators::NullifierPosition as usize] =
|
||||
find_group_hash(&[], constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION, &tmp_params);
|
||||
|
||||
fixed_base_generators[FixedGenerators::ValueCommitmentValue as usize] =
|
||||
find_group_hash(b"v", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params);
|
||||
|
||||
fixed_base_generators[FixedGenerators::ValueCommitmentRandomness as usize] =
|
||||
find_group_hash(b"r", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params);
|
||||
|
||||
fixed_base_generators[FixedGenerators::SpendingKeyGenerator as usize] =
|
||||
find_group_hash(&[], constants::SPENDING_KEY_GENERATOR_PERSONALIZATION, &tmp_params);
|
||||
|
||||
// Check for duplicates, far worse than spec inconsistencies!
|
||||
for (i, p1) in fixed_base_generators.iter().enumerate() {
|
||||
if p1 == &edwards::Point::zero() {
|
||||
panic!("Neutral element!");
|
||||
}
|
||||
|
||||
for p2 in fixed_base_generators.iter().skip(i+1) {
|
||||
if p1 == p2 {
|
||||
panic!("Duplicate generator!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tmp_params.fixed_base_generators = fixed_base_generators;
|
||||
}
|
||||
|
||||
// Create the 2-bit window table lookups for each 4-bit
|
||||
// "chunk" in each segment of the Pedersen hash
|
||||
{
|
||||
let mut pedersen_circuit_generators = vec![];
|
||||
|
||||
// Process each segment
|
||||
for mut gen in tmp_params.pedersen_hash_generators.iter().cloned() {
|
||||
let mut gen = montgomery::Point::from_edwards(&gen, &tmp_params);
|
||||
let mut windows = vec![];
|
||||
for _ in 0..tmp_params.pedersen_hash_chunks_per_generator() {
|
||||
// Create (x, y) coeffs for this chunk
|
||||
let mut coeffs = vec![];
|
||||
let mut g = gen.clone();
|
||||
|
||||
// coeffs = g, g*2, g*3, g*4
|
||||
for _ in 0..4 {
|
||||
coeffs.push(g.into_xy().expect("cannot produce O"));
|
||||
g = g.add(&gen, &tmp_params);
|
||||
}
|
||||
windows.push(coeffs);
|
||||
|
||||
// Our chunks are separated by 2 bits to prevent overlap.
|
||||
for _ in 0..4 {
|
||||
gen = gen.double(&tmp_params);
|
||||
}
|
||||
}
|
||||
pedersen_circuit_generators.push(windows);
|
||||
}
|
||||
|
||||
tmp_params.pedersen_circuit_generators = pedersen_circuit_generators;
|
||||
}
|
||||
|
||||
// Create the 3-bit window table lookups for fixed-base
|
||||
// exp of each base in the protocol.
|
||||
{
|
||||
let mut fixed_base_circuit_generators = vec![];
|
||||
|
||||
for mut gen in tmp_params.fixed_base_generators.iter().cloned() {
|
||||
let mut windows = vec![];
|
||||
for _ in 0..tmp_params.fixed_base_chunks_per_generator() {
|
||||
let mut coeffs = vec![(Fr::zero(), Fr::one())];
|
||||
let mut g = gen.clone();
|
||||
for _ in 0..7 {
|
||||
coeffs.push(g.into_xy());
|
||||
g = g.add(&gen, &tmp_params);
|
||||
}
|
||||
windows.push(coeffs);
|
||||
|
||||
// gen = gen * 8
|
||||
gen = g;
|
||||
}
|
||||
fixed_base_circuit_generators.push(windows);
|
||||
}
|
||||
|
||||
tmp_params.fixed_base_circuit_generators = fixed_base_circuit_generators;
|
||||
}
|
||||
|
||||
tmp_params
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_jubjub_bls12() {
|
||||
let params = JubjubBls12::new();
|
||||
|
||||
tests::test_suite::<Bls12>(¶ms);
|
||||
|
||||
let test_repr = hex!("9d12b88b08dcbef8a11ee0712d94cb236ee2f4ca17317075bfafc82ce3139d31");
|
||||
let p = edwards::Point::<Bls12, _>::read(&test_repr[..], ¶ms).unwrap();
|
||||
let q = edwards::Point::<Bls12, _>::get_for_y(
|
||||
Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(),
|
||||
false,
|
||||
¶ms
|
||||
).unwrap();
|
||||
|
||||
assert!(p == q);
|
||||
|
||||
// Same thing, but sign bit set
|
||||
let test_repr = hex!("9d12b88b08dcbef8a11ee0712d94cb236ee2f4ca17317075bfafc82ce3139db1");
|
||||
let p = edwards::Point::<Bls12, _>::read(&test_repr[..], ¶ms).unwrap();
|
||||
let q = edwards::Point::<Bls12, _>::get_for_y(
|
||||
Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(),
|
||||
true,
|
||||
¶ms
|
||||
).unwrap();
|
||||
|
||||
assert!(p == q);
|
||||
}
|
@ -1,358 +0,0 @@
|
||||
use pairing::{
|
||||
Field,
|
||||
SqrtField,
|
||||
PrimeField,
|
||||
PrimeFieldRepr,
|
||||
BitIterator
|
||||
};
|
||||
|
||||
use super::{
|
||||
JubjubEngine,
|
||||
JubjubParams,
|
||||
Unknown,
|
||||
PrimeOrder,
|
||||
edwards
|
||||
};
|
||||
|
||||
use rand::{
|
||||
Rng
|
||||
};
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// Represents the affine point (X, Y)
|
||||
pub struct Point<E: JubjubEngine, Subgroup> {
|
||||
x: E::Fr,
|
||||
y: E::Fr,
|
||||
infinity: bool,
|
||||
_marker: PhantomData<Subgroup>
|
||||
}
|
||||
|
||||
fn convert_subgroup<E: JubjubEngine, S1, S2>(from: &Point<E, S1>) -> Point<E, S2>
|
||||
{
|
||||
Point {
|
||||
x: from.x,
|
||||
y: from.y,
|
||||
infinity: from.infinity,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
convert_subgroup(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine, Subgroup> PartialEq for Point<E, Subgroup> {
|
||||
fn eq(&self, other: &Point<E, Subgroup>) -> bool {
|
||||
match (self.infinity, other.infinity) {
|
||||
(true, true) => true,
|
||||
(true, false) | (false, true) => false,
|
||||
(false, false) => {
|
||||
self.x == other.x && self.y == other.y
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> Point<E, Unknown> {
|
||||
pub fn get_for_x(x: E::Fr, sign: bool, params: &E::Params) -> Option<Self>
|
||||
{
|
||||
// Given an x on the curve, y = sqrt(x^3 + A*x^2 + x)
|
||||
|
||||
let mut x2 = x;
|
||||
x2.square();
|
||||
|
||||
let mut rhs = x2;
|
||||
rhs.mul_assign(params.montgomery_a());
|
||||
rhs.add_assign(&x);
|
||||
x2.mul_assign(&x);
|
||||
rhs.add_assign(&x2);
|
||||
|
||||
match rhs.sqrt() {
|
||||
Some(mut y) => {
|
||||
if y.into_repr().is_odd() != sign {
|
||||
y.negate();
|
||||
}
|
||||
|
||||
return Some(Point {
|
||||
x: x,
|
||||
y: y,
|
||||
infinity: false,
|
||||
_marker: PhantomData
|
||||
})
|
||||
},
|
||||
None => None
|
||||
}
|
||||
}
|
||||
|
||||
/// This guarantees the point is in the prime order subgroup
|
||||
#[must_use]
|
||||
pub fn mul_by_cofactor(&self, params: &E::Params) -> Point<E, PrimeOrder>
|
||||
{
|
||||
let tmp = self.double(params)
|
||||
.double(params)
|
||||
.double(params);
|
||||
|
||||
convert_subgroup(&tmp)
|
||||
}
|
||||
|
||||
pub fn rand<R: Rng>(rng: &mut R, params: &E::Params) -> Self
|
||||
{
|
||||
loop {
|
||||
let x: E::Fr = rng.gen();
|
||||
|
||||
match Self::get_for_x(x, rng.gen(), params) {
|
||||
Some(p) => {
|
||||
return p
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
/// Convert from an Edwards point
|
||||
pub fn from_edwards(
|
||||
e: &edwards::Point<E, Subgroup>,
|
||||
params: &E::Params
|
||||
) -> Self
|
||||
{
|
||||
let (x, y) = e.into_xy();
|
||||
|
||||
if y == E::Fr::one() {
|
||||
// The only solution for y = 1 is x = 0. (0, 1) is
|
||||
// the neutral element, so we map this to the point
|
||||
// at infinity.
|
||||
|
||||
Point::zero()
|
||||
} else {
|
||||
// The map from a twisted Edwards curve is defined as
|
||||
// (x, y) -> (u, v) where
|
||||
// u = (1 + y) / (1 - y)
|
||||
// v = u / x
|
||||
//
|
||||
// This mapping is not defined for y = 1 and for x = 0.
|
||||
//
|
||||
// We have that y != 1 above. If x = 0, the only
|
||||
// solutions for y are 1 (contradiction) or -1.
|
||||
if x.is_zero() {
|
||||
// (0, -1) is the point of order two which is not
|
||||
// the neutral element, so we map it to (0, 0) which is
|
||||
// the only affine point of order 2.
|
||||
|
||||
Point {
|
||||
x: E::Fr::zero(),
|
||||
y: E::Fr::zero(),
|
||||
infinity: false,
|
||||
_marker: PhantomData
|
||||
}
|
||||
} else {
|
||||
// The mapping is defined as above.
|
||||
//
|
||||
// (x, y) -> (u, v) where
|
||||
// u = (1 + y) / (1 - y)
|
||||
// v = u / x
|
||||
|
||||
let mut u = E::Fr::one();
|
||||
u.add_assign(&y);
|
||||
{
|
||||
let mut tmp = E::Fr::one();
|
||||
tmp.sub_assign(&y);
|
||||
u.mul_assign(&tmp.inverse().unwrap())
|
||||
}
|
||||
|
||||
let mut v = u;
|
||||
v.mul_assign(&x.inverse().unwrap());
|
||||
|
||||
// Scale it into the correct curve constants
|
||||
v.mul_assign(params.scale());
|
||||
|
||||
Point {
|
||||
x: u,
|
||||
y: v,
|
||||
infinity: false,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to cast this as a prime order element, failing if it's
|
||||
/// not in the prime order subgroup.
|
||||
pub fn as_prime_order(&self, params: &E::Params) -> Option<Point<E, PrimeOrder>> {
|
||||
if self.mul(E::Fs::char(), params) == Point::zero() {
|
||||
Some(convert_subgroup(self))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zero() -> Self {
|
||||
Point {
|
||||
x: E::Fr::zero(),
|
||||
y: E::Fr::zero(),
|
||||
infinity: true,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_xy(&self) -> Option<(E::Fr, E::Fr)>
|
||||
{
|
||||
if self.infinity {
|
||||
None
|
||||
} else {
|
||||
Some((self.x, self.y))
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn negate(&self) -> Self {
|
||||
let mut p = self.clone();
|
||||
|
||||
p.y.negate();
|
||||
|
||||
p
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn double(&self, params: &E::Params) -> Self {
|
||||
if self.infinity {
|
||||
return Point::zero();
|
||||
}
|
||||
|
||||
// (0, 0) is the point of order 2. Doubling
|
||||
// produces the point at infinity.
|
||||
if self.y == E::Fr::zero() {
|
||||
return Point::zero();
|
||||
}
|
||||
|
||||
// This is a standard affine point doubling formula
|
||||
// See 4.3.2 The group law for Weierstrass curves
|
||||
// Montgomery curves and the Montgomery Ladder
|
||||
// Daniel J. Bernstein and Tanja Lange
|
||||
|
||||
let mut delta = E::Fr::one();
|
||||
{
|
||||
let mut tmp = params.montgomery_a().clone();
|
||||
tmp.mul_assign(&self.x);
|
||||
tmp.double();
|
||||
delta.add_assign(&tmp);
|
||||
}
|
||||
{
|
||||
let mut tmp = self.x;
|
||||
tmp.square();
|
||||
delta.add_assign(&tmp);
|
||||
tmp.double();
|
||||
delta.add_assign(&tmp);
|
||||
}
|
||||
{
|
||||
let mut tmp = self.y;
|
||||
tmp.double();
|
||||
delta.mul_assign(&tmp.inverse().expect("y is nonzero so this must be nonzero"));
|
||||
}
|
||||
|
||||
let mut x3 = delta;
|
||||
x3.square();
|
||||
x3.sub_assign(params.montgomery_a());
|
||||
x3.sub_assign(&self.x);
|
||||
x3.sub_assign(&self.x);
|
||||
|
||||
let mut y3 = x3;
|
||||
y3.sub_assign(&self.x);
|
||||
y3.mul_assign(&delta);
|
||||
y3.add_assign(&self.y);
|
||||
y3.negate();
|
||||
|
||||
Point {
|
||||
x: x3,
|
||||
y: y3,
|
||||
infinity: false,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn add(&self, other: &Self, params: &E::Params) -> Self
|
||||
{
|
||||
// This is a standard affine point addition formula
|
||||
// See 4.3.2 The group law for Weierstrass curves
|
||||
// Montgomery curves and the Montgomery Ladder
|
||||
// Daniel J. Bernstein and Tanja Lange
|
||||
|
||||
match (self.infinity, other.infinity) {
|
||||
(true, true) => Point::zero(),
|
||||
(true, false) => other.clone(),
|
||||
(false, true) => self.clone(),
|
||||
(false, false) => {
|
||||
if self.x == other.x {
|
||||
if self.y == other.y {
|
||||
self.double(params)
|
||||
} else {
|
||||
Point::zero()
|
||||
}
|
||||
} else {
|
||||
let mut delta = other.y;
|
||||
delta.sub_assign(&self.y);
|
||||
{
|
||||
let mut tmp = other.x;
|
||||
tmp.sub_assign(&self.x);
|
||||
delta.mul_assign(&tmp.inverse().expect("self.x != other.x, so this must be nonzero"));
|
||||
}
|
||||
|
||||
let mut x3 = delta;
|
||||
x3.square();
|
||||
x3.sub_assign(params.montgomery_a());
|
||||
x3.sub_assign(&self.x);
|
||||
x3.sub_assign(&other.x);
|
||||
|
||||
let mut y3 = x3;
|
||||
y3.sub_assign(&self.x);
|
||||
y3.mul_assign(&delta);
|
||||
y3.add_assign(&self.y);
|
||||
y3.negate();
|
||||
|
||||
Point {
|
||||
x: x3,
|
||||
y: y3,
|
||||
infinity: false,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn mul<S: Into<<E::Fs as PrimeField>::Repr>>(
|
||||
&self,
|
||||
scalar: S,
|
||||
params: &E::Params
|
||||
) -> Self
|
||||
{
|
||||
// Standard double-and-add scalar multiplication
|
||||
|
||||
let mut res = Self::zero();
|
||||
|
||||
for b in BitIterator::new(scalar.into()) {
|
||||
res = res.double(params);
|
||||
|
||||
if b {
|
||||
res = res.add(self, params);
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
@ -1,416 +0,0 @@
|
||||
use super::{
|
||||
JubjubEngine,
|
||||
JubjubParams,
|
||||
PrimeOrder,
|
||||
montgomery,
|
||||
edwards
|
||||
};
|
||||
|
||||
use pairing::{
|
||||
Field,
|
||||
PrimeField,
|
||||
PrimeFieldRepr,
|
||||
SqrtField,
|
||||
LegendreSymbol
|
||||
};
|
||||
|
||||
use rand::{XorShiftRng, SeedableRng, Rand};
|
||||
|
||||
pub fn test_suite<E: JubjubEngine>(params: &E::Params) {
|
||||
test_back_and_forth::<E>(params);
|
||||
test_jubjub_params::<E>(params);
|
||||
test_rand::<E>(params);
|
||||
test_get_for::<E>(params);
|
||||
test_identities::<E>(params);
|
||||
test_addition_associativity::<E>(params);
|
||||
test_order::<E>(params);
|
||||
test_mul_associativity::<E>(params);
|
||||
test_loworder::<E>(params);
|
||||
test_read_write::<E>(params);
|
||||
}
|
||||
|
||||
fn is_on_mont_curve<E: JubjubEngine, P: JubjubParams<E>>(
|
||||
x: E::Fr,
|
||||
y: E::Fr,
|
||||
params: &P
|
||||
) -> bool
|
||||
{
|
||||
let mut lhs = y;
|
||||
lhs.square();
|
||||
|
||||
let mut x2 = x;
|
||||
x2.square();
|
||||
|
||||
let mut x3 = x2;
|
||||
x3.mul_assign(&x);
|
||||
|
||||
let mut rhs = x2;
|
||||
rhs.mul_assign(params.montgomery_a());
|
||||
rhs.add_assign(&x);
|
||||
rhs.add_assign(&x3);
|
||||
|
||||
lhs == rhs
|
||||
}
|
||||
|
||||
fn is_on_twisted_edwards_curve<E: JubjubEngine, P: JubjubParams<E>>(
|
||||
x: E::Fr,
|
||||
y: E::Fr,
|
||||
params: &P
|
||||
) -> bool
|
||||
{
|
||||
let mut x2 = x;
|
||||
x2.square();
|
||||
|
||||
let mut y2 = y;
|
||||
y2.square();
|
||||
|
||||
// -x^2 + y^2
|
||||
let mut lhs = y2;
|
||||
lhs.sub_assign(&x2);
|
||||
|
||||
// 1 + d x^2 y^2
|
||||
let mut rhs = y2;
|
||||
rhs.mul_assign(&x2);
|
||||
rhs.mul_assign(params.edwards_d());
|
||||
rhs.add_assign(&E::Fr::one());
|
||||
|
||||
lhs == rhs
|
||||
}
|
||||
|
||||
fn test_loworder<E: JubjubEngine>(params: &E::Params) {
|
||||
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
let inf = montgomery::Point::zero();
|
||||
|
||||
// try to find a point of order 8
|
||||
let p = loop {
|
||||
let r = montgomery::Point::<E, _>::rand(rng, params).mul(E::Fs::char(), params);
|
||||
|
||||
let r2 = r.double(params);
|
||||
let r4 = r2.double(params);
|
||||
let r8 = r4.double(params);
|
||||
|
||||
if r2 != inf && r4 != inf && r8 == inf {
|
||||
break r;
|
||||
}
|
||||
};
|
||||
|
||||
let mut loworder_points = vec![];
|
||||
{
|
||||
let mut tmp = p.clone();
|
||||
|
||||
for _ in 0..8 {
|
||||
assert!(!loworder_points.contains(&tmp));
|
||||
loworder_points.push(tmp.clone());
|
||||
tmp = tmp.add(&p, params);
|
||||
}
|
||||
}
|
||||
assert!(loworder_points[7] == inf);
|
||||
}
|
||||
|
||||
fn test_mul_associativity<E: JubjubEngine>(params: &E::Params) {
|
||||
use self::edwards::Point;
|
||||
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..100 {
|
||||
// Pick a random point and multiply it by the cofactor
|
||||
let base = Point::<E, _>::rand(rng, params).mul_by_cofactor(params);
|
||||
|
||||
let mut a = E::Fs::rand(rng);
|
||||
let b = E::Fs::rand(rng);
|
||||
let c = E::Fs::rand(rng);
|
||||
|
||||
let res1 = base.mul(a, params).mul(b, params).mul(c, params);
|
||||
let res2 = base.mul(b, params).mul(c, params).mul(a, params);
|
||||
let res3 = base.mul(c, params).mul(a, params).mul(b, params);
|
||||
a.mul_assign(&b);
|
||||
a.mul_assign(&c);
|
||||
let res4 = base.mul(a, params);
|
||||
|
||||
assert!(res1 == res2);
|
||||
assert!(res2 == res3);
|
||||
assert!(res3 == res4);
|
||||
|
||||
let (x, y) = res1.into_xy();
|
||||
assert!(is_on_twisted_edwards_curve(x, y, params));
|
||||
|
||||
let (x, y) = res2.into_xy();
|
||||
assert!(is_on_twisted_edwards_curve(x, y, params));
|
||||
|
||||
let (x, y) = res3.into_xy();
|
||||
assert!(is_on_twisted_edwards_curve(x, y, params));
|
||||
}
|
||||
}
|
||||
|
||||
fn test_order<E: JubjubEngine>(params: &E::Params) {
|
||||
use self::edwards::Point;
|
||||
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
// The neutral element is in the prime order subgroup.
|
||||
assert!(Point::<E, PrimeOrder>::zero().as_prime_order(params).is_some());
|
||||
|
||||
for _ in 0..50 {
|
||||
// Pick a random point and multiply it by the cofactor
|
||||
let base = Point::<E, _>::rand(rng, params).mul_by_cofactor(params);
|
||||
|
||||
// Any point multiplied by the cofactor will be in the prime
|
||||
// order subgroup
|
||||
assert!(base.as_prime_order(params).is_some());
|
||||
}
|
||||
|
||||
// It's very likely that at least one out of 50 random points on the curve
|
||||
// is not in the prime order subgroup.
|
||||
let mut at_least_one_not_in_prime_order_subgroup = false;
|
||||
for _ in 0..50 {
|
||||
// Pick a random point.
|
||||
let base = Point::<E, _>::rand(rng, params);
|
||||
|
||||
at_least_one_not_in_prime_order_subgroup |= base.as_prime_order(params).is_none();
|
||||
}
|
||||
assert!(at_least_one_not_in_prime_order_subgroup);
|
||||
}
|
||||
|
||||
fn test_addition_associativity<E: JubjubEngine>(params: &E::Params) {
|
||||
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
use self::montgomery::Point;
|
||||
|
||||
let a = Point::<E, _>::rand(rng, params);
|
||||
let b = Point::<E, _>::rand(rng, params);
|
||||
let c = Point::<E, _>::rand(rng, params);
|
||||
|
||||
assert!(a.add(&b, ¶ms).add(&c, ¶ms) == c.add(&a, ¶ms).add(&b, ¶ms));
|
||||
}
|
||||
|
||||
for _ in 0..1000 {
|
||||
use self::edwards::Point;
|
||||
|
||||
let a = Point::<E, _>::rand(rng, params);
|
||||
let b = Point::<E, _>::rand(rng, params);
|
||||
let c = Point::<E, _>::rand(rng, params);
|
||||
|
||||
assert!(a.add(&b, ¶ms).add(&c, ¶ms) == c.add(&a, ¶ms).add(&b, ¶ms));
|
||||
}
|
||||
}
|
||||
|
||||
fn test_identities<E: JubjubEngine>(params: &E::Params) {
|
||||
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
{
|
||||
use self::edwards::Point;
|
||||
|
||||
let z = Point::<E, PrimeOrder>::zero();
|
||||
assert!(z.double(¶ms) == z);
|
||||
assert!(z.negate() == z);
|
||||
|
||||
for _ in 0..100 {
|
||||
let r = Point::<E, _>::rand(rng, params);
|
||||
|
||||
assert!(r.add(&Point::zero(), ¶ms) == r);
|
||||
assert!(r.add(&r.negate(), ¶ms) == Point::zero());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
use self::montgomery::Point;
|
||||
|
||||
let z = Point::<E, PrimeOrder>::zero();
|
||||
assert!(z.double(¶ms) == z);
|
||||
assert!(z.negate() == z);
|
||||
|
||||
for _ in 0..100 {
|
||||
let r = Point::<E, _>::rand(rng, params);
|
||||
|
||||
assert!(r.add(&Point::zero(), ¶ms) == r);
|
||||
assert!(r.add(&r.negate(), ¶ms) == Point::zero());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_get_for<E: JubjubEngine>(params: &E::Params) {
|
||||
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let y = E::Fr::rand(rng);
|
||||
let sign = bool::rand(rng);
|
||||
|
||||
if let Some(mut p) = edwards::Point::<E, _>::get_for_y(y, sign, params) {
|
||||
assert!(p.into_xy().0.into_repr().is_odd() == sign);
|
||||
p = p.negate();
|
||||
assert!(
|
||||
edwards::Point::<E, _>::get_for_y(y, !sign, params).unwrap()
|
||||
==
|
||||
p
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_read_write<E: JubjubEngine>(params: &E::Params) {
|
||||
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let e = edwards::Point::<E, _>::rand(rng, params);
|
||||
|
||||
let mut v = vec![];
|
||||
e.write(&mut v).unwrap();
|
||||
|
||||
let e2 = edwards::Point::read(&v[..], params).unwrap();
|
||||
|
||||
assert!(e == e2);
|
||||
}
|
||||
}
|
||||
|
||||
fn test_rand<E: JubjubEngine>(params: &E::Params) {
|
||||
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let p = montgomery::Point::<E, _>::rand(rng, params);
|
||||
let e = edwards::Point::<E, _>::rand(rng, params);
|
||||
|
||||
{
|
||||
let (x, y) = p.into_xy().unwrap();
|
||||
assert!(is_on_mont_curve(x, y, params));
|
||||
}
|
||||
|
||||
{
|
||||
let (x, y) = e.into_xy();
|
||||
assert!(is_on_twisted_edwards_curve(x, y, params));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_back_and_forth<E: JubjubEngine>(params: &E::Params) {
|
||||
let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let s = E::Fs::rand(rng);
|
||||
let edwards_p1 = edwards::Point::<E, _>::rand(rng, params);
|
||||
let mont_p1 = montgomery::Point::from_edwards(&edwards_p1, params);
|
||||
let mont_p2 = montgomery::Point::<E, _>::rand(rng, params);
|
||||
let edwards_p2 = edwards::Point::from_montgomery(&mont_p2, params);
|
||||
|
||||
let mont = mont_p1.add(&mont_p2, params).mul(s, params);
|
||||
let edwards = edwards_p1.add(&edwards_p2, params).mul(s, params);
|
||||
|
||||
assert!(
|
||||
montgomery::Point::from_edwards(&edwards, params) == mont
|
||||
);
|
||||
|
||||
assert!(
|
||||
edwards::Point::from_montgomery(&mont, params) == edwards
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn test_jubjub_params<E: JubjubEngine>(params: &E::Params) {
|
||||
// a = -1
|
||||
let mut a = E::Fr::one();
|
||||
a.negate();
|
||||
|
||||
{
|
||||
// Check that 2A is consistent with A
|
||||
let mut tmp = *params.montgomery_a();
|
||||
tmp.double();
|
||||
|
||||
assert_eq!(&tmp, params.montgomery_2a());
|
||||
}
|
||||
|
||||
{
|
||||
// The twisted Edwards addition law is complete when d is nonsquare
|
||||
// and a is square.
|
||||
|
||||
assert!(params.edwards_d().legendre() == LegendreSymbol::QuadraticNonResidue);
|
||||
assert!(a.legendre() == LegendreSymbol::QuadraticResidue);
|
||||
}
|
||||
|
||||
{
|
||||
// Other convenient sanity checks regarding d
|
||||
|
||||
// tmp = d
|
||||
let mut tmp = *params.edwards_d();
|
||||
|
||||
// 1 / d is nonsquare
|
||||
assert!(tmp.inverse().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue);
|
||||
|
||||
// tmp = -d
|
||||
tmp.negate();
|
||||
|
||||
// -d is nonsquare
|
||||
assert!(tmp.legendre() == LegendreSymbol::QuadraticNonResidue);
|
||||
|
||||
// 1 / -d is nonsquare
|
||||
assert!(tmp.inverse().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue);
|
||||
}
|
||||
|
||||
{
|
||||
// Check that A^2 - 4 is nonsquare:
|
||||
let mut tmp = params.montgomery_a().clone();
|
||||
tmp.square();
|
||||
tmp.sub_assign(&E::Fr::from_str("4").unwrap());
|
||||
assert!(tmp.legendre() == LegendreSymbol::QuadraticNonResidue);
|
||||
}
|
||||
|
||||
{
|
||||
// Check that A - 2 is nonsquare:
|
||||
let mut tmp = params.montgomery_a().clone();
|
||||
tmp.sub_assign(&E::Fr::from_str("2").unwrap());
|
||||
assert!(tmp.legendre() == LegendreSymbol::QuadraticNonResidue);
|
||||
}
|
||||
|
||||
{
|
||||
// Check the validity of the scaling factor
|
||||
let mut tmp = a;
|
||||
tmp.sub_assign(¶ms.edwards_d());
|
||||
tmp = tmp.inverse().unwrap();
|
||||
tmp.mul_assign(&E::Fr::from_str("4").unwrap());
|
||||
tmp = tmp.sqrt().unwrap();
|
||||
assert_eq!(&tmp, params.scale());
|
||||
}
|
||||
|
||||
{
|
||||
// Check that the number of windows per generator
|
||||
// in the Pedersen hash does not allow for collisions
|
||||
|
||||
let mut cur = E::Fs::one().into_repr();
|
||||
|
||||
let mut max = E::Fs::char();
|
||||
{
|
||||
max.sub_noborrow(&E::Fs::one().into_repr());
|
||||
max.div2();
|
||||
}
|
||||
|
||||
let mut pacc = E::Fs::zero().into_repr();
|
||||
let mut nacc = E::Fs::char();
|
||||
|
||||
for _ in 0..params.pedersen_hash_chunks_per_generator()
|
||||
{
|
||||
// tmp = cur * 4
|
||||
let mut tmp = cur;
|
||||
tmp.mul2();
|
||||
tmp.mul2();
|
||||
|
||||
pacc.add_nocarry(&tmp);
|
||||
nacc.sub_noborrow(&tmp);
|
||||
|
||||
assert!(pacc < max);
|
||||
assert!(pacc < nacc);
|
||||
|
||||
// cur = cur * 16
|
||||
for _ in 0..4 {
|
||||
cur.mul2();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Check that the number of windows for fixed-base
|
||||
// scalar multiplication is sufficient for all scalars.
|
||||
|
||||
assert!(params.fixed_base_chunks_per_generator() * 3 >= E::Fs::NUM_BITS as usize);
|
||||
|
||||
// ... and that it's *just* efficient enough.
|
||||
|
||||
assert!((params.fixed_base_chunks_per_generator() - 1) * 3 < E::Fs::NUM_BITS as usize);
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
extern crate pairing;
|
||||
extern crate bellman;
|
||||
extern crate blake2_rfc;
|
||||
extern crate digest;
|
||||
extern crate rand;
|
||||
extern crate byteorder;
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate hex_literal;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate crypto;
|
||||
|
||||
pub mod jubjub;
|
||||
pub mod group_hash;
|
||||
pub mod circuit;
|
||||
pub mod pedersen_hash;
|
||||
pub mod primitives;
|
||||
pub mod constants;
|
||||
pub mod redjubjub;
|
||||
pub mod util;
|
@ -1,103 +0,0 @@
|
||||
use jubjub::*;
|
||||
use pairing::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Personalization {
|
||||
NoteCommitment,
|
||||
MerkleTree(usize)
|
||||
}
|
||||
|
||||
impl Personalization {
|
||||
pub fn get_bits(&self) -> Vec<bool> {
|
||||
match *self {
|
||||
Personalization::NoteCommitment =>
|
||||
vec![true, true, true, true, true, true],
|
||||
Personalization::MerkleTree(num) => {
|
||||
assert!(num < 63);
|
||||
|
||||
(0..6).map(|i| (num >> i) & 1 == 1).collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pedersen_hash<E, I>(
|
||||
personalization: Personalization,
|
||||
bits: I,
|
||||
params: &E::Params
|
||||
) -> edwards::Point<E, PrimeOrder>
|
||||
where I: IntoIterator<Item=bool>,
|
||||
E: JubjubEngine
|
||||
{
|
||||
let mut bits = personalization.get_bits().into_iter().chain(bits.into_iter());
|
||||
|
||||
let mut result = edwards::Point::zero();
|
||||
let mut generators = params.pedersen_hash_exp_table().iter();
|
||||
|
||||
loop {
|
||||
let mut acc = E::Fs::zero();
|
||||
let mut cur = E::Fs::one();
|
||||
let mut chunks_remaining = params.pedersen_hash_chunks_per_generator();
|
||||
let mut encountered_bits = false;
|
||||
|
||||
// Grab three bits from the input
|
||||
while let Some(a) = bits.next() {
|
||||
encountered_bits = true;
|
||||
|
||||
let b = bits.next().unwrap_or(false);
|
||||
let c = bits.next().unwrap_or(false);
|
||||
|
||||
// Start computing this portion of the scalar
|
||||
let mut tmp = cur;
|
||||
if a {
|
||||
tmp.add_assign(&cur);
|
||||
}
|
||||
cur.double(); // 2^1 * cur
|
||||
if b {
|
||||
tmp.add_assign(&cur);
|
||||
}
|
||||
|
||||
// conditionally negate
|
||||
if c {
|
||||
tmp.negate();
|
||||
}
|
||||
|
||||
acc.add_assign(&tmp);
|
||||
|
||||
chunks_remaining -= 1;
|
||||
|
||||
if chunks_remaining == 0 {
|
||||
break;
|
||||
} else {
|
||||
cur.double(); // 2^2 * cur
|
||||
cur.double(); // 2^3 * cur
|
||||
cur.double(); // 2^4 * cur
|
||||
}
|
||||
}
|
||||
|
||||
if !encountered_bits {
|
||||
break;
|
||||
}
|
||||
|
||||
let mut table: &[Vec<edwards::Point<E, _>>] = &generators.next().expect("we don't have enough generators");
|
||||
let window = JubjubBls12::pedersen_hash_exp_window_size();
|
||||
let window_mask = (1 << window) - 1;
|
||||
|
||||
let mut acc = acc.into_repr();
|
||||
|
||||
let mut tmp = edwards::Point::zero();
|
||||
|
||||
while !acc.is_zero() {
|
||||
let i = (acc.as_ref()[0] & window_mask) as usize;
|
||||
|
||||
tmp = tmp.add(&table[0][i], params);
|
||||
|
||||
acc.shr(window);
|
||||
table = &table[1..];
|
||||
}
|
||||
|
||||
result = result.add(&tmp, params);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
@ -1,258 +0,0 @@
|
||||
use pairing::{
|
||||
Field,
|
||||
PrimeField,
|
||||
PrimeFieldRepr
|
||||
};
|
||||
|
||||
use constants;
|
||||
|
||||
use group_hash::group_hash;
|
||||
|
||||
use pedersen_hash::{
|
||||
pedersen_hash,
|
||||
Personalization
|
||||
};
|
||||
|
||||
use byteorder::{
|
||||
LittleEndian,
|
||||
WriteBytesExt
|
||||
};
|
||||
|
||||
use jubjub::{
|
||||
JubjubEngine,
|
||||
JubjubParams,
|
||||
edwards,
|
||||
PrimeOrder,
|
||||
FixedGenerators
|
||||
};
|
||||
|
||||
use blake2_rfc::blake2s::Blake2s;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ValueCommitment<E: JubjubEngine> {
|
||||
pub value: u64,
|
||||
pub randomness: E::Fs
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> ValueCommitment<E> {
|
||||
pub fn cm(
|
||||
&self,
|
||||
params: &E::Params
|
||||
) -> edwards::Point<E, PrimeOrder>
|
||||
{
|
||||
params.generator(FixedGenerators::ValueCommitmentValue)
|
||||
.mul(self.value, params)
|
||||
.add(
|
||||
¶ms.generator(FixedGenerators::ValueCommitmentRandomness)
|
||||
.mul(self.randomness, params),
|
||||
params
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ProofGenerationKey<E: JubjubEngine> {
|
||||
pub ak: edwards::Point<E, PrimeOrder>,
|
||||
pub nsk: E::Fs
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> ProofGenerationKey<E> {
|
||||
pub fn into_viewing_key(&self, params: &E::Params) -> ViewingKey<E> {
|
||||
ViewingKey {
|
||||
ak: self.ak.clone(),
|
||||
nk: params.generator(FixedGenerators::ProofGenerationKey)
|
||||
.mul(self.nsk, params)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ViewingKey<E: JubjubEngine> {
|
||||
pub ak: edwards::Point<E, PrimeOrder>,
|
||||
pub nk: edwards::Point<E, PrimeOrder>
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> ViewingKey<E> {
|
||||
pub fn rk(
|
||||
&self,
|
||||
ar: E::Fs,
|
||||
params: &E::Params
|
||||
) -> edwards::Point<E, PrimeOrder> {
|
||||
self.ak.add(
|
||||
¶ms.generator(FixedGenerators::SpendingKeyGenerator)
|
||||
.mul(ar, params),
|
||||
params
|
||||
)
|
||||
}
|
||||
|
||||
pub fn ivk(&self) -> E::Fs {
|
||||
let mut preimage = [0; 64];
|
||||
|
||||
self.ak.write(&mut preimage[0..32]).unwrap();
|
||||
self.nk.write(&mut preimage[32..64]).unwrap();
|
||||
|
||||
let mut h = Blake2s::with_params(32, &[], &[], constants::CRH_IVK_PERSONALIZATION);
|
||||
h.update(&preimage);
|
||||
let mut h = h.finalize().as_ref().to_vec();
|
||||
|
||||
// Drop the most significant five bits, so it can be interpreted as a scalar.
|
||||
h[31] &= 0b0000_0111;
|
||||
|
||||
let mut e = <E::Fs as PrimeField>::Repr::default();
|
||||
e.read_le(&h[..]).unwrap();
|
||||
|
||||
E::Fs::from_repr(e).expect("should be a valid scalar")
|
||||
}
|
||||
|
||||
pub fn into_payment_address(
|
||||
&self,
|
||||
diversifier: Diversifier,
|
||||
params: &E::Params
|
||||
) -> Option<PaymentAddress<E>>
|
||||
{
|
||||
diversifier.g_d(params).map(|g_d| {
|
||||
let pk_d = g_d.mul(self.ivk(), params);
|
||||
|
||||
PaymentAddress {
|
||||
pk_d: pk_d,
|
||||
diversifier: diversifier
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Diversifier(pub [u8; 11]);
|
||||
|
||||
impl Diversifier {
|
||||
pub fn g_d<E: JubjubEngine>(
|
||||
&self,
|
||||
params: &E::Params
|
||||
) -> Option<edwards::Point<E, PrimeOrder>>
|
||||
{
|
||||
group_hash::<E>(&self.0, constants::KEY_DIVERSIFICATION_PERSONALIZATION, params)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PaymentAddress<E: JubjubEngine> {
|
||||
pub pk_d: edwards::Point<E, PrimeOrder>,
|
||||
pub diversifier: Diversifier
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> PaymentAddress<E> {
|
||||
pub fn g_d(
|
||||
&self,
|
||||
params: &E::Params
|
||||
) -> Option<edwards::Point<E, PrimeOrder>>
|
||||
{
|
||||
self.diversifier.g_d(params)
|
||||
}
|
||||
|
||||
pub fn create_note(
|
||||
&self,
|
||||
value: u64,
|
||||
randomness: E::Fs,
|
||||
params: &E::Params
|
||||
) -> Option<Note<E>>
|
||||
{
|
||||
self.g_d(params).map(|g_d| {
|
||||
Note {
|
||||
value: value,
|
||||
r: randomness,
|
||||
g_d: g_d,
|
||||
pk_d: self.pk_d.clone()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Note<E: JubjubEngine> {
|
||||
/// The value of the note
|
||||
pub value: u64,
|
||||
/// The diversified base of the address, GH(d)
|
||||
pub g_d: edwards::Point<E, PrimeOrder>,
|
||||
/// The public key of the address, g_d^ivk
|
||||
pub pk_d: edwards::Point<E, PrimeOrder>,
|
||||
/// The commitment randomness
|
||||
pub r: E::Fs
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> Note<E> {
|
||||
pub fn uncommitted() -> E::Fr {
|
||||
// The smallest u-coordinate that is not on the curve
|
||||
// is one.
|
||||
// TODO: This should be relocated to JubjubEngine as
|
||||
// it's specific to the curve we're using, not all
|
||||
// twisted edwards curves.
|
||||
E::Fr::one()
|
||||
}
|
||||
|
||||
/// Computes the note commitment, returning the full point.
|
||||
fn cm_full_point(&self, params: &E::Params) -> edwards::Point<E, PrimeOrder>
|
||||
{
|
||||
// Calculate the note contents, as bytes
|
||||
let mut note_contents = vec![];
|
||||
|
||||
// Writing the value in little endian
|
||||
(&mut note_contents).write_u64::<LittleEndian>(self.value).unwrap();
|
||||
|
||||
// Write g_d
|
||||
self.g_d.write(&mut note_contents).unwrap();
|
||||
|
||||
// Write pk_d
|
||||
self.pk_d.write(&mut note_contents).unwrap();
|
||||
|
||||
assert_eq!(note_contents.len(), 32 + 32 + 8);
|
||||
|
||||
// Compute the Pedersen hash of the note contents
|
||||
let hash_of_contents = pedersen_hash(
|
||||
Personalization::NoteCommitment,
|
||||
note_contents.into_iter()
|
||||
.flat_map(|byte| {
|
||||
(0..8).map(move |i| ((byte >> i) & 1) == 1)
|
||||
}),
|
||||
params
|
||||
);
|
||||
|
||||
// Compute final commitment
|
||||
params.generator(FixedGenerators::NoteCommitmentRandomness)
|
||||
.mul(self.r, params)
|
||||
.add(&hash_of_contents, params)
|
||||
}
|
||||
|
||||
/// Computes the nullifier given the viewing key and
|
||||
/// note position
|
||||
pub fn nf(
|
||||
&self,
|
||||
viewing_key: &ViewingKey<E>,
|
||||
position: u64,
|
||||
params: &E::Params
|
||||
) -> Vec<u8>
|
||||
{
|
||||
// Compute rho = cm + position.G
|
||||
let rho = self
|
||||
.cm_full_point(params)
|
||||
.add(
|
||||
¶ms.generator(FixedGenerators::NullifierPosition)
|
||||
.mul(position, params),
|
||||
params
|
||||
);
|
||||
|
||||
// Compute nf = BLAKE2s(nk | rho)
|
||||
let mut nf_preimage = [0u8; 64];
|
||||
viewing_key.nk.write(&mut nf_preimage[0..32]).unwrap();
|
||||
rho.write(&mut nf_preimage[32..64]).unwrap();
|
||||
let mut h = Blake2s::with_params(32, &[], &[], constants::PRF_NF_PERSONALIZATION);
|
||||
h.update(&nf_preimage);
|
||||
|
||||
h.finalize().as_ref().to_vec()
|
||||
}
|
||||
|
||||
/// Computes the note commitment
|
||||
pub fn cm(&self, params: &E::Params) -> E::Fr
|
||||
{
|
||||
// The commitment is in the prime order subgroup, so mapping the
|
||||
// commitment to the x-coordinate is an injective encoding.
|
||||
self.cm_full_point(params).into_xy().0
|
||||
}
|
||||
}
|
@ -1,343 +0,0 @@
|
||||
//! Implementation of RedJubjub, a specialization of RedDSA to the Jubjub curve.
|
||||
//! See section 5.4.6 of the Sapling protocol specification.
|
||||
|
||||
use pairing::{Field, PrimeField, PrimeFieldRepr};
|
||||
use rand::{Rng, Rand};
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use jubjub::{FixedGenerators, JubjubEngine, JubjubParams, Unknown, edwards::Point};
|
||||
use util::{hash_to_scalar};
|
||||
|
||||
fn read_scalar<E: JubjubEngine, R: Read>(reader: R) -> io::Result<E::Fs> {
|
||||
let mut s_repr = <E::Fs as PrimeField>::Repr::default();
|
||||
s_repr.read_le(reader)?;
|
||||
|
||||
match E::Fs::from_repr(s_repr) {
|
||||
Ok(s) => Ok(s),
|
||||
Err(_) => Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"scalar is not in field",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_scalar<E: JubjubEngine, W: Write>(s: &E::Fs, writer: W) -> io::Result<()> {
|
||||
s.into_repr().write_le(writer)
|
||||
}
|
||||
|
||||
fn h_star<E: JubjubEngine>(a: &[u8], b: &[u8]) -> E::Fs {
|
||||
hash_to_scalar::<E>(b"Zcash_RedJubjubH", a, b)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Signature {
|
||||
rbar: [u8; 32],
|
||||
sbar: [u8; 32],
|
||||
}
|
||||
|
||||
pub struct PrivateKey<E: JubjubEngine>(pub E::Fs);
|
||||
|
||||
pub struct PublicKey<E: JubjubEngine>(pub Point<E, Unknown>);
|
||||
|
||||
impl Signature {
|
||||
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||
let mut rbar = [0u8; 32];
|
||||
let mut sbar = [0u8; 32];
|
||||
reader.read_exact(&mut rbar)?;
|
||||
reader.read_exact(&mut sbar)?;
|
||||
Ok(Signature { rbar, sbar })
|
||||
}
|
||||
|
||||
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||
writer.write_all(&self.rbar)?;
|
||||
writer.write_all(&self.sbar)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> PrivateKey<E> {
|
||||
pub fn randomize(&self, alpha: E::Fs) -> Self {
|
||||
let mut tmp = self.0;
|
||||
tmp.add_assign(&alpha);
|
||||
PrivateKey(tmp)
|
||||
}
|
||||
|
||||
pub fn read<R: Read>(reader: R) -> io::Result<Self> {
|
||||
let pk = read_scalar::<E, R>(reader)?;
|
||||
Ok(PrivateKey(pk))
|
||||
}
|
||||
|
||||
pub fn write<W: Write>(&self, writer: W) -> io::Result<()> {
|
||||
write_scalar::<E, W>(&self.0, writer)
|
||||
}
|
||||
|
||||
pub fn sign<R: Rng>(
|
||||
&self,
|
||||
msg: &[u8],
|
||||
rng: &mut R,
|
||||
p_g: FixedGenerators,
|
||||
params: &E::Params,
|
||||
) -> Signature {
|
||||
// T = (l_H + 128) bits of randomness
|
||||
// For H*, l_H = 512 bits
|
||||
let mut t = [0u8; 80];
|
||||
rng.fill_bytes(&mut t[..]);
|
||||
|
||||
// r = H*(T || M)
|
||||
let r = h_star::<E>(&t[..], msg);
|
||||
|
||||
// R = r . P_G
|
||||
let r_g = params.generator(p_g).mul(r, params);
|
||||
let mut rbar = [0u8; 32];
|
||||
r_g.write(&mut rbar[..])
|
||||
.expect("Jubjub points should serialize to 32 bytes");
|
||||
|
||||
// S = r + H*(Rbar || M) . sk
|
||||
let mut s = h_star::<E>(&rbar[..], msg);
|
||||
s.mul_assign(&self.0);
|
||||
s.add_assign(&r);
|
||||
let mut sbar = [0u8; 32];
|
||||
write_scalar::<E, &mut [u8]>(&s, &mut sbar[..])
|
||||
.expect("Jubjub scalars should serialize to 32 bytes");
|
||||
|
||||
Signature { rbar, sbar }
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> PublicKey<E> {
|
||||
pub fn from_private(privkey: &PrivateKey<E>, p_g: FixedGenerators, params: &E::Params) -> Self {
|
||||
let res = params.generator(p_g).mul(privkey.0, params).into();
|
||||
PublicKey(res)
|
||||
}
|
||||
|
||||
pub fn randomize(&self, alpha: E::Fs, p_g: FixedGenerators, params: &E::Params) -> Self {
|
||||
let res: Point<E, Unknown> = params.generator(p_g).mul(alpha, params).into();
|
||||
let res = res.add(&self.0, params);
|
||||
PublicKey(res)
|
||||
}
|
||||
|
||||
pub fn read<R: Read>(reader: R, params: &E::Params) -> io::Result<Self> {
|
||||
let p = Point::read(reader, params)?;
|
||||
Ok(PublicKey(p))
|
||||
}
|
||||
|
||||
pub fn write<W: Write>(&self, writer: W) -> io::Result<()> {
|
||||
self.0.write(writer)
|
||||
}
|
||||
|
||||
pub fn verify(
|
||||
&self,
|
||||
msg: &[u8],
|
||||
sig: &Signature,
|
||||
p_g: FixedGenerators,
|
||||
params: &E::Params,
|
||||
) -> bool {
|
||||
// c = H*(Rbar || M)
|
||||
let c = h_star::<E>(&sig.rbar[..], msg);
|
||||
|
||||
// Signature checks:
|
||||
// R != invalid
|
||||
let r = match Point::read(&sig.rbar[..], params) {
|
||||
Ok(r) => r,
|
||||
Err(_) => return false,
|
||||
};
|
||||
// S < order(G)
|
||||
// (E::Fs guarantees its representation is in the field)
|
||||
let s = match read_scalar::<E, &[u8]>(&sig.sbar[..]) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return false,
|
||||
};
|
||||
// 0 = h_G(-S . P_G + R + c . vk)
|
||||
self.0.mul(c, params).add(&r, params).add(
|
||||
¶ms.generator(p_g).mul(s, params).negate().into(),
|
||||
params
|
||||
).mul_by_cofactor(params).eq(&Point::zero())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BatchEntry<'a, E: JubjubEngine> {
|
||||
vk: PublicKey<E>,
|
||||
msg: &'a [u8],
|
||||
sig: Signature,
|
||||
}
|
||||
|
||||
// TODO: #82: This is a naive implementation currently,
|
||||
// and doesn't use multiexp.
|
||||
pub fn batch_verify<'a, E: JubjubEngine, R: Rng>(
|
||||
rng: &mut R,
|
||||
batch: &[BatchEntry<'a, E>],
|
||||
p_g: FixedGenerators,
|
||||
params: &E::Params,
|
||||
) -> bool
|
||||
{
|
||||
let mut acc = Point::<E, Unknown>::zero();
|
||||
|
||||
for entry in batch {
|
||||
let mut r = match Point::<E, Unknown>::read(&entry.sig.rbar[..], params) {
|
||||
Ok(r) => r,
|
||||
Err(_) => return false,
|
||||
};
|
||||
let mut s = match read_scalar::<E, &[u8]>(&entry.sig.sbar[..]) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
let mut c = h_star::<E>(&entry.sig.rbar[..], entry.msg);
|
||||
|
||||
let z = E::Fs::rand(rng);
|
||||
|
||||
s.mul_assign(&z);
|
||||
s.negate();
|
||||
|
||||
r = r.mul(z, params);
|
||||
|
||||
c.mul_assign(&z);
|
||||
|
||||
acc = acc.add(&r, params);
|
||||
acc = acc.add(&entry.vk.0.mul(c, params), params);
|
||||
acc = acc.add(¶ms.generator(p_g).mul(s, params).into(), params);
|
||||
}
|
||||
|
||||
acc = acc.mul_by_cofactor(params).into();
|
||||
|
||||
acc.eq(&Point::zero())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pairing::bls12_381::Bls12;
|
||||
use rand::thread_rng;
|
||||
|
||||
use jubjub::{JubjubBls12, fs::Fs, edwards};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_batch_verify() {
|
||||
let rng = &mut thread_rng();
|
||||
let params = &JubjubBls12::new();
|
||||
let p_g = FixedGenerators::SpendingKeyGenerator;
|
||||
|
||||
let sk1 = PrivateKey::<Bls12>(rng.gen());
|
||||
let vk1 = PublicKey::from_private(&sk1, p_g, params);
|
||||
let msg1 = b"Foo bar";
|
||||
let sig1 = sk1.sign(msg1, rng, p_g, params);
|
||||
assert!(vk1.verify(msg1, &sig1, p_g, params));
|
||||
|
||||
let sk2 = PrivateKey::<Bls12>(rng.gen());
|
||||
let vk2 = PublicKey::from_private(&sk2, p_g, params);
|
||||
let msg2 = b"Foo bar";
|
||||
let sig2 = sk2.sign(msg2, rng, p_g, params);
|
||||
assert!(vk2.verify(msg2, &sig2, p_g, params));
|
||||
|
||||
let mut batch = vec![
|
||||
BatchEntry { vk: vk1, msg: msg1, sig: sig1 },
|
||||
BatchEntry { vk: vk2, msg: msg2, sig: sig2 }
|
||||
];
|
||||
|
||||
assert!(batch_verify(rng, &batch, p_g, params));
|
||||
|
||||
batch[0].sig = sig2;
|
||||
|
||||
assert!(!batch_verify(rng, &batch, p_g, params));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cofactor_check() {
|
||||
let rng = &mut thread_rng();
|
||||
let params = &JubjubBls12::new();
|
||||
let zero = edwards::Point::zero();
|
||||
let p_g = FixedGenerators::SpendingKeyGenerator;
|
||||
|
||||
// Get a point of order 8
|
||||
let p8 = loop {
|
||||
let r = edwards::Point::<Bls12, _>::rand(rng, params).mul(Fs::char(), params);
|
||||
|
||||
let r2 = r.double(params);
|
||||
let r4 = r2.double(params);
|
||||
let r8 = r4.double(params);
|
||||
|
||||
if r2 != zero && r4 != zero && r8 == zero {
|
||||
break r;
|
||||
}
|
||||
};
|
||||
|
||||
let sk = PrivateKey::<Bls12>(rng.gen());
|
||||
let vk = PublicKey::from_private(&sk, p_g, params);
|
||||
|
||||
// TODO: This test will need to change when #77 is fixed
|
||||
let msg = b"Foo bar";
|
||||
let sig = sk.sign(msg, rng, p_g, params);
|
||||
assert!(vk.verify(msg, &sig, p_g, params));
|
||||
|
||||
let vktorsion = PublicKey(vk.0.add(&p8, params));
|
||||
assert!(vktorsion.verify(msg, &sig, p_g, params));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_serialization() {
|
||||
let rng = &mut thread_rng();
|
||||
let p_g = FixedGenerators::SpendingKeyGenerator;
|
||||
let params = &JubjubBls12::new();
|
||||
|
||||
for _ in 0..1000 {
|
||||
let sk = PrivateKey::<Bls12>(rng.gen());
|
||||
let vk = PublicKey::from_private(&sk, p_g, params);
|
||||
let msg = b"Foo bar";
|
||||
let sig = sk.sign(msg, rng, p_g, params);
|
||||
|
||||
let mut sk_bytes = [0u8; 32];
|
||||
let mut vk_bytes = [0u8; 32];
|
||||
let mut sig_bytes = [0u8; 64];
|
||||
sk.write(&mut sk_bytes[..]).unwrap();
|
||||
vk.write(&mut vk_bytes[..]).unwrap();
|
||||
sig.write(&mut sig_bytes[..]).unwrap();
|
||||
|
||||
let sk_2 = PrivateKey::<Bls12>::read(&sk_bytes[..]).unwrap();
|
||||
let vk_2 = PublicKey::from_private(&sk_2, p_g, params);
|
||||
let mut vk_2_bytes = [0u8; 32];
|
||||
vk_2.write(&mut vk_2_bytes[..]).unwrap();
|
||||
assert!(vk_bytes == vk_2_bytes);
|
||||
|
||||
let vk_2 = PublicKey::<Bls12>::read(&vk_bytes[..], params).unwrap();
|
||||
let sig_2 = Signature::read(&sig_bytes[..]).unwrap();
|
||||
assert!(vk.verify(msg, &sig_2, p_g, params));
|
||||
assert!(vk_2.verify(msg, &sig, p_g, params));
|
||||
assert!(vk_2.verify(msg, &sig_2, p_g, params));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_signatures() {
|
||||
let rng = &mut thread_rng();
|
||||
let p_g = FixedGenerators::SpendingKeyGenerator;
|
||||
let params = &JubjubBls12::new();
|
||||
|
||||
for _ in 0..1000 {
|
||||
let sk = PrivateKey::<Bls12>(rng.gen());
|
||||
let vk = PublicKey::from_private(&sk, p_g, params);
|
||||
|
||||
let msg1 = b"Foo bar";
|
||||
let msg2 = b"Spam eggs";
|
||||
|
||||
let sig1 = sk.sign(msg1, rng, p_g, params);
|
||||
let sig2 = sk.sign(msg2, rng, p_g, params);
|
||||
|
||||
assert!(vk.verify(msg1, &sig1, p_g, params));
|
||||
assert!(vk.verify(msg2, &sig2, p_g, params));
|
||||
assert!(!vk.verify(msg1, &sig2, p_g, params));
|
||||
assert!(!vk.verify(msg2, &sig1, p_g, params));
|
||||
|
||||
let alpha = rng.gen();
|
||||
let rsk = sk.randomize(alpha);
|
||||
let rvk = vk.randomize(alpha, p_g, params);
|
||||
|
||||
let sig1 = rsk.sign(msg1, rng, p_g, params);
|
||||
let sig2 = rsk.sign(msg2, rng, p_g, params);
|
||||
|
||||
assert!(rvk.verify(msg1, &sig1, p_g, params));
|
||||
assert!(rvk.verify(msg2, &sig2, p_g, params));
|
||||
assert!(!rvk.verify(msg1, &sig2, p_g, params));
|
||||
assert!(!rvk.verify(msg2, &sig1, p_g, params));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
use blake2_rfc::blake2b::Blake2b;
|
||||
|
||||
use jubjub::{JubjubEngine, ToUniform};
|
||||
|
||||
pub fn hash_to_scalar<E: JubjubEngine>(persona: &[u8], a: &[u8], b: &[u8]) -> E::Fs {
|
||||
let mut hasher = Blake2b::with_params(64, &[], &[], persona);
|
||||
hasher.update(a);
|
||||
hasher.update(b);
|
||||
let ret = hasher.finalize();
|
||||
E::Fs::to_uniform(ret.as_ref())
|
||||
}
|
@ -1,21 +1,20 @@
|
||||
//! This module contains an `EvaluationDomain` abstraction for
|
||||
//! performing various kinds of polynomial arithmetic on top of
|
||||
//! the scalar field.
|
||||
//! This module contains an [`EvaluationDomain`] abstraction for performing
|
||||
//! various kinds of polynomial arithmetic on top of the scalar field.
|
||||
//!
|
||||
//! In pairing-based SNARKs like Groth16, we need to calculate
|
||||
//! a quotient polynomial over a target polynomial with roots
|
||||
//! at distinct points associated with each constraint of the
|
||||
//! constraint system. In order to be efficient, we choose these
|
||||
//! roots to be the powers of a 2^n root of unity in the field.
|
||||
//! This allows us to perform polynomial operations in O(n)
|
||||
//! by performing an O(n log n) FFT over such a domain.
|
||||
//! In pairing-based SNARKs like [Groth16], we need to calculate a quotient
|
||||
//! polynomial over a target polynomial with roots at distinct points associated
|
||||
//! with each constraint of the constraint system. In order to be efficient, we
|
||||
//! choose these roots to be the powers of a 2<sup>n</sup> root of unity in the
|
||||
//! field. This allows us to perform polynomial operations in O(n) by performing
|
||||
//! an O(n log n) FFT over such a domain.
|
||||
//!
|
||||
//! [`EvaluationDomain`]: crate::domain::EvaluationDomain
|
||||
//! [Groth16]: https://eprint.iacr.org/2016/260
|
||||
|
||||
use ff::{Field, PrimeField, ScalarEngine};
|
||||
use group::CurveProjective;
|
||||
|
||||
use super::{
|
||||
SynthesisError
|
||||
};
|
||||
use super::SynthesisError;
|
||||
|
||||
use super::multicore::Worker;
|
||||
|
||||
@ -25,24 +24,27 @@ pub struct EvaluationDomain<E: ScalarEngine, G: Group<E>> {
|
||||
omega: E::Fr,
|
||||
omegainv: E::Fr,
|
||||
geninv: E::Fr,
|
||||
minv: E::Fr
|
||||
minv: E::Fr,
|
||||
}
|
||||
|
||||
impl<E: ScalarEngine, G: Group<E>> AsRef<[G]> for EvaluationDomain<E, G> {
|
||||
fn as_ref(&self) -> &[G] {
|
||||
&self.coeffs
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: ScalarEngine, G: Group<E>> AsMut<[G]> for EvaluationDomain<E, G> {
|
||||
fn as_mut(&mut self) -> &mut [G] {
|
||||
&mut self.coeffs
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
||||
pub fn as_ref(&self) -> &[G] {
|
||||
&self.coeffs
|
||||
}
|
||||
|
||||
pub fn as_mut(&mut self) -> &mut [G] {
|
||||
&mut self.coeffs
|
||||
}
|
||||
|
||||
pub fn into_coeffs(self) -> Vec<G> {
|
||||
self.coeffs
|
||||
}
|
||||
|
||||
pub fn from_coeffs(mut coeffs: Vec<G>) -> Result<EvaluationDomain<E, G>, SynthesisError>
|
||||
{
|
||||
pub fn from_coeffs(mut coeffs: Vec<G>) -> Result<EvaluationDomain<E, G>, SynthesisError> {
|
||||
// Compute the size of our evaluation domain
|
||||
let mut m = 1;
|
||||
let mut exp = 0;
|
||||
@ -53,7 +55,7 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
||||
// The pairing-friendly curve may not be able to support
|
||||
// large enough (radix2) evaluation domains.
|
||||
if exp >= E::Fr::S {
|
||||
return Err(SynthesisError::PolynomialDegreeTooLarge)
|
||||
return Err(SynthesisError::PolynomialDegreeTooLarge);
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,29 +69,30 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
||||
coeffs.resize(m, G::group_zero());
|
||||
|
||||
Ok(EvaluationDomain {
|
||||
coeffs: coeffs,
|
||||
exp: exp,
|
||||
omega: omega,
|
||||
coeffs,
|
||||
exp,
|
||||
omega,
|
||||
omegainv: omega.inverse().unwrap(),
|
||||
geninv: E::Fr::multiplicative_generator().inverse().unwrap(),
|
||||
minv: E::Fr::from_str(&format!("{}", m)).unwrap().inverse().unwrap()
|
||||
minv: E::Fr::from_str(&format!("{}", m))
|
||||
.unwrap()
|
||||
.inverse()
|
||||
.unwrap(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fft(&mut self, worker: &Worker)
|
||||
{
|
||||
pub fn fft(&mut self, worker: &Worker) {
|
||||
best_fft(&mut self.coeffs, worker, &self.omega, self.exp);
|
||||
}
|
||||
|
||||
pub fn ifft(&mut self, worker: &Worker)
|
||||
{
|
||||
pub fn ifft(&mut self, worker: &Worker) {
|
||||
best_fft(&mut self.coeffs, worker, &self.omegainv, self.exp);
|
||||
|
||||
worker.scope(self.coeffs.len(), |scope, chunk| {
|
||||
let minv = self.minv;
|
||||
|
||||
for v in self.coeffs.chunks_mut(chunk) {
|
||||
scope.spawn(move || {
|
||||
scope.spawn(move |_scope| {
|
||||
for v in v {
|
||||
v.group_mul_assign(&minv);
|
||||
}
|
||||
@ -98,11 +101,10 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn distribute_powers(&mut self, worker: &Worker, g: E::Fr)
|
||||
{
|
||||
pub fn distribute_powers(&mut self, worker: &Worker, g: E::Fr) {
|
||||
worker.scope(self.coeffs.len(), |scope, chunk| {
|
||||
for (i, v) in self.coeffs.chunks_mut(chunk).enumerate() {
|
||||
scope.spawn(move || {
|
||||
scope.spawn(move |_scope| {
|
||||
let mut u = g.pow(&[(i * chunk) as u64]);
|
||||
for v in v.iter_mut() {
|
||||
v.group_mul_assign(&u);
|
||||
@ -113,14 +115,12 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn coset_fft(&mut self, worker: &Worker)
|
||||
{
|
||||
pub fn coset_fft(&mut self, worker: &Worker) {
|
||||
self.distribute_powers(worker, E::Fr::multiplicative_generator());
|
||||
self.fft(worker);
|
||||
}
|
||||
|
||||
pub fn icoset_fft(&mut self, worker: &Worker)
|
||||
{
|
||||
pub fn icoset_fft(&mut self, worker: &Worker) {
|
||||
let geninv = self.geninv;
|
||||
|
||||
self.ifft(worker);
|
||||
@ -139,13 +139,15 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
||||
/// The target polynomial is the zero polynomial in our
|
||||
/// evaluation domain, so we must perform division over
|
||||
/// a coset.
|
||||
pub fn divide_by_z_on_coset(&mut self, worker: &Worker)
|
||||
{
|
||||
let i = self.z(&E::Fr::multiplicative_generator()).inverse().unwrap();
|
||||
pub fn divide_by_z_on_coset(&mut self, worker: &Worker) {
|
||||
let i = self
|
||||
.z(&E::Fr::multiplicative_generator())
|
||||
.inverse()
|
||||
.unwrap();
|
||||
|
||||
worker.scope(self.coeffs.len(), |scope, chunk| {
|
||||
for v in self.coeffs.chunks_mut(chunk) {
|
||||
scope.spawn(move || {
|
||||
scope.spawn(move |_scope| {
|
||||
for v in v {
|
||||
v.group_mul_assign(&i);
|
||||
}
|
||||
@ -159,8 +161,12 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
||||
assert_eq!(self.coeffs.len(), other.coeffs.len());
|
||||
|
||||
worker.scope(self.coeffs.len(), |scope, chunk| {
|
||||
for (a, b) in self.coeffs.chunks_mut(chunk).zip(other.coeffs.chunks(chunk)) {
|
||||
scope.spawn(move || {
|
||||
for (a, b) in self
|
||||
.coeffs
|
||||
.chunks_mut(chunk)
|
||||
.zip(other.coeffs.chunks(chunk))
|
||||
{
|
||||
scope.spawn(move |_scope| {
|
||||
for (a, b) in a.iter_mut().zip(b.iter()) {
|
||||
a.group_mul_assign(&b.0);
|
||||
}
|
||||
@ -174,8 +180,12 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
||||
assert_eq!(self.coeffs.len(), other.coeffs.len());
|
||||
|
||||
worker.scope(self.coeffs.len(), |scope, chunk| {
|
||||
for (a, b) in self.coeffs.chunks_mut(chunk).zip(other.coeffs.chunks(chunk)) {
|
||||
scope.spawn(move || {
|
||||
for (a, b) in self
|
||||
.coeffs
|
||||
.chunks_mut(chunk)
|
||||
.zip(other.coeffs.chunks(chunk))
|
||||
{
|
||||
scope.spawn(move |_scope| {
|
||||
for (a, b) in a.iter_mut().zip(b.iter()) {
|
||||
a.group_sub_assign(&b);
|
||||
}
|
||||
@ -200,7 +210,7 @@ impl<G: CurveProjective> PartialEq for Point<G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: CurveProjective> Copy for Point<G> { }
|
||||
impl<G: CurveProjective> Copy for Point<G> {}
|
||||
|
||||
impl<G: CurveProjective> Clone for Point<G> {
|
||||
fn clone(&self) -> Point<G> {
|
||||
@ -231,7 +241,7 @@ impl<E: ScalarEngine> PartialEq for Scalar<E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: ScalarEngine> Copy for Scalar<E> { }
|
||||
impl<E: ScalarEngine> Copy for Scalar<E> {}
|
||||
|
||||
impl<E: ScalarEngine> Clone for Scalar<E> {
|
||||
fn clone(&self) -> Scalar<E> {
|
||||
@ -254,8 +264,7 @@ impl<E: ScalarEngine> Group<E> for Scalar<E> {
|
||||
}
|
||||
}
|
||||
|
||||
fn best_fft<E: ScalarEngine, 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();
|
||||
|
||||
if log_n <= log_cpus {
|
||||
@ -265,8 +274,7 @@ fn best_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], worker: &Worker, omega: &
|
||||
}
|
||||
}
|
||||
|
||||
fn serial_fft<E: ScalarEngine, 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 {
|
||||
let mut r = 0;
|
||||
for _ in 0..l {
|
||||
@ -288,22 +296,22 @@ fn serial_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u
|
||||
|
||||
let mut m = 1;
|
||||
for _ in 0..log_n {
|
||||
let w_m = omega.pow(&[(n / (2*m)) as u64]);
|
||||
let w_m = omega.pow(&[u64::from(n / (2 * m))]);
|
||||
|
||||
let mut k = 0;
|
||||
while k < n {
|
||||
let mut w = E::Fr::one();
|
||||
for j in 0..m {
|
||||
let mut t = a[(k+j+m) as usize];
|
||||
let mut t = a[(k + j + m) as usize];
|
||||
t.group_mul_assign(&w);
|
||||
let mut tmp = a[(k+j) as usize];
|
||||
let mut tmp = a[(k + j) as usize];
|
||||
tmp.group_sub_assign(&t);
|
||||
a[(k+j+m) as usize] = tmp;
|
||||
a[(k+j) as usize].group_add_assign(&t);
|
||||
a[(k + j + m) as usize] = tmp;
|
||||
a[(k + j) as usize].group_add_assign(&t);
|
||||
w.mul_assign(&w_m);
|
||||
}
|
||||
|
||||
k += 2*m;
|
||||
k += 2 * m;
|
||||
}
|
||||
|
||||
m *= 2;
|
||||
@ -315,9 +323,8 @@ fn parallel_fft<E: ScalarEngine, T: Group<E>>(
|
||||
worker: &Worker,
|
||||
omega: &E::Fr,
|
||||
log_n: u32,
|
||||
log_cpus: u32
|
||||
)
|
||||
{
|
||||
log_cpus: u32,
|
||||
) {
|
||||
assert!(log_n >= log_cpus);
|
||||
|
||||
let num_cpus = 1 << log_cpus;
|
||||
@ -329,18 +336,18 @@ fn parallel_fft<E: ScalarEngine, T: Group<E>>(
|
||||
let a = &*a;
|
||||
|
||||
for (j, tmp) in tmp.iter_mut().enumerate() {
|
||||
scope.spawn(move || {
|
||||
scope.spawn(move |_scope| {
|
||||
// Shuffle into a sub-FFT
|
||||
let omega_j = omega.pow(&[j as u64]);
|
||||
let omega_step = omega.pow(&[(j as u64) << log_new_n]);
|
||||
|
||||
let mut elt = E::Fr::one();
|
||||
for i in 0..(1 << log_new_n) {
|
||||
for (i, tmp) in tmp.iter_mut().enumerate() {
|
||||
for s in 0..num_cpus {
|
||||
let idx = (i + (s << log_new_n)) % (1 << log_n);
|
||||
let mut t = a[idx];
|
||||
t.group_mul_assign(&elt);
|
||||
tmp[i].group_add_assign(&t);
|
||||
tmp.group_add_assign(&t);
|
||||
elt.mul_assign(&omega_step);
|
||||
}
|
||||
elt.mul_assign(&omega_j);
|
||||
@ -357,7 +364,7 @@ fn parallel_fft<E: ScalarEngine, T: Group<E>>(
|
||||
let tmp = &tmp;
|
||||
|
||||
for (idx, a) in a.chunks_mut(chunk).enumerate() {
|
||||
scope.spawn(move || {
|
||||
scope.spawn(move |_scope| {
|
||||
let mut idx = idx * chunk;
|
||||
let mask = (1 << log_cpus) - 1;
|
||||
for a in a {
|
||||
@ -375,16 +382,19 @@ fn parallel_fft<E: ScalarEngine, T: Group<E>>(
|
||||
#[test]
|
||||
fn polynomial_arith() {
|
||||
use pairing::bls12_381::Bls12;
|
||||
use rand::{self, Rand};
|
||||
use rand_core::RngCore;
|
||||
|
||||
fn test_mul<E: ScalarEngine, R: rand::Rng>(rng: &mut R)
|
||||
{
|
||||
fn test_mul<E: ScalarEngine, R: RngCore>(rng: &mut R) {
|
||||
let worker = Worker::new();
|
||||
|
||||
for coeffs_a in 0..70 {
|
||||
for coeffs_b in 0..70 {
|
||||
let mut a: Vec<_> = (0..coeffs_a).map(|_| Scalar::<E>(E::Fr::rand(rng))).collect();
|
||||
let mut b: Vec<_> = (0..coeffs_b).map(|_| Scalar::<E>(E::Fr::rand(rng))).collect();
|
||||
let mut a: Vec<_> = (0..coeffs_a)
|
||||
.map(|_| Scalar::<E>(E::Fr::random(rng)))
|
||||
.collect();
|
||||
let mut b: Vec<_> = (0..coeffs_b)
|
||||
.map(|_| Scalar::<E>(E::Fr::random(rng)))
|
||||
.collect();
|
||||
|
||||
// naive evaluation
|
||||
let mut naive = vec![Scalar(E::Fr::zero()); coeffs_a + coeffs_b];
|
||||
@ -423,10 +433,9 @@ fn polynomial_arith() {
|
||||
#[test]
|
||||
fn fft_composition() {
|
||||
use pairing::bls12_381::Bls12;
|
||||
use rand;
|
||||
use rand_core::RngCore;
|
||||
|
||||
fn test_comp<E: ScalarEngine, R: rand::Rng>(rng: &mut R)
|
||||
{
|
||||
fn test_comp<E: ScalarEngine, R: RngCore>(rng: &mut R) {
|
||||
let worker = Worker::new();
|
||||
|
||||
for coeffs in 0..10 {
|
||||
@ -434,7 +443,7 @@ fn fft_composition() {
|
||||
|
||||
let mut v = vec![];
|
||||
for _ in 0..coeffs {
|
||||
v.push(Scalar::<E>(rng.gen()));
|
||||
v.push(Scalar::<E>(E::Fr::random(rng)));
|
||||
}
|
||||
|
||||
let mut domain = EvaluationDomain::from_coeffs(v.clone()).unwrap();
|
||||
@ -462,22 +471,23 @@ fn fft_composition() {
|
||||
#[test]
|
||||
fn parallel_fft_consistency() {
|
||||
use pairing::bls12_381::Bls12;
|
||||
use rand::{self, Rand};
|
||||
use rand_core::RngCore;
|
||||
use std::cmp::min;
|
||||
|
||||
fn test_consistency<E: ScalarEngine, R: rand::Rng>(rng: &mut R)
|
||||
{
|
||||
fn test_consistency<E: ScalarEngine, R: RngCore>(rng: &mut R) {
|
||||
let worker = Worker::new();
|
||||
|
||||
for _ in 0..5 {
|
||||
for log_d in 0..10 {
|
||||
let d = 1 << log_d;
|
||||
|
||||
let v1 = (0..d).map(|_| Scalar::<E>(E::Fr::rand(rng))).collect::<Vec<_>>();
|
||||
let v1 = (0..d)
|
||||
.map(|_| Scalar::<E>(E::Fr::random(rng)))
|
||||
.collect::<Vec<_>>();
|
||||
let mut v1 = EvaluationDomain::from_coeffs(v1).unwrap();
|
||||
let mut v2 = EvaluationDomain::from_coeffs(v1.coeffs.clone()).unwrap();
|
||||
|
||||
for log_cpus in log_d..min(log_d+1, 3) {
|
||||
for log_cpus in log_d..min(log_d + 1, 3) {
|
||||
parallel_fft(&mut v1.coeffs, &worker, &v1.omega, log_d, log_cpus);
|
||||
serial_fft(&mut v2.coeffs, &v2.omega, log_d);
|
||||
|
@ -1,23 +1,17 @@
|
||||
#[cfg(test)]
|
||||
//! Self-contained sub-circuit implementations for various primitives.
|
||||
|
||||
pub mod test;
|
||||
|
||||
pub mod boolean;
|
||||
pub mod multieq;
|
||||
pub mod uint32;
|
||||
pub mod blake2s;
|
||||
pub mod num;
|
||||
pub mod boolean;
|
||||
pub mod lookup;
|
||||
pub mod ecc;
|
||||
pub mod pedersen_hash;
|
||||
pub mod multieq;
|
||||
pub mod multipack;
|
||||
pub mod num;
|
||||
pub mod sha256;
|
||||
pub mod uint32;
|
||||
|
||||
pub mod sapling;
|
||||
pub mod sprout;
|
||||
|
||||
use bellman::{
|
||||
SynthesisError
|
||||
};
|
||||
use crate::SynthesisError;
|
||||
|
||||
// TODO: This should probably be removed and we
|
||||
// should use existing helper methods on `Option`
|
||||
@ -25,7 +19,7 @@ use bellman::{
|
||||
/// This basically is just an extension to `Option`
|
||||
/// which allows for a convenient mapping to an
|
||||
/// error on `None`.
|
||||
trait Assignment<T> {
|
||||
pub trait Assignment<T> {
|
||||
fn get(&self) -> Result<&T, SynthesisError>;
|
||||
}
|
||||
|
||||
@ -33,7 +27,7 @@ impl<T> Assignment<T> for Option<T> {
|
||||
fn get(&self) -> Result<&T, SynthesisError> {
|
||||
match *self {
|
||||
Some(ref v) => Ok(v),
|
||||
None => Err(SynthesisError::AssignmentMissing)
|
||||
None => Err(SynthesisError::AssignmentMissing),
|
||||
}
|
||||
}
|
||||
}
|
696
src/gadgets/blake2s.rs
Normal file
696
src/gadgets/blake2s.rs
Normal file
@ -0,0 +1,696 @@
|
||||
//! The [BLAKE2s] hash function with personalization support.
|
||||
//!
|
||||
//! [BLAKE2s]: https://tools.ietf.org/html/rfc7693
|
||||
|
||||
use super::{boolean::Boolean, multieq::MultiEq, uint32::UInt32};
|
||||
use crate::{ConstraintSystem, SynthesisError};
|
||||
use ff::ScalarEngine;
|
||||
|
||||
/*
|
||||
2.1. Parameters
|
||||
The following table summarizes various parameters and their ranges:
|
||||
| BLAKE2b | BLAKE2s |
|
||||
--------------+------------------+------------------+
|
||||
Bits in word | w = 64 | w = 32 |
|
||||
Rounds in F | r = 12 | r = 10 |
|
||||
Block bytes | bb = 128 | bb = 64 |
|
||||
Hash bytes | 1 <= nn <= 64 | 1 <= nn <= 32 |
|
||||
Key bytes | 0 <= kk <= 64 | 0 <= kk <= 32 |
|
||||
Input bytes | 0 <= ll < 2**128 | 0 <= ll < 2**64 |
|
||||
--------------+------------------+------------------+
|
||||
G Rotation | (R1, R2, R3, R4) | (R1, R2, R3, R4) |
|
||||
constants = | (32, 24, 16, 63) | (16, 12, 8, 7) |
|
||||
--------------+------------------+------------------+
|
||||
*/
|
||||
|
||||
const R1: usize = 16;
|
||||
const R2: usize = 12;
|
||||
const R3: usize = 8;
|
||||
const R4: usize = 7;
|
||||
|
||||
/*
|
||||
Round | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
||||
----------+-------------------------------------------------+
|
||||
SIGMA[0] | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
||||
SIGMA[1] | 14 10 4 8 9 15 13 6 1 12 0 2 11 7 5 3 |
|
||||
SIGMA[2] | 11 8 12 0 5 2 15 13 10 14 3 6 7 1 9 4 |
|
||||
SIGMA[3] | 7 9 3 1 13 12 11 14 2 6 5 10 4 0 15 8 |
|
||||
SIGMA[4] | 9 0 5 7 2 4 10 15 14 1 11 12 6 8 3 13 |
|
||||
SIGMA[5] | 2 12 6 10 0 11 8 3 4 13 7 5 15 14 1 9 |
|
||||
SIGMA[6] | 12 5 1 15 14 13 4 10 0 7 6 3 9 2 8 11 |
|
||||
SIGMA[7] | 13 11 7 14 12 1 3 9 5 0 15 4 8 6 2 10 |
|
||||
SIGMA[8] | 6 15 14 9 11 3 0 8 12 2 13 7 1 4 10 5 |
|
||||
SIGMA[9] | 10 2 8 4 7 6 1 5 15 11 9 14 3 12 13 0 |
|
||||
----------+-------------------------------------------------+
|
||||
*/
|
||||
|
||||
const SIGMA: [[usize; 16]; 10] = [
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
||||
[14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
|
||||
[11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
|
||||
[7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
|
||||
[9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
|
||||
[2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
|
||||
[12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
|
||||
[13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
|
||||
[6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
|
||||
[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
|
||||
];
|
||||
|
||||
/*
|
||||
3.1. Mixing Function G
|
||||
The G primitive function mixes two input words, "x" and "y", into
|
||||
four words indexed by "a", "b", "c", and "d" in the working vector
|
||||
v[0..15]. The full modified vector is returned. The rotation
|
||||
constants (R1, R2, R3, R4) are given in Section 2.1.
|
||||
FUNCTION G( v[0..15], a, b, c, d, x, y )
|
||||
|
|
||||
| v[a] := (v[a] + v[b] + x) mod 2**w
|
||||
| v[d] := (v[d] ^ v[a]) >>> R1
|
||||
| v[c] := (v[c] + v[d]) mod 2**w
|
||||
| v[b] := (v[b] ^ v[c]) >>> R2
|
||||
| v[a] := (v[a] + v[b] + y) mod 2**w
|
||||
| v[d] := (v[d] ^ v[a]) >>> R3
|
||||
| v[c] := (v[c] + v[d]) mod 2**w
|
||||
| v[b] := (v[b] ^ v[c]) >>> R4
|
||||
|
|
||||
| RETURN v[0..15]
|
||||
|
|
||||
END FUNCTION.
|
||||
*/
|
||||
|
||||
fn mixing_g<E: ScalarEngine, CS: ConstraintSystem<E>, M>(
|
||||
mut cs: M,
|
||||
v: &mut [UInt32],
|
||||
a: usize,
|
||||
b: usize,
|
||||
c: usize,
|
||||
d: usize,
|
||||
x: &UInt32,
|
||||
y: &UInt32,
|
||||
) -> Result<(), SynthesisError>
|
||||
where
|
||||
M: ConstraintSystem<E, Root = MultiEq<E, CS>>,
|
||||
{
|
||||
v[a] = UInt32::addmany(
|
||||
cs.namespace(|| "mixing step 1"),
|
||||
&[v[a].clone(), v[b].clone(), x.clone()],
|
||||
)?;
|
||||
v[d] = v[d].xor(cs.namespace(|| "mixing step 2"), &v[a])?.rotr(R1);
|
||||
v[c] = UInt32::addmany(
|
||||
cs.namespace(|| "mixing step 3"),
|
||||
&[v[c].clone(), v[d].clone()],
|
||||
)?;
|
||||
v[b] = v[b].xor(cs.namespace(|| "mixing step 4"), &v[c])?.rotr(R2);
|
||||
v[a] = UInt32::addmany(
|
||||
cs.namespace(|| "mixing step 5"),
|
||||
&[v[a].clone(), v[b].clone(), y.clone()],
|
||||
)?;
|
||||
v[d] = v[d].xor(cs.namespace(|| "mixing step 6"), &v[a])?.rotr(R3);
|
||||
v[c] = UInt32::addmany(
|
||||
cs.namespace(|| "mixing step 7"),
|
||||
&[v[c].clone(), v[d].clone()],
|
||||
)?;
|
||||
v[b] = v[b].xor(cs.namespace(|| "mixing step 8"), &v[c])?.rotr(R4);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/*
|
||||
3.2. Compression Function F
|
||||
Compression function F takes as an argument the state vector "h",
|
||||
message block vector "m" (last block is padded with zeros to full
|
||||
block size, if required), 2w-bit offset counter "t", and final block
|
||||
indicator flag "f". Local vector v[0..15] is used in processing. F
|
||||
returns a new state vector. The number of rounds, "r", is 12 for
|
||||
BLAKE2b and 10 for BLAKE2s. Rounds are numbered from 0 to r - 1.
|
||||
FUNCTION F( h[0..7], m[0..15], t, f )
|
||||
|
|
||||
| // Initialize local work vector v[0..15]
|
||||
| v[0..7] := h[0..7] // First half from state.
|
||||
| v[8..15] := IV[0..7] // Second half from IV.
|
||||
|
|
||||
| v[12] := v[12] ^ (t mod 2**w) // Low word of the offset.
|
||||
| v[13] := v[13] ^ (t >> w) // High word.
|
||||
|
|
||||
| IF f = TRUE THEN // last block flag?
|
||||
| | v[14] := v[14] ^ 0xFF..FF // Invert all bits.
|
||||
| END IF.
|
||||
|
|
||||
| // Cryptographic mixing
|
||||
| FOR i = 0 TO r - 1 DO // Ten or twelve rounds.
|
||||
| |
|
||||
| | // Message word selection permutation for this round.
|
||||
| | s[0..15] := SIGMA[i mod 10][0..15]
|
||||
| |
|
||||
| | v := G( v, 0, 4, 8, 12, m[s[ 0]], m[s[ 1]] )
|
||||
| | v := G( v, 1, 5, 9, 13, m[s[ 2]], m[s[ 3]] )
|
||||
| | v := G( v, 2, 6, 10, 14, m[s[ 4]], m[s[ 5]] )
|
||||
| | v := G( v, 3, 7, 11, 15, m[s[ 6]], m[s[ 7]] )
|
||||
| |
|
||||
| | v := G( v, 0, 5, 10, 15, m[s[ 8]], m[s[ 9]] )
|
||||
| | v := G( v, 1, 6, 11, 12, m[s[10]], m[s[11]] )
|
||||
| | v := G( v, 2, 7, 8, 13, m[s[12]], m[s[13]] )
|
||||
| | v := G( v, 3, 4, 9, 14, m[s[14]], m[s[15]] )
|
||||
| |
|
||||
| END FOR
|
||||
|
|
||||
| FOR i = 0 TO 7 DO // XOR the two halves.
|
||||
| | h[i] := h[i] ^ v[i] ^ v[i + 8]
|
||||
| END FOR.
|
||||
|
|
||||
| RETURN h[0..7] // New state.
|
||||
|
|
||||
END FUNCTION.
|
||||
*/
|
||||
|
||||
fn blake2s_compression<E: ScalarEngine, CS: ConstraintSystem<E>>(
|
||||
mut cs: CS,
|
||||
h: &mut [UInt32],
|
||||
m: &[UInt32],
|
||||
t: u64,
|
||||
f: bool,
|
||||
) -> Result<(), SynthesisError> {
|
||||
assert_eq!(h.len(), 8);
|
||||
assert_eq!(m.len(), 16);
|
||||
|
||||
/*
|
||||
static const uint32_t blake2s_iv[8] =
|
||||
{
|
||||
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
|
||||
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
|
||||
};
|
||||
*/
|
||||
|
||||
let mut v = Vec::with_capacity(16);
|
||||
v.extend_from_slice(h);
|
||||
v.push(UInt32::constant(0x6A09E667));
|
||||
v.push(UInt32::constant(0xBB67AE85));
|
||||
v.push(UInt32::constant(0x3C6EF372));
|
||||
v.push(UInt32::constant(0xA54FF53A));
|
||||
v.push(UInt32::constant(0x510E527F));
|
||||
v.push(UInt32::constant(0x9B05688C));
|
||||
v.push(UInt32::constant(0x1F83D9AB));
|
||||
v.push(UInt32::constant(0x5BE0CD19));
|
||||
|
||||
assert_eq!(v.len(), 16);
|
||||
|
||||
v[12] = v[12].xor(cs.namespace(|| "first xor"), &UInt32::constant(t as u32))?;
|
||||
v[13] = v[13].xor(
|
||||
cs.namespace(|| "second xor"),
|
||||
&UInt32::constant((t >> 32) as u32),
|
||||
)?;
|
||||
|
||||
if f {
|
||||
v[14] = v[14].xor(
|
||||
cs.namespace(|| "third xor"),
|
||||
&UInt32::constant(u32::max_value()),
|
||||
)?;
|
||||
}
|
||||
|
||||
{
|
||||
let mut cs = MultiEq::new(&mut cs);
|
||||
|
||||
for i in 0..10 {
|
||||
let mut cs = cs.namespace(|| format!("round {}", i));
|
||||
|
||||
let s = SIGMA[i % 10];
|
||||
|
||||
mixing_g(
|
||||
cs.namespace(|| "mixing invocation 1"),
|
||||
&mut v,
|
||||
0,
|
||||
4,
|
||||
8,
|
||||
12,
|
||||
&m[s[0]],
|
||||
&m[s[1]],
|
||||
)?;
|
||||
mixing_g(
|
||||
cs.namespace(|| "mixing invocation 2"),
|
||||
&mut v,
|
||||
1,
|
||||
5,
|
||||
9,
|
||||
13,
|
||||
&m[s[2]],
|
||||
&m[s[3]],
|
||||
)?;
|
||||
mixing_g(
|
||||
cs.namespace(|| "mixing invocation 3"),
|
||||
&mut v,
|
||||
2,
|
||||
6,
|
||||
10,
|
||||
14,
|
||||
&m[s[4]],
|
||||
&m[s[5]],
|
||||
)?;
|
||||
mixing_g(
|
||||
cs.namespace(|| "mixing invocation 4"),
|
||||
&mut v,
|
||||
3,
|
||||
7,
|
||||
11,
|
||||
15,
|
||||
&m[s[6]],
|
||||
&m[s[7]],
|
||||
)?;
|
||||
|
||||
mixing_g(
|
||||
cs.namespace(|| "mixing invocation 5"),
|
||||
&mut v,
|
||||
0,
|
||||
5,
|
||||
10,
|
||||
15,
|
||||
&m[s[8]],
|
||||
&m[s[9]],
|
||||
)?;
|
||||
mixing_g(
|
||||
cs.namespace(|| "mixing invocation 6"),
|
||||
&mut v,
|
||||
1,
|
||||
6,
|
||||
11,
|
||||
12,
|
||||
&m[s[10]],
|
||||
&m[s[11]],
|
||||
)?;
|
||||
mixing_g(
|
||||
cs.namespace(|| "mixing invocation 7"),
|
||||
&mut v,
|
||||
2,
|
||||
7,
|
||||
8,
|
||||
13,
|
||||
&m[s[12]],
|
||||
&m[s[13]],
|
||||
)?;
|
||||
mixing_g(
|
||||
cs.namespace(|| "mixing invocation 8"),
|
||||
&mut v,
|
||||
3,
|
||||
4,
|
||||
9,
|
||||
14,
|
||||
&m[s[14]],
|
||||
&m[s[15]],
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0..8 {
|
||||
let mut cs = cs.namespace(|| format!("h[{i}] ^ v[{i}] ^ v[{i} + 8]", i = i));
|
||||
|
||||
h[i] = h[i].xor(cs.namespace(|| "first xor"), &v[i])?;
|
||||
h[i] = h[i].xor(cs.namespace(|| "second xor"), &v[i + 8])?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION BLAKE2( d[0..dd-1], ll, kk, nn )
|
||||
|
|
||||
| h[0..7] := IV[0..7] // Initialization Vector.
|
||||
|
|
||||
| // Parameter block p[0]
|
||||
| h[0] := h[0] ^ 0x01010000 ^ (kk << 8) ^ nn
|
||||
|
|
||||
| // Process padded key and data blocks
|
||||
| IF dd > 1 THEN
|
||||
| | FOR i = 0 TO dd - 2 DO
|
||||
| | | h := F( h, d[i], (i + 1) * bb, FALSE )
|
||||
| | END FOR.
|
||||
| END IF.
|
||||
|
|
||||
| // Final block.
|
||||
| IF kk = 0 THEN
|
||||
| | h := F( h, d[dd - 1], ll, TRUE )
|
||||
| ELSE
|
||||
| | h := F( h, d[dd - 1], ll + bb, TRUE )
|
||||
| END IF.
|
||||
|
|
||||
| RETURN first "nn" bytes from little-endian word array h[].
|
||||
|
|
||||
END FUNCTION.
|
||||
*/
|
||||
|
||||
pub fn blake2s<E: ScalarEngine, CS: ConstraintSystem<E>>(
|
||||
mut cs: CS,
|
||||
input: &[Boolean],
|
||||
personalization: &[u8],
|
||||
) -> Result<Vec<Boolean>, SynthesisError> {
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
assert_eq!(personalization.len(), 8);
|
||||
assert!(input.len() % 8 == 0);
|
||||
|
||||
let mut h = Vec::with_capacity(8);
|
||||
h.push(UInt32::constant(0x6A09E667 ^ 0x01010000 ^ 32));
|
||||
h.push(UInt32::constant(0xBB67AE85));
|
||||
h.push(UInt32::constant(0x3C6EF372));
|
||||
h.push(UInt32::constant(0xA54FF53A));
|
||||
h.push(UInt32::constant(0x510E527F));
|
||||
h.push(UInt32::constant(0x9B05688C));
|
||||
|
||||
// Personalization is stored here
|
||||
h.push(UInt32::constant(
|
||||
0x1F83D9AB ^ LittleEndian::read_u32(&personalization[0..4]),
|
||||
));
|
||||
h.push(UInt32::constant(
|
||||
0x5BE0CD19 ^ LittleEndian::read_u32(&personalization[4..8]),
|
||||
));
|
||||
|
||||
let mut blocks: Vec<Vec<UInt32>> = vec![];
|
||||
|
||||
for block in input.chunks(512) {
|
||||
let mut this_block = Vec::with_capacity(16);
|
||||
for word in block.chunks(32) {
|
||||
let mut tmp = word.to_vec();
|
||||
while tmp.len() < 32 {
|
||||
tmp.push(Boolean::constant(false));
|
||||
}
|
||||
this_block.push(UInt32::from_bits(&tmp));
|
||||
}
|
||||
while this_block.len() < 16 {
|
||||
this_block.push(UInt32::constant(0));
|
||||
}
|
||||
blocks.push(this_block);
|
||||
}
|
||||
|
||||
if blocks.is_empty() {
|
||||
blocks.push((0..16).map(|_| UInt32::constant(0)).collect());
|
||||
}
|
||||
|
||||
for (i, block) in blocks[0..blocks.len() - 1].iter().enumerate() {
|
||||
let cs = cs.namespace(|| format!("block {}", i));
|
||||
|
||||
blake2s_compression(cs, &mut h, block, ((i as u64) + 1) * 64, false)?;
|
||||
}
|
||||
|
||||
{
|
||||
let cs = cs.namespace(|| "final block");
|
||||
|
||||
blake2s_compression(
|
||||
cs,
|
||||
&mut h,
|
||||
&blocks[blocks.len() - 1],
|
||||
(input.len() / 8) as u64,
|
||||
true,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(h.into_iter().flat_map(|b| b.into_bits()).collect())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use blake2s_simd::Params as Blake2sParams;
|
||||
use pairing::bls12_381::Bls12;
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
use super::blake2s;
|
||||
use crate::gadgets::boolean::{AllocatedBit, Boolean};
|
||||
use crate::gadgets::test::TestConstraintSystem;
|
||||
use crate::ConstraintSystem;
|
||||
|
||||
#[test]
|
||||
fn test_blank_hash() {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
let input_bits = vec![];
|
||||
let out = blake2s(&mut cs, &input_bits, b"12345678").unwrap();
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 0);
|
||||
|
||||
// >>> import blake2s from hashlib
|
||||
// >>> h = blake2s(digest_size=32, person=b'12345678')
|
||||
// >>> h.hexdigest()
|
||||
let expected = hex!("c59f682376d137f3f255e671e207d1f2374ebe504e9314208a52d9f88d69e8c8");
|
||||
|
||||
let mut out = out.into_iter();
|
||||
for b in expected.iter() {
|
||||
for i in 0..8 {
|
||||
let c = out.next().unwrap().get_value().unwrap();
|
||||
|
||||
assert_eq!(c, (b >> i) & 1u8 == 1u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2s_constraints() {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
let input_bits: Vec<_> = (0..512)
|
||||
.map(|i| {
|
||||
AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true))
|
||||
.unwrap()
|
||||
.into()
|
||||
})
|
||||
.collect();
|
||||
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 21518);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2s_precomp_constraints() {
|
||||
// Test that 512 fixed leading bits (constants)
|
||||
// doesn't result in more constraints.
|
||||
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
let input_bits: Vec<_> = (0..512)
|
||||
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
|
||||
.chain((0..512).map(|i| {
|
||||
AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true))
|
||||
.unwrap()
|
||||
.into()
|
||||
}))
|
||||
.collect();
|
||||
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 21518);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2s_constant_constraints() {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
let input_bits: Vec<_> = (0..512)
|
||||
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
|
||||
.collect();
|
||||
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
|
||||
assert_eq!(cs.num_constraints(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2s() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) {
|
||||
let mut h = Blake2sParams::new()
|
||||
.hash_length(32)
|
||||
.personal(b"12345678")
|
||||
.to_state();
|
||||
|
||||
let data: Vec<u8> = (0..input_len).map(|_| rng.next_u32() as u8).collect();
|
||||
|
||||
h.update(&data);
|
||||
|
||||
let hash_result = h.finalize();
|
||||
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let mut input_bits = vec![];
|
||||
|
||||
for (byte_i, input_byte) in data.into_iter().enumerate() {
|
||||
for bit_i in 0..8 {
|
||||
let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i));
|
||||
|
||||
input_bits.push(
|
||||
AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8))
|
||||
.unwrap()
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let r = blake2s(&mut cs, &input_bits, b"12345678").unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
let mut s = hash_result
|
||||
.as_ref()
|
||||
.iter()
|
||||
.flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8));
|
||||
|
||||
for b in r {
|
||||
match b {
|
||||
Boolean::Is(b) => {
|
||||
assert!(s.next().unwrap() == b.get_value().unwrap());
|
||||
}
|
||||
Boolean::Not(b) => {
|
||||
assert!(s.next().unwrap() != b.get_value().unwrap());
|
||||
}
|
||||
Boolean::Constant(b) => {
|
||||
assert!(input_len == 0);
|
||||
assert!(s.next().unwrap() == b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2s_256_vars() {
|
||||
let data: Vec<u8> = hex!("be9f9c485e670acce8b1516a378176161b20583637b6f1c536fbc1158a0a3296831df2920e57a442d5738f4be4dd6be89dd7913fc8b4d1c0a815646a4d674b77f7caf313bd880bf759fcac27037c48c2b2a20acd2fd5248e3be426c84a341c0a3c63eaf36e0d537d10b8db5c6e4c801832c41eb1a3ed602177acded8b4b803bd34339d99a18b71df399641cc8dfae2ad193fcd74b5913e704551777160d14c78f2e8d5c32716a8599c1080cb89a40ccd6ba596694a8b4a065d9f2d0667ef423ed2e418093caff884540858b4f4b62acd47edcea880523e1b1cda8eb225c128c2e9e83f14f6e7448c5733a195cac7d79a53dde5083172462c45b2f799e42af1c9").to_vec();
|
||||
assert_eq!(data.len(), 256);
|
||||
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let mut input_bits = vec![];
|
||||
|
||||
for (byte_i, input_byte) in data.into_iter().enumerate() {
|
||||
for bit_i in 0..8 {
|
||||
let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i));
|
||||
|
||||
input_bits.push(
|
||||
AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8))
|
||||
.unwrap()
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let r = blake2s(&mut cs, &input_bits, b"12345678").unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
let expected = hex!("0af5695115ced92c8a0341e43869209636e9aa6472e4576f0f2b996cf812b30e");
|
||||
|
||||
let mut out = r.into_iter();
|
||||
for b in expected.into_iter() {
|
||||
for i in 0..8 {
|
||||
let c = out.next().unwrap().get_value().unwrap();
|
||||
|
||||
assert_eq!(c, (b >> i) & 1u8 == 1u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2s_700_vars() {
|
||||
let data: Vec<u8> = hex!("5dcfe8bab4c758d2eb1ddb7ef337583e0df3e2c358e1755b7cd303a658de9a1227eed1d1114179a5c3c38d692ff2cf2d4e5c92a9516de750106774bbf9f7d063f707f4c9b6a02c0a77e4feb99e036c3ccaee7d1a31cb144093aa074bc9da608f8ff30b39c3c60e4a243cc0bbd406d1262a7d6607b31c60275c6bcc8b0ac49a06a4b629a98693c5f7640f3bca45e4977cfabc5b17f52838af3433b1fd407dbbdc131e8e4bd58bcee85bbab4b57b656c6a2ec6cf852525bc8423675e2bf29159139cd5df99db94719f3f7167230e0d5bd76f6d7891b656732cef9c3c0d48a5fa3d7a879988157b39015a85451b25af0301ca5e759ac35fea79dca38c673ec6db9f3885d9103e2dcb3304bd3d59b0b1d01babc97ef8a74d91b6ab6bf50f29eb5adf7250a28fd85db37bff0133193635da69caeefc72979cf3bef1d2896d847eea7e8a81e0927893dbd010feb6fb845d0399007d9a148a0596d86cd8f4192631f975c560f4de8da5f712c161342063af3c11029d93d6df7ff46db48343499de9ec4786cac059c4025ef418c9fe40132428ff8b91259d71d1709ff066add84ae944b45a817f60b4c1bf719e39ae23e9b413469db2310793e9137cf38741e5dd2a3c138a566dbde1950c00071b20ac457b46ba9b0a7ebdddcc212bd228d2a4c4146a970e54158477247c27871af1564b176576e9fd43bf63740bf77434bc4ea3b1a4b430e1a11714bf43160145578a575c3f78ddeaa48de97f73460f26f8df2b5d63e31800100d16bc27160fea5ced5a977ef541cfe8dadc7b3991ed1c0d4f16a3076bbfed96ba3e155113e794987af8abb133f06feefabc2ac32eb4d4d4ba1541ca08b9e518d2e74b7f946b0cbd2663d58c689359b9a565821acc619011233d1011963fa302cde34fc9c5ba2e03eeb2512f547391e940d56218e22ae325f2dfa38d4bae35744ee707aa5dc9c17674025d15390a08f5c452343546ef6da0f7").to_vec();
|
||||
assert_eq!(data.len(), 700);
|
||||
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let mut input_bits = vec![];
|
||||
|
||||
for (byte_i, input_byte) in data.into_iter().enumerate() {
|
||||
for bit_i in 0..8 {
|
||||
let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i));
|
||||
|
||||
input_bits.push(
|
||||
AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8))
|
||||
.unwrap()
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let r = blake2s(&mut cs, &input_bits, b"12345678").unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
let expected = hex!("2ab8f0683167ba220eef19dccf4f9b1a8193cc09b35e0235842323950530f18a");
|
||||
|
||||
let mut out = r.into_iter();
|
||||
for b in expected.into_iter() {
|
||||
for i in 0..8 {
|
||||
let c = out.next().unwrap().get_value().unwrap();
|
||||
|
||||
assert_eq!(c, (b >> i) & 1u8 == 1u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2s_test_vectors() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
let expecteds = [
|
||||
hex!("a1309e334376c8f36a736a4ab0e691ef931ee3ebdb9ea96187127136fea622a1"),
|
||||
hex!("82fefff60f265cea255252f7c194a7f93965dffee0609ef74eb67f0d76cd41c6"),
|
||||
];
|
||||
for i in 0..2 {
|
||||
let mut h = Blake2sParams::new()
|
||||
.hash_length(32)
|
||||
.personal(b"12345678")
|
||||
.to_state();
|
||||
let input_len = 1024;
|
||||
let data: Vec<u8> = (0..input_len).map(|_| rng.next_u32() as u8).collect();
|
||||
|
||||
h.update(&data);
|
||||
|
||||
let hash_result = h.finalize();
|
||||
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let mut input_bits = vec![];
|
||||
|
||||
for (byte_i, input_byte) in data.into_iter().enumerate() {
|
||||
for bit_i in 0..8 {
|
||||
let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i));
|
||||
|
||||
input_bits.push(
|
||||
AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8))
|
||||
.unwrap()
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let r = blake2s(&mut cs, &input_bits, b"12345678").unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
let mut s = hash_result
|
||||
.as_ref()
|
||||
.iter()
|
||||
.flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8));
|
||||
|
||||
for b in r {
|
||||
match b {
|
||||
Boolean::Is(b) => {
|
||||
assert!(s.next().unwrap() == b.get_value().unwrap());
|
||||
}
|
||||
Boolean::Not(b) => {
|
||||
assert!(s.next().unwrap() != b.get_value().unwrap());
|
||||
}
|
||||
Boolean::Constant(b) => {
|
||||
assert!(input_len == 0);
|
||||
assert!(s.next().unwrap() == b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(expecteds[i], hash_result.as_bytes());
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,21 +1,16 @@
|
||||
use pairing::{Engine, Field};
|
||||
use super::*;
|
||||
use super::num::{
|
||||
AllocatedNum,
|
||||
Num
|
||||
};
|
||||
//! Window table lookup gadgets.
|
||||
|
||||
use ff::{Field, ScalarEngine};
|
||||
|
||||
use super::boolean::Boolean;
|
||||
use bellman::{
|
||||
ConstraintSystem
|
||||
};
|
||||
use super::num::{AllocatedNum, Num};
|
||||
use super::*;
|
||||
use crate::ConstraintSystem;
|
||||
|
||||
// Synthesize the constants for each base pattern.
|
||||
fn synth<'a, E: Engine, I>(
|
||||
window_size: usize,
|
||||
constants: I,
|
||||
assignment: &mut [E::Fr]
|
||||
)
|
||||
where I: IntoIterator<Item=&'a E::Fr>
|
||||
fn synth<'a, E: ScalarEngine, I>(window_size: usize, constants: I, assignment: &mut [E::Fr])
|
||||
where
|
||||
I: IntoIterator<Item = &'a E::Fr>,
|
||||
{
|
||||
assert_eq!(assignment.len(), 1 << window_size);
|
||||
|
||||
@ -34,19 +29,23 @@ fn synth<'a, E: Engine, I>(
|
||||
|
||||
/// Performs a 3-bit window table lookup. `bits` is in
|
||||
/// little-endian order.
|
||||
pub fn lookup3_xy<E: Engine, CS>(
|
||||
pub fn lookup3_xy<E: ScalarEngine, CS>(
|
||||
mut cs: CS,
|
||||
bits: &[Boolean],
|
||||
coords: &[(E::Fr, E::Fr)]
|
||||
coords: &[(E::Fr, E::Fr)],
|
||||
) -> Result<(AllocatedNum<E>, AllocatedNum<E>), SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
assert_eq!(bits.len(), 3);
|
||||
assert_eq!(coords.len(), 8);
|
||||
|
||||
// Calculate the index into `coords`
|
||||
let i =
|
||||
match (bits[0].get_value(), bits[1].get_value(), bits[2].get_value()) {
|
||||
let i = match (
|
||||
bits[0].get_value(),
|
||||
bits[1].get_value(),
|
||||
bits[2].get_value(),
|
||||
) {
|
||||
(Some(a_value), Some(b_value), Some(c_value)) => {
|
||||
let mut tmp = 0;
|
||||
if a_value {
|
||||
@ -59,25 +58,15 @@ pub fn lookup3_xy<E: Engine, CS>(
|
||||
tmp += 4;
|
||||
}
|
||||
Some(tmp)
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// Allocate the x-coordinate resulting from the lookup
|
||||
let res_x = AllocatedNum::alloc(
|
||||
cs.namespace(|| "x"),
|
||||
|| {
|
||||
Ok(coords[*i.get()?].0)
|
||||
}
|
||||
)?;
|
||||
let res_x = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(coords[*i.get()?].0))?;
|
||||
|
||||
// Allocate the y-coordinate resulting from the lookup
|
||||
let res_y = AllocatedNum::alloc(
|
||||
cs.namespace(|| "y"),
|
||||
|| {
|
||||
Ok(coords[*i.get()?].1)
|
||||
}
|
||||
)?;
|
||||
let res_y = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(coords[*i.get()?].1))?;
|
||||
|
||||
// Compute the coefficients for the lookup constraints
|
||||
let mut x_coeffs = [E::Fr::zero(); 8];
|
||||
@ -91,30 +80,38 @@ pub fn lookup3_xy<E: Engine, CS>(
|
||||
|
||||
cs.enforce(
|
||||
|| "x-coordinate lookup",
|
||||
|lc| lc + (x_coeffs[0b001], one)
|
||||
|lc| {
|
||||
lc + (x_coeffs[0b001], one)
|
||||
+ &bits[1].lc::<E>(one, x_coeffs[0b011])
|
||||
+ &bits[2].lc::<E>(one, x_coeffs[0b101])
|
||||
+ &precomp.lc::<E>(one, x_coeffs[0b111]),
|
||||
+ &precomp.lc::<E>(one, x_coeffs[0b111])
|
||||
},
|
||||
|lc| lc + &bits[0].lc::<E>(one, E::Fr::one()),
|
||||
|lc| lc + res_x.get_variable()
|
||||
|lc| {
|
||||
lc + res_x.get_variable()
|
||||
- (x_coeffs[0b000], one)
|
||||
- &bits[1].lc::<E>(one, x_coeffs[0b010])
|
||||
- &bits[2].lc::<E>(one, x_coeffs[0b100])
|
||||
- &precomp.lc::<E>(one, x_coeffs[0b110]),
|
||||
- &precomp.lc::<E>(one, x_coeffs[0b110])
|
||||
},
|
||||
);
|
||||
|
||||
cs.enforce(
|
||||
|| "y-coordinate lookup",
|
||||
|lc| lc + (y_coeffs[0b001], one)
|
||||
|lc| {
|
||||
lc + (y_coeffs[0b001], one)
|
||||
+ &bits[1].lc::<E>(one, y_coeffs[0b011])
|
||||
+ &bits[2].lc::<E>(one, y_coeffs[0b101])
|
||||
+ &precomp.lc::<E>(one, y_coeffs[0b111]),
|
||||
+ &precomp.lc::<E>(one, y_coeffs[0b111])
|
||||
},
|
||||
|lc| lc + &bits[0].lc::<E>(one, E::Fr::one()),
|
||||
|lc| lc + res_y.get_variable()
|
||||
|lc| {
|
||||
lc + res_y.get_variable()
|
||||
- (y_coeffs[0b000], one)
|
||||
- &bits[1].lc::<E>(one, y_coeffs[0b010])
|
||||
- &bits[2].lc::<E>(one, y_coeffs[0b100])
|
||||
- &precomp.lc::<E>(one, y_coeffs[0b110]),
|
||||
- &precomp.lc::<E>(one, y_coeffs[0b110])
|
||||
},
|
||||
);
|
||||
|
||||
Ok((res_x, res_y))
|
||||
@ -122,19 +119,19 @@ pub fn lookup3_xy<E: Engine, CS>(
|
||||
|
||||
/// Performs a 3-bit window table lookup, where
|
||||
/// one of the bits is a sign bit.
|
||||
pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
|
||||
pub fn lookup3_xy_with_conditional_negation<E: ScalarEngine, CS>(
|
||||
mut cs: CS,
|
||||
bits: &[Boolean],
|
||||
coords: &[(E::Fr, E::Fr)]
|
||||
coords: &[(E::Fr, E::Fr)],
|
||||
) -> Result<(Num<E>, Num<E>), SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
assert_eq!(bits.len(), 3);
|
||||
assert_eq!(coords.len(), 4);
|
||||
|
||||
// Calculate the index into `coords`
|
||||
let i =
|
||||
match (bits[0].get_value(), bits[1].get_value()) {
|
||||
let i = match (bits[0].get_value(), bits[1].get_value()) {
|
||||
(Some(a_value), Some(b_value)) => {
|
||||
let mut tmp = 0;
|
||||
if a_value {
|
||||
@ -144,22 +141,19 @@ pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
|
||||
tmp += 2;
|
||||
}
|
||||
Some(tmp)
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// Allocate the y-coordinate resulting from the lookup
|
||||
// and conditional negation
|
||||
let y = AllocatedNum::alloc(
|
||||
cs.namespace(|| "y"),
|
||||
|| {
|
||||
let mut tmp = coords[*i.get()?].1;
|
||||
if *bits[2].get_value().get()? {
|
||||
tmp.negate();
|
||||
}
|
||||
Ok(tmp)
|
||||
let y = AllocatedNum::alloc(cs.namespace(|| "y"), || {
|
||||
let mut tmp = coords[*i.get()?].1;
|
||||
if *bits[2].get_value().get()? {
|
||||
tmp.negate();
|
||||
}
|
||||
)?;
|
||||
Ok(tmp)
|
||||
})?;
|
||||
|
||||
let one = CS::one();
|
||||
|
||||
@ -172,21 +166,21 @@ pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
|
||||
let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[0], &bits[1])?;
|
||||
|
||||
let x = Num::zero()
|
||||
.add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00])
|
||||
.add_bool_with_coeff(one, &bits[0], x_coeffs[0b01])
|
||||
.add_bool_with_coeff(one, &bits[1], x_coeffs[0b10])
|
||||
.add_bool_with_coeff(one, &precomp, x_coeffs[0b11]);
|
||||
.add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00])
|
||||
.add_bool_with_coeff(one, &bits[0], x_coeffs[0b01])
|
||||
.add_bool_with_coeff(one, &bits[1], x_coeffs[0b10])
|
||||
.add_bool_with_coeff(one, &precomp, x_coeffs[0b11]);
|
||||
|
||||
let y_lc = precomp.lc::<E>(one, y_coeffs[0b11]) +
|
||||
&bits[1].lc::<E>(one, y_coeffs[0b10]) +
|
||||
&bits[0].lc::<E>(one, y_coeffs[0b01]) +
|
||||
(y_coeffs[0b00], one);
|
||||
let y_lc = precomp.lc::<E>(one, y_coeffs[0b11])
|
||||
+ &bits[1].lc::<E>(one, y_coeffs[0b10])
|
||||
+ &bits[0].lc::<E>(one, y_coeffs[0b01])
|
||||
+ (y_coeffs[0b00], one);
|
||||
|
||||
cs.enforce(
|
||||
|| "y-coordinate lookup",
|
||||
|lc| lc + &y_lc + &y_lc,
|
||||
|lc| lc + &bits[2].lc::<E>(one, E::Fr::one()),
|
||||
|lc| lc + &y_lc - y.get_variable()
|
||||
|lc| lc + &y_lc - y.get_variable(),
|
||||
);
|
||||
|
||||
Ok((x, y.into()))
|
||||
@ -194,46 +188,52 @@ pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use rand::{SeedableRng, Rand, Rng, XorShiftRng};
|
||||
use super::*;
|
||||
use ::circuit::test::*;
|
||||
use ::circuit::boolean::{Boolean, AllocatedBit};
|
||||
use crate::gadgets::boolean::{AllocatedBit, Boolean};
|
||||
use crate::gadgets::test::*;
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
#[test]
|
||||
fn test_lookup3_xy() {
|
||||
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0656]);
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..100 {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let a_val = rng.gen();
|
||||
let a = Boolean::from(
|
||||
AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap()
|
||||
);
|
||||
let a_val = rng.next_u32() % 2 != 0;
|
||||
let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap());
|
||||
|
||||
let b_val = rng.gen();
|
||||
let b = Boolean::from(
|
||||
AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap()
|
||||
);
|
||||
let b_val = rng.next_u32() % 2 != 0;
|
||||
let b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap());
|
||||
|
||||
let c_val = rng.gen();
|
||||
let c = Boolean::from(
|
||||
AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap()
|
||||
);
|
||||
let c_val = rng.next_u32() % 2 != 0;
|
||||
let c = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap());
|
||||
|
||||
let bits = vec![a, b, c];
|
||||
|
||||
let points: Vec<(Fr, Fr)> = (0..8).map(|_| (rng.gen(), rng.gen())).collect();
|
||||
let points: Vec<(Fr, Fr)> = (0..8)
|
||||
.map(|_| (Fr::random(&mut rng), Fr::random(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let res = lookup3_xy(&mut cs, &bits, &points).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
let mut index = 0;
|
||||
if a_val { index += 1 }
|
||||
if b_val { index += 2 }
|
||||
if c_val { index += 4 }
|
||||
if a_val {
|
||||
index += 1
|
||||
}
|
||||
if b_val {
|
||||
index += 2
|
||||
}
|
||||
if c_val {
|
||||
index += 4
|
||||
}
|
||||
|
||||
assert_eq!(res.0.get_value().unwrap(), points[index].0);
|
||||
assert_eq!(res.1.get_value().unwrap(), points[index].1);
|
||||
@ -242,53 +242,63 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_lookup3_xy_with_conditional_negation() {
|
||||
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..100 {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let a_val = rng.gen();
|
||||
let a = Boolean::from(
|
||||
AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap()
|
||||
);
|
||||
let a_val = rng.next_u32() % 2 != 0;
|
||||
let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap());
|
||||
|
||||
let b_val = rng.gen();
|
||||
let b = Boolean::from(
|
||||
AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap()
|
||||
);
|
||||
let b_val = rng.next_u32() % 2 != 0;
|
||||
let b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap());
|
||||
|
||||
let c_val = rng.gen();
|
||||
let c = Boolean::from(
|
||||
AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap()
|
||||
);
|
||||
let c_val = rng.next_u32() % 2 != 0;
|
||||
let c = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap());
|
||||
|
||||
let bits = vec![a, b, c];
|
||||
|
||||
let points: Vec<(Fr, Fr)> = (0..4).map(|_| (rng.gen(), rng.gen())).collect();
|
||||
let points: Vec<(Fr, Fr)> = (0..4)
|
||||
.map(|_| (Fr::random(&mut rng), Fr::random(&mut rng)))
|
||||
.collect();
|
||||
|
||||
let res = lookup3_xy_with_conditional_negation(&mut cs, &bits, &points).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
let mut index = 0;
|
||||
if a_val { index += 1 }
|
||||
if b_val { index += 2 }
|
||||
if a_val {
|
||||
index += 1
|
||||
}
|
||||
if b_val {
|
||||
index += 2
|
||||
}
|
||||
|
||||
assert_eq!(res.0.get_value().unwrap(), points[index].0);
|
||||
let mut tmp = points[index].1;
|
||||
if c_val { tmp.negate() }
|
||||
if c_val {
|
||||
tmp.negate()
|
||||
}
|
||||
assert_eq!(res.1.get_value().unwrap(), tmp);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_synth() {
|
||||
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
let window_size = 4;
|
||||
|
||||
let mut assignment = vec![Fr::zero(); 1 << window_size];
|
||||
let constants: Vec<_> = (0..(1 << window_size)).map(|_| Fr::rand(&mut rng)).collect();
|
||||
let constants: Vec<_> = (0..(1 << window_size))
|
||||
.map(|_| Fr::random(&mut rng))
|
||||
.collect();
|
||||
|
||||
synth::<Bls12, _>(window_size, &constants, &mut assignment);
|
||||
|
@ -1,17 +1,8 @@
|
||||
use pairing::{
|
||||
Engine,
|
||||
Field,
|
||||
PrimeField
|
||||
};
|
||||
use ff::{Field, PrimeField, ScalarEngine};
|
||||
|
||||
use bellman::{
|
||||
SynthesisError,
|
||||
ConstraintSystem,
|
||||
LinearCombination,
|
||||
Variable
|
||||
};
|
||||
use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
|
||||
|
||||
pub struct MultiEq<E: Engine, CS: ConstraintSystem<E>>{
|
||||
pub struct MultiEq<E: ScalarEngine, CS: ConstraintSystem<E>> {
|
||||
cs: CS,
|
||||
ops: usize,
|
||||
bits_used: usize,
|
||||
@ -19,19 +10,18 @@ pub struct MultiEq<E: Engine, CS: ConstraintSystem<E>>{
|
||||
rhs: LinearCombination<E>,
|
||||
}
|
||||
|
||||
impl<E: Engine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
|
||||
impl<E: ScalarEngine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
|
||||
pub fn new(cs: CS) -> Self {
|
||||
MultiEq {
|
||||
cs: cs,
|
||||
cs,
|
||||
ops: 0,
|
||||
bits_used: 0,
|
||||
lhs: LinearCombination::zero(),
|
||||
rhs: LinearCombination::zero()
|
||||
rhs: LinearCombination::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
fn accumulate(&mut self)
|
||||
{
|
||||
fn accumulate(&mut self) {
|
||||
let ops = self.ops;
|
||||
let lhs = self.lhs.clone();
|
||||
let rhs = self.rhs.clone();
|
||||
@ -39,7 +29,7 @@ impl<E: Engine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
|
||||
|| format!("multieq {}", ops),
|
||||
|_| lhs,
|
||||
|lc| lc + CS::one(),
|
||||
|_| rhs
|
||||
|_| rhs,
|
||||
);
|
||||
self.lhs = LinearCombination::zero();
|
||||
self.rhs = LinearCombination::zero();
|
||||
@ -51,9 +41,8 @@ impl<E: Engine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
|
||||
&mut self,
|
||||
num_bits: usize,
|
||||
lhs: &LinearCombination<E>,
|
||||
rhs: &LinearCombination<E>
|
||||
)
|
||||
{
|
||||
rhs: &LinearCombination<E>,
|
||||
) {
|
||||
// Check if we will exceed the capacity
|
||||
if (E::Fr::CAPACITY as usize) <= (self.bits_used + num_bits) {
|
||||
self.accumulate();
|
||||
@ -68,70 +57,63 @@ impl<E: Engine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, CS: ConstraintSystem<E>> Drop for MultiEq<E, CS> {
|
||||
impl<E: ScalarEngine, CS: ConstraintSystem<E>> Drop for MultiEq<E, CS> {
|
||||
fn drop(&mut self) {
|
||||
if self.bits_used > 0 {
|
||||
self.accumulate();
|
||||
self.accumulate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, CS: ConstraintSystem<E>> ConstraintSystem<E> for MultiEq<E, CS>
|
||||
{
|
||||
impl<E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for MultiEq<E, CS> {
|
||||
type Root = Self;
|
||||
|
||||
fn one() -> Variable {
|
||||
CS::one()
|
||||
}
|
||||
|
||||
fn alloc<F, A, AR>(
|
||||
&mut self,
|
||||
annotation: A,
|
||||
f: F
|
||||
) -> Result<Variable, SynthesisError>
|
||||
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
||||
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>,
|
||||
{
|
||||
self.cs.alloc(annotation, f)
|
||||
}
|
||||
|
||||
fn alloc_input<F, A, AR>(
|
||||
&mut self,
|
||||
annotation: A,
|
||||
f: F
|
||||
) -> Result<Variable, SynthesisError>
|
||||
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
||||
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>,
|
||||
{
|
||||
self.cs.alloc_input(annotation, f)
|
||||
}
|
||||
|
||||
fn enforce<A, AR, LA, LB, LC>(
|
||||
&mut self,
|
||||
annotation: A,
|
||||
a: LA,
|
||||
b: LB,
|
||||
c: LC
|
||||
)
|
||||
where A: FnOnce() -> AR, AR: Into<String>,
|
||||
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
||||
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
||||
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>
|
||||
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
|
||||
where
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>,
|
||||
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
||||
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
||||
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
||||
{
|
||||
self.cs.enforce(annotation, a, b, c)
|
||||
}
|
||||
|
||||
fn push_namespace<NR, N>(&mut self, name_fn: N)
|
||||
where NR: Into<String>, N: FnOnce() -> NR
|
||||
where
|
||||
NR: Into<String>,
|
||||
N: FnOnce() -> NR,
|
||||
{
|
||||
self.cs.get_root().push_namespace(name_fn)
|
||||
}
|
||||
|
||||
fn pop_namespace(&mut self)
|
||||
{
|
||||
fn pop_namespace(&mut self) {
|
||||
self.cs.get_root().pop_namespace()
|
||||
}
|
||||
|
||||
fn get_root(&mut self) -> &mut Self::Root
|
||||
{
|
||||
fn get_root(&mut self) -> &mut Self::Root {
|
||||
self
|
||||
}
|
||||
}
|
111
src/gadgets/multipack.rs
Normal file
111
src/gadgets/multipack.rs
Normal file
@ -0,0 +1,111 @@
|
||||
//! Helpers for packing vectors of bits into scalar field elements.
|
||||
|
||||
use super::boolean::Boolean;
|
||||
use super::num::Num;
|
||||
use super::Assignment;
|
||||
use crate::{ConstraintSystem, SynthesisError};
|
||||
use ff::{Field, PrimeField, ScalarEngine};
|
||||
|
||||
/// Takes a sequence of booleans and exposes them as compact
|
||||
/// public inputs
|
||||
pub fn pack_into_inputs<E, CS>(mut cs: CS, bits: &[Boolean]) -> Result<(), SynthesisError>
|
||||
where
|
||||
E: ScalarEngine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate() {
|
||||
let mut num = Num::<E>::zero();
|
||||
let mut coeff = E::Fr::one();
|
||||
for bit in bits {
|
||||
num = num.add_bool_with_coeff(CS::one(), bit, coeff);
|
||||
|
||||
coeff.double();
|
||||
}
|
||||
|
||||
let input = cs.alloc_input(|| format!("input {}", i), || Ok(*num.get_value().get()?))?;
|
||||
|
||||
// num * 1 = input
|
||||
cs.enforce(
|
||||
|| format!("packing constraint {}", i),
|
||||
|_| num.lc(E::Fr::one()),
|
||||
|lc| lc + CS::one(),
|
||||
|lc| lc + input,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn bytes_to_bits(bytes: &[u8]) -> Vec<bool> {
|
||||
bytes
|
||||
.iter()
|
||||
.flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec<bool> {
|
||||
bytes
|
||||
.iter()
|
||||
.flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn compute_multipacking<E: ScalarEngine>(bits: &[bool]) -> Vec<E::Fr> {
|
||||
let mut result = vec![];
|
||||
|
||||
for bits in bits.chunks(E::Fr::CAPACITY as usize) {
|
||||
let mut cur = E::Fr::zero();
|
||||
let mut coeff = E::Fr::one();
|
||||
|
||||
for bit in bits {
|
||||
if *bit {
|
||||
cur.add_assign(&coeff);
|
||||
}
|
||||
|
||||
coeff.double();
|
||||
}
|
||||
|
||||
result.push(cur);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multipacking() {
|
||||
use crate::ConstraintSystem;
|
||||
use pairing::bls12_381::Bls12;
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
use super::boolean::{AllocatedBit, Boolean};
|
||||
use crate::gadgets::test::*;
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
]);
|
||||
|
||||
for num_bits in 0..1500 {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let bits: Vec<bool> = (0..num_bits).map(|_| rng.next_u32() % 2 != 0).collect();
|
||||
|
||||
let circuit_bits = bits
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, &b)| {
|
||||
Boolean::from(
|
||||
AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), Some(b)).unwrap(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let expected_inputs = compute_multipacking::<Bls12>(&bits);
|
||||
|
||||
pack_into_inputs(cs.namespace(|| "pack"), &circuit_bits).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
assert!(cs.verify(&expected_inputs));
|
||||
}
|
||||
}
|
@ -1,83 +1,62 @@
|
||||
use pairing::{
|
||||
Engine,
|
||||
Field,
|
||||
PrimeField,
|
||||
PrimeFieldRepr,
|
||||
BitIterator
|
||||
};
|
||||
//! Gadgets representing numbers in the scalar field of the underlying curve.
|
||||
|
||||
use bellman::{
|
||||
SynthesisError,
|
||||
ConstraintSystem,
|
||||
LinearCombination,
|
||||
Variable
|
||||
};
|
||||
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, ScalarEngine};
|
||||
|
||||
use super::{
|
||||
Assignment
|
||||
};
|
||||
use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
|
||||
|
||||
use super::boolean::{
|
||||
self,
|
||||
Boolean,
|
||||
AllocatedBit
|
||||
};
|
||||
use super::Assignment;
|
||||
|
||||
pub struct AllocatedNum<E: Engine> {
|
||||
use super::boolean::{self, AllocatedBit, Boolean};
|
||||
|
||||
pub struct AllocatedNum<E: ScalarEngine> {
|
||||
value: Option<E::Fr>,
|
||||
variable: Variable
|
||||
variable: Variable,
|
||||
}
|
||||
|
||||
impl<E: Engine> Clone for AllocatedNum<E> {
|
||||
impl<E: ScalarEngine> Clone for AllocatedNum<E> {
|
||||
fn clone(&self) -> Self {
|
||||
AllocatedNum {
|
||||
value: self.value,
|
||||
variable: self.variable
|
||||
variable: self.variable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> AllocatedNum<E> {
|
||||
pub fn alloc<CS, F>(
|
||||
mut cs: CS,
|
||||
value: F,
|
||||
) -> Result<Self, SynthesisError>
|
||||
where CS: ConstraintSystem<E>,
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>
|
||||
impl<E: ScalarEngine> AllocatedNum<E> {
|
||||
pub fn alloc<CS, F>(mut cs: CS, value: F) -> Result<Self, SynthesisError>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
{
|
||||
let mut new_value = None;
|
||||
let var = cs.alloc(|| "num", || {
|
||||
let tmp = value()?;
|
||||
let var = cs.alloc(
|
||||
|| "num",
|
||||
|| {
|
||||
let tmp = value()?;
|
||||
|
||||
new_value = Some(tmp);
|
||||
new_value = Some(tmp);
|
||||
|
||||
Ok(tmp)
|
||||
})?;
|
||||
Ok(tmp)
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(AllocatedNum {
|
||||
value: new_value,
|
||||
variable: var
|
||||
variable: var,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn inputize<CS>(
|
||||
&self,
|
||||
mut cs: CS
|
||||
) -> Result<(), SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
pub fn inputize<CS>(&self, mut cs: CS) -> Result<(), SynthesisError>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
let input = cs.alloc_input(
|
||||
|| "input variable",
|
||||
|| {
|
||||
Ok(*self.value.get()?)
|
||||
}
|
||||
)?;
|
||||
let input = cs.alloc_input(|| "input variable", || Ok(*self.value.get()?))?;
|
||||
|
||||
cs.enforce(
|
||||
|| "enforce input is correct",
|
||||
|lc| lc + input,
|
||||
|lc| lc + CS::one(),
|
||||
|lc| lc + self.variable
|
||||
|lc| lc + self.variable,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@ -88,20 +67,19 @@ impl<E: Engine> AllocatedNum<E> {
|
||||
/// order, requiring that the representation
|
||||
/// strictly exists "in the field" (i.e., a
|
||||
/// congruency is not allowed.)
|
||||
pub fn into_bits_le_strict<CS>(
|
||||
&self,
|
||||
mut cs: CS
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
pub fn to_bits_le_strict<CS>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
pub fn kary_and<E, CS>(
|
||||
mut cs: CS,
|
||||
v: &[AllocatedBit]
|
||||
v: &[AllocatedBit],
|
||||
) -> Result<AllocatedBit, SynthesisError>
|
||||
where E: Engine,
|
||||
CS: ConstraintSystem<E>
|
||||
where
|
||||
E: ScalarEngine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
assert!(v.len() > 0);
|
||||
assert!(!v.is_empty());
|
||||
|
||||
// Let's keep this simple for now and just AND them all
|
||||
// manually
|
||||
@ -114,7 +92,7 @@ impl<E: Engine> AllocatedNum<E> {
|
||||
cur = Some(AllocatedBit::and(
|
||||
cs.namespace(|| format!("and {}", i)),
|
||||
cur.as_ref().unwrap(),
|
||||
v
|
||||
v,
|
||||
)?);
|
||||
}
|
||||
}
|
||||
@ -150,15 +128,12 @@ impl<E: Engine> AllocatedNum<E> {
|
||||
if b {
|
||||
// This is part of a run of ones. Let's just
|
||||
// allocate the boolean with the expected value.
|
||||
let a_bit = AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("bit {}", i)),
|
||||
a_bit
|
||||
)?;
|
||||
let a_bit = AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), a_bit)?;
|
||||
// ... and add it to the current run of ones.
|
||||
current_run.push(a_bit.clone());
|
||||
result.push(a_bit);
|
||||
} else {
|
||||
if current_run.len() > 0 {
|
||||
if !current_run.is_empty() {
|
||||
// This is the start of a run of zeros, but we need
|
||||
// to k-ary AND against `last_run` first.
|
||||
|
||||
@ -167,7 +142,7 @@ impl<E: Engine> AllocatedNum<E> {
|
||||
}
|
||||
last_run = Some(kary_and(
|
||||
cs.namespace(|| format!("run ending at {}", i)),
|
||||
¤t_run
|
||||
¤t_run,
|
||||
)?);
|
||||
current_run.truncate(0);
|
||||
}
|
||||
@ -180,7 +155,7 @@ impl<E: Engine> AllocatedNum<E> {
|
||||
let a_bit = AllocatedBit::alloc_conditionally(
|
||||
cs.namespace(|| format!("bit {}", i)),
|
||||
a_bit,
|
||||
&last_run.as_ref().expect("char always starts with a one")
|
||||
&last_run.as_ref().expect("char always starts with a one"),
|
||||
)?;
|
||||
result.push(a_bit);
|
||||
}
|
||||
@ -206,30 +181,20 @@ impl<E: Engine> AllocatedNum<E> {
|
||||
|
||||
lc = lc - self.variable;
|
||||
|
||||
cs.enforce(
|
||||
|| "unpacking constraint",
|
||||
|lc| lc,
|
||||
|lc| lc,
|
||||
|_| lc
|
||||
);
|
||||
cs.enforce(|| "unpacking constraint", |lc| lc, |lc| lc, |_| lc);
|
||||
|
||||
// Convert into booleans, and reverse for little-endian bit order
|
||||
Ok(result.into_iter().map(|b| Boolean::from(b)).rev().collect())
|
||||
Ok(result.into_iter().map(Boolean::from).rev().collect())
|
||||
}
|
||||
|
||||
/// Convert the allocated number into its little-endian representation.
|
||||
/// Note that this does not strongly enforce that the commitment is
|
||||
/// "in the field."
|
||||
pub fn into_bits_le<CS>(
|
||||
&self,
|
||||
mut cs: CS
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
pub fn to_bits_le<CS>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
let bits = boolean::field_into_allocated_bits_le(
|
||||
&mut cs,
|
||||
self.value
|
||||
)?;
|
||||
let bits = boolean::field_into_allocated_bits_le(&mut cs, self.value)?;
|
||||
|
||||
let mut lc = LinearCombination::zero();
|
||||
let mut coeff = E::Fr::one();
|
||||
@ -242,94 +207,91 @@ impl<E: Engine> AllocatedNum<E> {
|
||||
|
||||
lc = lc - self.variable;
|
||||
|
||||
cs.enforce(
|
||||
|| "unpacking constraint",
|
||||
|lc| lc,
|
||||
|lc| lc,
|
||||
|_| lc
|
||||
);
|
||||
cs.enforce(|| "unpacking constraint", |lc| lc, |lc| lc, |_| lc);
|
||||
|
||||
Ok(bits.into_iter().map(|b| Boolean::from(b)).collect())
|
||||
Ok(bits.into_iter().map(Boolean::from).collect())
|
||||
}
|
||||
|
||||
pub fn mul<CS>(
|
||||
&self,
|
||||
mut cs: CS,
|
||||
other: &Self
|
||||
) -> Result<Self, SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
pub fn mul<CS>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
let mut value = None;
|
||||
|
||||
let var = cs.alloc(|| "product num", || {
|
||||
let mut tmp = *self.value.get()?;
|
||||
tmp.mul_assign(other.value.get()?);
|
||||
let var = cs.alloc(
|
||||
|| "product num",
|
||||
|| {
|
||||
let mut tmp = *self.value.get()?;
|
||||
tmp.mul_assign(other.value.get()?);
|
||||
|
||||
value = Some(tmp);
|
||||
value = Some(tmp);
|
||||
|
||||
Ok(tmp)
|
||||
})?;
|
||||
Ok(tmp)
|
||||
},
|
||||
)?;
|
||||
|
||||
// Constrain: a * b = ab
|
||||
cs.enforce(
|
||||
|| "multiplication constraint",
|
||||
|lc| lc + self.variable,
|
||||
|lc| lc + other.variable,
|
||||
|lc| lc + var
|
||||
|lc| lc + var,
|
||||
);
|
||||
|
||||
Ok(AllocatedNum {
|
||||
value: value,
|
||||
variable: var
|
||||
value,
|
||||
variable: var,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn square<CS>(
|
||||
&self,
|
||||
mut cs: CS
|
||||
) -> Result<Self, SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
pub fn square<CS>(&self, mut cs: CS) -> Result<Self, SynthesisError>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
let mut value = None;
|
||||
|
||||
let var = cs.alloc(|| "squared num", || {
|
||||
let mut tmp = *self.value.get()?;
|
||||
tmp.square();
|
||||
let var = cs.alloc(
|
||||
|| "squared num",
|
||||
|| {
|
||||
let mut tmp = *self.value.get()?;
|
||||
tmp.square();
|
||||
|
||||
value = Some(tmp);
|
||||
value = Some(tmp);
|
||||
|
||||
Ok(tmp)
|
||||
})?;
|
||||
Ok(tmp)
|
||||
},
|
||||
)?;
|
||||
|
||||
// Constrain: a * a = aa
|
||||
cs.enforce(
|
||||
|| "squaring constraint",
|
||||
|lc| lc + self.variable,
|
||||
|lc| lc + self.variable,
|
||||
|lc| lc + var
|
||||
|lc| lc + var,
|
||||
);
|
||||
|
||||
Ok(AllocatedNum {
|
||||
value: value,
|
||||
variable: var
|
||||
value,
|
||||
variable: var,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn assert_nonzero<CS>(
|
||||
&self,
|
||||
mut cs: CS
|
||||
) -> Result<(), SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
pub fn assert_nonzero<CS>(&self, mut cs: CS) -> Result<(), SynthesisError>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
let inv = cs.alloc(|| "ephemeral inverse", || {
|
||||
let tmp = *self.value.get()?;
|
||||
|
||||
if tmp.is_zero() {
|
||||
Err(SynthesisError::DivisionByZero)
|
||||
} else {
|
||||
Ok(tmp.inverse().unwrap())
|
||||
}
|
||||
})?;
|
||||
let inv = cs.alloc(
|
||||
|| "ephemeral inverse",
|
||||
|| {
|
||||
let tmp = *self.value.get()?;
|
||||
|
||||
if tmp.is_zero() {
|
||||
Err(SynthesisError::DivisionByZero)
|
||||
} else {
|
||||
Ok(tmp.inverse().unwrap())
|
||||
}
|
||||
},
|
||||
)?;
|
||||
|
||||
// Constrain a * inv = 1, which is only valid
|
||||
// iff a has a multiplicative inverse, untrue
|
||||
@ -338,7 +300,7 @@ impl<E: Engine> AllocatedNum<E> {
|
||||
|| "nonzero assertion constraint",
|
||||
|lc| lc + self.variable,
|
||||
|lc| lc + inv,
|
||||
|lc| lc + CS::one()
|
||||
|lc| lc + CS::one(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@ -351,44 +313,39 @@ impl<E: Engine> AllocatedNum<E> {
|
||||
mut cs: CS,
|
||||
a: &Self,
|
||||
b: &Self,
|
||||
condition: &Boolean
|
||||
condition: &Boolean,
|
||||
) -> Result<(Self, Self), SynthesisError>
|
||||
where CS: ConstraintSystem<E>
|
||||
where
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
let c = Self::alloc(
|
||||
cs.namespace(|| "conditional reversal result 1"),
|
||||
|| {
|
||||
if *condition.get_value().get()? {
|
||||
Ok(*b.value.get()?)
|
||||
} else {
|
||||
Ok(*a.value.get()?)
|
||||
}
|
||||
let c = Self::alloc(cs.namespace(|| "conditional reversal result 1"), || {
|
||||
if *condition.get_value().get()? {
|
||||
Ok(*b.value.get()?)
|
||||
} else {
|
||||
Ok(*a.value.get()?)
|
||||
}
|
||||
)?;
|
||||
})?;
|
||||
|
||||
cs.enforce(
|
||||
|| "first conditional reversal",
|
||||
|lc| lc + a.variable - b.variable,
|
||||
|_| condition.lc(CS::one(), E::Fr::one()),
|
||||
|lc| lc + a.variable - c.variable
|
||||
|lc| lc + a.variable - c.variable,
|
||||
);
|
||||
|
||||
let d = Self::alloc(
|
||||
cs.namespace(|| "conditional reversal result 2"),
|
||||
|| {
|
||||
if *condition.get_value().get()? {
|
||||
Ok(*a.value.get()?)
|
||||
} else {
|
||||
Ok(*b.value.get()?)
|
||||
}
|
||||
let d = Self::alloc(cs.namespace(|| "conditional reversal result 2"), || {
|
||||
if *condition.get_value().get()? {
|
||||
Ok(*a.value.get()?)
|
||||
} else {
|
||||
Ok(*b.value.get()?)
|
||||
}
|
||||
)?;
|
||||
})?;
|
||||
|
||||
cs.enforce(
|
||||
|| "second conditional reversal",
|
||||
|lc| lc + b.variable - a.variable,
|
||||
|_| condition.lc(CS::one(), E::Fr::one()),
|
||||
|lc| lc + b.variable - d.variable
|
||||
|lc| lc + b.variable - d.variable,
|
||||
);
|
||||
|
||||
Ok((c, d))
|
||||
@ -403,25 +360,25 @@ impl<E: Engine> AllocatedNum<E> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Num<E: Engine> {
|
||||
pub struct Num<E: ScalarEngine> {
|
||||
value: Option<E::Fr>,
|
||||
lc: LinearCombination<E>
|
||||
lc: LinearCombination<E>,
|
||||
}
|
||||
|
||||
impl<E: Engine> From<AllocatedNum<E>> for Num<E> {
|
||||
impl<E: ScalarEngine> From<AllocatedNum<E>> for Num<E> {
|
||||
fn from(num: AllocatedNum<E>) -> Num<E> {
|
||||
Num {
|
||||
value: num.value,
|
||||
lc: LinearCombination::<E>::zero() + num.variable
|
||||
lc: LinearCombination::<E>::zero() + num.variable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Num<E> {
|
||||
impl<E: ScalarEngine> Num<E> {
|
||||
pub fn zero() -> Self {
|
||||
Num {
|
||||
value: Some(E::Fr::zero()),
|
||||
lc: LinearCombination::zero()
|
||||
lc: LinearCombination::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,13 +390,7 @@ impl<E: Engine> Num<E> {
|
||||
LinearCombination::zero() + (coeff, &self.lc)
|
||||
}
|
||||
|
||||
pub fn add_bool_with_coeff(
|
||||
self,
|
||||
one: Variable,
|
||||
bit: &Boolean,
|
||||
coeff: E::Fr
|
||||
) -> Self
|
||||
{
|
||||
pub fn add_bool_with_coeff(self, one: Variable, bit: &Boolean, coeff: E::Fr) -> Self {
|
||||
let newval = match (self.value, bit.get_value()) {
|
||||
(Some(mut curval), Some(bval)) => {
|
||||
if bval {
|
||||
@ -447,25 +398,27 @@ impl<E: Engine> Num<E> {
|
||||
}
|
||||
|
||||
Some(curval)
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
Num {
|
||||
value: newval,
|
||||
lc: self.lc + &bit.lc(one, coeff)
|
||||
lc: self.lc + &bit.lc(one, coeff),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use rand::{SeedableRng, Rand, Rng, XorShiftRng};
|
||||
use bellman::{ConstraintSystem};
|
||||
use crate::ConstraintSystem;
|
||||
use ff::{BitIterator, Field, PrimeField};
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
use pairing::{Field, PrimeField, BitIterator};
|
||||
use ::circuit::test::*;
|
||||
use rand_core::SeedableRng;
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
use super::{AllocatedNum, Boolean};
|
||||
use crate::gadgets::test::*;
|
||||
|
||||
#[test]
|
||||
fn test_allocated_num() {
|
||||
@ -494,8 +447,10 @@ mod test {
|
||||
fn test_num_multiplication() {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let n = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap();
|
||||
let n2 = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::from_str("10").unwrap())).unwrap();
|
||||
let n =
|
||||
AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap();
|
||||
let n2 =
|
||||
AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::from_str("10").unwrap())).unwrap();
|
||||
let n3 = n.mul(&mut cs, &n2).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
@ -507,12 +462,15 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_num_conditional_reversal() {
|
||||
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
{
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(rng.gen())).unwrap();
|
||||
let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(rng.gen())).unwrap();
|
||||
let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::random(&mut rng))).unwrap();
|
||||
let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::random(&mut rng))).unwrap();
|
||||
let condition = Boolean::constant(false);
|
||||
let (c, d) = AllocatedNum::conditionally_reverse(&mut cs, &a, &b, &condition).unwrap();
|
||||
|
||||
@ -525,8 +483,8 @@ mod test {
|
||||
{
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(rng.gen())).unwrap();
|
||||
let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(rng.gen())).unwrap();
|
||||
let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::random(&mut rng))).unwrap();
|
||||
let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::random(&mut rng))).unwrap();
|
||||
let condition = Boolean::constant(true);
|
||||
let (c, d) = AllocatedNum::conditionally_reverse(&mut cs, &a, &b, &condition).unwrap();
|
||||
|
||||
@ -565,7 +523,7 @@ mod test {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let n = AllocatedNum::alloc(&mut cs, || Ok(negone)).unwrap();
|
||||
n.into_bits_le_strict(&mut cs).unwrap();
|
||||
n.to_bits_le_strict(&mut cs).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
@ -573,28 +531,37 @@ mod test {
|
||||
cs.set("bit 254/boolean", Fr::one());
|
||||
|
||||
// this makes the conditional boolean constraint fail
|
||||
assert_eq!(cs.which_is_unsatisfied().unwrap(), "bit 254/boolean constraint");
|
||||
assert_eq!(
|
||||
cs.which_is_unsatisfied().unwrap(),
|
||||
"bit 254/boolean constraint"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_bits() {
|
||||
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for i in 0..200 {
|
||||
let r = Fr::rand(&mut rng);
|
||||
let r = Fr::random(&mut rng);
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let n = AllocatedNum::alloc(&mut cs, || Ok(r)).unwrap();
|
||||
|
||||
let bits = if i % 2 == 0 {
|
||||
n.into_bits_le(&mut cs).unwrap()
|
||||
n.to_bits_le(&mut cs).unwrap()
|
||||
} else {
|
||||
n.into_bits_le_strict(&mut cs).unwrap()
|
||||
n.to_bits_le_strict(&mut cs).unwrap()
|
||||
};
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
for (b, a) in BitIterator::new(r.into_repr()).skip(1).zip(bits.iter().rev()) {
|
||||
for (b, a) in BitIterator::new(r.into_repr())
|
||||
.skip(1)
|
||||
.zip(bits.iter().rev())
|
||||
{
|
||||
if let &Boolean::Is(ref a) = a {
|
||||
assert_eq!(b, a.get_value().unwrap());
|
||||
} else {
|
||||
@ -602,7 +569,7 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
cs.set("num", Fr::rand(&mut rng));
|
||||
cs.set("num", Fr::random(&mut rng));
|
||||
assert!(!cs.is_satisfied());
|
||||
cs.set("num", r);
|
||||
assert!(cs.is_satisfied());
|
@ -1,9 +1,15 @@
|
||||
use super::uint32::UInt32;
|
||||
use super::multieq::MultiEq;
|
||||
use super::boolean::Boolean;
|
||||
use bellman::{ConstraintSystem, SynthesisError};
|
||||
use pairing::Engine;
|
||||
//! Circuits for the [SHA-256] hash function and its internal compression
|
||||
//! function.
|
||||
//!
|
||||
//! [SHA-256]: https://tools.ietf.org/html/rfc6234
|
||||
|
||||
use super::boolean::Boolean;
|
||||
use super::multieq::MultiEq;
|
||||
use super::uint32::UInt32;
|
||||
use crate::{ConstraintSystem, SynthesisError};
|
||||
use ff::ScalarEngine;
|
||||
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
const ROUND_CONSTANTS: [u32; 64] = [
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
@ -12,37 +18,36 @@ const ROUND_CONSTANTS: [u32; 64] = [
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
||||
];
|
||||
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
const IV: [u32; 8] = [
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
||||
];
|
||||
|
||||
pub fn sha256_block_no_padding<E, CS>(
|
||||
mut cs: CS,
|
||||
input: &[Boolean]
|
||||
input: &[Boolean],
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>
|
||||
where
|
||||
E: ScalarEngine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
assert_eq!(input.len(), 512);
|
||||
|
||||
Ok(sha256_compression_function(
|
||||
&mut cs,
|
||||
&input,
|
||||
&get_sha256_iv()
|
||||
)?
|
||||
.into_iter()
|
||||
.flat_map(|e| e.into_bits_be())
|
||||
.collect())
|
||||
Ok(
|
||||
sha256_compression_function(&mut cs, &input, &get_sha256_iv())?
|
||||
.into_iter()
|
||||
.flat_map(|e| e.into_bits_be())
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn sha256<E, CS>(
|
||||
mut cs: CS,
|
||||
input: &[Boolean]
|
||||
) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>
|
||||
pub fn sha256<E, CS>(mut cs: CS, input: &[Boolean]) -> Result<Vec<Boolean>, SynthesisError>
|
||||
where
|
||||
E: ScalarEngine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
assert!(input.len() % 8 == 0);
|
||||
|
||||
@ -62,16 +67,10 @@ pub fn sha256<E, CS>(
|
||||
|
||||
let mut cur = get_sha256_iv();
|
||||
for (i, block) in padded.chunks(512).enumerate() {
|
||||
cur = sha256_compression_function(
|
||||
cs.namespace(|| format!("block {}", i)),
|
||||
block,
|
||||
&cur
|
||||
)?;
|
||||
cur = sha256_compression_function(cs.namespace(|| format!("block {}", i)), block, &cur)?;
|
||||
}
|
||||
|
||||
Ok(cur.into_iter()
|
||||
.flat_map(|e| e.into_bits_be())
|
||||
.collect())
|
||||
Ok(cur.into_iter().flat_map(|e| e.into_bits_be()).collect())
|
||||
}
|
||||
|
||||
fn get_sha256_iv() -> Vec<UInt32> {
|
||||
@ -81,16 +80,19 @@ fn get_sha256_iv() -> Vec<UInt32> {
|
||||
fn sha256_compression_function<E, CS>(
|
||||
cs: CS,
|
||||
input: &[Boolean],
|
||||
current_hash_value: &[UInt32]
|
||||
current_hash_value: &[UInt32],
|
||||
) -> Result<Vec<UInt32>, SynthesisError>
|
||||
where E: Engine, CS: ConstraintSystem<E>
|
||||
where
|
||||
E: ScalarEngine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
assert_eq!(input.len(), 512);
|
||||
assert_eq!(current_hash_value.len(), 8);
|
||||
|
||||
let mut w = input.chunks(32)
|
||||
.map(|e| UInt32::from_bits_be(e))
|
||||
.collect::<Vec<_>>();
|
||||
let mut w = input
|
||||
.chunks(32)
|
||||
.map(|e| UInt32::from_bits_be(e))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// We can save some constraints by combining some of
|
||||
// the constraints in different u32 additions
|
||||
@ -100,30 +102,18 @@ fn sha256_compression_function<E, CS>(
|
||||
let cs = &mut cs.namespace(|| format!("w extension {}", i));
|
||||
|
||||
// s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3)
|
||||
let mut s0 = w[i-15].rotr(7);
|
||||
s0 = s0.xor(
|
||||
cs.namespace(|| "first xor for s0"),
|
||||
&w[i-15].rotr(18)
|
||||
)?;
|
||||
s0 = s0.xor(
|
||||
cs.namespace(|| "second xor for s0"),
|
||||
&w[i-15].shr(3)
|
||||
)?;
|
||||
let mut s0 = w[i - 15].rotr(7);
|
||||
s0 = s0.xor(cs.namespace(|| "first xor for s0"), &w[i - 15].rotr(18))?;
|
||||
s0 = s0.xor(cs.namespace(|| "second xor for s0"), &w[i - 15].shr(3))?;
|
||||
|
||||
// s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10)
|
||||
let mut s1 = w[i-2].rotr(17);
|
||||
s1 = s1.xor(
|
||||
cs.namespace(|| "first xor for s1"),
|
||||
&w[i-2].rotr(19)
|
||||
)?;
|
||||
s1 = s1.xor(
|
||||
cs.namespace(|| "second xor for s1"),
|
||||
&w[i-2].shr(10)
|
||||
)?;
|
||||
let mut s1 = w[i - 2].rotr(17);
|
||||
s1 = s1.xor(cs.namespace(|| "first xor for s1"), &w[i - 2].rotr(19))?;
|
||||
s1 = s1.xor(cs.namespace(|| "second xor for s1"), &w[i - 2].shr(10))?;
|
||||
|
||||
let tmp = UInt32::addmany(
|
||||
cs.namespace(|| "computation of w[i]"),
|
||||
&[w[i-16].clone(), s0, w[i-7].clone(), s1]
|
||||
&[w[i - 16].clone(), s0, w[i - 7].clone(), s1],
|
||||
)?;
|
||||
|
||||
// w[i] := w[i-16] + s0 + w[i-7] + s1
|
||||
@ -134,29 +124,21 @@ fn sha256_compression_function<E, CS>(
|
||||
|
||||
enum Maybe {
|
||||
Deferred(Vec<UInt32>),
|
||||
Concrete(UInt32)
|
||||
Concrete(UInt32),
|
||||
}
|
||||
|
||||
impl Maybe {
|
||||
fn compute<E, CS, M>(
|
||||
self,
|
||||
cs: M,
|
||||
others: &[UInt32]
|
||||
) -> Result<UInt32, SynthesisError>
|
||||
where E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
M: ConstraintSystem<E, Root=MultiEq<E, CS>>
|
||||
fn compute<E, CS, M>(self, cs: M, others: &[UInt32]) -> Result<UInt32, SynthesisError>
|
||||
where
|
||||
E: ScalarEngine,
|
||||
CS: ConstraintSystem<E>,
|
||||
M: ConstraintSystem<E, Root = MultiEq<E, CS>>,
|
||||
{
|
||||
Ok(match self {
|
||||
Maybe::Concrete(ref v) => {
|
||||
return Ok(v.clone())
|
||||
},
|
||||
Maybe::Concrete(ref v) => return Ok(v.clone()),
|
||||
Maybe::Deferred(mut v) => {
|
||||
v.extend(others.into_iter().cloned());
|
||||
UInt32::addmany(
|
||||
cs,
|
||||
&v
|
||||
)?
|
||||
v.extend(others.iter().cloned());
|
||||
UInt32::addmany(cs, &v)?
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -177,22 +159,11 @@ fn sha256_compression_function<E, CS>(
|
||||
// S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
|
||||
let new_e = e.compute(cs.namespace(|| "deferred e computation"), &[])?;
|
||||
let mut s1 = new_e.rotr(6);
|
||||
s1 = s1.xor(
|
||||
cs.namespace(|| "first xor for s1"),
|
||||
&new_e.rotr(11)
|
||||
)?;
|
||||
s1 = s1.xor(
|
||||
cs.namespace(|| "second xor for s1"),
|
||||
&new_e.rotr(25)
|
||||
)?;
|
||||
s1 = s1.xor(cs.namespace(|| "first xor for s1"), &new_e.rotr(11))?;
|
||||
s1 = s1.xor(cs.namespace(|| "second xor for s1"), &new_e.rotr(25))?;
|
||||
|
||||
// ch := (e and f) xor ((not e) and g)
|
||||
let ch = UInt32::sha256_ch(
|
||||
cs.namespace(|| "ch"),
|
||||
&new_e,
|
||||
&f,
|
||||
&g
|
||||
)?;
|
||||
let ch = UInt32::sha256_ch(cs.namespace(|| "ch"), &new_e, &f, &g)?;
|
||||
|
||||
// temp1 := h + S1 + ch + k[i] + w[i]
|
||||
let temp1 = vec![
|
||||
@ -200,28 +171,17 @@ fn sha256_compression_function<E, CS>(
|
||||
s1,
|
||||
ch,
|
||||
UInt32::constant(ROUND_CONSTANTS[i]),
|
||||
w[i].clone()
|
||||
w[i].clone(),
|
||||
];
|
||||
|
||||
// S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
|
||||
let new_a = a.compute(cs.namespace(|| "deferred a computation"), &[])?;
|
||||
let mut s0 = new_a.rotr(2);
|
||||
s0 = s0.xor(
|
||||
cs.namespace(|| "first xor for s0"),
|
||||
&new_a.rotr(13)
|
||||
)?;
|
||||
s0 = s0.xor(
|
||||
cs.namespace(|| "second xor for s0"),
|
||||
&new_a.rotr(22)
|
||||
)?;
|
||||
s0 = s0.xor(cs.namespace(|| "first xor for s0"), &new_a.rotr(13))?;
|
||||
s0 = s0.xor(cs.namespace(|| "second xor for s0"), &new_a.rotr(22))?;
|
||||
|
||||
// maj := (a and b) xor (a and c) xor (b and c)
|
||||
let maj = UInt32::sha256_maj(
|
||||
cs.namespace(|| "maj"),
|
||||
&new_a,
|
||||
&b,
|
||||
&c
|
||||
)?;
|
||||
let maj = UInt32::sha256_maj(cs.namespace(|| "maj"), &new_a, &b, &c)?;
|
||||
|
||||
// temp2 := S0 + maj
|
||||
let temp2 = vec![s0, maj];
|
||||
@ -244,7 +204,13 @@ fn sha256_compression_function<E, CS>(
|
||||
d = c;
|
||||
c = b;
|
||||
b = new_a;
|
||||
a = Maybe::Deferred(temp1.iter().cloned().chain(temp2.iter().cloned()).collect::<Vec<_>>());
|
||||
a = Maybe::Deferred(
|
||||
temp1
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(temp2.iter().cloned())
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -261,42 +227,42 @@ fn sha256_compression_function<E, CS>(
|
||||
|
||||
let h0 = a.compute(
|
||||
cs.namespace(|| "deferred h0 computation"),
|
||||
&[current_hash_value[0].clone()]
|
||||
&[current_hash_value[0].clone()],
|
||||
)?;
|
||||
|
||||
let h1 = UInt32::addmany(
|
||||
cs.namespace(|| "new h1"),
|
||||
&[current_hash_value[1].clone(), b]
|
||||
&[current_hash_value[1].clone(), b],
|
||||
)?;
|
||||
|
||||
let h2 = UInt32::addmany(
|
||||
cs.namespace(|| "new h2"),
|
||||
&[current_hash_value[2].clone(), c]
|
||||
&[current_hash_value[2].clone(), c],
|
||||
)?;
|
||||
|
||||
let h3 = UInt32::addmany(
|
||||
cs.namespace(|| "new h3"),
|
||||
&[current_hash_value[3].clone(), d]
|
||||
&[current_hash_value[3].clone(), d],
|
||||
)?;
|
||||
|
||||
let h4 = e.compute(
|
||||
cs.namespace(|| "deferred h4 computation"),
|
||||
&[current_hash_value[4].clone()]
|
||||
&[current_hash_value[4].clone()],
|
||||
)?;
|
||||
|
||||
let h5 = UInt32::addmany(
|
||||
cs.namespace(|| "new h5"),
|
||||
&[current_hash_value[5].clone(), f]
|
||||
&[current_hash_value[5].clone(), f],
|
||||
)?;
|
||||
|
||||
let h6 = UInt32::addmany(
|
||||
cs.namespace(|| "new h6"),
|
||||
&[current_hash_value[6].clone(), g]
|
||||
&[current_hash_value[6].clone(), g],
|
||||
)?;
|
||||
|
||||
let h7 = UInt32::addmany(
|
||||
cs.namespace(|| "new h7"),
|
||||
&[current_hash_value[7].clone(), h]
|
||||
&[current_hash_value[7].clone(), h],
|
||||
)?;
|
||||
|
||||
Ok(vec![h0, h1, h2, h3, h4, h5, h6, h7])
|
||||
@ -305,10 +271,11 @@ fn sha256_compression_function<E, CS>(
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use circuit::boolean::AllocatedBit;
|
||||
use crate::gadgets::boolean::AllocatedBit;
|
||||
use crate::gadgets::test::TestConstraintSystem;
|
||||
use pairing::bls12_381::Bls12;
|
||||
use circuit::test::TestConstraintSystem;
|
||||
use rand::{XorShiftRng, SeedableRng, Rng};
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
#[test]
|
||||
fn test_blank_hash() {
|
||||
@ -317,11 +284,7 @@ mod test {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
let mut input_bits: Vec<_> = (0..512).map(|_| Boolean::Constant(false)).collect();
|
||||
input_bits[0] = Boolean::Constant(true);
|
||||
let out = sha256_compression_function(
|
||||
&mut cs,
|
||||
&input_bits,
|
||||
&iv
|
||||
).unwrap();
|
||||
let out = sha256_compression_function(&mut cs, &input_bits, &iv).unwrap();
|
||||
let out_bits: Vec<_> = out.into_iter().flat_map(|e| e.into_bits_be()).collect();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
@ -330,7 +293,7 @@ mod test {
|
||||
let expected = hex!("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
|
||||
|
||||
let mut out = out_bits.into_iter();
|
||||
for b in expected.into_iter() {
|
||||
for b in expected.iter() {
|
||||
for i in (0..8).rev() {
|
||||
let c = out.next().unwrap().get_value().unwrap();
|
||||
|
||||
@ -341,25 +304,27 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_full_block() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
let iv = get_sha256_iv();
|
||||
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
let input_bits: Vec<_> = (0..512).map(|i| {
|
||||
Boolean::from(
|
||||
AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("input bit {}", i)),
|
||||
Some(rng.gen())
|
||||
).unwrap()
|
||||
)
|
||||
}).collect();
|
||||
let input_bits: Vec<_> = (0..512)
|
||||
.map(|i| {
|
||||
Boolean::from(
|
||||
AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("input bit {}", i)),
|
||||
Some(rng.next_u32() % 2 != 0),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
sha256_compression_function(
|
||||
cs.namespace(|| "sha256"),
|
||||
&input_bits,
|
||||
&iv
|
||||
).unwrap();
|
||||
sha256_compression_function(cs.namespace(|| "sha256"), &input_bits, &iv).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints() - 512, 25840);
|
||||
@ -367,18 +332,18 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_against_vectors() {
|
||||
use crypto::sha2::Sha256;
|
||||
use crypto::digest::Digest;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0))
|
||||
{
|
||||
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) {
|
||||
let mut h = Sha256::new();
|
||||
let data: Vec<u8> = (0..input_len).map(|_| rng.gen()).collect();
|
||||
let data: Vec<u8> = (0..input_len).map(|_| rng.next_u32() as u8).collect();
|
||||
h.input(&data);
|
||||
let mut hash_result = [0u8; 32];
|
||||
h.result(&mut hash_result[..]);
|
||||
let hash_result = h.result();
|
||||
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
let mut input_bits = vec![];
|
||||
@ -387,7 +352,11 @@ mod test {
|
||||
for bit_i in (0..8).rev() {
|
||||
let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i));
|
||||
|
||||
input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into());
|
||||
input_bits.push(
|
||||
AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8))
|
||||
.unwrap()
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -395,17 +364,19 @@ mod test {
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
let mut s = hash_result.as_ref().iter()
|
||||
.flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8));
|
||||
let mut s = hash_result
|
||||
.as_ref()
|
||||
.iter()
|
||||
.flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8));
|
||||
|
||||
for b in r {
|
||||
match b {
|
||||
Boolean::Is(b) => {
|
||||
assert!(s.next().unwrap() == b.get_value().unwrap());
|
||||
},
|
||||
}
|
||||
Boolean::Not(b) => {
|
||||
assert!(s.next().unwrap() != b.get_value().unwrap());
|
||||
},
|
||||
}
|
||||
Boolean::Constant(b) => {
|
||||
assert!(input_len == 0);
|
||||
assert!(s.next().unwrap() == b);
|
@ -1,17 +1,8 @@
|
||||
use pairing::{
|
||||
Engine,
|
||||
Field,
|
||||
PrimeField,
|
||||
PrimeFieldRepr
|
||||
};
|
||||
//! Helpers for testing circuit implementations.
|
||||
|
||||
use bellman::{
|
||||
LinearCombination,
|
||||
SynthesisError,
|
||||
ConstraintSystem,
|
||||
Variable,
|
||||
Index
|
||||
};
|
||||
use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine};
|
||||
|
||||
use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Write;
|
||||
@ -20,27 +11,27 @@ use byteorder::{BigEndian, ByteOrder};
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use blake2_rfc::blake2s::Blake2s;
|
||||
use blake2s_simd::{Params as Blake2sParams, State as Blake2sState};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum NamedObject {
|
||||
Constraint(usize),
|
||||
Var(Variable),
|
||||
Namespace
|
||||
Namespace,
|
||||
}
|
||||
|
||||
/// Constraint system for testing purposes.
|
||||
pub struct TestConstraintSystem<E: Engine> {
|
||||
pub struct TestConstraintSystem<E: ScalarEngine> {
|
||||
named_objects: HashMap<String, NamedObject>,
|
||||
current_namespace: Vec<String>,
|
||||
constraints: Vec<(
|
||||
LinearCombination<E>,
|
||||
LinearCombination<E>,
|
||||
LinearCombination<E>,
|
||||
String
|
||||
String,
|
||||
)>,
|
||||
inputs: Vec<(E::Fr, String)>,
|
||||
aux: Vec<(E::Fr, String)>
|
||||
aux: Vec<(E::Fr, String)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
@ -52,7 +43,7 @@ impl PartialEq for OrderedVariable {
|
||||
match (self.0.get_unchecked(), other.0.get_unchecked()) {
|
||||
(Index::Input(ref a), Index::Input(ref b)) => a == b,
|
||||
(Index::Aux(ref a), Index::Aux(ref b)) => a == b,
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -67,20 +58,17 @@ impl Ord for OrderedVariable {
|
||||
(Index::Input(ref a), Index::Input(ref b)) => a.cmp(b),
|
||||
(Index::Aux(ref a), Index::Aux(ref b)) => a.cmp(b),
|
||||
(Index::Input(_), Index::Aux(_)) => Ordering::Less,
|
||||
(Index::Aux(_), Index::Input(_)) => Ordering::Greater
|
||||
(Index::Aux(_), Index::Input(_)) => Ordering::Greater,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn proc_lc<E: Engine>(
|
||||
terms: &[(Variable, E::Fr)],
|
||||
) -> BTreeMap<OrderedVariable, E::Fr>
|
||||
{
|
||||
fn proc_lc<E: ScalarEngine>(terms: &[(Variable, E::Fr)]) -> BTreeMap<OrderedVariable, E::Fr> {
|
||||
let mut map = BTreeMap::new();
|
||||
for &(var, coeff) in terms {
|
||||
map.entry(OrderedVariable(var))
|
||||
.or_insert(E::Fr::zero())
|
||||
.add_assign(&coeff);
|
||||
.or_insert_with(E::Fr::zero)
|
||||
.add_assign(&coeff);
|
||||
}
|
||||
|
||||
// Remove terms that have a zero coefficient to normalize
|
||||
@ -98,11 +86,7 @@ fn proc_lc<E: Engine>(
|
||||
map
|
||||
}
|
||||
|
||||
fn hash_lc<E: Engine>(
|
||||
terms: &[(Variable, E::Fr)],
|
||||
h: &mut Blake2s
|
||||
)
|
||||
{
|
||||
fn hash_lc<E: ScalarEngine>(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) {
|
||||
let map = proc_lc::<E>(terms);
|
||||
|
||||
let mut buf = [0u8; 9 + 32];
|
||||
@ -114,31 +98,30 @@ fn hash_lc<E: Engine>(
|
||||
Index::Input(i) => {
|
||||
buf[0] = b'I';
|
||||
BigEndian::write_u64(&mut buf[1..9], i as u64);
|
||||
},
|
||||
}
|
||||
Index::Aux(i) => {
|
||||
buf[0] = b'A';
|
||||
BigEndian::write_u64(&mut buf[1..9], i as u64);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
coeff.into_repr().write_be(&mut buf[9..]).unwrap();
|
||||
|
||||
h.update(&buf);
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_lc<E: Engine>(
|
||||
fn eval_lc<E: ScalarEngine>(
|
||||
terms: &[(Variable, E::Fr)],
|
||||
inputs: &[(E::Fr, String)],
|
||||
aux: &[(E::Fr, String)]
|
||||
) -> E::Fr
|
||||
{
|
||||
aux: &[(E::Fr, String)],
|
||||
) -> E::Fr {
|
||||
let mut acc = E::Fr::zero();
|
||||
|
||||
for &(var, ref coeff) in terms {
|
||||
let mut tmp = match var.get_unchecked() {
|
||||
Index::Input(index) => inputs[index].0,
|
||||
Index::Aux(index) => aux[index].0
|
||||
Index::Aux(index) => aux[index].0,
|
||||
};
|
||||
|
||||
tmp.mul_assign(&coeff);
|
||||
@ -148,17 +131,20 @@ fn eval_lc<E: Engine>(
|
||||
acc
|
||||
}
|
||||
|
||||
impl<E: Engine> TestConstraintSystem<E> {
|
||||
impl<E: ScalarEngine> TestConstraintSystem<E> {
|
||||
pub fn new() -> TestConstraintSystem<E> {
|
||||
let mut map = HashMap::new();
|
||||
map.insert("ONE".into(), NamedObject::Var(TestConstraintSystem::<E>::one()));
|
||||
map.insert(
|
||||
"ONE".into(),
|
||||
NamedObject::Var(TestConstraintSystem::<E>::one()),
|
||||
);
|
||||
|
||||
TestConstraintSystem {
|
||||
named_objects: map,
|
||||
current_namespace: vec![],
|
||||
constraints: vec![],
|
||||
inputs: vec![(E::Fr::one(), "ONE".into())],
|
||||
aux: vec![]
|
||||
aux: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,9 +157,9 @@ impl<E: Engine> TestConstraintSystem<E> {
|
||||
tmp
|
||||
};
|
||||
|
||||
let powers_of_two = (0..E::Fr::NUM_BITS).map(|i| {
|
||||
E::Fr::from_str("2").unwrap().pow(&[i as u64])
|
||||
}).collect::<Vec<_>>();
|
||||
let powers_of_two = (0..E::Fr::NUM_BITS)
|
||||
.map(|i| E::Fr::from_str("2").unwrap().pow(&[u64::from(i)]))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let pp = |s: &mut String, lc: &LinearCombination<E>| {
|
||||
write!(s, "(").unwrap();
|
||||
@ -200,7 +186,7 @@ impl<E: Engine> TestConstraintSystem<E> {
|
||||
match var.0.get_unchecked() {
|
||||
Index::Input(i) => {
|
||||
write!(s, "`{}`", &self.inputs[i].1).unwrap();
|
||||
},
|
||||
}
|
||||
Index::Aux(i) => {
|
||||
write!(s, "`{}`", &self.aux[i].1).unwrap();
|
||||
}
|
||||
@ -230,7 +216,7 @@ impl<E: Engine> TestConstraintSystem<E> {
|
||||
}
|
||||
|
||||
pub fn hash(&self) -> String {
|
||||
let mut h = Blake2s::new(32);
|
||||
let mut h = Blake2sParams::new().hash_length(32).to_state();
|
||||
{
|
||||
let mut buf = [0u8; 24];
|
||||
|
||||
@ -263,57 +249,52 @@ impl<E: Engine> TestConstraintSystem<E> {
|
||||
a.mul_assign(&b);
|
||||
|
||||
if a != c {
|
||||
return Some(&*path)
|
||||
return Some(&*path);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn is_satisfied(&self) -> bool
|
||||
{
|
||||
pub fn is_satisfied(&self) -> bool {
|
||||
self.which_is_unsatisfied().is_none()
|
||||
}
|
||||
|
||||
pub fn num_constraints(&self) -> usize
|
||||
{
|
||||
pub fn num_constraints(&self) -> usize {
|
||||
self.constraints.len()
|
||||
}
|
||||
|
||||
pub fn set(&mut self, path: &str, to: E::Fr)
|
||||
{
|
||||
pub fn set(&mut self, path: &str, to: E::Fr) {
|
||||
match self.named_objects.get(path) {
|
||||
Some(&NamedObject::Var(ref v)) => {
|
||||
match v.get_unchecked() {
|
||||
Index::Input(index) => self.inputs[index].0 = to,
|
||||
Index::Aux(index) => self.aux[index].0 = to
|
||||
}
|
||||
}
|
||||
Some(e) => panic!("tried to set path `{}` to value, but `{:?}` already exists there.", path, e),
|
||||
_ => panic!("no variable exists at path: {}", path)
|
||||
Some(&NamedObject::Var(ref v)) => match v.get_unchecked() {
|
||||
Index::Input(index) => self.inputs[index].0 = to,
|
||||
Index::Aux(index) => self.aux[index].0 = to,
|
||||
},
|
||||
Some(e) => panic!(
|
||||
"tried to set path `{}` to value, but `{:?}` already exists there.",
|
||||
path, e
|
||||
),
|
||||
_ => panic!("no variable exists at path: {}", path),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify(&self, expected: &[E::Fr]) -> bool
|
||||
{
|
||||
pub fn verify(&self, expected: &[E::Fr]) -> bool {
|
||||
assert_eq!(expected.len() + 1, self.inputs.len());
|
||||
|
||||
for (a, b) in self.inputs.iter().skip(1).zip(expected.iter())
|
||||
{
|
||||
for (a, b) in self.inputs.iter().skip(1).zip(expected.iter()) {
|
||||
if &a.0 != b {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
true
|
||||
}
|
||||
|
||||
pub fn num_inputs(&self) -> usize {
|
||||
self.inputs.len()
|
||||
}
|
||||
|
||||
pub fn get_input(&mut self, index: usize, path: &str) -> E::Fr
|
||||
{
|
||||
pub fn get_input(&mut self, index: usize, path: &str) -> E::Fr {
|
||||
let (assignment, name) = self.inputs[index].clone();
|
||||
|
||||
assert_eq!(path, name);
|
||||
@ -321,17 +302,17 @@ impl<E: Engine> TestConstraintSystem<E> {
|
||||
assignment
|
||||
}
|
||||
|
||||
pub fn get(&mut self, path: &str) -> E::Fr
|
||||
{
|
||||
pub fn get(&mut self, path: &str) -> E::Fr {
|
||||
match self.named_objects.get(path) {
|
||||
Some(&NamedObject::Var(ref v)) => {
|
||||
match v.get_unchecked() {
|
||||
Index::Input(index) => self.inputs[index].0,
|
||||
Index::Aux(index) => self.aux[index].0
|
||||
}
|
||||
}
|
||||
Some(e) => panic!("tried to get value of path `{}`, but `{:?}` exists there (not a variable)", path, e),
|
||||
_ => panic!("no variable exists at path: {}", path)
|
||||
Some(&NamedObject::Var(ref v)) => match v.get_unchecked() {
|
||||
Index::Input(index) => self.inputs[index].0,
|
||||
Index::Aux(index) => self.aux[index].0,
|
||||
},
|
||||
Some(e) => panic!(
|
||||
"tried to get value of path `{}`, but `{:?}` exists there (not a variable)",
|
||||
path, e
|
||||
),
|
||||
_ => panic!("no variable exists at path: {}", path),
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,8 +333,7 @@ fn compute_path(ns: &[String], this: String) -> String {
|
||||
let mut name = String::new();
|
||||
|
||||
let mut needs_separation = false;
|
||||
for ns in ns.iter().chain(Some(&this).into_iter())
|
||||
{
|
||||
for ns in ns.iter().chain(Some(&this).into_iter()) {
|
||||
if needs_separation {
|
||||
name += "/";
|
||||
}
|
||||
@ -365,15 +345,14 @@ fn compute_path(ns: &[String], this: String) -> String {
|
||||
name
|
||||
}
|
||||
|
||||
impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
|
||||
impl<E: ScalarEngine> ConstraintSystem<E> for TestConstraintSystem<E> {
|
||||
type Root = Self;
|
||||
|
||||
fn alloc<F, A, AR>(
|
||||
&mut self,
|
||||
annotation: A,
|
||||
f: F
|
||||
) -> Result<Variable, SynthesisError>
|
||||
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
||||
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>,
|
||||
{
|
||||
let index = self.aux.len();
|
||||
let path = compute_path(&self.current_namespace, annotation().into());
|
||||
@ -384,12 +363,11 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
|
||||
Ok(var)
|
||||
}
|
||||
|
||||
fn alloc_input<F, A, AR>(
|
||||
&mut self,
|
||||
annotation: A,
|
||||
f: F
|
||||
) -> Result<Variable, SynthesisError>
|
||||
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
||||
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<E::Fr, SynthesisError>,
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>,
|
||||
{
|
||||
let index = self.inputs.len();
|
||||
let path = compute_path(&self.current_namespace, annotation().into());
|
||||
@ -400,17 +378,13 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
|
||||
Ok(var)
|
||||
}
|
||||
|
||||
fn enforce<A, AR, LA, LB, LC>(
|
||||
&mut self,
|
||||
annotation: A,
|
||||
a: LA,
|
||||
b: LB,
|
||||
c: LC
|
||||
)
|
||||
where A: FnOnce() -> AR, AR: Into<String>,
|
||||
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
||||
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
||||
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>
|
||||
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
|
||||
where
|
||||
A: FnOnce() -> AR,
|
||||
AR: Into<String>,
|
||||
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
||||
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
||||
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
||||
{
|
||||
let path = compute_path(&self.current_namespace, annotation().into());
|
||||
let index = self.constraints.len();
|
||||
@ -424,7 +398,9 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
|
||||
}
|
||||
|
||||
fn push_namespace<NR, N>(&mut self, name_fn: N)
|
||||
where NR: Into<String>, N: FnOnce() -> NR
|
||||
where
|
||||
NR: Into<String>,
|
||||
N: FnOnce() -> NR,
|
||||
{
|
||||
let name = name_fn().into();
|
||||
let path = compute_path(&self.current_namespace, name.clone());
|
||||
@ -432,47 +408,43 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
|
||||
self.current_namespace.push(name);
|
||||
}
|
||||
|
||||
fn pop_namespace(&mut self)
|
||||
{
|
||||
fn pop_namespace(&mut self) {
|
||||
assert!(self.current_namespace.pop().is_some());
|
||||
}
|
||||
|
||||
fn get_root(&mut self) -> &mut Self::Root
|
||||
{
|
||||
fn get_root(&mut self) -> &mut Self::Root {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cs() {
|
||||
use ff::PrimeField;
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
use pairing::PrimeField;
|
||||
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 0);
|
||||
let a = cs.namespace(|| "a").alloc(|| "var", || Ok(Fr::from_str("10").unwrap())).unwrap();
|
||||
let b = cs.namespace(|| "b").alloc(|| "var", || Ok(Fr::from_str("4").unwrap())).unwrap();
|
||||
let c = cs.alloc(|| "product", || Ok(Fr::from_str("40").unwrap())).unwrap();
|
||||
let a = cs
|
||||
.namespace(|| "a")
|
||||
.alloc(|| "var", || Ok(Fr::from_str("10").unwrap()))
|
||||
.unwrap();
|
||||
let b = cs
|
||||
.namespace(|| "b")
|
||||
.alloc(|| "var", || Ok(Fr::from_str("4").unwrap()))
|
||||
.unwrap();
|
||||
let c = cs
|
||||
.alloc(|| "product", || Ok(Fr::from_str("40").unwrap()))
|
||||
.unwrap();
|
||||
|
||||
cs.enforce(
|
||||
|| "mult",
|
||||
|lc| lc + a,
|
||||
|lc| lc + b,
|
||||
|lc| lc + c
|
||||
);
|
||||
cs.enforce(|| "mult", |lc| lc + a, |lc| lc + b, |lc| lc + c);
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 1);
|
||||
|
||||
cs.set("a/var", Fr::from_str("4").unwrap());
|
||||
|
||||
let one = TestConstraintSystem::<Bls12>::one();
|
||||
cs.enforce(
|
||||
|| "eq",
|
||||
|lc| lc + a,
|
||||
|lc| lc + one,
|
||||
|lc| lc + b
|
||||
);
|
||||
cs.enforce(|| "eq", |lc| lc + a, |lc| lc + one, |lc| lc + b);
|
||||
|
||||
assert!(!cs.is_satisfied());
|
||||
assert!(cs.which_is_unsatisfied() == Some("mult"));
|
@ -1,19 +1,11 @@
|
||||
use pairing::{
|
||||
Engine,
|
||||
Field,
|
||||
PrimeField
|
||||
};
|
||||
//! Circuit representation of a [`u32`], with helpers for the [`sha256`]
|
||||
//! gadgets.
|
||||
|
||||
use bellman::{
|
||||
SynthesisError,
|
||||
ConstraintSystem,
|
||||
LinearCombination
|
||||
};
|
||||
use ff::{Field, PrimeField, ScalarEngine};
|
||||
|
||||
use super::boolean::{
|
||||
Boolean,
|
||||
AllocatedBit
|
||||
};
|
||||
use crate::{ConstraintSystem, LinearCombination, SynthesisError};
|
||||
|
||||
use super::boolean::{AllocatedBit, Boolean};
|
||||
|
||||
use super::multieq::MultiEq;
|
||||
|
||||
@ -23,13 +15,12 @@ use super::multieq::MultiEq;
|
||||
pub struct UInt32 {
|
||||
// Least significant bit first
|
||||
bits: Vec<Boolean>,
|
||||
value: Option<u32>
|
||||
value: Option<u32>,
|
||||
}
|
||||
|
||||
impl UInt32 {
|
||||
/// Construct a constant `UInt32` from a `u32`
|
||||
pub fn constant(value: u32) -> Self
|
||||
{
|
||||
pub fn constant(value: u32) -> Self {
|
||||
let mut bits = Vec::with_capacity(32);
|
||||
|
||||
let mut tmp = value;
|
||||
@ -44,18 +35,16 @@ impl UInt32 {
|
||||
}
|
||||
|
||||
UInt32 {
|
||||
bits: bits,
|
||||
value: Some(value)
|
||||
bits,
|
||||
value: Some(value),
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocate a `UInt32` in the constraint system
|
||||
pub fn alloc<E, CS>(
|
||||
mut cs: CS,
|
||||
value: Option<u32>
|
||||
) -> Result<Self, SynthesisError>
|
||||
where E: Engine,
|
||||
CS: ConstraintSystem<E>
|
||||
pub fn alloc<E, CS>(mut cs: CS, value: Option<u32>) -> Result<Self, SynthesisError>
|
||||
where
|
||||
E: ScalarEngine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
let values = match value {
|
||||
Some(mut val) => {
|
||||
@ -67,28 +56,28 @@ impl UInt32 {
|
||||
}
|
||||
|
||||
v
|
||||
},
|
||||
None => vec![None; 32]
|
||||
}
|
||||
None => vec![None; 32],
|
||||
};
|
||||
|
||||
let bits = values.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, v)| {
|
||||
Ok(Boolean::from(AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("allocated bit {}", i)),
|
||||
v
|
||||
)?))
|
||||
})
|
||||
.collect::<Result<Vec<_>, SynthesisError>>()?;
|
||||
let bits = values
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, v)| {
|
||||
Ok(Boolean::from(AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("allocated bit {}", i)),
|
||||
v,
|
||||
)?))
|
||||
})
|
||||
.collect::<Result<Vec<_>, SynthesisError>>()?;
|
||||
|
||||
Ok(UInt32 {
|
||||
bits: bits,
|
||||
value: value
|
||||
})
|
||||
Ok(UInt32 { bits, value })
|
||||
}
|
||||
|
||||
pub fn into_bits_be(&self) -> Vec<Boolean> {
|
||||
self.bits.iter().rev().cloned().collect()
|
||||
pub fn into_bits_be(self) -> Vec<Boolean> {
|
||||
let mut ret = self.bits;
|
||||
ret.reverse();
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn from_bits_be(bits: &[Boolean]) -> Self {
|
||||
@ -99,28 +88,30 @@ impl UInt32 {
|
||||
value.as_mut().map(|v| *v <<= 1);
|
||||
|
||||
match b.get_value() {
|
||||
Some(true) => { value.as_mut().map(|v| *v |= 1); },
|
||||
Some(false) => {},
|
||||
None => { value = None; }
|
||||
Some(true) => {
|
||||
value.as_mut().map(|v| *v |= 1);
|
||||
}
|
||||
Some(false) => {}
|
||||
None => {
|
||||
value = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 {
|
||||
value: value,
|
||||
bits: bits.iter().rev().cloned().collect()
|
||||
value,
|
||||
bits: bits.iter().rev().cloned().collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Turns this `UInt32` into its little-endian byte order representation.
|
||||
pub fn into_bits(&self) -> Vec<Boolean> {
|
||||
self.bits.clone()
|
||||
pub fn into_bits(self) -> Vec<Boolean> {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Converts a little-endian byte order representation of bits into a
|
||||
/// `UInt32`.
|
||||
pub fn from_bits(bits: &[Boolean]) -> Self
|
||||
{
|
||||
pub fn from_bits(bits: &[Boolean]) -> Self {
|
||||
assert_eq!(bits.len(), 32);
|
||||
|
||||
let new_bits = bits.to_vec();
|
||||
@ -129,48 +120,50 @@ impl UInt32 {
|
||||
for b in new_bits.iter().rev() {
|
||||
value.as_mut().map(|v| *v <<= 1);
|
||||
|
||||
match b {
|
||||
&Boolean::Constant(b) => {
|
||||
match *b {
|
||||
Boolean::Constant(b) => {
|
||||
if b {
|
||||
value.as_mut().map(|v| *v |= 1);
|
||||
}
|
||||
},
|
||||
&Boolean::Is(ref b) => {
|
||||
match b.get_value() {
|
||||
Some(true) => { value.as_mut().map(|v| *v |= 1); },
|
||||
Some(false) => {},
|
||||
None => { value = None }
|
||||
}
|
||||
},
|
||||
&Boolean::Not(ref b) => {
|
||||
match b.get_value() {
|
||||
Some(false) => { value.as_mut().map(|v| *v |= 1); },
|
||||
Some(true) => {},
|
||||
None => { value = None }
|
||||
}
|
||||
}
|
||||
Boolean::Is(ref b) => match b.get_value() {
|
||||
Some(true) => {
|
||||
value.as_mut().map(|v| *v |= 1);
|
||||
}
|
||||
Some(false) => {}
|
||||
None => value = None,
|
||||
},
|
||||
Boolean::Not(ref b) => match b.get_value() {
|
||||
Some(false) => {
|
||||
value.as_mut().map(|v| *v |= 1);
|
||||
}
|
||||
Some(true) => {}
|
||||
None => value = None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 {
|
||||
value: value,
|
||||
bits: new_bits
|
||||
value,
|
||||
bits: new_bits,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rotr(&self, by: usize) -> Self {
|
||||
let by = by % 32;
|
||||
|
||||
let new_bits = self.bits.iter()
|
||||
.skip(by)
|
||||
.chain(self.bits.iter())
|
||||
.take(32)
|
||||
.cloned()
|
||||
.collect();
|
||||
let new_bits = self
|
||||
.bits
|
||||
.iter()
|
||||
.skip(by)
|
||||
.chain(self.bits.iter())
|
||||
.take(32)
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
UInt32 {
|
||||
bits: new_bits,
|
||||
value: self.value.map(|v| v.rotate_right(by as u32))
|
||||
value: self.value.map(|v| v.rotate_right(by as u32)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,17 +172,18 @@ impl UInt32 {
|
||||
|
||||
let fill = Boolean::constant(false);
|
||||
|
||||
let new_bits = self.bits
|
||||
.iter() // The bits are least significant first
|
||||
.skip(by) // Skip the bits that will be lost during the shift
|
||||
.chain(Some(&fill).into_iter().cycle()) // Rest will be zeros
|
||||
.take(32) // Only 32 bits needed!
|
||||
.cloned()
|
||||
.collect();
|
||||
let new_bits = self
|
||||
.bits
|
||||
.iter() // The bits are least significant first
|
||||
.skip(by) // Skip the bits that will be lost during the shift
|
||||
.chain(Some(&fill).into_iter().cycle()) // Rest will be zeros
|
||||
.take(32) // Only 32 bits needed!
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
UInt32 {
|
||||
bits: new_bits,
|
||||
value: self.value.map(|v| v >> by as u32)
|
||||
value: self.value.map(|v| v >> by as u32),
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,121 +193,99 @@ impl UInt32 {
|
||||
b: &Self,
|
||||
c: &Self,
|
||||
tri_fn: F,
|
||||
circuit_fn: U
|
||||
circuit_fn: U,
|
||||
) -> Result<Self, SynthesisError>
|
||||
where E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
F: Fn(u32, u32, u32) -> u32,
|
||||
U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result<Boolean, SynthesisError>
|
||||
where
|
||||
E: ScalarEngine,
|
||||
CS: ConstraintSystem<E>,
|
||||
F: Fn(u32, u32, u32) -> u32,
|
||||
U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result<Boolean, SynthesisError>,
|
||||
{
|
||||
let new_value = match (a.value, b.value, c.value) {
|
||||
(Some(a), Some(b), Some(c)) => {
|
||||
Some(tri_fn(a, b, c))
|
||||
},
|
||||
_ => None
|
||||
(Some(a), Some(b), Some(c)) => Some(tri_fn(a, b, c)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let bits = a.bits.iter()
|
||||
.zip(b.bits.iter())
|
||||
.zip(c.bits.iter())
|
||||
.enumerate()
|
||||
.map(|(i, ((a, b), c))| circuit_fn(&mut cs, i, a, b, c))
|
||||
.collect::<Result<_, _>>()?;
|
||||
let bits = a
|
||||
.bits
|
||||
.iter()
|
||||
.zip(b.bits.iter())
|
||||
.zip(c.bits.iter())
|
||||
.enumerate()
|
||||
.map(|(i, ((a, b), c))| circuit_fn(&mut cs, i, a, b, c))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
Ok(UInt32 {
|
||||
bits: bits,
|
||||
value: new_value
|
||||
bits,
|
||||
value: new_value,
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute the `maj` value (a and b) xor (a and c) xor (b and c)
|
||||
/// during SHA256.
|
||||
pub fn sha256_maj<E, CS>(
|
||||
cs: CS,
|
||||
a: &Self,
|
||||
b: &Self,
|
||||
c: &Self
|
||||
) -> Result<Self, SynthesisError>
|
||||
where E: Engine,
|
||||
CS: ConstraintSystem<E>
|
||||
pub fn sha256_maj<E, CS>(cs: CS, a: &Self, b: &Self, c: &Self) -> Result<Self, SynthesisError>
|
||||
where
|
||||
E: ScalarEngine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
Self::triop(cs, a, b, c, |a, b, c| (a & b) ^ (a & c) ^ (b & c),
|
||||
|cs, i, a, b, c| {
|
||||
Boolean::sha256_maj(
|
||||
cs.namespace(|| format!("maj {}", i)),
|
||||
a,
|
||||
b,
|
||||
c
|
||||
)
|
||||
}
|
||||
Self::triop(
|
||||
cs,
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
|a, b, c| (a & b) ^ (a & c) ^ (b & c),
|
||||
|cs, i, a, b, c| Boolean::sha256_maj(cs.namespace(|| format!("maj {}", i)), a, b, c),
|
||||
)
|
||||
}
|
||||
|
||||
/// Compute the `ch` value `(a and b) xor ((not a) and c)`
|
||||
/// during SHA256.
|
||||
pub fn sha256_ch<E, CS>(
|
||||
cs: CS,
|
||||
a: &Self,
|
||||
b: &Self,
|
||||
c: &Self
|
||||
) -> Result<Self, SynthesisError>
|
||||
where E: Engine,
|
||||
CS: ConstraintSystem<E>
|
||||
pub fn sha256_ch<E, CS>(cs: CS, a: &Self, b: &Self, c: &Self) -> Result<Self, SynthesisError>
|
||||
where
|
||||
E: ScalarEngine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
Self::triop(cs, a, b, c, |a, b, c| (a & b) ^ ((!a) & c),
|
||||
|cs, i, a, b, c| {
|
||||
Boolean::sha256_ch(
|
||||
cs.namespace(|| format!("ch {}", i)),
|
||||
a,
|
||||
b,
|
||||
c
|
||||
)
|
||||
}
|
||||
Self::triop(
|
||||
cs,
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
|a, b, c| (a & b) ^ ((!a) & c),
|
||||
|cs, i, a, b, c| Boolean::sha256_ch(cs.namespace(|| format!("ch {}", i)), a, b, c),
|
||||
)
|
||||
}
|
||||
|
||||
/// XOR this `UInt32` with another `UInt32`
|
||||
pub fn xor<E, CS>(
|
||||
&self,
|
||||
mut cs: CS,
|
||||
other: &Self
|
||||
) -> Result<Self, SynthesisError>
|
||||
where E: Engine,
|
||||
CS: ConstraintSystem<E>
|
||||
pub fn xor<E, CS>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError>
|
||||
where
|
||||
E: ScalarEngine,
|
||||
CS: ConstraintSystem<E>,
|
||||
{
|
||||
let new_value = match (self.value, other.value) {
|
||||
(Some(a), Some(b)) => {
|
||||
Some(a ^ b)
|
||||
},
|
||||
_ => None
|
||||
(Some(a), Some(b)) => Some(a ^ b),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let bits = self.bits.iter()
|
||||
.zip(other.bits.iter())
|
||||
.enumerate()
|
||||
.map(|(i, (a, b))| {
|
||||
Boolean::xor(
|
||||
cs.namespace(|| format!("xor of bit {}", i)),
|
||||
a,
|
||||
b
|
||||
)
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
let bits = self
|
||||
.bits
|
||||
.iter()
|
||||
.zip(other.bits.iter())
|
||||
.enumerate()
|
||||
.map(|(i, (a, b))| Boolean::xor(cs.namespace(|| format!("xor of bit {}", i)), a, b))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
Ok(UInt32 {
|
||||
bits: bits,
|
||||
value: new_value
|
||||
bits,
|
||||
value: new_value,
|
||||
})
|
||||
}
|
||||
|
||||
/// Perform modular addition of several `UInt32` objects.
|
||||
pub fn addmany<E, CS, M>(
|
||||
mut cs: M,
|
||||
operands: &[Self]
|
||||
) -> Result<Self, SynthesisError>
|
||||
where E: Engine,
|
||||
CS: ConstraintSystem<E>,
|
||||
M: ConstraintSystem<E, Root=MultiEq<E, CS>>
|
||||
pub fn addmany<E, CS, M>(mut cs: M, operands: &[Self]) -> Result<Self, SynthesisError>
|
||||
where
|
||||
E: ScalarEngine,
|
||||
CS: ConstraintSystem<E>,
|
||||
M: ConstraintSystem<E, Root = MultiEq<E, CS>>,
|
||||
{
|
||||
// Make some arbitrary bounds for ourselves to avoid overflows
|
||||
// in the scalar field
|
||||
@ -323,7 +295,7 @@ impl UInt32 {
|
||||
|
||||
// Compute the maximum value of the sum so we allocate enough bits for
|
||||
// the result
|
||||
let mut max_value = (operands.len() as u64) * (u32::max_value() as u64);
|
||||
let mut max_value = (operands.len() as u64) * (u64::from(u32::max_value()));
|
||||
|
||||
// Keep track of the resulting value
|
||||
let mut result_value = Some(0u64);
|
||||
@ -339,8 +311,8 @@ impl UInt32 {
|
||||
// Accumulate the value
|
||||
match op.value {
|
||||
Some(val) => {
|
||||
result_value.as_mut().map(|v| *v += val as u64);
|
||||
},
|
||||
result_value.as_mut().map(|v| *v += u64::from(val));
|
||||
}
|
||||
None => {
|
||||
// If any of our operands have unknown value, we won't
|
||||
// know the value of the result
|
||||
@ -384,7 +356,7 @@ impl UInt32 {
|
||||
// Allocate the bit
|
||||
let b = AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("result bit {}", i)),
|
||||
result_value.map(|v| (v >> i) & 1 == 1)
|
||||
result_value.map(|v| (v >> i) & 1 == 1),
|
||||
)?;
|
||||
|
||||
// Add this bit to the result combination
|
||||
@ -405,48 +377,53 @@ impl UInt32 {
|
||||
|
||||
Ok(UInt32 {
|
||||
bits: result_bits,
|
||||
value: modular_value
|
||||
value: modular_value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use rand::{XorShiftRng, SeedableRng, Rng};
|
||||
use ::circuit::boolean::{Boolean};
|
||||
use super::{UInt32};
|
||||
use pairing::bls12_381::{Bls12};
|
||||
use pairing::{Field};
|
||||
use ::circuit::test::*;
|
||||
use bellman::{ConstraintSystem};
|
||||
use circuit::multieq::MultiEq;
|
||||
use super::UInt32;
|
||||
use crate::gadgets::boolean::Boolean;
|
||||
use crate::gadgets::multieq::MultiEq;
|
||||
use crate::gadgets::test::*;
|
||||
use crate::ConstraintSystem;
|
||||
use ff::Field;
|
||||
use pairing::bls12_381::Bls12;
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
#[test]
|
||||
fn test_uint32_from_bits_be() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]);
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let mut v = (0..32).map(|_| Boolean::constant(rng.gen())).collect::<Vec<_>>();
|
||||
let v = (0..32)
|
||||
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let b = UInt32::from_bits_be(&v);
|
||||
|
||||
for (i, bit) in b.bits.iter().enumerate() {
|
||||
match bit {
|
||||
&Boolean::Constant(bit) => {
|
||||
match *bit {
|
||||
Boolean::Constant(bit) => {
|
||||
assert!(bit == ((b.value.unwrap() >> i) & 1 == 1));
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
let expected_to_be_same = b.into_bits_be();
|
||||
|
||||
for x in v.iter().zip(expected_to_be_same.iter())
|
||||
{
|
||||
for x in v.iter().zip(expected_to_be_same.iter()) {
|
||||
match x {
|
||||
(&Boolean::Constant(true), &Boolean::Constant(true)) => {},
|
||||
(&Boolean::Constant(false), &Boolean::Constant(false)) => {},
|
||||
_ => unreachable!()
|
||||
(&Boolean::Constant(true), &Boolean::Constant(true)) => {}
|
||||
(&Boolean::Constant(false), &Boolean::Constant(false)) => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -454,30 +431,34 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_uint32_from_bits() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]);
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let mut v = (0..32).map(|_| Boolean::constant(rng.gen())).collect::<Vec<_>>();
|
||||
let v = (0..32)
|
||||
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let b = UInt32::from_bits(&v);
|
||||
|
||||
for (i, bit) in b.bits.iter().enumerate() {
|
||||
match bit {
|
||||
&Boolean::Constant(bit) => {
|
||||
match *bit {
|
||||
Boolean::Constant(bit) => {
|
||||
assert!(bit == ((b.value.unwrap() >> i) & 1 == 1));
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
let expected_to_be_same = b.into_bits();
|
||||
|
||||
for x in v.iter().zip(expected_to_be_same.iter())
|
||||
{
|
||||
for x in v.iter().zip(expected_to_be_same.iter()) {
|
||||
match x {
|
||||
(&Boolean::Constant(true), &Boolean::Constant(true)) => {},
|
||||
(&Boolean::Constant(false), &Boolean::Constant(false)) => {},
|
||||
_ => unreachable!()
|
||||
(&Boolean::Constant(true), &Boolean::Constant(true)) => {}
|
||||
(&Boolean::Constant(false), &Boolean::Constant(false)) => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -485,14 +466,17 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_uint32_xor() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]);
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let a: u32 = rng.gen();
|
||||
let b: u32 = rng.gen();
|
||||
let c: u32 = rng.gen();
|
||||
let a = rng.next_u32();
|
||||
let b = rng.next_u32();
|
||||
let c = rng.next_u32();
|
||||
|
||||
let mut expected = a ^ b ^ c;
|
||||
|
||||
@ -508,14 +492,14 @@ mod test {
|
||||
assert!(r.value == Some(expected));
|
||||
|
||||
for b in r.bits.iter() {
|
||||
match b {
|
||||
&Boolean::Is(ref b) => {
|
||||
match *b {
|
||||
Boolean::Is(ref b) => {
|
||||
assert!(b.get_value().unwrap() == (expected & 1 == 1));
|
||||
},
|
||||
&Boolean::Not(ref b) => {
|
||||
}
|
||||
Boolean::Not(ref b) => {
|
||||
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
|
||||
},
|
||||
&Boolean::Constant(b) => {
|
||||
}
|
||||
Boolean::Constant(b) => {
|
||||
assert!(b == (expected & 1 == 1));
|
||||
}
|
||||
}
|
||||
@ -527,14 +511,17 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_uint32_addmany_constants() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let a: u32 = rng.gen();
|
||||
let b: u32 = rng.gen();
|
||||
let c: u32 = rng.gen();
|
||||
let a = rng.next_u32();
|
||||
let b = rng.next_u32();
|
||||
let c = rng.next_u32();
|
||||
|
||||
let a_bit = UInt32::constant(a);
|
||||
let b_bit = UInt32::constant(b);
|
||||
@ -544,17 +531,18 @@ mod test {
|
||||
|
||||
let r = {
|
||||
let mut cs = MultiEq::new(&mut cs);
|
||||
let r = UInt32::addmany(cs.namespace(|| "addition"), &[a_bit, b_bit, c_bit]).unwrap();
|
||||
let r =
|
||||
UInt32::addmany(cs.namespace(|| "addition"), &[a_bit, b_bit, c_bit]).unwrap();
|
||||
r
|
||||
};
|
||||
|
||||
assert!(r.value == Some(expected));
|
||||
|
||||
for b in r.bits.iter() {
|
||||
match b {
|
||||
&Boolean::Is(_) => panic!(),
|
||||
&Boolean::Not(_) => panic!(),
|
||||
&Boolean::Constant(b) => {
|
||||
match *b {
|
||||
Boolean::Is(_) => panic!(),
|
||||
Boolean::Not(_) => panic!(),
|
||||
Boolean::Constant(b) => {
|
||||
assert!(b == (expected & 1 == 1));
|
||||
}
|
||||
}
|
||||
@ -566,15 +554,18 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_uint32_addmany() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let a: u32 = rng.gen();
|
||||
let b: u32 = rng.gen();
|
||||
let c: u32 = rng.gen();
|
||||
let d: u32 = rng.gen();
|
||||
let a = rng.next_u32();
|
||||
let b = rng.next_u32();
|
||||
let c = rng.next_u32();
|
||||
let d = rng.next_u32();
|
||||
|
||||
let mut expected = (a ^ b).wrapping_add(c).wrapping_add(d);
|
||||
|
||||
@ -586,8 +577,7 @@ mod test {
|
||||
let r = a_bit.xor(cs.namespace(|| "xor"), &b_bit).unwrap();
|
||||
let r = {
|
||||
let mut cs = MultiEq::new(&mut cs);
|
||||
let r = UInt32::addmany(cs.namespace(|| "addition"), &[r, c_bit, d_bit]).unwrap();
|
||||
r
|
||||
UInt32::addmany(cs.namespace(|| "addition"), &[r, c_bit, d_bit]).unwrap()
|
||||
};
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
@ -595,16 +585,14 @@ mod test {
|
||||
assert!(r.value == Some(expected));
|
||||
|
||||
for b in r.bits.iter() {
|
||||
match b {
|
||||
&Boolean::Is(ref b) => {
|
||||
match *b {
|
||||
Boolean::Is(ref b) => {
|
||||
assert!(b.get_value().unwrap() == (expected & 1 == 1));
|
||||
},
|
||||
&Boolean::Not(ref b) => {
|
||||
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
|
||||
},
|
||||
&Boolean::Constant(_) => {
|
||||
unreachable!()
|
||||
}
|
||||
Boolean::Not(ref b) => {
|
||||
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
|
||||
}
|
||||
Boolean::Constant(_) => unreachable!(),
|
||||
}
|
||||
|
||||
expected >>= 1;
|
||||
@ -623,9 +611,12 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_uint32_rotr() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
let mut num = rng.gen();
|
||||
let mut num = rng.next_u32();
|
||||
|
||||
let a = UInt32::constant(num);
|
||||
|
||||
@ -637,11 +628,11 @@ mod test {
|
||||
|
||||
let mut tmp = num;
|
||||
for b in &b.bits {
|
||||
match b {
|
||||
&Boolean::Constant(b) => {
|
||||
match *b {
|
||||
Boolean::Constant(b) => {
|
||||
assert_eq!(b, tmp & 1 == 1);
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
tmp >>= 1;
|
||||
@ -653,15 +644,18 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_uint32_shr() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..50 {
|
||||
for i in 0..60 {
|
||||
let num = rng.gen();
|
||||
let num = rng.next_u32();
|
||||
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());
|
||||
for (a, b) in a.bits.iter().zip(b.bits.iter()) {
|
||||
@ -673,14 +667,17 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_uint32_sha256_maj() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]);
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let a: u32 = rng.gen();
|
||||
let b: u32 = rng.gen();
|
||||
let c: u32 = rng.gen();
|
||||
let a = rng.next_u32();
|
||||
let b = rng.next_u32();
|
||||
let c = rng.next_u32();
|
||||
|
||||
let mut expected = (a & b) ^ (a & c) ^ (b & c);
|
||||
|
||||
@ -698,10 +695,10 @@ mod test {
|
||||
match b {
|
||||
&Boolean::Is(ref b) => {
|
||||
assert!(b.get_value().unwrap() == (expected & 1 == 1));
|
||||
},
|
||||
}
|
||||
&Boolean::Not(ref b) => {
|
||||
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
|
||||
},
|
||||
}
|
||||
&Boolean::Constant(b) => {
|
||||
assert!(b == (expected & 1 == 1));
|
||||
}
|
||||
@ -714,14 +711,17 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_uint32_sha256_ch() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]);
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||
0xbc, 0xe5,
|
||||
]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let a: u32 = rng.gen();
|
||||
let b: u32 = rng.gen();
|
||||
let c: u32 = rng.gen();
|
||||
let a = rng.next_u32();
|
||||
let b = rng.next_u32();
|
||||
let c = rng.next_u32();
|
||||
|
||||
let mut expected = (a & b) ^ ((!a) & c);
|
||||
|
||||
@ -739,10 +739,10 @@ mod test {
|
||||
match b {
|
||||
&Boolean::Is(ref b) => {
|
||||
assert!(b.get_value().unwrap() == (expected & 1 == 1));
|
||||
},
|
||||
}
|
||||
&Boolean::Not(ref b) => {
|
||||
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
|
||||
},
|
||||
}
|
||||
&Boolean::Constant(b) => {
|
||||
assert!(b == (expected & 1 == 1));
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user