FireMartZ
6 years ago
committed by
GitHub
216 changed files with 2123 additions and 2306 deletions
@ -0,0 +1,189 @@ |
|||
#!/usr/bin/env python2 |
|||
# Copyright (c) 2017 The Zcash developers |
|||
# Distributed under the MIT software license, see the accompanying |
|||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. |
|||
|
|||
from decimal import Decimal |
|||
from test_framework.test_framework import BitcoinTestFramework |
|||
from test_framework.util import assert_equal, assert_greater_than, start_nodes, initialize_chain_clean, connect_nodes_bi |
|||
|
|||
import logging |
|||
import time |
|||
import math |
|||
|
|||
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO) |
|||
|
|||
|
|||
class ZkeyImportExportTest (BitcoinTestFramework): |
|||
|
|||
def setup_chain(self): |
|||
print("Initializing test directory "+self.options.tmpdir) |
|||
initialize_chain_clean(self.options.tmpdir, 5) |
|||
|
|||
def setup_network(self, split=False): |
|||
self.nodes = start_nodes(5, self.options.tmpdir ) |
|||
connect_nodes_bi(self.nodes,0,1) |
|||
connect_nodes_bi(self.nodes,1,2) |
|||
connect_nodes_bi(self.nodes,0,2) |
|||
connect_nodes_bi(self.nodes,0,3) |
|||
connect_nodes_bi(self.nodes,0,4) |
|||
self.is_network_split=False |
|||
self.sync_all() |
|||
|
|||
# TODO: Refactor in z_addr test_framework file |
|||
# Returns txid if operation was a success or None |
|||
def wait_and_assert_operationid_status(self, node, myopid, in_status='success', in_errormsg=None): |
|||
print('waiting for async operation {}'.format(myopid)) |
|||
opids = [] |
|||
opids.append(myopid) |
|||
timeout = 300 |
|||
status = None |
|||
errormsg = None |
|||
txid = None |
|||
for x in xrange(1, timeout): |
|||
results = node.z_getoperationresult(opids) |
|||
if len(results)==0: |
|||
time.sleep(1) |
|||
else: |
|||
print("Results", results[0]) |
|||
status = results[0]["status"] |
|||
if status == "failed": |
|||
errormsg = results[0]['error']['message'] |
|||
elif status == "success": |
|||
txid = results[0]['result']['txid'] |
|||
break |
|||
print('...returned status: {}'.format(status)) |
|||
assert_equal(in_status, status) |
|||
if errormsg is not None: |
|||
assert(in_errormsg is not None) |
|||
assert_equal(in_errormsg in errormsg, True) |
|||
print('...returned error: {}'.format(errormsg)) |
|||
return txid |
|||
|
|||
def run_test(self): |
|||
[alice, bob, charlie, david, miner] = self.nodes |
|||
|
|||
def z_send(from_node, from_addr, to_addr, amount): |
|||
opid = from_node.z_sendmany(from_addr, [{"address": to_addr, "amount": Decimal(amount)}]) |
|||
self.wait_and_assert_operationid_status(from_node, opid) |
|||
self.sync_all() |
|||
miner.generate(1) |
|||
self.sync_all() |
|||
|
|||
def z_getbalance(node, zaddr): |
|||
bal = node.z_getbalance(zaddr) |
|||
# Ignore fees for sake of comparison |
|||
round_balance = math.ceil(bal*100)/100 |
|||
return round_balance |
|||
|
|||
def verify_utxos(node, amts, zaddr): |
|||
amts.sort(reverse=True) |
|||
txs = node.z_listreceivedbyaddress(zaddr) |
|||
|
|||
def cmp_confirmations_high_to_low(a, b): |
|||
return cmp(b["amount"], a["amount"]) |
|||
|
|||
txs.sort(cmp_confirmations_high_to_low) |
|||
print("Sorted txs", txs) |
|||
print("amts", amts) |
|||
|
|||
try: |
|||
assert_equal(amts, [tx["amount"] for tx in txs]) |
|||
except AssertionError: |
|||
logging.error( |
|||
'Expected amounts: %r; txs: %r', |
|||
amts, txs) |
|||
raise |
|||
|
|||
def get_private_balance(node): |
|||
balance = node.z_gettotalbalance() |
|||
return balance['private'] |
|||
|
|||
def find_imported_key(node, import_zaddr): |
|||
zaddrs = node.z_listaddresses() |
|||
assert(import_zaddr in zaddrs) |
|||
return import_zaddr |
|||
|
|||
# Seed Alice with some funds |
|||
alice.generate(10) |
|||
self.sync_all() |
|||
miner.generate(100) |
|||
self.sync_all() |
|||
# Shield Alice's coinbase funds to her zaddr |
|||
alice_zaddr = alice.z_getnewaddress() |
|||
res = alice.z_shieldcoinbase("*", alice_zaddr) |
|||
self.wait_and_assert_operationid_status(alice, res['opid']) |
|||
miner.generate(6) |
|||
self.sync_all() |
|||
|
|||
# Now get a pristine z-address for receiving transfers: |
|||
bob_zaddr = bob.z_getnewaddress() |
|||
verify_utxos(bob, [], bob_zaddr) |
|||
# TODO: Verify that charlie doesn't have funds in addr |
|||
# verify_utxos(charlie, []) |
|||
|
|||
# the amounts of each txn embodied which generates a single UTXO: |
|||
amounts = map(Decimal, ['2.3', '3.7', '0.1', '0.5', '1.0', '0.19']) |
|||
|
|||
# Internal test consistency assertion: |
|||
assert_greater_than( |
|||
get_private_balance(alice), |
|||
reduce(Decimal.__add__, amounts)) |
|||
|
|||
logging.info("Sending pre-export txns...") |
|||
for amount in amounts[0:2]: |
|||
z_send(alice, alice_zaddr, bob_zaddr, amount) |
|||
|
|||
logging.info("Exporting privkey from bob...") |
|||
privkey = bob.z_exportkey(bob_zaddr) |
|||
|
|||
logging.info("Sending post-export txns...") |
|||
for amount in amounts[2:4]: |
|||
z_send(alice, alice_zaddr, bob_zaddr, amount) |
|||
|
|||
print("Bob amounts:", amounts[:4]) |
|||
verify_utxos(bob, amounts[:4], bob_zaddr) |
|||
# verify_utxos(charlie, []) |
|||
|
|||
logging.info("Importing privkey into charlie...") |
|||
# z_importkey rescan defaults to "whenkeyisnew", so should rescan here |
|||
charlie.z_importkey(privkey) |
|||
ipk_zaddr = find_imported_key(charlie, bob_zaddr) |
|||
|
|||
# z_importkey should have rescanned for new key, so this should pass: |
|||
verify_utxos(charlie, amounts[:4], ipk_zaddr) |
|||
|
|||
# Verify idempotent behavior: |
|||
charlie.z_importkey(privkey) |
|||
ipk_zaddr2 = find_imported_key(charlie, bob_zaddr) |
|||
|
|||
# amounts should be unchanged |
|||
verify_utxos(charlie, amounts[:4], ipk_zaddr2) |
|||
|
|||
logging.info("Sending post-import txns...") |
|||
for amount in amounts[4:]: |
|||
z_send(alice, alice_zaddr, bob_zaddr, amount) |
|||
|
|||
verify_utxos(bob, amounts, bob_zaddr) |
|||
verify_utxos(charlie, amounts, ipk_zaddr) |
|||
verify_utxos(charlie, amounts, ipk_zaddr2) |
|||
|
|||
# Try to reproduce zombie balance reported in #1936 |
|||
# At generated zaddr, receive ZEC, and send ZEC back out. bob -> alice |
|||
for amount in amounts[:2]: |
|||
print("Sending amount from bob to alice: ", amount) |
|||
z_send(bob, bob_zaddr, alice_zaddr, amount) |
|||
|
|||
balance = float(sum(amounts) - sum(amounts[:2])) |
|||
assert_equal(z_getbalance(bob, bob_zaddr), balance) |
|||
|
|||
# z_import onto new node "david" (blockchain rescan, default or True?) |
|||
david.z_importkey(privkey) |
|||
d_ipk_zaddr = find_imported_key(david, bob_zaddr) |
|||
|
|||
# Check if amt bob spent is deducted for charlie and david |
|||
assert_equal(z_getbalance(charlie, ipk_zaddr), balance) |
|||
assert_equal(z_getbalance(david, d_ipk_zaddr), balance) |
|||
|
|||
if __name__ == '__main__': |
|||
ZkeyImportExportTest().main() |
@ -1,48 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of interfaces for the "extended radix-2" evaluation domain. |
|||
|
|||
Roughly, the domain has size m = 2^{k+1} and consists of |
|||
"the m-th roots of unity" union "a coset of these roots". |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libsnark, developed by SCIPR Lab |
|||
* and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef EXTENDED_RADIX2_DOMAIN_HPP_ |
|||
#define EXTENDED_RADIX2_DOMAIN_HPP_ |
|||
|
|||
#include "algebra/evaluation_domain/evaluation_domain.hpp" |
|||
|
|||
namespace libsnark { |
|||
|
|||
template<typename FieldT> |
|||
class extended_radix2_domain : public evaluation_domain<FieldT> { |
|||
public: |
|||
|
|||
size_t small_m; |
|||
FieldT omega; |
|||
FieldT shift; |
|||
|
|||
extended_radix2_domain(const size_t m); |
|||
|
|||
void FFT(std::vector<FieldT> &a); |
|||
void iFFT(std::vector<FieldT> &a); |
|||
void cosetFFT(std::vector<FieldT> &a, const FieldT &g); |
|||
void icosetFFT(std::vector<FieldT> &a, const FieldT &g); |
|||
std::vector<FieldT> lagrange_coeffs(const FieldT &t); |
|||
FieldT get_element(const size_t idx); |
|||
FieldT compute_Z(const FieldT &t); |
|||
void add_poly_Z(const FieldT &coeff, std::vector<FieldT> &H); |
|||
void divide_by_Z_on_coset(std::vector<FieldT> &P); |
|||
|
|||
}; |
|||
|
|||
} // libsnark
|
|||
|
|||
#include "algebra/evaluation_domain/domains/extended_radix2_domain.tcc" |
|||
|
|||
#endif // EXTENDED_RADIX2_DOMAIN_HPP_
|
@ -1,180 +0,0 @@ |
|||
/** @file |
|||
***************************************************************************** |
|||
|
|||
Implementation of interfaces for the "extended radix-2" evaluation domain. |
|||
|
|||
See extended_radix2_domain.hpp . |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libsnark, developed by SCIPR Lab |
|||
* and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef EXTENDED_RADIX2_DOMAIN_TCC_ |
|||
|
|||
#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp" |
|||
|
|||
namespace libsnark { |
|||
|
|||
template<typename FieldT> |
|||
extended_radix2_domain<FieldT>::extended_radix2_domain(const size_t m) : evaluation_domain<FieldT>(m) |
|||
{ |
|||
assert(m > 1); |
|||
|
|||
const size_t logm = log2(m); |
|||
|
|||
assert(logm == FieldT::s + 1); |
|||
|
|||
small_m = m/2; |
|||
omega = get_root_of_unity<FieldT>(small_m); |
|||
shift = coset_shift<FieldT>(); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void extended_radix2_domain<FieldT>::FFT(std::vector<FieldT> &a) |
|||
{ |
|||
assert(a.size() == this->m); |
|||
|
|||
std::vector<FieldT> a0(small_m, FieldT::zero()); |
|||
std::vector<FieldT> a1(small_m, FieldT::zero()); |
|||
|
|||
const FieldT shift_to_small_m = shift^bigint<1>(small_m); |
|||
|
|||
FieldT shift_i = FieldT::one(); |
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
a0[i] = a[i] + a[small_m + i]; |
|||
a1[i] = shift_i * (a[i] + shift_to_small_m * a[small_m + i]); |
|||
|
|||
shift_i *= shift; |
|||
} |
|||
|
|||
_basic_radix2_FFT(a0, omega); |
|||
_basic_radix2_FFT(a1, omega); |
|||
|
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
a[i] = a0[i]; |
|||
a[i+small_m] = a1[i]; |
|||
} |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void extended_radix2_domain<FieldT>::iFFT(std::vector<FieldT> &a) |
|||
{ |
|||
assert(a.size() == this->m); |
|||
|
|||
// note: this is not in-place |
|||
std::vector<FieldT> a0(a.begin(), a.begin() + small_m); |
|||
std::vector<FieldT> a1(a.begin() + small_m, a.end()); |
|||
|
|||
const FieldT omega_inverse = omega.inverse(); |
|||
_basic_radix2_FFT(a0, omega_inverse); |
|||
_basic_radix2_FFT(a1, omega_inverse); |
|||
|
|||
const FieldT shift_to_small_m = shift^bigint<1>(small_m); |
|||
const FieldT sconst = (FieldT(small_m) * (FieldT::one()-shift_to_small_m)).inverse(); |
|||
|
|||
const FieldT shift_inverse = shift.inverse(); |
|||
FieldT shift_inverse_i = FieldT::one(); |
|||
|
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
a[i] = sconst * (-shift_to_small_m * a0[i] + shift_inverse_i * a1[i]); |
|||
a[i+small_m] = sconst * (a0[i] - shift_inverse_i * a1[i]); |
|||
|
|||
shift_inverse_i *= shift_inverse; |
|||
} |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void extended_radix2_domain<FieldT>::cosetFFT(std::vector<FieldT> &a, const FieldT &g) |
|||
{ |
|||
_multiply_by_coset(a, g); |
|||
FFT(a); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void extended_radix2_domain<FieldT>::icosetFFT(std::vector<FieldT> &a, const FieldT &g) |
|||
{ |
|||
iFFT(a); |
|||
_multiply_by_coset(a, g.inverse()); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
std::vector<FieldT> extended_radix2_domain<FieldT>::lagrange_coeffs(const FieldT &t) |
|||
{ |
|||
const std::vector<FieldT> T0 = _basic_radix2_lagrange_coeffs(small_m, t); |
|||
const std::vector<FieldT> T1 = _basic_radix2_lagrange_coeffs(small_m, t * shift.inverse()); |
|||
|
|||
std::vector<FieldT> result(this->m, FieldT::zero()); |
|||
|
|||
const FieldT t_to_small_m = t ^ bigint<1>(small_m); |
|||
const FieldT shift_to_small_m = shift ^ bigint<1>(small_m); |
|||
const FieldT one_over_denom = (shift_to_small_m - FieldT::one()).inverse(); |
|||
const FieldT T0_coeff = (t_to_small_m - shift_to_small_m) * (-one_over_denom); |
|||
const FieldT T1_coeff = (t_to_small_m - FieldT::one()) * one_over_denom; |
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
result[i] = T0[i] * T0_coeff; |
|||
result[i+small_m] = T1[i] * T1_coeff; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
FieldT extended_radix2_domain<FieldT>::get_element(const size_t idx) |
|||
{ |
|||
if (idx < small_m) |
|||
{ |
|||
return omega^idx; |
|||
} |
|||
else |
|||
{ |
|||
return shift*(omega^(idx-small_m)); |
|||
} |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
FieldT extended_radix2_domain<FieldT>::compute_Z(const FieldT &t) |
|||
{ |
|||
return ((t^small_m) - FieldT::one()) * ((t^small_m) - (shift^small_m)); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void extended_radix2_domain<FieldT>::add_poly_Z(const FieldT &coeff, std::vector<FieldT> &H) |
|||
{ |
|||
assert(H.size() == this->m+1); |
|||
const FieldT shift_to_small_m = shift^small_m; |
|||
|
|||
H[this->m] += coeff; |
|||
H[small_m] -= coeff * (shift_to_small_m + FieldT::one()); |
|||
H[0] += coeff * shift_to_small_m; |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void extended_radix2_domain<FieldT>::divide_by_Z_on_coset(std::vector<FieldT> &P) |
|||
{ |
|||
const FieldT coset = FieldT::multiplicative_generator; |
|||
|
|||
const FieldT coset_to_small_m = coset^small_m; |
|||
const FieldT shift_to_small_m = shift^small_m; |
|||
|
|||
const FieldT Z0 = (coset_to_small_m - FieldT::one()) * (coset_to_small_m - shift_to_small_m); |
|||
const FieldT Z1 = (coset_to_small_m*shift_to_small_m - FieldT::one()) * (coset_to_small_m * shift_to_small_m - shift_to_small_m); |
|||
|
|||
const FieldT Z0_inverse = Z0.inverse(); |
|||
const FieldT Z1_inverse = Z1.inverse(); |
|||
|
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
P[i] *= Z0_inverse; |
|||
P[i+small_m] *= Z1_inverse; |
|||
} |
|||
} |
|||
|
|||
} // libsnark |
|||
|
|||
#endif // EXTENDED_RADIX2_DOMAIN_TCC_ |
@ -1,50 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of interfaces for the "step radix-2" evaluation domain. |
|||
|
|||
Roughly, the domain has size m = 2^k + 2^r and consists of |
|||
"the 2^k-th roots of unity" union "a coset of 2^r-th roots of unity". |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libsnark, developed by SCIPR Lab |
|||
* and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef STEP_RADIX2_DOMAIN_HPP_ |
|||
#define STEP_RADIX2_DOMAIN_HPP_ |
|||
|
|||
#include "algebra/evaluation_domain/evaluation_domain.hpp" |
|||
|
|||
namespace libsnark { |
|||
|
|||
template<typename FieldT> |
|||
class step_radix2_domain : public evaluation_domain<FieldT> { |
|||
public: |
|||
|
|||
size_t big_m; |
|||
size_t small_m; |
|||
FieldT omega; |
|||
FieldT big_omega; |
|||
FieldT small_omega; |
|||
|
|||
step_radix2_domain(const size_t m); |
|||
|
|||
void FFT(std::vector<FieldT> &a); |
|||
void iFFT(std::vector<FieldT> &a); |
|||
void cosetFFT(std::vector<FieldT> &a, const FieldT &g); |
|||
void icosetFFT(std::vector<FieldT> &a, const FieldT &g); |
|||
std::vector<FieldT> lagrange_coeffs(const FieldT &t); |
|||
FieldT get_element(const size_t idx); |
|||
FieldT compute_Z(const FieldT &t); |
|||
void add_poly_Z(const FieldT &coeff, std::vector<FieldT> &H); |
|||
void divide_by_Z_on_coset(std::vector<FieldT> &P); |
|||
|
|||
}; |
|||
|
|||
} // libsnark
|
|||
|
|||
#include "algebra/evaluation_domain/domains/step_radix2_domain.tcc" |
|||
|
|||
#endif // STEP_RADIX2_DOMAIN_HPP_
|
@ -1,247 +0,0 @@ |
|||
/** @file |
|||
***************************************************************************** |
|||
|
|||
Implementation of interfaces for the "step radix-2" evaluation domain. |
|||
|
|||
See step_radix2_domain.hpp . |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libsnark, developed by SCIPR Lab |
|||
* and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef STEP_RADIX2_DOMAIN_TCC_ |
|||
|
|||
#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp" |
|||
|
|||
namespace libsnark { |
|||
|
|||
template<typename FieldT> |
|||
step_radix2_domain<FieldT>::step_radix2_domain(const size_t m) : evaluation_domain<FieldT>(m) |
|||
{ |
|||
assert(m > 1); |
|||
|
|||
big_m = UINT64_C(1)<<(log2(m)-1); |
|||
small_m = m - big_m; |
|||
|
|||
assert(small_m == UINT64_C(1)<<log2(small_m)); |
|||
|
|||
omega = get_root_of_unity<FieldT>(UINT64_C(1)<<log2(m)); // rounded! |
|||
big_omega = omega.squared(); |
|||
small_omega = get_root_of_unity<FieldT>(small_m); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void step_radix2_domain<FieldT>::FFT(std::vector<FieldT> &a) |
|||
{ |
|||
assert(a.size() == this->m); |
|||
std::vector<FieldT> c(big_m, FieldT::zero()); |
|||
std::vector<FieldT> d(big_m, FieldT::zero()); |
|||
|
|||
FieldT omega_i = FieldT::one(); |
|||
for (size_t i = 0; i < big_m; ++i) |
|||
{ |
|||
c[i] = (i < small_m ? a[i] + a[i+big_m] : a[i]); |
|||
d[i] = omega_i * (i < small_m ? a[i] - a[i+big_m] : a[i]); |
|||
omega_i *= omega; |
|||
} |
|||
|
|||
std::vector<FieldT> e(small_m, FieldT::zero()); |
|||
const size_t compr = UINT64_C(1)<<(log2(big_m) - log2(small_m)); |
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
for (size_t j = 0; j < compr; ++j) |
|||
{ |
|||
e[i] += d[i + j * small_m]; |
|||
} |
|||
} |
|||
|
|||
_basic_radix2_FFT(c, omega.squared()); |
|||
_basic_radix2_FFT(e, get_root_of_unity<FieldT>(small_m)); |
|||
|
|||
for (size_t i = 0; i < big_m; ++i) |
|||
{ |
|||
a[i] = c[i]; |
|||
} |
|||
|
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
a[i+big_m] = e[i]; |
|||
} |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void step_radix2_domain<FieldT>::iFFT(std::vector<FieldT> &a) |
|||
{ |
|||
assert(a.size() == this->m); |
|||
|
|||
std::vector<FieldT> U0(a.begin(), a.begin() + big_m); |
|||
std::vector<FieldT> U1(a.begin() + big_m, a.end()); |
|||
|
|||
_basic_radix2_FFT(U0, omega.squared().inverse()); |
|||
_basic_radix2_FFT(U1, get_root_of_unity<FieldT>(small_m).inverse()); |
|||
|
|||
const FieldT U0_size_inv = FieldT(big_m).inverse(); |
|||
for (size_t i = 0; i < big_m; ++i) |
|||
{ |
|||
U0[i] *= U0_size_inv; |
|||
} |
|||
|
|||
const FieldT U1_size_inv = FieldT(small_m).inverse(); |
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
U1[i] *= U1_size_inv; |
|||
} |
|||
|
|||
std::vector<FieldT> tmp = U0; |
|||
FieldT omega_i = FieldT::one(); |
|||
for (size_t i = 0; i < big_m; ++i) |
|||
{ |
|||
tmp[i] *= omega_i; |
|||
omega_i *= omega; |
|||
} |
|||
|
|||
// save A_suffix |
|||
for (size_t i = small_m; i < big_m; ++i) |
|||
{ |
|||
a[i] = U0[i]; |
|||
} |
|||
|
|||
const size_t compr = UINT64_C(1)<<(log2(big_m) - log2(small_m)); |
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
for (size_t j = 1; j < compr; ++j) |
|||
{ |
|||
U1[i] -= tmp[i + j * small_m]; |
|||
} |
|||
} |
|||
|
|||
const FieldT omega_inv = omega.inverse(); |
|||
FieldT omega_inv_i = FieldT::one(); |
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
U1[i] *= omega_inv_i; |
|||
omega_inv_i *= omega_inv; |
|||
} |
|||
|
|||
// compute A_prefix |
|||
const FieldT over_two = FieldT(2).inverse(); |
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
a[i] = (U0[i]+U1[i]) * over_two; |
|||
} |
|||
|
|||
// compute B2 |
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
a[big_m + i] = (U0[i]-U1[i]) * over_two; |
|||
} |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void step_radix2_domain<FieldT>::cosetFFT(std::vector<FieldT> &a, const FieldT &g) |
|||
{ |
|||
_multiply_by_coset(a, g); |
|||
FFT(a); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void step_radix2_domain<FieldT>::icosetFFT(std::vector<FieldT> &a, const FieldT &g) |
|||
{ |
|||
iFFT(a); |
|||
_multiply_by_coset(a, g.inverse()); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
std::vector<FieldT> step_radix2_domain<FieldT>::lagrange_coeffs(const FieldT &t) |
|||
{ |
|||
std::vector<FieldT> inner_big = _basic_radix2_lagrange_coeffs(big_m, t); |
|||
std::vector<FieldT> inner_small = _basic_radix2_lagrange_coeffs(small_m, t * omega.inverse()); |
|||
|
|||
std::vector<FieldT> result(this->m, FieldT::zero()); |
|||
|
|||
const FieldT L0 = (t^small_m)-(omega^small_m); |
|||
const FieldT omega_to_small_m = omega^small_m; |
|||
const FieldT big_omega_to_small_m = big_omega ^ small_m; |
|||
FieldT elt = FieldT::one(); |
|||
for (size_t i = 0; i < big_m; ++i) |
|||
{ |
|||
result[i] = inner_big[i] * L0 * (elt - omega_to_small_m).inverse(); |
|||
elt *= big_omega_to_small_m; |
|||
} |
|||
|
|||
const FieldT L1 = ((t^big_m)-FieldT::one()) * ((omega^big_m) - FieldT::one()).inverse(); |
|||
|
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
result[big_m + i] = L1 * inner_small[i]; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
FieldT step_radix2_domain<FieldT>::get_element(const size_t idx) |
|||
{ |
|||
if (idx < big_m) |
|||
{ |
|||
return big_omega^idx; |
|||
} |
|||
else |
|||
{ |
|||
return omega * (small_omega^(idx-big_m)); |
|||
} |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
FieldT step_radix2_domain<FieldT>::compute_Z(const FieldT &t) |
|||
{ |
|||
return ((t^big_m) - FieldT::one()) * ((t^small_m) - (omega^small_m)); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void step_radix2_domain<FieldT>::add_poly_Z(const FieldT &coeff, std::vector<FieldT> &H) |
|||
{ |
|||
assert(H.size() == this->m+1); |
|||
const FieldT omega_to_small_m = omega^small_m; |
|||
|
|||
H[this->m] += coeff; |
|||
H[big_m] -= coeff * omega_to_small_m; |
|||
H[small_m] -= coeff; |
|||
H[0] += coeff * omega_to_small_m; |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void step_radix2_domain<FieldT>::divide_by_Z_on_coset(std::vector<FieldT> &P) |
|||
{ |
|||
// (c^{2^k}-1) * (c^{2^r} * w^{2^{r+1}*i) - w^{2^r}) |
|||
const FieldT coset = FieldT::multiplicative_generator; |
|||
|
|||
const FieldT Z0 = (coset^big_m) - FieldT::one(); |
|||
const FieldT coset_to_small_m_times_Z0 = (coset^small_m) * Z0; |
|||
const FieldT omega_to_small_m_times_Z0 = (omega^small_m) * Z0; |
|||
const FieldT omega_to_2small_m = omega^(2*small_m); |
|||
FieldT elt = FieldT::one(); |
|||
|
|||
for (size_t i = 0; i < big_m; ++i) |
|||
{ |
|||
P[i] *= (coset_to_small_m_times_Z0 * elt - omega_to_small_m_times_Z0).inverse(); |
|||
elt *= omega_to_2small_m; |
|||
} |
|||
|
|||
// (c^{2^k}*w^{2^k}-1) * (c^{2^k} * w^{2^r} - w^{2^r}) |
|||
|
|||
const FieldT Z1 = ((((coset*omega)^big_m) - FieldT::one()) * (((coset * omega)^small_m) - (omega^small_m))); |
|||
const FieldT Z1_inverse = Z1.inverse(); |
|||
|
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
P[big_m + i] *= Z1_inverse; |
|||
} |
|||
|
|||
} |
|||
|
|||
} // libsnark |
|||
|
|||
#endif // STEP_RADIX2_DOMAIN_TCC_ |
@ -1,122 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
Declaration of arithmetic in the finite field F[p^3]. |
|||
***************************************************************************** |
|||
* @author This file is part of libsnark, developed by SCIPR Lab |
|||
* and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef FP3_HPP_ |
|||
#define FP3_HPP_ |
|||
#include "algebra/fields/fp.hpp" |
|||
#include <vector> |
|||
|
|||
namespace libsnark { |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
class Fp3_model; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
std::ostream& operator<<(std::ostream &, const Fp3_model<n, modulus> &); |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
std::istream& operator>>(std::istream &, Fp3_model<n, modulus> &); |
|||
|
|||
/**
|
|||
* Arithmetic in the field F[p^3]. |
|||
* |
|||
* Let p := modulus. This interface provides arithmetic for the extension field |
|||
* Fp3 = Fp[U]/(U^3-non_residue), where non_residue is in Fp. |
|||
* |
|||
* ASSUMPTION: p = 1 (mod 6) |
|||
*/ |
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
class Fp3_model { |
|||
public: |
|||
typedef Fp_model<n, modulus> my_Fp; |
|||
|
|||
static bigint<3*n> euler; // (modulus^3-1)/2
|
|||
static unsigned long long s; // modulus^3 = 2^s * t + 1
|
|||
static bigint<3*n> t; // with t odd
|
|||
static bigint<3*n> t_minus_1_over_2; // (t-1)/2
|
|||
static my_Fp non_residue; // X^6-non_residue irreducible over Fp; used for constructing Fp3 = Fp[X] / (X^3 - non_residue)
|
|||
static Fp3_model<n, modulus> nqr; // a quadratic nonresidue in Fp3
|
|||
static Fp3_model<n, modulus> nqr_to_t; // nqr^t
|
|||
static my_Fp Frobenius_coeffs_c1[3]; // non_residue^((modulus^i-1)/3) for i=0,1,2
|
|||
static my_Fp Frobenius_coeffs_c2[3]; // non_residue^((2*modulus^i-2)/3) for i=0,1,2
|
|||
|
|||
my_Fp c0, c1, c2; |
|||
Fp3_model() {}; |
|||
Fp3_model(const my_Fp& c0, const my_Fp& c1, const my_Fp& c2) : c0(c0), c1(c1), c2(c2) {}; |
|||
|
|||
void clear() { c0.clear(); c1.clear(); c2.clear(); } |
|||
void print() const { printf("c0/c1/c2:\n"); c0.print(); c1.print(); c2.print(); } |
|||
|
|||
static Fp3_model<n, modulus> zero(); |
|||
static Fp3_model<n, modulus> one(); |
|||
static Fp3_model<n, modulus> random_element(); |
|||
|
|||
bool is_zero() const { return c0.is_zero() && c1.is_zero() && c2.is_zero(); } |
|||
bool operator==(const Fp3_model &other) const; |
|||
bool operator!=(const Fp3_model &other) const; |
|||
|
|||
Fp3_model operator+(const Fp3_model &other) const; |
|||
Fp3_model operator-(const Fp3_model &other) const; |
|||
Fp3_model operator*(const Fp3_model &other) const; |
|||
Fp3_model operator-() const; |
|||
Fp3_model squared() const; |
|||
Fp3_model inverse() const; |
|||
Fp3_model Frobenius_map(unsigned long power) const; |
|||
Fp3_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate)
|
|||
|
|||
template<mp_size_t m> |
|||
Fp3_model operator^(const bigint<m> &other) const; |
|||
|
|||
static unsigned long long size_in_bits() { return 3*my_Fp::size_in_bits(); } |
|||
static bigint<n> base_field_char() { return modulus; } |
|||
|
|||
friend std::ostream& operator<< <n, modulus>(std::ostream &out, const Fp3_model<n, modulus> &el); |
|||
friend std::istream& operator>> <n, modulus>(std::istream &in, Fp3_model<n, modulus> &el); |
|||
}; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
std::ostream& operator<<(std::ostream& out, const std::vector<Fp3_model<n, modulus> > &v); |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
std::istream& operator>>(std::istream& in, std::vector<Fp3_model<n, modulus> > &v); |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n, modulus> operator*(const Fp_model<n, modulus> &lhs, const Fp3_model<n, modulus> &rhs); |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
bigint<3*n> Fp3_model<n, modulus>::euler; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
unsigned long long Fp3_model<n, modulus>::s; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
bigint<3*n> Fp3_model<n, modulus>::t; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
bigint<3*n> Fp3_model<n, modulus>::t_minus_1_over_2; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp_model<n, modulus> Fp3_model<n, modulus>::non_residue; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n, modulus> Fp3_model<n, modulus>::nqr; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n, modulus> Fp3_model<n, modulus>::nqr_to_t; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp_model<n, modulus> Fp3_model<n, modulus>::Frobenius_coeffs_c1[3]; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp_model<n, modulus> Fp3_model<n, modulus>::Frobenius_coeffs_c2[3]; |
|||
|
|||
} // libsnark
|
|||
#include "algebra/fields/fp3.tcc" |
|||
|
|||
#endif // FP3_HPP_
|
@ -1,259 +0,0 @@ |
|||
/** @file |
|||
***************************************************************************** |
|||
Implementation of arithmetic in the finite field F[p^3]. |
|||
***************************************************************************** |
|||
* @author This file is part of libsnark, developed by SCIPR Lab |
|||
* and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef FP3_TCC_ |
|||
#define FP3_TCC_ |
|||
|
|||
#include "algebra/fields/field_utils.hpp" |
|||
|
|||
namespace libsnark { |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::zero() |
|||
{ |
|||
return Fp3_model<n, modulus>(my_Fp::zero(), my_Fp::zero(), my_Fp::zero()); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::one() |
|||
{ |
|||
return Fp3_model<n, modulus>(my_Fp::one(), my_Fp::zero(), my_Fp::zero()); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::random_element() |
|||
{ |
|||
Fp3_model<n, modulus> r; |
|||
r.c0 = my_Fp::random_element(); |
|||
r.c1 = my_Fp::random_element(); |
|||
r.c2 = my_Fp::random_element(); |
|||
|
|||
return r; |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
bool Fp3_model<n,modulus>::operator==(const Fp3_model<n,modulus> &other) const |
|||
{ |
|||
return (this->c0 == other.c0 && this->c1 == other.c1 && this->c2 == other.c2); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
bool Fp3_model<n,modulus>::operator!=(const Fp3_model<n,modulus> &other) const |
|||
{ |
|||
return !(operator==(other)); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::operator+(const Fp3_model<n,modulus> &other) const |
|||
{ |
|||
return Fp3_model<n,modulus>(this->c0 + other.c0, |
|||
this->c1 + other.c1, |
|||
this->c2 + other.c2); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::operator-(const Fp3_model<n,modulus> &other) const |
|||
{ |
|||
return Fp3_model<n,modulus>(this->c0 - other.c0, |
|||
this->c1 - other.c1, |
|||
this->c2 - other.c2); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n, modulus> operator*(const Fp_model<n, modulus> &lhs, const Fp3_model<n, modulus> &rhs) |
|||
{ |
|||
return Fp3_model<n,modulus>(lhs*rhs.c0, |
|||
lhs*rhs.c1, |
|||
lhs*rhs.c2); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::operator*(const Fp3_model<n,modulus> &other) const |
|||
{ |
|||
/* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (Karatsuba) */ |
|||
const my_Fp |
|||
&A = other.c0, &B = other.c1, &C = other.c2, |
|||
&a = this->c0, &b = this->c1, &c = this->c2; |
|||
const my_Fp aA = a*A; |
|||
const my_Fp bB = b*B; |
|||
const my_Fp cC = c*C; |
|||
|
|||
return Fp3_model<n,modulus>(aA + non_residue*((b+c)*(B+C)-bB-cC), |
|||
(a+b)*(A+B)-aA-bB+non_residue*cC, |
|||
(a+c)*(A+C)-aA+bB-cC); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::operator-() const |
|||
{ |
|||
return Fp3_model<n,modulus>(-this->c0, |
|||
-this->c1, |
|||
-this->c2); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::squared() const |
|||
{ |
|||
/* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (CH-SQR2) */ |
|||
const my_Fp |
|||
&a = this->c0, &b = this->c1, &c = this->c2; |
|||
const my_Fp s0 = a.squared(); |
|||
const my_Fp ab = a*b; |
|||
const my_Fp s1 = ab + ab; |
|||
const my_Fp s2 = (a - b + c).squared(); |
|||
const my_Fp bc = b*c; |
|||
const my_Fp s3 = bc + bc; |
|||
const my_Fp s4 = c.squared(); |
|||
|
|||
return Fp3_model<n,modulus>(s0 + non_residue * s3, |
|||
s1 + non_residue * s4, |
|||
s1 + s2 + s3 - s0 - s4); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::inverse() const |
|||
{ |
|||
const my_Fp |
|||
&a = this->c0, &b = this->c1, &c = this->c2; |
|||
|
|||
/* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 17 */ |
|||
const my_Fp t0 = a.squared(); |
|||
const my_Fp t1 = b.squared(); |
|||
const my_Fp t2 = c.squared(); |
|||
const my_Fp t3 = a*b; |
|||
const my_Fp t4 = a*c; |
|||
const my_Fp t5 = b*c; |
|||
const my_Fp c0 = t0 - non_residue * t5; |
|||
const my_Fp c1 = non_residue * t2 - t3; |
|||
const my_Fp c2 = t1 - t4; // typo in paper referenced above. should be "-" as per Scott, but is "*" |
|||
const my_Fp t6 = (a * c0 + non_residue * (c * c1 + b * c2)).inverse(); |
|||
return Fp3_model<n,modulus>(t6 * c0, t6 * c1, t6 * c2); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::Frobenius_map(unsigned long power) const |
|||
{ |
|||
return Fp3_model<n,modulus>(c0, |
|||
Frobenius_coeffs_c1[power % 3] * c1, |
|||
Frobenius_coeffs_c2[power % 3] * c2); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::sqrt() const |
|||
{ |
|||
Fp3_model<n,modulus> one = Fp3_model<n,modulus>::one(); |
|||
|
|||
unsigned long long v = Fp3_model<n,modulus>::s; |
|||
Fp3_model<n,modulus> z = Fp3_model<n,modulus>::nqr_to_t; |
|||
Fp3_model<n,modulus> w = (*this)^Fp3_model<n,modulus>::t_minus_1_over_2; |
|||
Fp3_model<n,modulus> x = (*this) * w; |
|||
Fp3_model<n,modulus> b = x * w; // b = (*this)^t |
|||
|
|||
#if DEBUG |
|||
// check if square with euler's criterion |
|||
Fp3_model<n,modulus> check = b; |
|||
for (size_t i = 0; i < v-1; ++i) |
|||
{ |
|||
check = check.squared(); |
|||
} |
|||
if (check != one) |
|||
{ |
|||
assert(0); |
|||
} |
|||
#endif |
|||
|
|||
// compute square root with Tonelli--Shanks |
|||
// (does not terminate if not a square!) |
|||
|
|||
while (b != one) |
|||
{ |
|||
unsigned long long m = 0; |
|||
Fp3_model<n,modulus> b2m = b; |
|||
while (b2m != one) |
|||
{ |
|||
/* invariant: b2m = b^(2^m) after entering this loop */ |
|||
b2m = b2m.squared(); |
|||
m += 1; |
|||
} |
|||
|
|||
int j = v-m-1; |
|||
w = z; |
|||
while (j > 0) |
|||
{ |
|||
w = w.squared(); |
|||
--j; |
|||
} // w = z^2^(v-m-1) |
|||
|
|||
z = w.squared(); |
|||
b = b * z; |
|||
x = x * w; |
|||
v = m; |
|||
} |
|||
|
|||
return x; |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
template<mp_size_t m> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::operator^(const bigint<m> &pow) const |
|||
{ |
|||
return power<Fp3_model<n, modulus> >(*this, pow); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
std::ostream& operator<<(std::ostream &out, const Fp3_model<n, modulus> &el) |
|||
{ |
|||
out << el.c0 << OUTPUT_SEPARATOR << el.c1 << OUTPUT_SEPARATOR << el.c2; |
|||
return out; |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
std::istream& operator>>(std::istream &in, Fp3_model<n, modulus> &el) |
|||
{ |
|||
in >> el.c0 >> el.c1 >> el.c2; |
|||
return in; |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
std::ostream& operator<<(std::ostream& out, const std::vector<Fp3_model<n, modulus> > &v) |
|||
{ |
|||
out << v.size() << "\n"; |
|||
for (const Fp3_model<n, modulus>& t : v) |
|||
{ |
|||
out << t << OUTPUT_NEWLINE; |
|||
} |
|||
|
|||
return out; |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
std::istream& operator>>(std::istream& in, std::vector<Fp3_model<n, modulus> > &v) |
|||
{ |
|||
v.clear(); |
|||
|
|||
unsigned long long s; |
|||
in >> s; |
|||
|
|||
char b; |
|||
in.read(&b, 1); |
|||
|
|||
v.reserve(s); |
|||
|
|||
for (size_t i = 0; i < s; ++i) |
|||
{ |
|||
Fp3_model<n, modulus> el; |
|||
in >> el; |
|||
v.emplace_back(el); |
|||
} |
|||
|
|||
return in; |
|||
} |
|||
|
|||
} // libsnark |
|||
#endif // FP3_TCC_ |
Loading…
Reference in new issue